11 #include "../utils/DeclRefExprUtils.h"
12 #include "../utils/FixItHintUtils.h"
13 #include "../utils/Matchers.h"
14 #include "../utils/OptionsUtils.h"
15 #include "clang/Basic/Diagnostic.h"
19 namespace performance {
22 void recordFixes(
const VarDecl &Var, ASTContext &Context,
25 if (!Var.getType().isLocalConstQualified()) {
27 Var, Context, DeclSpec::TQ::TQ_const))
44 auto ConstReference = referenceType(pointee(qualType(isConstQualified())));
52 auto ConstRefReturningMethodCall =
53 cxxMemberCallExpr(callee(cxxMethodDecl(returns(ConstReference))),
54 on(declRefExpr(to(varDecl().bind(
"objectArg")))));
55 auto ConstRefReturningFunctionCall =
56 callExpr(callee(functionDecl(returns(ConstReference))),
57 unless(callee(cxxMethodDecl())));
59 auto localVarCopiedFrom = [
this](
const internal::Matcher<Expr> &CopyCtorArg) {
63 has(varDecl(hasLocalStorage(),
67 unless(hasDeclaration(namedDecl(
68 matchers::matchesAnyListedName(
71 hasInitializer(traverse(
72 ast_type_traits::TK_AsIs,
74 hasDeclaration(cxxConstructorDecl(
75 isCopyConstructor())),
76 hasArgument(0, CopyCtorArg))
83 Finder->addMatcher(localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall,
84 ConstRefReturningMethodCall)),
87 Finder->addMatcher(localVarCopiedFrom(declRefExpr(
88 to(varDecl(hasLocalStorage()).bind(
"oldVarDecl")))),
93 const MatchFinder::MatchResult &Result) {
94 const auto *NewVar = Result.Nodes.getNodeAs<VarDecl>(
"newVarDecl");
95 const auto *OldVar = Result.Nodes.getNodeAs<VarDecl>(
"oldVarDecl");
96 const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>(
"objectArg");
97 const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>(
"blockStmt");
98 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctorCall");
100 TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
105 Result.Nodes.getNodeAs<DeclStmt>(
"declStmt")->isSingleDecl() &&
106 !NewVar->getLocation().isMacroID();
111 for (
unsigned int i = 1; i < CtorCall->getNumArgs(); ++i)
112 if (!CtorCall->getArg(i)->isDefaultArgument())
115 if (OldVar ==
nullptr) {
116 handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
119 handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix,
124 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
125 const VarDecl &Var,
const Stmt &BlockStmt,
bool IssueFix,
126 const VarDecl *ObjectArg, ASTContext &Context) {
127 bool IsConstQualified = Var.getType().isConstQualified();
130 if (ObjectArg !=
nullptr &&
135 diag(Var.getLocation(),
136 IsConstQualified ?
"the const qualified variable %0 is "
137 "copy-constructed from a const reference; "
138 "consider making it a const reference"
139 :
"the variable %0 is copy-constructed from a "
140 "const reference but is only used as const "
141 "reference; consider making it a const reference")
147 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
148 const VarDecl &NewVar,
const VarDecl &OldVar,
const Stmt &BlockStmt,
149 bool IssueFix, ASTContext &Context) {
155 "local copy %0 of the variable %1 is never modified; "
156 "consider avoiding the copy")
157 << &NewVar << &OldVar;