11 #include "../utils/DeclRefExprUtils.h"
12 #include "../utils/FixItHintUtils.h"
13 #include "../utils/Matchers.h"
14 #include "../utils/OptionsUtils.h"
15 #include "../utils/TypeTraits.h"
16 #include "clang/Frontend/CompilerInstance.h"
17 #include "clang/Lex/Lexer.h"
18 #include "clang/Lex/Preprocessor.h"
24 namespace performance {
28 std::string paramNameOrIndex(StringRef
Name,
size_t Index) {
29 return (
Name.empty() ? llvm::Twine(
'#') + llvm::Twine(
Index + 1)
34 bool isReferencedOutsideOfCallExpr(
const FunctionDecl &Function,
35 ASTContext &Context) {
36 auto Matches =
match(declRefExpr(to(functionDecl(equalsNode(&Function))),
37 unless(hasAncestor(callExpr()))),
39 return !Matches.empty();
43 ASTContext &Context) {
45 traverse(ast_type_traits::TK_AsIs,
46 decl(forEachDescendant(declRefExpr(
48 unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
49 whileStmt(), doStmt())))))))),
51 return Matches.empty();
55 if (
const auto *SpecializationInfo =
Function.getTemplateSpecializationInfo())
56 if (SpecializationInfo->getTemplateSpecializationKind() ==
57 TSK_ExplicitSpecialization)
59 if (
const auto *Method = llvm::dyn_cast<CXXMethodDecl>(&Function))
60 if (
Method->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization &&
61 Method->getMemberSpecializationInfo()->isExplicitSpecialization())
68 UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
71 IncludeStyle(Options.getLocalOrGlobal(
"IncludeStyle",
72 utils::IncludeSorter::IS_LLVM)),
77 const auto ExpensiveValueParamDecl = parmVarDecl(
80 unless(anyOf(hasCanonicalType(referenceType()),
81 hasDeclaration(namedDecl(
82 matchers::matchesAnyListedName(AllowedTypes))))))),
83 decl().bind(
"param"));
86 ast_type_traits::TK_AsIs,
87 functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()),
88 unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))),
89 has(typeLoc(forEach(ExpensiveValueParamDecl))),
90 unless(isInstantiated()), decl().bind(
"functionDecl"))),
95 const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>(
"param");
96 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
98 TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
100 FunctionParmMutationAnalyzer &Analyzer =
101 MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
103 if (Analyzer.isMutated(Param))
106 const bool IsConstQualified =
107 Param->getType().getCanonicalType().isConstQualified();
114 if (!IsConstQualified) {
116 *Param, *Function, *Result.Context);
117 if (AllDeclRefExprs.size() == 1) {
118 auto CanonicalType = Param->getType().getCanonicalType();
119 const auto &DeclRefExpr = **AllDeclRefExprs.begin();
121 if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context) &&
124 DeclRefExpr, *Function, *Result.Context)) ||
127 DeclRefExpr, *Function, *Result.Context)))) {
128 handleMoveFix(*Param, DeclRefExpr, *Result.Context);
134 const size_t Index = std::find(Function->parameters().begin(),
135 Function->parameters().end(), Param) -
136 Function->parameters().begin();
139 diag(Param->getLocation(),
140 IsConstQualified ?
"the const qualified parameter %0 is "
141 "copied for each invocation; consider "
142 "making it a reference"
143 :
"the parameter %0 is copied for each "
144 "invocation but only used as a const reference; "
145 "consider making it a const reference")
146 << paramNameOrIndex(Param->getName(),
Index);
153 const auto *Method = llvm::dyn_cast<CXXMethodDecl>(Function);
154 if (Param->getBeginLoc().isMacroID() || (Method && Method->isVirtual()) ||
155 isReferencedOutsideOfCallExpr(*Function, *Result.Context) ||
158 for (
const auto *FunctionDecl = Function; FunctionDecl !=
nullptr;
159 FunctionDecl = FunctionDecl->getPreviousDecl()) {
160 const auto &CurrentParam = *FunctionDecl->getParamDecl(
Index);
166 if (!CurrentParam.getType().getCanonicalType().isConstQualified()) {
168 CurrentParam, *Result.Context, DeclSpec::TQ::TQ_const))
175 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
176 Inserter = std::make_unique<utils::IncludeInserter>(SM,
getLangOpts(),
178 PP->addPPCallbacks(Inserter->CreatePPCallbacks());
189 MutationAnalyzers.clear();
192 void UnnecessaryValueParamCheck::handleMoveFix(
const ParmVarDecl &Var,
193 const DeclRefExpr &CopyArgument,
194 const ASTContext &Context) {
195 auto Diag =
diag(CopyArgument.getBeginLoc(),
196 "parameter %0 is passed by value and only copied once; "
197 "consider moving it to avoid unnecessary copies")
200 if (CopyArgument.getBeginLoc().isMacroID())
202 const auto &SM = Context.getSourceManager();
203 auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM,
204 Context.getLangOpts());
205 Diag << FixItHint::CreateInsertion(CopyArgument.getBeginLoc(),
"std::move(")
206 << FixItHint::CreateInsertion(EndLoc,
")")
207 << Inserter->CreateIncludeInsertion(
208 SM.getFileID(CopyArgument.getBeginLoc()),
"utility",