evelez7 created this revision.
Herald added a reviewer: ributzka.
Herald added a project: All.
evelez7 requested review of this revision.
Herald added a reviewer: dang.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Visit and serialize C++ fields by checking if a var template's context is a
CXXRecordDecl in VisitVarTemplateDecl.
Depends on D158027 <https://reviews.llvm.org/D158027>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D158029
Files:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/DeclarationFragments.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
clang/test/ExtractAPI/field_template.cpp
Index: clang/test/ExtractAPI/field_template.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/field_template.cpp
@@ -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"
+ }
+ ]
+ }
+ }
+ ]
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -422,6 +422,10 @@
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";
@@ -943,6 +947,19 @@
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)
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -465,6 +465,11 @@
? 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);
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -184,6 +184,21 @@
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,
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -179,6 +179,8 @@
void visitMethodTemplateSpecRecord(const CXXMethodTemplateSpecRecord &Record);
+ void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);
+
void visitConceptRecord(const ConceptRecord &Record);
void
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -43,6 +43,8 @@
getDerived()->traverseCXXMethodTemplateSpecializations();
+ getDerived()->traverseCXXFieldTemplates();
+
getDerived()->traverseConcepts();
getDerived()->traverseGlobalVariableTemplateRecords();
@@ -124,6 +126,11 @@
*ClassTemplatePartialSpec.second);
}
+ void traverseCXXFieldTemplates() {
+ for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates())
+ getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second);
+ }
+
void traverseGlobalVariableTemplateRecords() {
for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates())
getDerived()->visitGlobalVariableTemplateRecord(
@@ -210,6 +217,8 @@
void
visitMethodTemplateSpecRecord(const CXXMethodTemplateSpecRecord &Record){};
+ void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record){};
+
void visitGlobalVariableTemplateRecord(
const GlobalVariableTemplateRecord &Record) {}
Index: clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
===================================================================
--- clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -707,21 +707,29 @@
Context.getDiagnostics());
// Build declaration fragments and sub-heading for the variable.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForVarTemplate(
- Decl->getTemplatedDecl());
+ DeclarationFragments Declaration;
+ Declaration.append(
+ DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(Decl));
+ Declaration.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,
- DeclarationFragmentsBuilder::getTemplate(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),
+ DeclarationFragmentsBuilder::getTemplate(Decl), isInSystemHeader(Decl));
+ else
+ API.addGlobalVariableTemplate(
+ Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
+ SubHeading, DeclarationFragmentsBuilder::getTemplate(Decl),
+ isInSystemHeader(Decl));
return true;
}
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -73,6 +73,7 @@
RK_Union,
RK_StaticField,
RK_CXXField,
+ RK_CXXFieldTemplate,
RK_CXXClass,
RK_ClassTemplate,
RK_ClassTemplateSpecialization,
@@ -427,6 +428,25 @@
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;
@@ -1013,8 +1033,9 @@
template <>
struct has_access<CXXMethodTemplateRecord> : public std::true_type {};
template <>
-struct has_access<CXXMethodTemplateSpecRecord>
- : public std::true_type {};
+struct has_access<CXXMethodTemplateSpecRecord> : 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 {};
@@ -1030,6 +1051,8 @@
struct has_template<GlobalFunctionTemplateRecord> : public std::true_type {};
template <>
struct has_template<CXXMethodTemplateRecord> : public std::true_type {};
+template <>
+struct has_template<CXXFieldTemplateRecord> : public std::true_type {};
/// APISet holds the set of API records collected from given inputs.
class APISet {
@@ -1144,6 +1167,12 @@
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,
@@ -1373,6 +1402,9 @@
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;
@@ -1454,6 +1486,7 @@
RecordMap<CXXClassRecord> CXXClasses;
RecordMap<CXXMethodTemplateRecord> CXXMethodTemplates;
RecordMap<CXXMethodTemplateSpecRecord> CXXMethodTemplateSpecializations;
+ RecordMap<CXXFieldTemplateRecord> CXXFieldTemplates;
RecordMap<ClassTemplateRecord> ClassTemplates;
RecordMap<ClassTemplateSpecRecord> ClassTemplateSpecializations;
RecordMap<ClassTemplatePartialSpecRecord> ClassTemplatePartialSpecializations;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits