10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
20 auto CheckTemplate = [](
const TemplateSpecializationType *Spec) {
24 const TemplateDecl *TDecl = Spec->getTemplateName().getAsTemplateDecl();
26 return TDecl && TDecl->isInStdNamespace() &&
27 (TDecl->getName() ==
"enable_if" ||
28 TDecl->getName() ==
"enable_if_t");
30 const Type *BaseType =
Node.getTypePtr();
32 while (BaseType->isPointerType() || BaseType->isReferenceType()) {
33 BaseType = BaseType->getPointeeType().getTypePtr();
36 if (
const auto *Dependent = BaseType->getAs<DependentNameType>()) {
37 BaseType = Dependent->getQualifier()->getAsType();
41 if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>()))
43 if (
const auto *Elaborated = BaseType->getAs<ElaboratedType>()) {
44 if (
const auto *Q = Elaborated->getQualifier())
45 if (
const auto *Qualifier = Q->getAsType()) {
46 if (CheckTemplate(Qualifier->getAs<TemplateSpecializationType>())) {
54 clang::ast_matchers::internal::Matcher<QualType>, TypeMatcher) {
55 return Node.hasDefaultArgument() &&
57 Node.getDefaultArgument().getArgument().getAsType(), Finder,
60AST_MATCHER(TemplateDecl, hasAssociatedConstraints) {
61 return Node.hasAssociatedConstraints();
66 auto ForwardingRefParm =
68 hasType(qualType(rValueReferenceType(),
69 references(templateTypeParmType(hasDeclaration(
70 templateTypeParmDecl().bind(
"type-parm-decl")))),
71 unless(references(isConstQualified())))))
74 DeclarationMatcher FindOverload =
76 hasParameter(0, ForwardingRefParm), unless(isDeleted()),
77 unless(hasAnyParameter(
79 parmVarDecl(hasType(isEnableIf())))),
80 unless(hasParent(functionTemplateDecl(anyOf(
83 hasAssociatedConstraints(),
85 has(templateTypeParmDecl(hasDefaultArgument(isEnableIf()))),
87 has(nonTypeTemplateParmDecl(
88 hasType(isEnableIf()),
89 anyOf(hasDescendant(cxxBoolLiteral()),
90 hasDescendant(cxxNullPtrLiteralExpr()),
91 hasDescendant(integerLiteral())))))))))
93 Finder->addMatcher(FindOverload,
this);
97 const MatchFinder::MatchResult &Result) {
98 const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>(
"parm-var");
99 const auto *TypeParmDecl =
100 Result.Nodes.getNodeAs<TemplateTypeParmDecl>(
"type-parm-decl");
104 const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext());
107 const FunctionTemplateDecl *FuncTemplate =
108 FuncForParam->getDescribedFunctionTemplate();
115 const TemplateParameterList *Params = FuncTemplate->getTemplateParameters();
116 if (!llvm::is_contained(*Params, TypeParmDecl))
120 const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>(
"ctor");
121 for (
const auto *Param : llvm::drop_begin(Ctor->parameters())) {
122 if (!Param->hasDefaultArg())
125 bool EnabledCopy =
false, DisabledCopy =
false, EnabledMove =
false,
126 DisabledMove =
false;
127 for (
const auto *OtherCtor : Ctor->getParent()->ctors()) {
128 if (OtherCtor->isCopyOrMoveConstructor()) {
129 if (OtherCtor->isDeleted() || OtherCtor->getAccess() == AS_private)
130 (OtherCtor->isCopyConstructor() ? DisabledCopy : DisabledMove) =
true;
132 (OtherCtor->isCopyConstructor() ? EnabledCopy : EnabledMove) =
true;
135 bool Copy = (!EnabledMove && !DisabledMove && !DisabledCopy) || EnabledCopy;
136 bool Move = !DisabledMove || EnabledMove;
139 diag(Ctor->getLocation(),
140 "constructor accepting a forwarding reference can "
141 "hide the %select{copy|move|copy and move}0 constructor%s1")
142 << (Copy &&
Move ? 2 : (Copy ? 0 : 1)) << Copy +
Move;
143 for (
const auto *OtherCtor : Ctor->getParent()->ctors()) {
144 if (OtherCtor->isCopyOrMoveConstructor() && !OtherCtor->isDeleted() &&
145 OtherCtor->getAccess() != AS_private) {
146 diag(OtherCtor->getLocation(),
147 "%select{copy|move}0 constructor declared here", DiagnosticIDs::Note)
148 << OtherCtor->isMoveConstructor();
CodeCompletionBuilder Builder
::clang::DynTypedNode Node
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
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.
AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N)
Matches functions that have at least the specified amount of parameters.
AST_MATCHER(clang::VarDecl, hasConstantDeclaration)