12 #include "../utils/DeclRefExprUtils.h" 13 #include "../utils/FixItHintUtils.h" 14 #include "../utils/Matchers.h" 18 namespace performance {
21 void recordFixes(
const VarDecl &Var, ASTContext &Context,
22 DiagnosticBuilder &Diagnostic) {
24 if (!Var.getType().isLocalConstQualified())
34 auto ConstReference = referenceType(pointee(qualType(isConstQualified())));
35 auto ConstOrConstReference =
36 allOf(anyOf(ConstReference, isConstQualified()),
37 unless(allOf(pointerType(), unless(pointerType(pointee(
38 qualType(isConstQualified())))))));
46 auto ConstRefReturningMethodCall =
47 cxxMemberCallExpr(callee(cxxMethodDecl(returns(ConstReference))),
48 on(declRefExpr(to(varDecl().bind(
"objectArg")))));
49 auto ConstRefReturningFunctionCall =
50 callExpr(callee(functionDecl(returns(ConstReference))),
51 unless(callee(cxxMethodDecl())));
53 auto localVarCopiedFrom = [](
const internal::Matcher<Expr> &CopyCtorArg) {
57 has(varDecl(hasLocalStorage(),
62 hasDeclaration(cxxConstructorDecl(
63 isCopyConstructor())),
64 hasArgument(0, CopyCtorArg))
71 Finder->addMatcher(localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall,
72 ConstRefReturningMethodCall)),
75 Finder->addMatcher(localVarCopiedFrom(declRefExpr(
76 to(varDecl(hasLocalStorage()).bind(
"oldVarDecl")))),
81 const MatchFinder::MatchResult &Result) {
82 const auto *NewVar = Result.Nodes.getNodeAs<VarDecl>(
"newVarDecl");
83 const auto *OldVar = Result.Nodes.getNodeAs<VarDecl>(
"oldVarDecl");
84 const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>(
"objectArg");
85 const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>(
"blockStmt");
86 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctorCall");
90 Result.Nodes.getNodeAs<DeclStmt>(
"declStmt")->isSingleDecl() &&
91 !NewVar->getLocation().isMacroID();
96 for (
unsigned int i = 1; i < CtorCall->getNumArgs(); ++i)
97 if (!CtorCall->getArg(i)->isDefaultArgument())
100 if (OldVar ==
nullptr) {
101 handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
104 handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix,
109 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
110 const VarDecl &Var,
const Stmt &BlockStmt,
bool IssueFix,
111 const VarDecl *ObjectArg, ASTContext &Context) {
112 bool IsConstQualified = Var.getType().isConstQualified();
115 if (ObjectArg !=
nullptr &&
120 diag(Var.getLocation(),
121 IsConstQualified ?
"the const qualified variable %0 is " 122 "copy-constructed from a const reference; " 123 "consider making it a const reference" 124 :
"the variable %0 is copy-constructed from a " 125 "const reference but is only used as const " 126 "reference; consider making it a const reference")
129 recordFixes(Var, Context, Diagnostic);
132 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
133 const VarDecl &NewVar,
const VarDecl &OldVar,
const Stmt &BlockStmt,
134 bool IssueFix, ASTContext &Context) {
139 auto Diagnostic =
diag(NewVar.getLocation(),
140 "local copy %0 of the variable %1 is never modified; " 141 "consider avoiding the copy")
142 << &NewVar << &OldVar;
144 recordFixes(NewVar, Context, Diagnostic);
bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context)
Returns true if all DeclRefExpr to the variable within Stmt do not modify it.
llvm::Optional< bool > isExpensiveToCopy(QualType Type, const ASTContext &Context)
Returns true if Type is expensive to copy.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
FixItHint changeVarDeclToConst(const VarDecl &Var)
Creates fix to make VarDecl const qualified.
FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context)
Creates fix to make VarDecl a reference by adding &.