15#include "clang/Frontend/CompilerInstance.h"
16#include "clang/Lex/Lexer.h"
17#include "clang/Lex/Preprocessor.h"
25 return (Name.empty() ? llvm::Twine(
'#') + llvm::Twine(Index + 1)
26 : llvm::Twine(
'\'') + Name + llvm::Twine(
'\''))
31 ASTContext &Context) {
34 decl(forEachDescendant(declRefExpr(
36 unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
37 whileStmt(), doStmt())))))))),
39 return Matches.empty();
45 Inserter(Options.getLocalOrGlobal(
"IncludeStyle",
46 utils::IncludeSorter::IS_LLVM),
47 areDiagsSelfContained()),
49 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))),
50 IgnoreCoroutines(Options.get(
"IgnoreCoroutines", true)) {}
53 const auto ExpensiveValueParamDecl = parmVarDecl(
55 hasCanonicalType(matchers::isExpensiveToCopy()),
56 unless(anyOf(hasCanonicalType(referenceType()),
57 hasDeclaration(namedDecl(
59 decl().bind(
"param"));
63 hasBody(IgnoreCoroutines ? stmt(unless(coroutineBodyStmt()))
65 isDefinition(), unless(isImplicit()),
66 unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))),
67 has(typeLoc(forEach(ExpensiveValueParamDecl))),
68 decl().bind(
"functionDecl"))),
73 const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>(
"param");
74 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
76 TraversalKindScope RAII(*Result.Context, TK_AsIs);
78 FunctionParmMutationAnalyzer *Analyzer =
79 FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
80 *Function, *Result.Context, MutationAnalyzerCache);
81 if (Analyzer->isMutated(Param))
84 const bool IsConstQualified =
85 Param->getType().getCanonicalType().isConstQualified();
92 if (!IsConstQualified) {
94 *Param, *Function, *Result.Context);
95 if (AllDeclRefExprs.size() == 1) {
96 auto CanonicalType = Param->getType().getCanonicalType();
97 const auto &DeclRefExpr = **AllDeclRefExprs.begin();
102 DeclRefExpr, *Function, *Result.Context)) ||
105 DeclRefExpr, *Function, *Result.Context)))) {
116 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
117 Inserter.registerPreprocessor(PP);
122 Options.store(Opts,
"IncludeStyle", Inserter.getStyle());
123 Options.store(Opts,
"AllowedTypes",
125 Options.store(Opts,
"IgnoreCoroutines", IgnoreCoroutines);
129 MutationAnalyzerCache.clear();
133 const ParmVarDecl &Param,
134 ASTContext &Context) {
136 llvm::find(Function.parameters(), &Param) - Function.parameters().begin();
137 const bool IsConstQualified =
138 Param.getType().getCanonicalType().isConstQualified();
141 diag(Param.getLocation(),
142 "the %select{|const qualified }0parameter %1 of type %2 is copied "
144 "invocation%select{ but only used as a const reference|}0; consider "
145 "making it a %select{const |}0reference")
152 const auto *Method = llvm::dyn_cast<CXXMethodDecl>(&Function);
153 if (Param.getBeginLoc().isMacroID() || (Method && Method->isVirtual()) ||
154 Function.getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
156 for (
const auto *FunctionDecl = &Function; FunctionDecl !=
nullptr;
157 FunctionDecl = FunctionDecl->getPreviousDecl()) {
158 const auto &CurrentParam = *FunctionDecl->getParamDecl(Index);
163 if (!CurrentParam.getType().getCanonicalType().isConstQualified()) {
165 CurrentParam, Context, Qualifiers::Const))
172 const DeclRefExpr &CopyArgument,
173 ASTContext &Context) {
175 diag(CopyArgument.getBeginLoc(),
176 "parameter %0 of type %1 is passed by value and only copied once; "
177 "consider moving it to avoid unnecessary copies")
178 << &Param << Param.getType();
180 if (CopyArgument.getBeginLoc().isMacroID())
182 const auto &SM = Context.getSourceManager();
183 auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM,
184 Context.getLangOpts());
185 Diag << FixItHint::CreateInsertion(CopyArgument.getBeginLoc(),
"std::move(")
186 << FixItHint::CreateInsertion(EndLoc,
")")
187 << Inserter.createIncludeInsertion(
188 SM.getFileID(CopyArgument.getBeginLoc()),
"<utility>");
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
SmallPtrSet< const DeclRefExpr *, 16 > allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context)
Returns set of all DeclRefExprs to VarDecl within Stmt.
bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context)
Returns true if DeclRefExpr is the argument of a copy-constructor call expression within Decl.
bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context)
Returns true if DeclRefExpr is the argument of a copy-assignment operator CallExpr within Decl.
FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context)
Creates fix to make VarDecl a reference by adding &.
std::optional< FixItHint > addQualifierToVarDecl(const VarDecl &Var, const ASTContext &Context, Qualifiers::TQ Qualifier, QualifierTarget QualTarget, QualifierPolicy QualPolicy)
Creates fix to qualify VarDecl with the specified Qualifier. Requires that Var is isolated in written...
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
bool hasNonTrivialMoveAssignment(QualType Type)
Return true if Type has a non-trivial move assignment operator.
bool hasNonTrivialMoveConstructor(QualType Type)
Returns true if Type has a non-trivial move constructor.
llvm::StringMap< ClangTidyValue > OptionMap