[clang] 08f034f - [clang][ExtractAPI] Add support for namespaces
Erick Velez via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 22 09:57:00 PDT 2023
Author: Erick Velez
Date: 2023-08-22T09:56:34-07:00
New Revision: 08f034f952fa67fc379df4caee2904de466a69f9
URL: https://github.com/llvm/llvm-project/commit/08f034f952fa67fc379df4caee2904de466a69f9
DIFF: https://github.com/llvm/llvm-project/commit/08f034f952fa67fc379df4caee2904de466a69f9.diff
LOG: [clang][ExtractAPI] Add support for namespaces
Serialize namespaces, nested namespaces, and class relationships inside them.
Depends on D157076
Reviewed By: dang
Differential Revision: https://reviews.llvm.org/D158239
Added:
clang/test/ExtractAPI/namespace.cpp
clang/test/ExtractAPI/nested_namespaces.cpp
Modified:
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
Removed:
################################################################################
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index 7b2d28f738e260..b4c0e0ad39cdf2 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -157,6 +157,7 @@ struct APIRecord {
/// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
enum RecordKind {
RK_Unknown,
+ RK_Namespace,
RK_GlobalFunction,
RK_GlobalFunctionTemplate,
RK_GlobalFunctionTemplateSpecialization,
@@ -271,6 +272,20 @@ struct APIRecord {
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;
@@ -904,15 +919,17 @@ struct CXXClassRecord : APIRecord {
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);
@@ -929,9 +946,9 @@ struct ClassTemplateRecord : CXXClassRecord {
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) {}
@@ -941,16 +958,14 @@ struct ClassTemplateRecord : CXXClassRecord {
};
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;
@@ -963,10 +978,10 @@ struct ClassTemplatePartialSpecializationRecord : CXXClassRecord {
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) {
@@ -1138,6 +1153,13 @@ struct has_access<CXXMethodTemplateSpecializationRecord>
: 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 {};
@@ -1167,6 +1189,13 @@ struct has_function_signature<GlobalFunctionTemplateSpecializationRecord>
/// 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
@@ -1284,31 +1313,33 @@ class APISet {
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(
@@ -1483,6 +1514,7 @@ class APISet {
/// 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;
}
@@ -1596,6 +1628,7 @@ class APISet {
const Language Lang;
llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
+ RecordMap<NamespaceRecord> Namespaces;
RecordMap<GlobalFunctionRecord> GlobalFunctions;
RecordMap<GlobalFunctionTemplateRecord> GlobalFunctionTemplates;
RecordMap<GlobalFunctionTemplateSpecializationRecord>
diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index b72ce667c4d55a..3c05f43e829c60 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -257,17 +257,19 @@ class DeclarationFragmentsBuilder {
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 *);
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index 38239b09dd484f..17c2ab6fd20501 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -74,6 +74,10 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
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);
@@ -187,6 +191,17 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
}
return Bases;
}
+
+ APIRecord *determineParentRecord(const DeclContext *Context) {
+ SmallString<128> ParentUSR;
+ if (Context->getDeclKind() == Decl::TranslationUnit)
+ return nullptr;
+
+ index::generateUSRForDecl(dyn_cast<Decl>(Context), ParentUSR);
+
+ APIRecord *Parent = API.findRecordForUSR(ParentUSR);
+ return Parent;
+ }
};
template <typename T>
@@ -447,6 +462,44 @@ bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionTemplateDecl(
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);
+ APIRecord *Parent = determineParentRecord(Decl->getDeclContext());
+ 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 +565,9 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
Kind = APIRecord::RecordKind::RK_Struct;
else
Kind = APIRecord::RecordKind::RK_CXXClass;
+ auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+ APIRecord *Parent = determineParentRecord(Decl->getDeclContext());
CXXClassRecord *CXXClassRecord;
if (Decl->getDescribedClassTemplate()) {
// Inject template fragments before class fragments.
@@ -521,12 +576,13 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
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 +764,10 @@ bool ExtractAPIVisitorBase<Derived>::VisitClassTemplateSpecializationDecl(
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
+ APIRecord *Parent = determineParentRecord(Decl->getDeclContext());
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 +796,13 @@ bool ExtractAPIVisitorBase<Derived>::
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
+ APIRecord *Parent = determineParentRecord(Decl->getDeclContext());
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);
diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
index 269333245c8363..a188400a74d558 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -23,6 +23,8 @@ namespace extractapi {
template <typename Derived> class APISetVisitor {
public:
void traverseAPISet() {
+ getDerived()->traverseNamespaces();
+
getDerived()->traverseGlobalVariableRecords();
getDerived()->traverseGlobalFunctionRecords();
@@ -76,6 +78,11 @@ template <typename Derived> class APISetVisitor {
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);
@@ -220,6 +227,8 @@ template <typename Derived> class APISetVisitor {
getDerived()->visitTypedefRecord(*Typedef.second);
}
+ void visitNamespaceRecord(const NamespaceRecord &Record){};
+
/// Visit a global function record.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record){};
diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
index 05cc33a0cb8c08..a9b714dc484659 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -159,6 +159,8 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
llvm::StringSet<> visitedCategories;
public:
+ void visitNamespaceRecord(const NamespaceRecord &Record);
+
/// Visit a global function record.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 9e4cfe6dbab308..2973a31345c9b2 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -44,6 +44,22 @@ RecordTy *addTopLevelRecord(DenseMap<StringRef, APIRecord *> &USRLookupTable,
} // 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 @@ CXXFieldTemplateRecord *APISet::addCXXFieldTemplate(
}
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 *
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 36b0d1f07f1ba6..f1fff6bf513df6 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -423,6 +423,16 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
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;
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index e1b5f652764f11..229bf04c77fae4 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -357,6 +357,10 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
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";
@@ -834,6 +838,17 @@ void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
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);
@@ -887,6 +902,9 @@ void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
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(
@@ -898,6 +916,9 @@ void SymbolGraphSerializer::visitClassTemplateRecord(
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(
@@ -910,6 +931,9 @@ void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
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(
@@ -922,6 +946,9 @@ void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
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(
diff --git a/clang/test/ExtractAPI/namespace.cpp b/clang/test/ExtractAPI/namespace.cpp
new file mode 100644
index 00000000000000..2346093db7d5fd
--- /dev/null
+++ b/clang/test/ExtractAPI/namespace.cpp
@@ -0,0 +1,164 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at 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 at Foo@S at Bar",
+ "target": "c:@N at 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 at 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 at Foo@S at 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"
+ ]
+ }
+ ]
+}
diff --git a/clang/test/ExtractAPI/nested_namespaces.cpp b/clang/test/ExtractAPI/nested_namespaces.cpp
new file mode 100644
index 00000000000000..2e562fa1e2e2e0
--- /dev/null
+++ b/clang/test/ExtractAPI/nested_namespaces.cpp
@@ -0,0 +1,164 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at 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 at Foo@N at Bar",
+ "target": "c:@N at 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 at 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 at Foo@N at 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"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list