Skip to content

Commit

Permalink
[clang][ExtractAPI] Add support for C++ member templates
Browse files Browse the repository at this point in the history
Visit and serialize C++ fields by checking if a var template's context is a CXXRecordDecl in VisitVarTemplateDecl.

Depends on D158027

Reviewed By: dang

Differential Revision: https://reviews.llvm.org/D158029
  • Loading branch information
evelez7 committed Aug 21, 2023
1 parent 0303137 commit 634b2fd
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 11 deletions.
34 changes: 34 additions & 0 deletions clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ struct APIRecord {
RK_Union,
RK_StaticField,
RK_CXXField,
RK_CXXFieldTemplate,
RK_CXXClass,
RK_ClassTemplate,
RK_ClassTemplateSpecialization,
Expand Down Expand Up @@ -530,6 +531,25 @@ struct CXXFieldRecord : APIRecord {
virtual void anchor();
};

struct CXXFieldTemplateRecord : CXXFieldRecord {
Template Templ;

CXXFieldTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities,
const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, AccessControl Access,
Template Template, bool IsFromSystemHeader)
: CXXFieldRecord(RK_CXXFieldTemplate, USR, Name, Loc,
std::move(Availabilities), Comment, Declaration,
SubHeading, Access, IsFromSystemHeader),
Templ(Template) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_CXXFieldTemplate;
}
};

struct CXXMethodRecord : APIRecord {
FunctionSignature Signature;
AccessControl Access;
Expand Down Expand Up @@ -1113,6 +1133,8 @@ struct has_access<CXXMethodTemplateRecord> : public std::true_type {};
template <>
struct has_access<CXXMethodTemplateSpecializationRecord>
: public std::true_type {};
template <>
struct has_access<CXXFieldTemplateRecord> : public std::true_type {};

template <typename RecordTy> struct has_template : public std::false_type {};
template <> struct has_template<ClassTemplateRecord> : public std::true_type {};
Expand All @@ -1127,6 +1149,8 @@ struct has_template<GlobalVariableTemplatePartialSpecializationRecord>
: public std::true_type {};
template <>
struct has_template<CXXMethodTemplateRecord> : public std::true_type {};
template <>
struct has_template<CXXFieldTemplateRecord> : public std::true_type {};

template <>
struct has_template<GlobalFunctionTemplateRecord> : public std::true_type {};
Expand Down Expand Up @@ -1251,6 +1275,12 @@ class APISet {
DeclarationFragments SubHeading,
AccessControl Access, bool IsFromSystemHeader);

CXXFieldTemplateRecord *addCXXFieldTemplate(
APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
AccessControl Access, Template Template, bool IsFromSystemHeader);

CXXClassRecord *
addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
Expand Down Expand Up @@ -1482,6 +1512,9 @@ class APISet {
getCXXMethodTemplateSpecializations() const {
return CXXMethodTemplateSpecializations;
}
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
return CXXFieldTemplates;
}
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
return ClassTemplates;
Expand Down Expand Up @@ -1564,6 +1597,7 @@ class APISet {
RecordMap<CXXMethodTemplateRecord> CXXMethodTemplates;
RecordMap<CXXMethodTemplateSpecializationRecord>
CXXMethodTemplateSpecializations;
RecordMap<CXXFieldTemplateRecord> CXXFieldTemplates;
RecordMap<ClassTemplateRecord> ClassTemplates;
RecordMap<ClassTemplateSpecializationRecord> ClassTemplateSpecializations;
RecordMap<ClassTemplatePartialSpecializationRecord>
Expand Down
31 changes: 20 additions & 11 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,20 +697,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitVarTemplateDecl(
Context.getDiagnostics());

// Build declaration fragments and sub-heading for the variable.
DeclarationFragments Declaration =
DeclarationFragmentsBuilder::getFragmentsForVarTemplate(
Decl->getTemplatedDecl());
DeclarationFragments Declaration;
Declaration
.append(DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
Decl))
.append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(
Decl->getTemplatedDecl()));
// Inject template fragments before var fragments.
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);

// Inject template fragments before var fragments.
Declaration.insert(
Declaration.begin(),
DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(Decl));

