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 std::vector<FixItHint> Hints;
72 Hints.emplace_back(FixItHint::CreateInsertion(
73 Ctor->getBeginLoc().getLocWithOffset(-1),
"private:\n"));
75 const ASTContext &ASTCtx = Ctor->getASTContext();
76 const SourceLocation CtorEndLoc =
77 Ctor->isExplicitlyDefaulted()
79 ASTCtx.getSourceManager(),
82 Hints.emplace_back(FixItHint::CreateInsertion(
83 CtorEndLoc.getLocWithOffset(1),
'\n' + OriginalAccess +
':' +
'\n'));
100 const MatchFinder::MatchResult &Result) {
101 const auto *CRTPInstantiation =
102 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"crtp");
103 const auto *DerivedRecord = Result.Nodes.getNodeAs<CXXRecordDecl>(
"derived");
104 const CXXRecordDecl *CRTPDeclaration =
105 CRTPInstantiation->getSpecializedTemplate()->getTemplatedDecl();
107 if (!CRTPDeclaration->hasDefinition())
110 const auto *DerivedTemplateParameter =
113 assert(DerivedTemplateParameter &&
114 "No template parameter corresponds to the derived class of the CRTP.");
116 const bool NeedsFriend =
118 DerivedTemplateParameter) &&
121 const FixItHint HintFriend = FixItHint::CreateInsertion(
122 CRTPDeclaration->getBraceRange().getEnd(),
123 "friend " + DerivedTemplateParameter->getNameAsString() +
';' +
'\n');
126 diag(CRTPDeclaration->getLocation(),
127 "the CRTP cannot be constructed from the derived class; consider "
128 "declaring the derived class as friend")
132 auto WithFriendHintIfNeeded = [&](
const DiagnosticBuilder &Diag,
138 if (!CRTPDeclaration->hasUserDeclaredConstructor()) {
139 const bool IsStruct = CRTPDeclaration->isStruct();
141 WithFriendHintIfNeeded(
142 diag(CRTPDeclaration->getLocation(),
143 "the implicit default constructor of the CRTP is publicly "
144 "accessible; consider making it private%select{| and declaring "
145 "the derived class as friend}0")
147 << FixItHint::CreateInsertion(
148 CRTPDeclaration->getBraceRange().getBegin().getLocWithOffset(
150 (IsStruct ?
"\nprivate:\n" :
"\n") +
151 CRTPDeclaration->getNameAsString() +
"() = default;\n" +
152 (IsStruct ?
"public:\n" :
"")),
156 for (
auto &&Ctor : CRTPDeclaration->ctors()) {
157 if (Ctor->getAccess() == AS_private || Ctor->isDeleted())
160 const bool IsPublic = Ctor->getAccess() == AS_public;
161 const std::string Access = IsPublic ?
"public" :
"protected";
163 WithFriendHintIfNeeded(
164 diag(Ctor->getLocation(),
165 "%0 constructor allows the CRTP to be %select{inherited "
166 "from|constructed}1 as a regular template class; consider making "
167 "it private%select{| and declaring the derived class as friend}2")
168 << Access << IsPublic << NeedsFriend