1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 // Find places where various things are passed by value.
16 // It's not very efficient, because we generally end up copying it twice - once into the parameter and
17 // again into the destination.
18 // They should rather be passed by reference.
20 // Generally recommending lambda capture by-ref rather than by-copy is even more
21 // problematic than with function parameters, as a lambda instance can easily
22 // outlive a referrenced variable. So once lambdas start to get used in more
23 // sophisticated ways than passing them into standard algorithms, this plugin's
24 // advice, at least for explicit captures, will need to be revisited.
29 public RecursiveASTVisitor
<PassStuffByRef
>, public loplugin::Plugin
32 explicit PassStuffByRef(InstantiationData
const & data
): Plugin(data
) {}
34 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
36 bool VisitFunctionDecl(const FunctionDecl
* decl
);
38 bool VisitLambdaExpr(const LambdaExpr
* expr
);
41 bool isFat(QualType type
, std::string
* name
);
44 bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl
* functionDecl
) {
45 if (ignoreLocation(functionDecl
)) {
48 // only warn on the definition/prototype of the function,
49 // not on the function implementation
50 if ((functionDecl
->isThisDeclarationADefinition()
51 && functionDecl
->getPreviousDecl() != nullptr)
52 || functionDecl
->isDeleted())
56 // only consider base declarations, not overriden ones, or we warn on methods that
57 // are overriding stuff from external libraries
58 if (isa
<CXXMethodDecl
>(functionDecl
)) {
59 CXXMethodDecl
const * m
= dyn_cast
<CXXMethodDecl
>(functionDecl
);
60 if (m
->size_overridden_methods() > 0)
63 unsigned n
= functionDecl
->getNumParams();
64 for (unsigned i
= 0; i
!= n
; ++i
) {
65 const ParmVarDecl
* pvDecl
= functionDecl
->getParamDecl(i
);
67 if (isFat(pvDecl
->getType(), &name
)) {
69 DiagnosticsEngine::Warning
,
70 ("passing '%0' by value, rather pass by reference, e.g., '%0"
72 pvDecl
->getLocation())
73 << name
<< pvDecl
->getSourceRange();
79 bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr
* expr
) {
80 if (ignoreLocation(expr
)) {
83 for (auto i(expr
->capture_begin()); i
!= expr
->capture_end(); ++i
) {
84 if (i
->getCaptureKind() == LambdaCaptureKind::LCK_ByCopy
) {
86 if (isFat(i
->getCapturedVar()->getType(), &name
)) {
88 DiagnosticsEngine::Warning
,
89 ("%0 capture of '%1' variable by copy, rather use capture"
90 " by reference---UNLESS THE LAMBDA OUTLIVES THE VARIABLE"),
92 << (i
->isImplicit() ? "implicit" : "explicit") << name
93 << expr
->getSourceRange();
100 bool PassStuffByRef::isFat(QualType type
, std::string
* name
) {
101 if (!type
->isRecordType()) {
104 *name
= type
.getUnqualifiedType().getCanonicalType().getAsString();
105 if (*name
== "class rtl::OUString" || *name
== "class rtl::OString"
106 || name
->find("class com::sun::star::uno::Sequence") == 0)
110 if (type
->isIncompleteType()) {
113 Type
const * t2
= type
.getTypePtrOrNull();
115 && compiler
.getASTContext().getTypeSizeInChars(t2
).getQuantity() > 64;
118 loplugin::Plugin::Registration
< PassStuffByRef
> X("passstuffbyref");
122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */