evelez7 created this revision.
evelez7 added a reviewer: dang.
Herald added a reviewer: ributzka.
Herald added a project: All.
evelez7 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Serialize namespaces, nested namespaces, and class relationships inside them.
Depends on D157076 <https://reviews.llvm.org/D157076>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D158239
Files:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/DeclarationFragments.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/namespace.cpp
clang/test/ExtractAPI/nested_namespaces.cpp
Index: clang/test/ExtractAPI/nested_namespaces.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/nested_namespaces.cpp
@@ -0,0 +1,164 @@
+// 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 -std=c++20 -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
+namespace Foo {
+ namespace 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:@N@Foo@N@Bar",
+ "target": "c:@N@Foo",
+ "targetFallback": "Foo"
+ }
+ ],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "namespace"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@N@Foo"
+ },
+ "kind": {
+ "displayName": "Namespace",
+ "identifier": "c++.namespace"
+ },
+ "location": {
+ "position": {
+ "character": 11,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "title": "Foo"
+ },
+ "pathComponents": [
+ "Foo"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "namespace"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@N@Foo@N@Bar"
+ },
+ "kind": {
+ "displayName": "Namespace",
+ "identifier": "c++.namespace"
+ },
+ "location": {
+ "position": {
+ "character": 13,
+ "line": 2
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ }
+ ],
+ "title": "Bar"
+ },
+ "pathComponents": [
+ "Foo",
+ "Bar"
+ ]
+ }
+ ]
+}
Index: clang/test/ExtractAPI/namespace.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/namespace.cpp
@@ -0,0 +1,164 @@
+// 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 -std=c++20 -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
+namespace Foo {
+ class 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:@N@Foo@S@Bar",
+ "target": "c:@N@Foo",
+ "targetFallback": "Foo"
+ }
+ ],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "namespace"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@N@Foo"
+ },
+ "kind": {
+ "displayName": "Namespace",
+ "identifier": "c++.namespace"
+ },
+ "location": {
+ "position": {
+ "character": 11,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "title": "Foo"
+ },
+ "pathComponents": [
+ "Foo"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "class"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@N@Foo@S@Bar"
+ },
+ "kind": {
+ "displayName": "Class",
+ "identifier": "c++.class"
+ },
+ "location": {
+ "position": {
+ "character": 9,
+ "line": 2
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Bar"
+ }
+ ],
+ "title": "Bar"
+ },
+ "pathComponents": [
+ "Foo",
+ "Bar"
+ ]
+ }
+ ]
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -351,6 +351,10 @@
case APIRecord::RK_Unknown:
llvm_unreachable("Records should have an explicit kind");
break;
+ case APIRecord::RK_Namespace:
+ Kind["identifier"] = AddLangPrefix("namespace");
+ Kind["displayName"] = "Namespace";
+ break;
case APIRecord::RK_GlobalFunction:
Kind["identifier"] = AddLangPrefix("func");
Kind["displayName"] = "Function";
@@ -821,6 +825,17 @@
Relationships.emplace_back(std::move(Relationship));
}
+void SymbolGraphSerializer::visitNamespaceRecord(
+ const NamespaceRecord &Record) {
+ auto Namespace = serializeAPIRecord(Record);
+ if (!Namespace)
+ return;
+ Symbols.emplace_back(std::move(*Namespace));
+ if (!Record.ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, Record,
+ Record.ParentInformation.ParentRecord);
+}
+
void SymbolGraphSerializer::visitGlobalFunctionRecord(
const GlobalFunctionRecord &Record) {
auto Obj = serializeAPIRecord(Record);
@@ -874,6 +889,9 @@
Symbols.emplace_back(std::move(*Class));
for (const auto Base : Record.Bases)
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
+ if (!Record.ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, Record,
+ Record.ParentInformation.ParentRecord);
}
void SymbolGraphSerializer::visitClassTemplateRecord(
@@ -885,6 +903,9 @@
Symbols.emplace_back(std::move(*Class));
for (const auto Base : Record.Bases)
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
+ if (!Record.ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, Record,
+ Record.ParentInformation.ParentRecord);
}
void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
@@ -897,6 +918,9 @@
for (const auto Base : Record.Bases)
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
+ if (!Record.ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, Record,
+ Record.ParentInformation.ParentRecord);
}
void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
@@ -909,6 +933,9 @@
for (const auto Base : Record.Bases)
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
+ if (!Record.ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, Record,
+ Record.ParentInformation.ParentRecord);
}
void SymbolGraphSerializer::visitCXXInstanceMethodRecord(
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -423,6 +423,16 @@
return QualsFragments.appendSpace().append(std::move(TypeFragments));
}
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace(
+ const NamespaceDecl *Decl) {
+ DeclarationFragments Fragments;
+ Fragments.append("namespace", DeclarationFragments::FragmentKind::Keyword);
+ if (!Decl->isAnonymousNamespace())
+ Fragments.appendSpace().append(
+ Decl->getName(), DeclarationFragments::FragmentKind::Identifier);
+ return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
+}
+
DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
DeclarationFragments Fragments;
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -44,6 +44,22 @@
} // namespace
+NamespaceRecord *
+APISet::addNamespace(APIRecord *Parent, StringRef Name, StringRef USR,
+ PresumedLoc Loc, AvailabilitySet Availability,
+ LinkageInfo Linkage, const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading, bool IsFromSystemHeader) {
+ auto *Record = addTopLevelRecord(
+ USRBasedLookupTable, Namespaces, USR, Name, Loc, std::move(Availability),
+ Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader);
+
+ if (Parent)
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Parent->USR, Parent->Name, Parent->getKind(), Parent);
+ return Record;
+}
+
GlobalVariableRecord *
APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availabilities, LinkageInfo Linkage,
@@ -200,47 +216,65 @@
}
CXXClassRecord *
-APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
- AvailabilitySet Availabilities, const DocComment &Comment,
- DeclarationFragments Declaration,
+APISet::addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR,
+ PresumedLoc Loc, AvailabilitySet Availabilities,
+ const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, APIRecord::RecordKind Kind,
- bool IsFromSystemHeader) {
- return addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc,
- std::move(Availabilities), Comment, Declaration,
- SubHeading, Kind, IsFromSystemHeader);
+ AccessControl Access, bool IsFromSystemHeader) {
+ auto *Record =
+ addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, Kind, Access, IsFromSystemHeader);
+ if (Parent)
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Parent->USR, Parent->Name, Parent->getKind(), Parent);
+ return Record;
}
ClassTemplateRecord *APISet::addClassTemplate(
- StringRef Name, StringRef USR, PresumedLoc Loc,
+ APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- Template Template, bool IsFromSystemHeader) {
-
- return addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc,
- std::move(Availability), Comment, Declaration,
- SubHeading, Template, IsFromSystemHeader);
+ Template Template, AccessControl Access, bool IsFromSystemHeader) {
+ auto *Record =
+ addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc,
+ std::move(Availability), Comment, Declaration,
+ SubHeading, Template, Access, IsFromSystemHeader);
+ if (Parent)
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Parent->USR, Parent->Name, Parent->getKind(), Parent);
+ return Record;
}
ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization(
- StringRef Name, StringRef USR, PresumedLoc Loc,
+ APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- bool IsFromSystemHeader) {
- return addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations,
- USR, Name, Loc, std::move(Availability), Comment,
- Declaration, SubHeading, IsFromSystemHeader);
+ AccessControl Access, bool IsFromSystemHeader) {
+ auto *Record =
+ addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, USR,
+ Name, Loc, std::move(Availability), Comment,
+ Declaration, SubHeading, Access, IsFromSystemHeader);
+ if (Parent)
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Parent->USR, Parent->Name, Parent->getKind(), Parent);
+ return Record;
}
ClassTemplatePartialSpecializationRecord *
APISet::addClassTemplatePartialSpecialization(
- StringRef Name, StringRef USR, PresumedLoc Loc,
+ APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- Template Template, bool IsFromSystemHeader) {
- return addTopLevelRecord(USRBasedLookupTable,
- ClassTemplatePartialSpecializations, USR, Name, Loc,
- std::move(Availability), Comment, Declaration,
- SubHeading, Template, IsFromSystemHeader);
+ Template Template, AccessControl Access, bool IsFromSystemHeader) {
+ auto *Record = addTopLevelRecord(
+ USRBasedLookupTable, ClassTemplatePartialSpecializations, USR, Name, Loc,
+ std::move(Availability), Comment, Declaration, SubHeading, Template,
+ Access, IsFromSystemHeader);
+ if (Parent)
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Parent->USR, Parent->Name, Parent->getKind(), Parent);
+ return Record;
}
GlobalVariableTemplateSpecializationRecord *
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -152,6 +152,8 @@
SymbolGraphSerializerOption Options;
public:
+ void visitNamespaceRecord(const NamespaceRecord &Record);
+
/// Visit a global function record.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -23,6 +23,8 @@
template <typename Derived> class APISetVisitor {
public:
void traverseAPISet() {
+ getDerived()->traverseNamespaces();
+
getDerived()->traverseGlobalVariableRecords();
getDerived()->traverseGlobalFunctionRecords();
@@ -74,6 +76,11 @@
getDerived()->traverseTypedefRecords();
}
+ void traverseNamespaces() {
+ for (const auto &Namespace : API.getNamespaces())
+ getDerived()->visitNamespaceRecord(*Namespace.second);
+ }
+
void traverseGlobalFunctionRecords() {
for (const auto &GlobalFunction : API.getGlobalFunctions())
getDerived()->visitGlobalFunctionRecord(*GlobalFunction.second);
@@ -213,6 +220,8 @@
getDerived()->visitTypedefRecord(*Typedef.second);
}
+ void visitNamespaceRecord(const NamespaceRecord &Record){};
+
/// Visit a global function record.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record){};
Index: clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
===================================================================
--- clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -34,6 +34,18 @@
namespace clang {
namespace extractapi {
namespace impl {
+namespace {
+inline SmallString<128> DetermineParentDecl(const DeclContext *Context) {
+ SmallString<128> ParentUSR;
+ if (Context->getDeclKind() == Decl::Namespace)
+ index::generateUSRForDecl(dyn_cast<NamespaceDecl>(Context), ParentUSR);
+
+ if (Context->getDeclKind() == Decl::CXXRecord)
+ index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Context), ParentUSR);
+
+ return ParentUSR;
+}
+} // namespace
template <typename Derived>
class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
@@ -74,6 +86,10 @@
bool WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl *Decl);
+ bool WalkUpFromNamespaceDecl(const NamespaceDecl *Decl);
+
+ bool VisitNamespaceDecl(const NamespaceDecl *Decl);
+
bool VisitRecordDecl(const RecordDecl *Decl);
bool VisitCXXRecordDecl(const CXXRecordDecl *Decl);
@@ -447,6 +463,51 @@
return true;
}
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::WalkUpFromNamespaceDecl(
+ const NamespaceDecl *Decl) {
+ getDerivedExtractAPIVisitor().VisitNamespaceDecl(Decl);
+ return true;
+}
+
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::VisitNamespaceDecl(
+ const NamespaceDecl *Decl) {
+
+ if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
+ return true;
+ if (Decl->isAnonymousNamespace())
+ return true;
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ DocComment Comment;
+ if (auto *RawComment =
+ getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the struct.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForNamespace(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+ SmallString<128> ParentUSR;
+ APIRecord *Parent;
+ if (Decl->getDeclContext()->getDeclKind() == Decl::TranslationUnit)
+ Parent = nullptr;
+ else {
+ ParentUSR = DetermineParentDecl(Decl->getDeclContext());
+ Parent = API.findRecordForUSR(ParentUSR);
+ }
+ API.addNamespace(Parent, Name, USR, Loc, AvailabilitySet(Decl), Linkage,
+ Comment, Declaration, SubHeading, isInSystemHeader(Decl));
+
+ return true;
+}
+
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
@@ -512,7 +573,16 @@
Kind = APIRecord::RecordKind::RK_Struct;
else
Kind = APIRecord::RecordKind::RK_CXXClass;
+ auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+ SmallString<128> ParentUSR;
+ APIRecord *Parent;
+ if (Decl->getDeclContext()->getDeclKind() == Decl::TranslationUnit)
+ Parent = nullptr;
+ else {
+ ParentUSR = DetermineParentDecl(Decl->getDeclContext());
+ Parent = API.findRecordForUSR(ParentUSR);
+ }
CXXClassRecord *CXXClassRecord;
if (Decl->getDescribedClassTemplate()) {
// Inject template fragments before class fragments.
@@ -521,12 +591,13 @@
DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
Decl->getDescribedClassTemplate()));
CXXClassRecord = API.addClassTemplate(
- Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
- Template(Decl->getDescribedClassTemplate()), isInSystemHeader(Decl));
+ Parent, Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, Template(Decl->getDescribedClassTemplate()), Access,
+ isInSystemHeader(Decl));
} else
- CXXClassRecord =
- API.addCXXClass(Name, USR, Loc, AvailabilitySet(Decl), Comment,
- Declaration, SubHeading, Kind, isInSystemHeader(Decl));
+ CXXClassRecord = API.addCXXClass(
+ Parent, Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, Kind, Access, isInSystemHeader(Decl));
CXXClassRecord->Bases = getBases(Decl);
@@ -708,8 +779,17 @@
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
+ SmallString<128> ParentUSR;
+ APIRecord *Parent;
+ if (Decl->getDeclContext()->getDeclKind() == Decl::TranslationUnit)
+ Parent = nullptr;
+ else {
+ ParentUSR = DetermineParentDecl(Decl->getDeclContext());
+ Parent = API.findRecordForUSR(ParentUSR);
+ }
auto *ClassTemplateSpecializationRecord = API.addClassTemplateSpecialization(
- Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+ Parent, Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl),
isInSystemHeader(Decl));
ClassTemplateSpecializationRecord->Bases = getBases(Decl);
@@ -738,10 +818,20 @@
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
+ SmallString<128> ParentUSR;
+ APIRecord *Parent;
+ if (Decl->getDeclContext()->getDeclKind() == Decl::TranslationUnit)
+ Parent = nullptr;
+ else {
+ ParentUSR = DetermineParentDecl(Decl->getDeclContext());
+ Parent = API.findRecordForUSR(ParentUSR);
+ }
auto *ClassTemplatePartialSpecRecord =
API.addClassTemplatePartialSpecialization(
- Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
- SubHeading, Template(Decl), isInSystemHeader(Decl));
+ Parent, Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, Template(Decl),
+ DeclarationFragmentsBuilder::getAccessControl(Decl),
+ isInSystemHeader(Decl));
ClassTemplatePartialSpecRecord->Bases = getBases(Decl);
Index: clang/include/clang/ExtractAPI/DeclarationFragments.h
===================================================================
--- clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -257,17 +257,19 @@
static AccessControl getAccessControl(const Decl *Decl) {
switch (Decl->getAccess()) {
case AS_public:
+ case AS_none:
return AccessControl("public");
case AS_private:
return AccessControl("private");
case AS_protected:
return AccessControl("protected");
- case AS_none:
- return AccessControl("none");
}
llvm_unreachable("Unhandled access control");
}
+ static DeclarationFragments
+ getFragmentsForNamespace(const NamespaceDecl *Decl);
+
/// Build DeclarationFragments for a variable declaration VarDecl.
static DeclarationFragments getFragmentsForVar(const VarDecl *);
@@ -334,8 +336,8 @@
static DeclarationFragments
getFragmentsForFunctionTemplate(const FunctionTemplateDecl *Decl);
- static DeclarationFragments getFragmentsForFunctionTemplateSpecialization(
- const FunctionDecl *Decl);
+ static DeclarationFragments
+ getFragmentsForFunctionTemplateSpecialization(const FunctionDecl *Decl);
/// Build DeclarationFragments for an Objective-C category declaration
/// ObjCCategoryDecl.
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -157,6 +157,7 @@
/// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
enum RecordKind {
RK_Unknown,
+ RK_Namespace,
RK_GlobalFunction,
RK_GlobalFunctionTemplate,
RK_GlobalFunctionTemplateSpecialization,
@@ -267,6 +268,20 @@
virtual ~APIRecord() = 0;
};
+struct NamespaceRecord : APIRecord {
+ NamespaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+ AvailabilitySet Availabilities, LinkageInfo Linkage,
+ const DocComment &Comment, DeclarationFragments Declaration,
+ DeclarationFragments SubHeading, bool IsFromSystemHeader)
+ : APIRecord(RK_Namespace, USR, Name, Loc, std::move(Availabilities),
+ Linkage, Comment, Declaration, SubHeading,
+ IsFromSystemHeader) {}
+
+ static bool classof(const APIRecord *Record) {
+ return Record->getKind() == RK_Namespace;
+ }
+};
+
/// This holds information associated with global functions.
struct GlobalFunctionRecord : APIRecord {
FunctionSignature Signature;
@@ -900,15 +915,17 @@
SmallVector<std::unique_ptr<CXXFieldRecord>> Fields;
SmallVector<std::unique_ptr<CXXMethodRecord>> Methods;
SmallVector<SymbolReference> Bases;
+ AccessControl Access;
CXXClassRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, RecordKind Kind,
- bool IsFromSystemHeader)
+ AccessControl Access, bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader) {}
+ IsFromSystemHeader),
+ Access(Access) {}
static bool classof(const APIRecord *Record) {
return (Record->getKind() == RK_CXXClass);
@@ -925,9 +942,9 @@
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, Template Template,
- bool IsFromSystemHeader)
+ AccessControl Access, bool IsFromSystemHeader)
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
- Declaration, SubHeading, RK_ClassTemplate,
+ Declaration, SubHeading, RK_ClassTemplate, Access,
IsFromSystemHeader),
Templ(Template) {}
@@ -937,16 +954,14 @@
};
struct ClassTemplateSpecializationRecord : CXXClassRecord {
- ClassTemplateSpecializationRecord(StringRef USR, StringRef Name,
- PresumedLoc Loc,
- AvailabilitySet Availabilities,
- const DocComment &Comment,
- DeclarationFragments Declaration,
- DeclarationFragments SubHeading,
- bool IsFromSystemHeader)
+ ClassTemplateSpecializationRecord(
+ StringRef USR, StringRef Name, PresumedLoc Loc,
+ AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
+ AccessControl Access, bool IsFromSystemHeader)
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
Declaration, SubHeading, RK_ClassTemplateSpecialization,
- IsFromSystemHeader) {}
+ Access, IsFromSystemHeader) {}
static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_ClassTemplateSpecialization;
@@ -959,10 +974,10 @@
StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- Template Template, bool IsFromSystemHeader)
+ Template Template, AccessControl Access, bool IsFromSystemHeader)
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
Declaration, SubHeading, RK_ClassTemplateSpecialization,
- IsFromSystemHeader),
+ Access, IsFromSystemHeader),
Templ(Template) {}
static bool classof(const APIRecord *Record) {
@@ -1111,7 +1126,8 @@
template <>
struct has_function_signature<ObjCClassMethodRecord> : public std::true_type {};
template <>
-struct has_function_signature<CXXInstanceMethodRecord> : public std::true_type {};
+struct has_function_signature<CXXInstanceMethodRecord> : public std::true_type {
+};
template <>
struct has_function_signature<CXXStaticMethodRecord> : public std::true_type {};
template <>
@@ -1128,7 +1144,8 @@
: public std::true_type {};
template <typename RecordTy> struct has_access : public std::false_type {};
-template <> struct has_access<CXXInstanceMethodRecord> : public std::true_type {};
+template <>
+struct has_access<CXXInstanceMethodRecord> : public std::true_type {};
template <> struct has_access<CXXStaticMethodRecord> : public std::true_type {};
template <> struct has_access<CXXFieldRecord> : public std::true_type {};
template <>
@@ -1138,6 +1155,13 @@
: public std::true_type {};
template <>
struct has_access<CXXFieldTemplateRecord> : public std::true_type {};
+template <> struct has_access<CXXClassRecord> : public std::true_type {};
+template <> struct has_access<ClassTemplateRecord> : public std::true_type {};
+template <>
+struct has_access<ClassTemplateSpecializationRecord> : public std::true_type {};
+template <>
+struct has_access<ClassTemplatePartialSpecializationRecord>
+ : public std::true_type {};
template <typename RecordTy> struct has_template : public std::false_type {};
template <> struct has_template<ClassTemplateRecord> : public std::true_type {};
@@ -1160,7 +1184,15 @@
/// APISet holds the set of API records collected from given inputs.
class APISet {
public:
+ NamespaceRecord *addNamespace(APIRecord *Parent, StringRef Name,
+ StringRef USR, PresumedLoc Loc,
+ AvailabilitySet Availability,
+ LinkageInfo Linkage, const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeaderg);
/// Create and add a global variable record into the API set.
+
///
/// Note: the caller is responsible for keeping the StringRef \p Name and
/// \p USR alive. APISet::copyString provides a way to copy strings into
@@ -1277,31 +1309,33 @@
DeclarationFragments Declaration, DeclarationFragments SubHeading,
AccessControl Access, Template Template, bool IsFromSystemHeader);
- CXXClassRecord *
- addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
- AvailabilitySet Availability, const DocComment &Comment,
- DeclarationFragments Declaration, DeclarationFragments SubHeading,
- APIRecord::RecordKind Kind, bool IsFromSystemHeader);
+ CXXClassRecord *addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR,
+ PresumedLoc Loc, AvailabilitySet Availability,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ APIRecord::RecordKind Kind, AccessControl Access,
+ bool IsFromSystemHeader);
ClassTemplateRecord *
- addClassTemplate(StringRef Name, StringRef USR, PresumedLoc Loc,
- AvailabilitySet Availability, const DocComment &Comment,
- DeclarationFragments Declaration,
+ addClassTemplate(APIRecord *Parent, StringRef Name, StringRef USR,
+ PresumedLoc Loc, AvailabilitySet Availability,
+ const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, Template Template,
- bool IsFromSystemHeader);
+ AccessControl Access, bool IsFromSystemHeader);
ClassTemplateSpecializationRecord *addClassTemplateSpecialization(
- StringRef Name, StringRef USR, PresumedLoc Loc,
+ APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- bool IsFromSystemHeader);
+ AccessControl Access, bool IsFromSystemHeader);
ClassTemplatePartialSpecializationRecord *
addClassTemplatePartialSpecialization(
- StringRef Name, StringRef USR, PresumedLoc Loc,
+ APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- Template Template, bool IsFromSystemHeader);
+ Template Template, AccessControl Access, bool IsFromSystemHeader);
GlobalVariableTemplateSpecializationRecord *
addGlobalVariableTemplateSpecialization(
@@ -1476,6 +1510,7 @@
/// Get the language used by the APIs.
Language getLanguage() const { return Lang; }
+ const RecordMap<NamespaceRecord> &getNamespaces() const { return Namespaces; }
const RecordMap<GlobalFunctionRecord> &getGlobalFunctions() const {
return GlobalFunctions;
}
@@ -1589,6 +1624,7 @@
const Language Lang;
llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
+ RecordMap<NamespaceRecord> Namespaces;
RecordMap<GlobalFunctionRecord> GlobalFunctions;
RecordMap<GlobalFunctionTemplateRecord> GlobalFunctionTemplates;
RecordMap<GlobalFunctionTemplateSpecializationRecord>
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits