38 const CXXRecordDecl *Derived) {
39 return llvm::any_of(CRTP->friends(), [&](
const FriendDecl *Friend) {
40 const TypeSourceInfo *const FriendType = Friend->getFriendType();
44 return declaresSameEntity(FriendType->getType()->getAsCXXRecordDecl(),
51 const CXXRecordDecl *Derived) {
53 const bool AnyOf = llvm::any_of(
54 CRTP->getTemplateArgs().asArray(), [&](
const TemplateArgument &Arg) {
56 return Arg.getKind() == TemplateArgument::Type &&
57 declaresSameEntity(Arg.getAsType()->getAsCXXRecordDecl(),
61 return AnyOf ? CRTP->getSpecializedTemplate()
62 ->getTemplateParameters()
69 const std::string &OriginalAccess) {
70 const ASTContext &ASTCtx = Ctor->getASTContext();
71 const SourceManager &SM = ASTCtx.getSourceManager();
72 const LangOptions &LangOpts = ASTCtx.getLangOpts();
76 SourceLocation CtorBeginLoc = Ctor->getBeginLoc();
77 if (CtorBeginLoc.isMacroID() &&
78 !Lexer::isAtStartOfMacroExpansion(CtorBeginLoc, SM, LangOpts,
82 const SourceLocation CtorEndLoc = Lexer::getLocForEndOfToken(
83 Ctor->isExplicitlyDefaulted()
87 if (CtorEndLoc.isInvalid())
90 return {FixItHint::CreateInsertion(CtorBeginLoc,
"private:\n"),
91 FixItHint::CreateInsertion(CtorEndLoc,
92 '\n' + OriginalAccess +
':' +
'\n')};
107 const MatchFinder::MatchResult &Result) {
108 const auto *CRTPInstantiation =
109 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"crtp");
110 const auto *DerivedRecord = Result.Nodes.getNodeAs<CXXRecordDecl>(
"derived");
111 const CXXRecordDecl *CRTPDeclaration =
112 CRTPInstantiation->getSpecializedTemplate()->getTemplatedDecl();
114 if (!CRTPDeclaration->hasDefinition())
117 const auto *DerivedTemplateParameter =
120 assert(DerivedTemplateParameter &&
121 "No template parameter corresponds to the derived class of the CRTP.");
123 const bool NeedsFriend =
125 DerivedTemplateParameter) &&
128 const FixItHint HintFriend = FixItHint::CreateInsertion(
129 CRTPDeclaration->getBraceRange().getEnd(),
130 "friend " + DerivedTemplateParameter->getNameAsString() +
';' +
'\n');
133 diag(CRTPDeclaration->getLocation(),
134 "the CRTP cannot be constructed from the derived class; consider "
135 "declaring the derived class as friend")
139 const auto WithFriendHintIfNeeded = [&](
const DiagnosticBuilder &Diag,
145 if (!CRTPDeclaration->hasUserDeclaredConstructor()) {
146 const bool IsStruct = CRTPDeclaration->isStruct();
148 WithFriendHintIfNeeded(
149 diag(CRTPDeclaration->getLocation(),
150 "the implicit default constructor of the CRTP is publicly "
151 "accessible; consider making it private%select{| and declaring "
152 "the derived class as friend}0")
154 << FixItHint::CreateInsertion(
155 CRTPDeclaration->getBraceRange().getBegin().getLocWithOffset(
157 (IsStruct ?
"\nprivate:\n" :
"\n") +
158 CRTPDeclaration->getNameAsString() +
"() = default;\n" +
159 (IsStruct ?
"public:\n" :
"")),
163 for (
auto &&Ctor : CRTPDeclaration->ctors()) {
164 if (Ctor->getAccess() == AS_private || Ctor->isDeleted())
167 const bool IsPublic = Ctor->getAccess() == AS_public;
168 const std::string Access = IsPublic ?
"public" :
"protected";
171 WithFriendHintIfNeeded(
172 diag(Ctor->getLocation(),
173 "%0 constructor allows the CRTP to be %select{inherited "
174 "from|constructed}1 as a regular template class; consider making "
175 "it private%select{| and declaring the derived class as friend}2")
176 << Access << IsPublic << NeedsFriend << CtorHints,
177 NeedsFriend && !CtorHints.empty());