Skip to content

Commit 7ba37f4

Browse files
committed
[clang][ExtractAPI] Add support for C++ class templates and concepts
Add has_template template, DeclarationFragmentBuilder functions, and tests for class templates, specializations/partial specs, and concepts. Depends on D157007 Reviewed By: dang Differential Revision: https://reviews.llvm.org/D157076
1 parent d8900f6 commit 7ba37f4

File tree

13 files changed

+1648
-16
lines changed

13 files changed

+1648
-16
lines changed

clang/include/clang/ExtractAPI/API.h

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,86 @@
3636
namespace clang {
3737
namespace extractapi {
3838

39+
class Template {
40+
struct TemplateParameter {
41+
// "class", "typename", or concept name
42+
std::string Type;
43+
std::string Name;
44+
unsigned int Index;
45+
unsigned int Depth;
46+
bool IsParameterPack;
47+
48+
TemplateParameter(std::string Type, std::string Name, unsigned int Index,
49+
unsigned int Depth, bool IsParameterPack)
50+
: Type(Type), Name(Name), Index(Index), Depth(Depth),
51+
IsParameterPack(IsParameterPack) {}
52+
};
53+
54+
struct TemplateConstraint {
55+
// type name of the constraint, if it has one
56+
std::string Type;
57+
std::string Kind;
58+
std::string LHS, RHS;
59+
};
60+
llvm::SmallVector<TemplateParameter> Parameters;
61+
llvm::SmallVector<TemplateConstraint> Constraints;
62+
63+
public:
64+
Template() = default;
65+
66+
Template(const TemplateDecl *Decl) {
67+
for (auto *const Parameter : *Decl->getTemplateParameters()) {
68+
const auto *Param = dyn_cast<TemplateTypeParmDecl>(Parameter);
69+
if (!Param) // some params are null
70+
continue;
71+
std::string Type;
72+
if (Param->hasTypeConstraint())
73+
Type = Param->getTypeConstraint()->getNamedConcept()->getName().str();
74+
else if (Param->wasDeclaredWithTypename())
75+
Type = "typename";
76+
else
77+
Type = "class";
78+
79+
addTemplateParameter(Type, Param->getName().str(), Param->getIndex(),
80+
Param->getDepth(), Param->isParameterPack());
81+
}
82+
}
83+
84+
Template(const ClassTemplatePartialSpecializationDecl *Decl) {
85+
for (auto *const Parameter : *Decl->getTemplateParameters()) {
86+
const auto *Param = dyn_cast<TemplateTypeParmDecl>(Parameter);
87+
if (!Param) // some params are null
88+
continue;
89+
std::string Type;
90+
if (Param->hasTypeConstraint())
91+
Type = Param->getTypeConstraint()->getNamedConcept()->getName().str();
92+
else if (Param->wasDeclaredWithTypename())
93+
Type = "typename";
94+
else
95+
Type = "class";
96+
97+
addTemplateParameter(Type, Param->getName().str(), Param->getIndex(),
98+
Param->getDepth(), Param->isParameterPack());
99+
}
100+
}
101+
102+
const llvm::SmallVector<TemplateParameter> &getParameters() const {
103+
return Parameters;
104+
}
105+
106+
const llvm::SmallVector<TemplateConstraint> &getConstraints() const {
107+
return Constraints;
108+
}
109+
110+
void addTemplateParameter(std::string Type, std::string Name,
111+
unsigned int Index, unsigned int Depth,
112+
bool IsParameterPack) {
113+
Parameters.emplace_back(Type, Name, Index, Depth, IsParameterPack);
114+
}
115+
116+
bool empty() const { return Parameters.empty() && Constraints.empty(); }
117+
};
118+
39119
/// DocComment is a vector of RawComment::CommentLine.
40120
///
41121
/// Each line represents one line of striped documentation comment,
@@ -69,6 +149,10 @@ struct APIRecord {
69149
RK_StaticField,
70150
RK_CXXField,
71151
RK_CXXClass,
152+
RK_ClassTemplate,
153+
RK_ClassTemplateSpecialization,
154+
RK_ClassTemplatePartialSpecialization,
155+
RK_Concept,
72156
RK_CXXStaticMethod,
73157
RK_CXXInstanceMethod,
74158
RK_CXXConstructorMethod,
@@ -644,6 +728,75 @@ struct CXXClassRecord : APIRecord {
644728
virtual void anchor();
645729
};
646730

731+
struct ClassTemplateRecord : CXXClassRecord {
732+
Template Templ;
733+
734+
ClassTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
735+
AvailabilitySet Availabilities, const DocComment &Comment,
736+
DeclarationFragments Declaration,
737+
DeclarationFragments SubHeading, Template Template,
738+
bool IsFromSystemHeader)
739+
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
740+
Declaration, SubHeading, RK_ClassTemplate,
741+
IsFromSystemHeader),
742+
Templ(Template) {}
743+
744+
static bool classof(const APIRecord *Record) {
745+
return Record->getKind() == RK_ClassTemplate;
746+
}
747+
};
748+
749+
struct ClassTemplateSpecializationRecord : CXXClassRecord {
750+
ClassTemplateSpecializationRecord(StringRef USR, StringRef Name,
751+
PresumedLoc Loc,
752+
AvailabilitySet Availabilities,
753+
const DocComment &Comment,
754+
DeclarationFragments Declaration,
755+
DeclarationFragments SubHeading,
756+
bool IsFromSystemHeader)
757+
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
758+
Declaration, SubHeading, RK_ClassTemplateSpecialization,
759+
IsFromSystemHeader) {}
760+
761+
static bool classof(const APIRecord *Record) {
762+
return Record->getKind() == RK_ClassTemplateSpecialization;
763+
}
764+
};
765+
766+
struct ClassTemplatePartialSpecializationRecord : CXXClassRecord {
767+
Template Templ;
768+
ClassTemplatePartialSpecializationRecord(
769+
StringRef USR, StringRef Name, PresumedLoc Loc,
770+
AvailabilitySet Availabilities, const DocComment &Comment,
771+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
772+
Template Template, bool IsFromSystemHeader)
773+
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
774+
Declaration, SubHeading, RK_ClassTemplateSpecialization,
775+
IsFromSystemHeader),
776+
Templ(Template) {}
777+
778+
static bool classof(const APIRecord *Record) {
779+
return Record->getKind() == RK_ClassTemplatePartialSpecialization;
780+
}
781+
};
782+
783+
struct ConceptRecord : APIRecord {
784+
Template Templ;
785+
ConceptRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
786+
AvailabilitySet Availabilities, const DocComment &Comment,
787+
DeclarationFragments Declaration,
788+
DeclarationFragments SubHeading, Template Template,
789+
bool IsFromSystemHeader)
790+
: APIRecord(RK_Concept, USR, Name, Loc, std::move(Availabilities),
791+
LinkageInfo::none(), Comment, Declaration, SubHeading,
792+
IsFromSystemHeader),
793+
Templ(Template) {}
794+
795+
static bool classof(const APIRecord *Record) {
796+
return Record->getKind() == RK_Concept;
797+
}
798+
};
799+
647800
/// This holds information associated with Objective-C categories.
648801
struct ObjCCategoryRecord : ObjCContainerRecord {
649802
SymbolReference Interface;
@@ -779,6 +932,13 @@ template <typename RecordTy> struct has_access : public std::false_type {};
779932
template <> struct has_access<CXXMethodRecord> : public std::true_type {};
780933
template <> struct has_access<CXXFieldRecord> : public std::true_type {};
781934

935+
template <typename RecordTy> struct has_template : public std::false_type {};
936+
template <> struct has_template<ClassTemplateRecord> : public std::true_type {};
937+
template <>
938+
struct has_template<ClassTemplatePartialSpecializationRecord>
939+
: public std::true_type {};
940+
template <> struct has_template<ConceptRecord> : public std::true_type {};
941+
782942
/// APISet holds the set of API records collected from given inputs.
783943
class APISet {
784944
public:
@@ -876,6 +1036,26 @@ class APISet {
8761036
DeclarationFragments Declaration, DeclarationFragments SubHeading,
8771037
APIRecord::RecordKind Kind, bool IsFromSystemHeader);
8781038

1039+
ClassTemplateRecord *
1040+
addClassTemplate(StringRef Name, StringRef USR, PresumedLoc Loc,
1041+
AvailabilitySet Availability, const DocComment &Comment,
1042+
DeclarationFragments Declaration,
1043+
DeclarationFragments SubHeading, Template Template,
1044+
bool IsFromSystemHeader);
1045+
1046+
ClassTemplateSpecializationRecord *addClassTemplateSpecialization(
1047+
StringRef Name, StringRef USR, PresumedLoc Loc,
1048+
AvailabilitySet Availability, const DocComment &Comment,
1049+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
1050+
bool IsFromSystemHeader);
1051+
1052+
ClassTemplatePartialSpecializationRecord *
1053+
addClassTemplatePartialSpecialization(
1054+
StringRef Name, StringRef USR, PresumedLoc Loc,
1055+
AvailabilitySet Availability, const DocComment &Comment,
1056+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
1057+
Template Template, bool IsFromSystemHeader);
1058+
8791059
CXXMethodRecord *
8801060
addCXXMethod(CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
8811061
PresumedLoc Loc, AvailabilitySet Availability,
@@ -890,6 +1070,13 @@ class APISet {
8901070
FunctionSignature Signature, bool IsConstructor, AccessControl Access,
8911071
bool IsFromSystemHeader);
8921072

1073+
ConceptRecord *addConcept(StringRef Name, StringRef USR, PresumedLoc Loc,
1074+
AvailabilitySet Availability,
1075+
const DocComment &Comment,
1076+
DeclarationFragments Declaration,
1077+
DeclarationFragments SubHeading, Template Template,
1078+
bool IsFromSystemHeader);
1079+
8931080
/// Create and add an Objective-C category record into the API set.
8941081
///
8951082
/// Note: the caller is responsible for keeping the StringRef \p Name and
@@ -1018,6 +1205,19 @@ class APISet {
10181205
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
10191206
const RecordMap<StructRecord> &getStructs() const { return Structs; }
10201207
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
1208+
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
1209+
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
1210+
return ClassTemplates;
1211+
}
1212+
const RecordMap<ClassTemplateSpecializationRecord> &
1213+
getClassTemplateSpecializations() const {
1214+
return ClassTemplateSpecializations;
1215+
}
1216+
const RecordMap<ClassTemplatePartialSpecializationRecord> &
1217+
getClassTemplatePartialSpecializations() const {
1218+
return ClassTemplatePartialSpecializations;
1219+
}
1220+
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
10211221
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
10221222
return ObjCCategories;
10231223
}
@@ -1071,10 +1271,15 @@ class APISet {
10711271
llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
10721272
RecordMap<GlobalFunctionRecord> GlobalFunctions;
10731273
RecordMap<GlobalVariableRecord> GlobalVariables;
1274+
RecordMap<ConceptRecord> Concepts;
10741275
RecordMap<StaticFieldRecord> StaticFields;
10751276
RecordMap<EnumRecord> Enums;
10761277
RecordMap<StructRecord> Structs;
10771278
RecordMap<CXXClassRecord> CXXClasses;
1279+
RecordMap<ClassTemplateRecord> ClassTemplates;
1280+
RecordMap<ClassTemplateSpecializationRecord> ClassTemplateSpecializations;
1281+
RecordMap<ClassTemplatePartialSpecializationRecord>
1282+
ClassTemplatePartialSpecializations;
10781283
RecordMap<ObjCCategoryRecord> ObjCCategories;
10791284
RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
10801285
RecordMap<ObjCProtocolRecord> ObjCProtocols;

clang/include/clang/ExtractAPI/DeclarationFragments.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "clang/AST/Decl.h"
2323
#include "clang/AST/DeclCXX.h"
2424
#include "clang/AST/DeclObjC.h"
25+
#include "clang/AST/DeclTemplate.h"
2526
#include "clang/Lex/MacroInfo.h"
2627
#include "llvm/ADT/StringRef.h"
2728
#include <vector>
@@ -161,6 +162,11 @@ class DeclarationFragments {
161162
return *this;
162163
}
163164

165+
DeclarationFragments &pop_back() {
166+
Fragments.pop_back();
167+
return *this;
168+
}
169+
164170
/// Append a text Fragment of a space character.
165171
///
166172
/// \returns a reference to the DeclarationFragments object itself after
@@ -292,6 +298,28 @@ class DeclarationFragmentsBuilder {
292298
static DeclarationFragments
293299
getFragmentsForOverloadedOperator(const CXXMethodDecl *);
294300

301+
static DeclarationFragments
302+
getFragmentsForTemplateParameters(ArrayRef<NamedDecl *>);
303+
304+
static std::string getNameForTemplateArgument(const ArrayRef<NamedDecl *>,
305+
std::string);
306+
307+
static DeclarationFragments
308+
getFragmentsForTemplateArguments(const ArrayRef<TemplateArgument>,
309+
ASTContext &,
310+
const std::optional<ArrayRef<NamedDecl *>>);
311+
312+
static DeclarationFragments getFragmentsForConcept(const ConceptDecl *);
313+
314+
static DeclarationFragments
315+
getFragmentsForRedeclarableTemplate(const RedeclarableTemplateDecl *);
316+
317+
static DeclarationFragments getFragmentsForClassTemplateSpecialization(
318+
const ClassTemplateSpecializationDecl *);
319+
320+
static DeclarationFragments getFragmentsForClassTemplatePartialSpecialization(
321+
const ClassTemplatePartialSpecializationDecl *);
322+
295323
/// Build DeclarationFragments for an Objective-C category declaration
296324
/// ObjCCategoryDecl.
297325
static DeclarationFragments

0 commit comments

Comments
 (0)