mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[clang][ExtractAPI] Add support for C++ member templates
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
This commit is contained in:
parent
0303137bfc
commit
634b2fd2ca
@ -171,6 +171,7 @@ struct APIRecord {
|
||||
RK_Union,
|
||||
RK_StaticField,
|
||||
RK_CXXField,
|
||||
RK_CXXFieldTemplate,
|
||||
RK_CXXClass,
|
||||
RK_ClassTemplate,
|
||||
RK_ClassTemplateSpecialization,
|
||||
@ -530,6 +531,25 @@ private:
|
||||
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;
|
||||
@ -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 {};
|
||||
@ -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 {};
|
||||
@ -1251,6 +1275,12 @@ public:
|
||||
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,
|
||||
@ -1482,6 +1512,9 @@ public:
|
||||
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;
|
||||
@ -1564,6 +1597,7 @@ private:
|
||||
RecordMap<CXXMethodTemplateRecord> CXXMethodTemplates;
|
||||
RecordMap<CXXMethodTemplateSpecializationRecord>
|
||||
CXXMethodTemplateSpecializations;
|
||||
RecordMap<CXXFieldTemplateRecord> CXXFieldTemplates;
|
||||
RecordMap<ClassTemplateRecord> ClassTemplates;
|
||||
RecordMap<ClassTemplateSpecializationRecord> ClassTemplateSpecializations;
|
||||
RecordMap<ClassTemplatePartialSpecializationRecord>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,8 @@ public:
|
||||
|
||||
getDerived()->traverseCXXMethodTemplateSpecializations();
|
||||
|
||||
getDerived()->traverseCXXFieldTemplates();
|
||||
|
||||
getDerived()->traverseConcepts();
|
||||
|
||||
getDerived()->traverseGlobalVariableTemplateRecords();
|
||||
@ -129,6 +131,11 @@ public:
|
||||
*ClassTemplatePartialSpecialization.second);
|
||||
}
|
||||
|
||||
void traverseCXXFieldTemplates() {
|
||||
for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates())
|
||||
getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second);
|
||||
}
|
||||
|
||||
void traverseGlobalVariableTemplateRecords() {
|
||||
for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates())
|
||||
getDerived()->visitGlobalVariableTemplateRecord(
|
||||
@ -221,6 +228,8 @@ public:
|
||||
void visitMethodTemplateSpecializationRecord(
|
||||
const CXXMethodTemplateSpecializationRecord &Record){};
|
||||
|
||||
void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record){};
|
||||
|
||||
void visitGlobalVariableTemplateRecord(
|
||||
const GlobalVariableTemplateRecord &Record) {}
|
||||
|
||||
|
@ -188,6 +188,8 @@ public:
|
||||
void visitMethodTemplateSpecializationRecord(
|
||||
const CXXMethodTemplateSpecializationRecord &Record);
|
||||
|
||||
void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);
|
||||
|
||||
void visitConceptRecord(const ConceptRecord &Record);
|
||||
|
||||
void
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
@ -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)
|
||||
|
206
clang/test/ExtractAPI/field_template.cpp
Normal file
206
clang/test/ExtractAPI/field_template.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \
|
||||
// RUN: %t/reference.output.json.in >> %t/reference.output.json
|
||||
// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \
|
||||
// RUN: -x c++-header %t/input.h -o %t/output.json -verify
|
||||
|
||||
// Generator version is not consistent across test runs, normalize it.
|
||||
// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
|
||||
// RUN: %t/output.json >> %t/output-normalized.json
|
||||
// RUN: diff %t/reference.output.json %t/output-normalized.json
|
||||
|
||||
//--- input.h
|
||||
class Foo {
|
||||
template<typename T> static T Bar;
|
||||
};
|
||||
|
||||
/// expected-no-diagnostics
|
||||
|
||||
//--- reference.output.json.in
|
||||
{
|
||||
"metadata": {
|
||||
"formatVersion": {
|
||||
"major": 0,
|
||||
"minor": 5,
|
||||
"patch": 3
|
||||
},
|
||||
"generator": "?"
|
||||
},
|
||||
"module": {
|
||||
"name": "",
|
||||
"platform": {
|
||||
"architecture": "arm64",
|
||||
"operatingSystem": {
|
||||
"minimumVersion": {
|
||||
"major": 11,
|
||||
"minor": 0,
|
||||
"patch": 0
|
||||
},
|
||||
"name": "macosx"
|
||||
},
|
||||
"vendor": "apple"
|
||||
}
|
||||
},
|
||||
"relationships": [
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@S@Foo@Bar",
|
||||
"target": "c:@S@Foo",
|
||||
"targetFallback": "Foo"
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"accessLevel": "public",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@S@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 7,
|
||||
"line": 1
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"navigator": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
}
|
||||
],
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
}
|
||||
],
|
||||
"title": "Foo"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Foo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"accessLevel": "private",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "template"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "<"
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "typename"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "genericParameter",
|
||||
"spelling": "T"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "> "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "static"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:t0.0",
|
||||
"spelling": "T"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Bar"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@S@Foo@Bar"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Template Property",
|
||||
"identifier": "c++.property"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 33,
|
||||
"line": 2
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"navigator": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Bar"
|
||||
}
|
||||
],
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Bar"
|
||||
}
|
||||
],
|
||||
"title": "Bar"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Foo",
|
||||
"Bar"
|
||||
],
|
||||
"swiftGenerics": {
|
||||
"parameters": [
|
||||
{
|
||||
"depth": 0,
|
||||
"index": 0,
|
||||
"name": "T"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user