39 const CXXRecordDecl *Derived) {
40 return llvm::any_of(CRTP->friends(), [&](
const FriendDecl *Friend) {
41 const TypeSourceInfo *const FriendType = Friend->getFriendType();
46 return declaresSameEntity(FriendType->getType()->getAsCXXRecordDecl(),
53 const CXXRecordDecl *Derived) {
55 const bool AnyOf = llvm::any_of(
56 CRTP->getTemplateArgs().asArray(), [&](
const TemplateArgument &Arg) {
58 return Arg.getKind() == TemplateArgument::Type &&
59 declaresSameEntity(Arg.getAsType()->getAsCXXRecordDecl(),
63 return AnyOf ? CRTP->getSpecializedTemplate()
64 ->getTemplateParameters()
71 const std::string &OriginalAccess) {
72 std::vector<FixItHint> Hints;
74 Hints.emplace_back(FixItHint::CreateInsertion(
75 Ctor->getBeginLoc().getLocWithOffset(-1),
"private:\n"));
77 const ASTContext &ASTCtx = Ctor->getASTContext();
78 const SourceLocation CtorEndLoc =
79 Ctor->isExplicitlyDefaulted()
81 ASTCtx.getSourceManager(),
84 Hints.emplace_back(FixItHint::CreateInsertion(
85 CtorEndLoc.getLocWithOffset(1),
'\n' + OriginalAccess +
':' +
'\n'));
102 const MatchFinder::MatchResult &Result) {
103 const auto *CRTPInstantiation =
104 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"crtp");
105 const auto *DerivedRecord = Result.Nodes.getNodeAs<CXXRecordDecl>(
"derived");
106 const CXXRecordDecl *CRTPDeclaration =
107 CRTPInstantiation->getSpecializedTemplate()->getTemplatedDecl();
109 if (!CRTPDeclaration->hasDefinition()) {
113 const auto *DerivedTemplateParameter =
116 assert(DerivedTemplateParameter &&
117 "No template parameter corresponds to the derived class of the CRTP.");
120 DerivedTemplateParameter) &&
123 const FixItHint HintFriend = FixItHint::CreateInsertion(
124 CRTPDeclaration->getBraceRange().getEnd(),
125 "friend " + DerivedTemplateParameter->getNameAsString() +
';' +
'\n');
128 diag(CRTPDeclaration->getLocation(),
129 "the CRTP cannot be constructed from the derived class; consider "
130 "declaring the derived class as friend")
134 auto WithFriendHintIfNeeded = [&](
const DiagnosticBuilder &Diag,
140 if (!CRTPDeclaration->hasUserDeclaredConstructor()) {
141 const bool IsStruct = CRTPDeclaration->isStruct();
143 WithFriendHintIfNeeded(
144 diag(CRTPDeclaration->getLocation(),
145 "the implicit default constructor of the CRTP is publicly "
146 "accessible; consider making it private%select{| and declaring "
147 "the derived class as friend}0")
149 << FixItHint::CreateInsertion(
150 CRTPDeclaration->getBraceRange().getBegin().getLocWithOffset(
152 (IsStruct ?
"\nprivate:\n" :
"\n") +
153 CRTPDeclaration->getNameAsString() +
"() = default;\n" +
154 (IsStruct ?
"public:\n" :
"")),
158 for (
auto &&Ctor : CRTPDeclaration->ctors()) {
159 if (Ctor->getAccess() == AS_private || Ctor->isDeleted())
162 const bool IsPublic = Ctor->getAccess() == AS_public;
163 const std::string Access = IsPublic ?
"public" :
"protected";
165 WithFriendHintIfNeeded(
166 diag(Ctor->getLocation(),
167 "%0 constructor allows the CRTP to be %select{inherited "
168 "from|constructed}1 as a regular template class; consider making "
169 "it private%select{| and declaring the derived class as friend}2")
170 << Access << IsPublic << NeedsFriend