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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to