API.addGlobalVariableTemplate(Name, USR, Loc, AvailabilitySet(Decl), Linkage,
Comment, Declaration, SubHeading,
Template(Decl), isInSystemHeader(Decl));
SmallString<128> ParentUSR;
index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
ParentUSR);
if (Decl->getDeclContext()->getDeclKind() == Decl::CXXRecord)
API.addCXXFieldTemplate(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
AvailabilitySet(Decl), Comment, Declaration,
SubHeading,
DeclarationFragmentsBuilder::getAccessControl(Decl),
Template(Decl), isInSystemHeader(Decl));
else
API.addGlobalVariableTemplate(Name, USR, Loc, AvailabilitySet(Decl),
Linkage, Comment, Declaration, SubHeading,
Template(Decl), isInSystemHeader(Decl));
return true;
}

Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ template <typename Derived> class APISetVisitor {

getDerived()->traverseCXXMethodTemplateSpecializations();

getDerived()->traverseCXXFieldTemplates();

getDerived()->traverseConcepts();

getDerived()->traverseGlobalVariableTemplateRecords();
Expand Down Expand Up @@ -129,6 +131,11 @@ template <typename Derived> class APISetVisitor {
*ClassTemplatePartialSpecialization.second);
}

void traverseCXXFieldTemplates() {
for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates())
getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second);
}

void traverseGlobalVariableTemplateRecords() {
for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates())
getDerived()->visitGlobalVariableTemplateRecord(
Expand Down Expand Up @@ -221,6 +228,8 @@ template <typename Derived> class APISetVisitor {
void visitMethodTemplateSpecializationRecord(
const CXXMethodTemplateSpecializationRecord &Record){};

void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record){};

void visitGlobalVariableTemplateRecord(
const GlobalVariableTemplateRecord &Record) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
void visitMethodTemplateSpecializationRecord(
const CXXMethodTemplateSpecializationRecord &Record);

void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);

void visitConceptRecord(const ConceptRecord &Record);

void
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/ExtractAPI/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,21 @@ APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR,
return CXXClass->Fields.emplace_back(std::move(Record)).get();
}

CXXFieldTemplateRecord *APISet::addCXXFieldTemplate(
APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
AccessControl Access, Template Template, bool IsFromSystemHeader) {
auto *Record =
addTopLevelRecord(USRBasedLookupTable, CXXFieldTemplates, USR, Name, Loc,
std::move(Availability), Comment, Declaration,
SubHeading, Access, Template, IsFromSystemHeader);
Record->ParentInformation = APIRecord::HierarchyInformation(
Parent->USR, Parent->Name, Parent->getKind(), Parent);

return Record;
}

CXXClassRecord *
APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availabilities, const DocComment &Comment,
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,11 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) {
? Var->getTypeSourceInfo()->getType()
: Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());

// Might be a member, so might be static.
if (Var->isStaticDataMember())
Fragments.append("static", DeclarationFragments::FragmentKind::Keyword)
.appendSpace();

DeclarationFragments After;
DeclarationFragments ArgumentFragment =
getFragmentsForType(T, Var->getASTContext(), After);
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
Kind["identifier"] = AddLangPrefix("method");
Kind["displayName"] = "Method Template Specialization";
break;
case APIRecord::RK_CXXFieldTemplate:
Kind["identifier"] = AddLangPrefix("property");
Kind["displayName"] = "Template Property";
break;
case APIRecord::RK_Concept:
Kind["identifier"] = AddLangPrefix("concept");
Kind["displayName"] = "Concept";
Expand Down Expand Up @@ -956,6 +960,19 @@ void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
Record.ParentInformation.ParentRecord);
}

void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
const CXXFieldTemplateRecord &Record) {
if (!ShouldRecurse)
// Ignore child symbols
return;
auto CXXFieldTemplate = serializeAPIRecord(Record);
if (!CXXFieldTemplate)
return;
Symbols.emplace_back(std::move(*CXXFieldTemplate));
serializeRelationship(RelationshipKind::MemberOf, Record,
Record.ParentInformation.ParentRecord);
}

void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
auto Concept = serializeAPIRecord(Record);
if (!Concept)
Expand Down

0 comments on commit 634b2fd

Please sign in to comment.