10 #include "../utils/DeclRefExprUtils.h"
11 #include "../utils/FixItHintUtils.h"
12 #include "../utils/Matchers.h"
13 #include "../utils/OptionsUtils.h"
14 #include "../utils/TypeTraits.h"
15 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
16 #include "clang/Basic/Diagnostic.h"
22 namespace performance {
26 WarnOnAllAutoCopies(Options.get(
"WarnOnAllAutoCopies", false)),
31 Options.
store(Opts,
"WarnOnAllAutoCopies", WarnOnAllAutoCopies);
40 auto HasReferenceOrPointerTypeOrIsAllowed = hasType(qualType(
41 unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
42 hasDeclaration(namedDecl(
44 auto IteratorReturnsValueType = cxxOperatorCallExpr(
45 hasOverloadedOperatorName(
"*"),
47 cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()))))));
48 auto NotConstructedByCopy = cxxConstructExpr(
49 hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor()))));
50 auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl()));
52 varDecl(HasReferenceOrPointerTypeOrIsAllowed,
53 unless(hasInitializer(expr(hasDescendant(expr(
54 anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
55 NotConstructedByCopy, ConstructedByConversion)))))));
58 cxxForRangeStmt(hasLoopVariable(LoopVar.bind(
"loopVar")))
64 const auto *Var = Result.Nodes.getNodeAs<VarDecl>(
"loopVar");
67 if (Var->getBeginLoc().isMacroID())
69 if (handleConstValueCopy(*Var, *Result.Context))
71 const auto *ForRange = Result.Nodes.getNodeAs<CXXForRangeStmt>(
"forRange");
72 handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context);
75 bool ForRangeCopyCheck::handleConstValueCopy(
const VarDecl &LoopVar,
76 ASTContext &Context) {
77 if (WarnOnAllAutoCopies) {
79 if (!isa<AutoType>(LoopVar.getType()))
81 }
else if (!LoopVar.getType().isConstQualified()) {
84 llvm::Optional<bool> Expensive =
86 if (!Expensive || !*Expensive)
89 diag(LoopVar.getLocation(),
90 "the loop variable's type is not a reference type; this creates a "
91 "copy in each iteration; consider making this a reference")
93 if (!LoopVar.getType().isConstQualified()) {
95 LoopVar, Context, DeclSpec::TQ::TQ_const))
101 bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
102 const VarDecl &LoopVar,
const CXXForRangeStmt &ForRange,
103 ASTContext &Context) {
104 llvm::Optional<bool> Expensive =
106 if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive)
116 if (!ExprMutationAnalyzer(*ForRange.getBody(), Context).isMutated(&LoopVar) &&
121 LoopVar.getLocation(),
122 "loop variable is copied but only used as const reference; consider "
123 "making it a const reference");
126 LoopVar, Context, DeclSpec::TQ::TQ_const))