10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
23 auto CheckTemplate = [](
const TemplateSpecializationType *Spec) {
24 if (!Spec || !Spec->getTemplateName().getAsTemplateDecl()) {
27 const NamedDecl *TypeDecl =
28 Spec->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
29 return TypeDecl->isInStdNamespace() &&
30 (TypeDecl->getName().equals(
"enable_if") ||
31 TypeDecl->getName().equals(
"enable_if_t"));
33 const Type *BaseType = Node.getTypePtr();
35 while (BaseType->isPointerType() || BaseType->isReferenceType()) {
36 BaseType = BaseType->getPointeeType().getTypePtr();
39 if (
const auto *Dependent = BaseType->getAs<DependentNameType>()) {
40 BaseType = Dependent->getQualifier()->getAsType();
44 if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>())) {
46 }
else if (
const auto *Elaborated = BaseType->getAs<ElaboratedType>()) {
47 if (
const auto *Qualifier = Elaborated->getQualifier()->getAsType()) {
48 if (CheckTemplate(
Qualifier->getAs<TemplateSpecializationType>())) {
56 clang::ast_matchers::internal::Matcher<QualType>, TypeMatcher) {
57 return Node.hasDefaultArgument() &&
58 TypeMatcher.matches(Node.getDefaultArgument(), Finder,
Builder);
62 void ForwardingReferenceOverloadCheck::registerMatchers(MatchFinder *Finder) {
63 auto ForwardingRefParm =
65 hasType(qualType(rValueReferenceType(),
66 references(templateTypeParmType(hasDeclaration(
67 templateTypeParmDecl().bind(
"type-parm-decl")))),
68 unless(references(isConstQualified())))))
71 DeclarationMatcher findOverload =
73 hasParameter(0, ForwardingRefParm),
74 unless(hasAnyParameter(
76 parmVarDecl(hasType(isEnableIf())))),
77 unless(hasParent(functionTemplateDecl(has(templateTypeParmDecl(
79 hasDefaultArgument(isEnableIf())))))))
81 Finder->addMatcher(findOverload,
this);
84 void ForwardingReferenceOverloadCheck::check(
85 const MatchFinder::MatchResult &Result) {
86 const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>(
"parm-var");
87 const auto *TypeParmDecl =
88 Result.Nodes.getNodeAs<TemplateTypeParmDecl>(
"type-parm-decl");
92 const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext());
95 const FunctionTemplateDecl *FuncTemplate =
96 FuncForParam->getDescribedFunctionTemplate();
103 const TemplateParameterList *Params = FuncTemplate->getTemplateParameters();
104 if (!llvm::is_contained(*Params, TypeParmDecl))
108 const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>(
"ctor");
109 for (
auto Iter = Ctor->param_begin() + 1; Iter != Ctor->param_end(); ++Iter) {
110 if (!(*Iter)->hasDefaultArg())
113 bool EnabledCopy =
false, DisabledCopy =
false, EnabledMove =
false,
114 DisabledMove =
false;
115 for (
const auto *OtherCtor : Ctor->getParent()->ctors()) {
116 if (OtherCtor->isCopyOrMoveConstructor()) {
117 if (OtherCtor->isDeleted() || OtherCtor->getAccess() == AS_private)
118 (OtherCtor->isCopyConstructor() ? DisabledCopy : DisabledMove) =
true;
120 (OtherCtor->isCopyConstructor() ? EnabledCopy : EnabledMove) =
true;
123 bool Copy = (!EnabledMove && !DisabledMove && !DisabledCopy) || EnabledCopy;
124 bool Move = !DisabledMove || EnabledMove;
127 diag(Ctor->getLocation(),
128 "constructor accepting a forwarding reference can "
129 "hide the %select{copy|move|copy and move}0 constructor%s1")
130 << (Copy && Move ? 2 : (Copy ? 0 : 1)) << Copy + Move;
131 for (
const auto *OtherCtor : Ctor->getParent()->ctors()) {
132 if (OtherCtor->isCopyOrMoveConstructor() && !OtherCtor->isDeleted() &&
133 OtherCtor->getAccess() != AS_private) {
134 diag(OtherCtor->getLocation(),
135 "%select{copy|move}0 constructor declared here", DiagnosticIDs::Note)
136 << OtherCtor->isMoveConstructor();