11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
20 UseTransparentFunctorsCheck::UseTransparentFunctorsCheck(
22 :
ClangTidyCheck(Name, Context), SafeMode(Options.get(
"SafeMode", 0)) {}
33 const auto TransparentFunctors =
34 classTemplateSpecializationDecl(
35 unless(hasAnyTemplateArgument(refersToType(voidType()))),
36 hasAnyName(
"::std::plus",
"::std::minus",
"::std::multiplies",
37 "::std::divides",
"::std::modulus",
"::std::negate",
38 "::std::equal_to",
"::std::not_equal_to",
"::std::greater",
39 "::std::less",
"::std::greater_equal",
"::std::less_equal",
40 "::std::logical_and",
"::std::logical_or",
41 "::std::logical_not",
"::std::bit_and",
"::std::bit_or",
42 "::std::bit_xor",
"::std::bit_not"))
43 .bind(
"FunctorClass");
48 unless(elaboratedType()),
49 hasDeclaration(classTemplateSpecializationDecl(
50 unless(hasAnyTemplateArgument(templateArgument(refersToType(
51 qualType(pointsTo(qualType(isAnyCharacter()))))))),
52 hasAnyTemplateArgument(
53 templateArgument(refersToType(qualType(hasDeclaration(
54 TransparentFunctors))))
56 .bind(
"FunctorParentLoc"),
64 Finder->addMatcher(cxxConstructExpr(hasDeclaration(cxxMethodDecl(
65 ofClass(TransparentFunctors))),
66 unless(isInTemplateInstantiation()))
71 static const StringRef
Message =
"prefer transparent functors '%0'";
75 while (Result.isNull() && !Loc.isNull()) {
76 Result = Loc.getAs<T>();
77 Loc = Loc.getNextTypeLoc();
83 const MatchFinder::MatchResult &
Result) {
84 const auto *FuncClass =
85 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"FunctorClass");
86 if (
const auto *FuncInst =
87 Result.Nodes.getNodeAs<CXXConstructExpr>(
"FuncInst")) {
89 << (FuncClass->getName() +
"<>").str();
93 const auto *Functor = Result.Nodes.getNodeAs<TemplateArgument>(
"Functor");
94 const auto FunctorParentLoc =
95 Result.Nodes.getNodeAs<TypeLoc>(
"FunctorParentLoc")
96 ->getAs<TemplateSpecializationTypeLoc>();
98 if (!FunctorParentLoc)
102 const auto *FunctorParentType =
103 FunctorParentLoc.getType()->castAs<TemplateSpecializationType>();
104 for (; ArgNum < FunctorParentType->getNumArgs(); ++ArgNum) {
105 const TemplateArgument &Arg = FunctorParentType->getArg(ArgNum);
106 if (Arg.getKind() != TemplateArgument::Type)
108 QualType ParentArgType = Arg.getAsType();
109 if (ParentArgType->isRecordType() &&
110 ParentArgType->getAsCXXRecordDecl() ==
111 Functor->getAsType()->getAsCXXRecordDecl())
115 if (ArgNum == FunctorParentType->getNumArgs())
117 TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum);
118 auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>(
119 FunctorLoc.getTypeSourceInfo()->getTypeLoc());
120 if (FunctorTypeLoc.isNull())
123 SourceLocation ReportLoc = FunctorLoc.getLocation();
124 diag(ReportLoc,
Message) << (FuncClass->getName() +
"<>").str()
125 << FixItHint::CreateRemoval(
126 FunctorTypeLoc.getArgLoc(0).getSourceRange());
SourceLocation Loc
'#' location in the include directive
LangOptions getLangOpts() const
Returns the language options from the context.
std::unique_ptr< ast_matchers::MatchFinder > Finder
static T getInnerTypeLocAs(TypeLoc Loc)
static const StringRef Message
Base class for all clang-tidy checks.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
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.
std::map< std::string, std::string > OptionMap
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.