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@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" + ] + } + ] +} 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@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" + ] + } + ] +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits