10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
27 const auto TransparentFunctors =
28 classTemplateSpecializationDecl(
29 unless(hasAnyTemplateArgument(refersToType(voidType()))),
30 hasAnyName(
"::std::plus",
"::std::minus",
"::std::multiplies",
31 "::std::divides",
"::std::modulus",
"::std::negate",
32 "::std::equal_to",
"::std::not_equal_to",
"::std::greater",
33 "::std::less",
"::std::greater_equal",
"::std::less_equal",
34 "::std::logical_and",
"::std::logical_or",
35 "::std::logical_not",
"::std::bit_and",
"::std::bit_or",
36 "::std::bit_xor",
"::std::bit_not"))
37 .bind(
"FunctorClass");
42 unless(elaboratedType()),
43 hasDeclaration(classTemplateSpecializationDecl(
44 unless(hasAnyTemplateArgument(templateArgument(refersToType(
45 qualType(pointsTo(qualType(isAnyCharacter()))))))),
46 hasAnyTemplateArgument(
47 templateArgument(refersToType(qualType(hasDeclaration(
48 TransparentFunctors))))
50 .bind(
"FunctorParentLoc"),
58 Finder->addMatcher(cxxConstructExpr(hasDeclaration(cxxMethodDecl(
59 ofClass(TransparentFunctors))),
60 unless(isInTemplateInstantiation()))
65static const StringRef
Message =
"prefer transparent functors '%0<>'";
69 while (Result.isNull() && !
Loc.isNull()) {
70 Result =
Loc.getAs<T>();
71 Loc =
Loc.getNextTypeLoc();
77 const MatchFinder::MatchResult &Result) {
78 const auto *FuncClass =
79 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"FunctorClass");
80 if (
const auto *FuncInst =
81 Result.Nodes.getNodeAs<CXXConstructExpr>(
"FuncInst")) {
82 diag(FuncInst->getBeginLoc(),
Message) << FuncClass->getName();
86 const auto *Functor = Result.Nodes.getNodeAs<TemplateArgument>(
"Functor");
87 const auto FunctorParentLoc =
88 Result.Nodes.getNodeAs<TypeLoc>(
"FunctorParentLoc")
89 ->getAs<TemplateSpecializationTypeLoc>();
91 if (!FunctorParentLoc)
95 const auto *FunctorParentType =
96 FunctorParentLoc.getType()->castAs<TemplateSpecializationType>();
97 for (; ArgNum < FunctorParentType->template_arguments().size(); ++ArgNum) {
98 const TemplateArgument &Arg =
99 FunctorParentType->template_arguments()[ArgNum];
100 if (Arg.getKind() != TemplateArgument::Type)
102 QualType ParentArgType = Arg.getAsType();
103 if (ParentArgType->isRecordType() &&
104 ParentArgType->getAsCXXRecordDecl() ==
105 Functor->getAsType()->getAsCXXRecordDecl())
109 if (ArgNum == FunctorParentType->template_arguments().size())
111 TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum);
112 auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>(
113 FunctorLoc.getTypeSourceInfo()->getTypeLoc());
114 if (FunctorTypeLoc.isNull())
117 SourceLocation ReportLoc = FunctorLoc.getLocation();
118 if (ReportLoc.isInvalid())
121 << FixItHint::CreateRemoval(
122 FunctorTypeLoc.getArgLoc(0).getSourceRange());
llvm::SmallString< 256U > Name
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.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
UseTransparentFunctorsCheck(StringRef Name, ClangTidyContext *Context)
static T getInnerTypeLocAs(TypeLoc Loc)
constexpr llvm::StringLiteral Message
llvm::StringMap< ClangTidyValue > OptionMap