10 #include "../utils/OptionsUtils.h" 19 return Node.hasExplicitTemplateArgs();
22 const auto DefaultContainersWithPushBack =
23 "::std::vector; ::std::list; ::std::deque";
24 const auto DefaultSmartPointers =
25 "::std::shared_ptr; ::std::unique_ptr; ::std::auto_ptr; ::std::weak_ptr";
26 const auto DefaultTupleTypes =
"::std::pair; ::std::tuple";
27 const auto DefaultTupleMakeFunctions =
"::std::make_pair; ::std::make_tuple";
32 IgnoreImplicitConstructors(Options.get(
"IgnoreImplicitConstructors", 0)),
34 "ContainersWithPushBack", DefaultContainersWithPushBack))),
36 Options.get(
"SmartPointers", DefaultSmartPointers))),
38 Options.get(
"TupleTypes", DefaultTupleTypes))),
40 Options.get(
"TupleMakeFunctions", DefaultTupleMakeFunctions))) {}
54 auto CallPushBack = cxxMemberCallExpr(
55 hasDeclaration(functionDecl(hasName(
"push_back"))),
56 on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
57 ContainersWithPushBack.begin(), ContainersWithPushBack.end()))))));
63 auto IsCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
64 SmallVector<StringRef, 5>(SmartPointers.begin(), SmartPointers.end())))));
67 auto BitFieldAsArgument = hasAnyArgument(
68 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
71 auto InitializerListAsArgument = hasAnyArgument(
72 ignoringImplicit(cxxConstructExpr(isListInitialization())));
75 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
77 auto ConstructingDerived =
78 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
81 auto IsPrivateCtor = hasDeclaration(cxxConstructorDecl(isPrivate()));
83 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
84 has(cxxStdInitializerListExpr()));
88 auto SoughtConstructExpr =
90 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
91 InitializerListAsArgument, NewExprAsArgument,
92 ConstructingDerived, IsPrivateCtor)))
94 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
96 auto MakeTuple = ignoringImplicit(
98 callee(expr(ignoringImplicit(declRefExpr(
99 unless(hasExplicitTemplateArgs()),
100 to(functionDecl(hasAnyName(SmallVector<StringRef, 2>(
101 TupleMakeFunctions.begin(), TupleMakeFunctions.end())))))))))
106 auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
107 has(materializeTemporaryExpr(MakeTuple)),
108 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
109 SmallVector<StringRef, 2>(TupleTypes.begin(), TupleTypes.end())))))));
111 auto SoughtParam = materializeTemporaryExpr(
112 anyOf(has(MakeTuple), has(MakeTupleCtor),
113 HasConstructExpr, has(cxxFunctionalCastExpr(HasConstructExpr))));
115 Finder->addMatcher(cxxMemberCallExpr(CallPushBack, has(SoughtParam),
116 unless(isInTemplateInstantiation()))
122 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"call");
123 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
124 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
125 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
127 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
128 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
131 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
132 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
134 auto Diag =
diag(Call->getExprLoc(),
"use emplace_back instead of push_back");
136 if (FunctionNameSourceRange.getBegin().isMacroID())
139 const auto *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
140 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, EmplacePrefix);
142 const SourceRange CallParensRange =
143 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
144 MakeCall->getRParenLoc())
145 : CtorCall->getParenOrBraceRange();
148 if (CallParensRange.getBegin().isInvalid())
151 const SourceLocation ExprBegin =
152 MakeCall ? MakeCall->getExprLoc() : CtorCall->getExprLoc();
155 const auto ParamCallSourceRange =
158 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
160 CallParensRange.getEnd(), CallParensRange.getEnd()));
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
AST_MATCHER(Expr, isMacroID)
Base class for all clang-tidy checks.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.