[clang-tools-extra] r364963 - [clang-doc] Serialize child namespaces and records

Julie Hockett via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 12:59:56 PDT 2019


Author: juliehockett
Date: Tue Jul  2 12:59:56 2019
New Revision: 364963

URL: http://llvm.org/viewvc/llvm-project?rev=364963&view=rev
Log:
[clang-doc] Serialize child namespaces and records

Serialization of child namespaces and records is now handled.
Namespaces can have child records and child namespaces.
Records can only have child records.

Committed on behalf of Diego Astiazarán (diegoaat97 at gmail.com).

Differential Revision: https://reviews.llvm.org/D63911

Modified:
    clang-tools-extra/trunk/clang-doc/Mapper.cpp
    clang-tools-extra/trunk/clang-doc/Serialize.cpp
    clang-tools-extra/trunk/clang-doc/Serialize.h
    clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
    clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp

Modified: clang-tools-extra/trunk/clang-doc/Mapper.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Mapper.cpp?rev=364963&r1=364962&r2=364963&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Mapper.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Mapper.cpp Tue Jul  2 12:59:56 2019
@@ -43,9 +43,12 @@ template <typename T> bool MapASTVisitor
 
   // A null in place of I indicates that the serializer is skipping this decl
   // for some reason (e.g. we're only reporting public decls).
-  if (I)
-    CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I->USR)),
-                       serialize::serialize(I));
+  if (I.first)
+    CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.first->USR)),
+                             serialize::serialize(I.first));
+  if (I.second)
+    CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I.second->USR)),
+                             serialize::serialize(I.second));
   return true;
 }
 

Modified: clang-tools-extra/trunk/clang-doc/Serialize.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=364963&r1=364962&r2=364963&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp Tue Jul  2 12:59:56 2019
@@ -335,30 +335,39 @@ static void populateFunctionInfo(Functio
   parseParameters(I, D);
 }
 
-std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
-                               int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
+         llvm::StringRef File, bool PublicOnly) {
   auto I = llvm::make_unique<NamespaceInfo>();
   bool IsInAnonymousNamespace = false;
   populateInfo(*I, D, FC, IsInAnonymousNamespace);
   if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) ||
                      !isPublic(D->getAccess(), D->getLinkageInternal())))
-    return nullptr;
+    return {};
   I->Name = D->isAnonymousNamespace()
                 ? llvm::SmallString<16>("@nonymous_namespace")
                 : I->Name;
-  return std::unique_ptr<Info>{std::move(I)};
+  if (I->Namespace.empty() && I->USR == SymbolID())
+    return {std::unique_ptr<Info>{std::move(I)}, nullptr};
+
+  SymbolID ParentUSR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
+
+  auto Parent = llvm::make_unique<NamespaceInfo>();
+  Parent->USR = ParentUSR;
+  Parent->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace);
+  return {std::unique_ptr<Info>{std::move(I)},
+          std::unique_ptr<Info>{std::move(Parent)}};
 }
 
-std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
-                               int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+         llvm::StringRef File, bool PublicOnly) {
   auto I = llvm::make_unique<RecordInfo>();
   bool IsInAnonymousNamespace = false;
   populateSymbolInfo(*I, D, FC, LineNumber, File, IsInAnonymousNamespace);
   if (PublicOnly && ((IsInAnonymousNamespace ||
                       !isPublic(D->getAccess(), D->getLinkageInternal()))))
-    return nullptr;
+    return {};
 
   I->TagType = D->getTagKind();
   parseFields(*I, D, PublicOnly);
@@ -369,18 +378,44 @@ std::unique_ptr<Info> emitInfo(const Rec
     }
     parseBases(*I, C);
   }
-  return std::unique_ptr<Info>{std::move(I)};
+
+  if (I->Namespace.empty()) {
+    auto Parent = llvm::make_unique<NamespaceInfo>();
+    Parent->USR = SymbolID();
+    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    return {std::unique_ptr<Info>{std::move(I)},
+            std::unique_ptr<Info>{std::move(Parent)}};
+  }
+
+  switch (I->Namespace[0].RefType) {
+  case InfoType::IT_namespace: {
+    auto Parent = llvm::make_unique<NamespaceInfo>();
+    Parent->USR = I->Namespace[0].USR;
+    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    return {std::unique_ptr<Info>{std::move(I)},
+            std::unique_ptr<Info>{std::move(Parent)}};
+  }
+  case InfoType::IT_record: {
+    auto Parent = llvm::make_unique<RecordInfo>();
+    Parent->USR = I->Namespace[0].USR;
+    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    return {std::unique_ptr<Info>{std::move(I)},
+            std::unique_ptr<Info>{std::move(Parent)}};
+  }
+  default:
+    llvm_unreachable("Invalid reference type");
+  }
 }
 
-std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
-                               int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
+         llvm::StringRef File, bool PublicOnly) {
   FunctionInfo Func;
   bool IsInAnonymousNamespace = false;
   populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
   if (PublicOnly && ((IsInAnonymousNamespace ||
                       !isPublic(D->getAccess(), D->getLinkageInternal()))))
-    return nullptr;
+    return {};
 
   Func.Access = clang::AccessSpecifier::AS_none;
 
@@ -391,18 +426,19 @@ std::unique_ptr<Info> emitInfo(const Fun
   else
     I->USR = SymbolID();
   I->ChildFunctions.emplace_back(std::move(Func));
-  return std::unique_ptr<Info>{std::move(I)};
+  // Info es wrapped in its parent scope so it's returned in the second position
+  return {nullptr, std::unique_ptr<Info>{std::move(I)}};
 }
 
-std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
-                               int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
+         llvm::StringRef File, bool PublicOnly) {
   FunctionInfo Func;
   bool IsInAnonymousNamespace = false;
   populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
   if (PublicOnly && ((IsInAnonymousNamespace ||
                       !isPublic(D->getAccess(), D->getLinkageInternal()))))
-    return nullptr;
+    return {};
 
   Func.IsMethod = true;
 
@@ -422,18 +458,19 @@ std::unique_ptr<Info> emitInfo(const CXX
   auto I = llvm::make_unique<RecordInfo>();
   I->USR = ParentUSR;
   I->ChildFunctions.emplace_back(std::move(Func));
-  return std::unique_ptr<Info>{std::move(I)};
+  // Info is wrapped in its parent scope so it's returned in the second position
+  return {nullptr, std::unique_ptr<Info>{std::move(I)}};
 }
 
-std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
-                               int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+         llvm::StringRef File, bool PublicOnly) {
   EnumInfo Enum;
   bool IsInAnonymousNamespace = false;
   populateSymbolInfo(Enum, D, FC, LineNumber, File, IsInAnonymousNamespace);
   if (PublicOnly && ((IsInAnonymousNamespace ||
                       !isPublic(D->getAccess(), D->getLinkageInternal()))))
-    return nullptr;
+    return {};
 
   Enum.Scoped = D->isScoped();
   parseEnumerators(Enum, D);
@@ -445,13 +482,17 @@ std::unique_ptr<Info> emitInfo(const Enu
       auto I = llvm::make_unique<NamespaceInfo>();
       I->USR = Enum.Namespace[0].USR;
       I->ChildEnums.emplace_back(std::move(Enum));
-      return std::unique_ptr<Info>{std::move(I)};
+      // Info is wrapped in its parent scope so it's returned in the second
+      // position
+      return {nullptr, std::unique_ptr<Info>{std::move(I)}};
     }
     case InfoType::IT_record: {
       auto I = llvm::make_unique<RecordInfo>();
       I->USR = Enum.Namespace[0].USR;
       I->ChildEnums.emplace_back(std::move(Enum));
-      return std::unique_ptr<Info>{std::move(I)};
+      // Info is wrapped in its parent scope so it's returned in the second
+      // position
+      return {nullptr, std::unique_ptr<Info>{std::move(I)}};
     }
     default:
       break;
@@ -462,7 +503,8 @@ std::unique_ptr<Info> emitInfo(const Enu
   auto I = llvm::make_unique<NamespaceInfo>();
   I->USR = SymbolID();
   I->ChildEnums.emplace_back(std::move(Enum));
-  return std::unique_ptr<Info>{std::move(I)};
+  // Info is wrapped in its parent scope so it's returned in the second position
+  return {nullptr, std::unique_ptr<Info>{std::move(I)}};
 }
 
 } // namespace serialize

Modified: clang-tools-extra/trunk/clang-doc/Serialize.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.h?rev=364963&r1=364962&r2=364963&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.h (original)
+++ clang-tools-extra/trunk/clang-doc/Serialize.h Tue Jul  2 12:59:56 2019
@@ -27,16 +27,30 @@ namespace clang {
 namespace doc {
 namespace serialize {
 
-std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
-std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
-std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
-std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
-std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+// The first element will contain the relevant information about the declaration
+// passed as parameter.
+// The second element will contain the relevant information about the
+// declaration's parent, it can be a NamespaceInfo or RecordInfo.
+// Both elements can be nullptrs if the declaration shouldn't be handled.
+// When the declaration is handled, the first element will be a nullptr for
+// EnumDecl, FunctionDecl and CXXMethodDecl; they are only returned wrapped in
+// its parent scope. For NamespaceDecl and RecordDecl both elements are not
+// nullptr.
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool PublicOnly);
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool PublicOnly);
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool PublicOnly);
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool PublicOnly);
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool PublicOnly);
 
 // Function to hash a given USR value for storage.
 // As USRs (Unified Symbol Resolution) could be large, especially for functions

Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp?rev=364963&r1=364962&r2=364963&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp Tue Jul  2 12:59:56 2019
@@ -130,11 +130,12 @@ void CheckNamespaceInfo(NamespaceInfo *E
 
   ASSERT_EQ(Expected->ChildNamespaces.size(), Actual->ChildNamespaces.size());
   for (size_t Idx = 0; Idx < Actual->ChildNamespaces.size(); ++Idx)
-    EXPECT_EQ(Expected->ChildNamespaces[Idx], Actual->ChildNamespaces[Idx]);
+    CheckReference(Expected->ChildNamespaces[Idx],
+                   Actual->ChildNamespaces[Idx]);
 
   ASSERT_EQ(Expected->ChildRecords.size(), Actual->ChildRecords.size());
   for (size_t Idx = 0; Idx < Actual->ChildRecords.size(); ++Idx)
-    EXPECT_EQ(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
+    CheckReference(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
 
   ASSERT_EQ(Expected->ChildFunctions.size(), Actual->ChildFunctions.size());
   for (size_t Idx = 0; Idx < Actual->ChildFunctions.size(); ++Idx)
@@ -167,7 +168,7 @@ void CheckRecordInfo(RecordInfo *Expecte
 
   ASSERT_EQ(Expected->ChildRecords.size(), Actual->ChildRecords.size());
   for (size_t Idx = 0; Idx < Actual->ChildRecords.size(); ++Idx)
-    EXPECT_EQ(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
+    CheckReference(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
 
   ASSERT_EQ(Expected->ChildFunctions.size(), Actual->ChildFunctions.size());
   for (size_t Idx = 0; Idx < Actual->ChildFunctions.size(); ++Idx)

Modified: clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp?rev=364963&r1=364962&r2=364963&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp Tue Jul  2 12:59:56 2019
@@ -35,48 +35,30 @@ public:
   ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public)
       : EmittedInfos(EmittedInfos), Public(Public) {}
 
-  bool VisitNamespaceDecl(const NamespaceDecl *D) {
+  template <typename T> bool mapDecl(const T *D) {
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
                                  /*File=*/"test.cpp", Public);
-    if (I)
-      EmittedInfos.emplace_back(std::move(I));
+    if (I.first)
+      EmittedInfos.emplace_back(std::move(I.first));
+    if (I.second)
+      EmittedInfos.emplace_back(std::move(I.second));
     return true;
   }
 
+  bool VisitNamespaceDecl(const NamespaceDecl *D) { return mapDecl(D); }
+
   bool VisitFunctionDecl(const FunctionDecl *D) {
     // Don't visit CXXMethodDecls twice
     if (dyn_cast<CXXMethodDecl>(D))
       return true;
-    auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
-    if (I)
-      EmittedInfos.emplace_back(std::move(I));
-    return true;
+    return mapDecl(D);
   }
 
-  bool VisitCXXMethodDecl(const CXXMethodDecl *D) {
-    auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
-    if (I)
-      EmittedInfos.emplace_back(std::move(I));
-    return true;
-  }
+  bool VisitCXXMethodDecl(const CXXMethodDecl *D) { return mapDecl(D); }
 
-  bool VisitRecordDecl(const RecordDecl *D) {
-    auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
-    if (I)
-      EmittedInfos.emplace_back(std::move(I));
-    return true;
-  }
+  bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
 
-  bool VisitEnumDecl(const EnumDecl *D) {
-    auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
-    if (I)
-      EmittedInfos.emplace_back(std::move(I));
-    return true;
-  }
+  bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
 };
 
 void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,
@@ -101,19 +83,19 @@ void ExtractInfosFromCodeWithArgs(String
 // Test serialization of namespace declarations.
 TEST(SerializeTest, emitNamespaceInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 3,
+  ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
                        /*Public=*/false, Infos);
 
   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID, "A");
   CheckNamespaceInfo(&ExpectedA, A);
 
-  NamespaceInfo *B = InfoAsNamespace(Infos[1].get());
+  NamespaceInfo *B = InfoAsNamespace(Infos[2].get());
   NamespaceInfo ExpectedB(EmptySID, "B");
   ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
   CheckNamespaceInfo(&ExpectedB, B);
 
-  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[2].get());
+  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
   FunctionInfo F;
   F.Name = "f";
@@ -127,7 +109,7 @@ TEST(SerializeTest, emitNamespaceInfo) {
 
 TEST(SerializeTest, emitAnonymousNamespaceInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace { }", 1, /*Public=*/false, Infos);
+  ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos);
 
   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID);
@@ -151,7 +133,7 @@ struct F {
 template <>
 void F<int>::TemplateMethod();
 typedef struct {} G;)raw",
-                       7, /*Public=*/false, Infos);
+                       10, /*Public=*/false, Infos);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, "E");
@@ -159,7 +141,7 @@ typedef struct {} G;)raw",
   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[1].get());
+  RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get());
   RecordInfo ExpectedRecordWithEConstructor(EmptySID);
   FunctionInfo EConstructor;
   EConstructor.Name = "E";
@@ -173,7 +155,7 @@ typedef struct {} G;)raw",
       std::move(EConstructor));
   CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
 
-  RecordInfo *RecordWithMethod = InfoAsRecord(Infos[2].get());
+  RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedRecordWithMethod(EmptySID);
   FunctionInfo Method;
   Method.Name = "ProtectedMethod";
@@ -186,13 +168,13 @@ typedef struct {} G;)raw",
   ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method));
   CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
 
-  RecordInfo *F = InfoAsRecord(Infos[3].get());
+  RecordInfo *F = InfoAsRecord(Infos[4].get());
   RecordInfo ExpectedF(EmptySID, "F");
   ExpectedF.TagType = TagTypeKind::TTK_Struct;
   ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedF, F);
 
-  RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[4].get());
+  RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());
   RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);
   FunctionInfo TemplateMethod;
   TemplateMethod.Name = "TemplateMethod";
@@ -206,7 +188,7 @@ typedef struct {} G;)raw",
       std::move(TemplateMethod));
   CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
 
-  RecordInfo *TemplatedRecord = InfoAsRecord(Infos[5].get());
+  RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());
   RecordInfo ExpectedTemplatedRecord(EmptySID);
   FunctionInfo SpecializedTemplateMethod;
   SpecializedTemplateMethod.Name = "TemplateMethod";
@@ -224,7 +206,7 @@ typedef struct {} G;)raw",
       std::move(SpecializedTemplateMethod));
   CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
 
-  RecordInfo *G = InfoAsRecord(Infos[6].get());
+  RecordInfo *G = InfoAsRecord(Infos[8].get());
   RecordInfo ExpectedG(EmptySID, "G");
   ExpectedG.TagType = TagTypeKind::TTK_Struct;
   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
@@ -262,7 +244,7 @@ TEST(SerializeTest, emitEnumInfo) {
 
 TEST(SerializeTest, emitUndefinedRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("class E;", 1, /*Public=*/false, Infos);
+  ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, "E");
@@ -273,7 +255,7 @@ TEST(SerializeTest, emitUndefinedRecordI
 
 TEST(SerializeTest, emitRecordMemberInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("struct E { int I; };", 1, /*Public=*/false, Infos);
+  ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, "E");
@@ -285,7 +267,7 @@ TEST(SerializeTest, emitRecordMemberInfo
 
 TEST(SerializeTest, emitInternalRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("class E { class G {}; };", 2, /*Public=*/false, Infos);
+  ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, "E");
@@ -293,7 +275,7 @@ TEST(SerializeTest, emitInternalRecordIn
   ExpectedE.TagType = TagTypeKind::TTK_Class;
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *G = InfoAsRecord(Infos[1].get());
+  RecordInfo *G = InfoAsRecord(Infos[2].get());
   RecordInfo ExpectedG(EmptySID, "G");
   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   ExpectedG.TagType = TagTypeKind::TTK_Class;
@@ -336,7 +318,7 @@ TEST(SerializeTest, emitInlinedFunctionI
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
-TEST(SerializeTest, emitInheritedRecordInfo) {
+TEST(SerializeTest, ) {
   EmittedInfoList Infos;
   ExtractInfosFromCode(R"raw(class F {};
 class G {} ;
@@ -344,7 +326,7 @@ class E : public F, virtual private G {}
 template <typename T>
 class H {} ;
 class I : public H<int> {} ;)raw",
-                       5, /*Public=*/false, Infos);
+                       10, /*Public=*/false, Infos);
 
   RecordInfo *F = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedF(EmptySID, "F");
@@ -352,13 +334,13 @@ class I : public H<int> {} ;)raw",
   ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedF, F);
 
-  RecordInfo *G = InfoAsRecord(Infos[1].get());
+  RecordInfo *G = InfoAsRecord(Infos[2].get());
   RecordInfo ExpectedG(EmptySID, "G");
   ExpectedG.TagType = TagTypeKind::TTK_Class;
   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedG, G);
 
-  RecordInfo *E = InfoAsRecord(Infos[2].get());
+  RecordInfo *E = InfoAsRecord(Infos[4].get());
   RecordInfo ExpectedE(EmptySID, "E");
   ExpectedE.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
   ExpectedE.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
@@ -366,13 +348,13 @@ class I : public H<int> {} ;)raw",
   ExpectedE.TagType = TagTypeKind::TTK_Class;
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *H = InfoAsRecord(Infos[3].get());
+  RecordInfo *H = InfoAsRecord(Infos[6].get());
   RecordInfo ExpectedH(EmptySID, "H");
   ExpectedH.TagType = TagTypeKind::TTK_Class;
   ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedH, H);
 
-  RecordInfo *I = InfoAsRecord(Infos[4].get());
+  RecordInfo *I = InfoAsRecord(Infos[8].get());
   RecordInfo ExpectedI(EmptySID, "I");
   ExpectedI.Parents.emplace_back(EmptySID, "H<int>", InfoType::IT_record);
   ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
@@ -412,5 +394,46 @@ export double exportedModuleFunction(dou
   CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
 }
 
+// Test serialization of child records in namespaces and other records
+TEST(SerializeTest, emitChildRecords) {
+  EmittedInfoList Infos;
+  ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,
+                       /*Public=*/false, Infos);
+
+  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
+  NamespaceInfo ExpectedParentA(EmptySID);
+  ExpectedParentA.ChildRecords.emplace_back(EmptySID, "A", InfoType::IT_record);
+  CheckNamespaceInfo(&ExpectedParentA, ParentA);
+
+  RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
+  RecordInfo ExpectedParentB(EmptySID);
+  ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record);
+  CheckRecordInfo(&ExpectedParentB, ParentB);
+
+  NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
+  NamespaceInfo ExpectedParentC(EmptySID);
+  ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record);
+  CheckNamespaceInfo(&ExpectedParentC, ParentC);
+}
+
+// Test serialization of child namespaces
+TEST(SerializeTest, emitChildNamespaces) {
+  EmittedInfoList Infos;
+  ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
+                       Infos);
+
+  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
+  NamespaceInfo ExpectedParentA(EmptySID);
+  ExpectedParentA.ChildNamespaces.emplace_back(EmptySID, "A",
+                                               InfoType::IT_namespace);
+  CheckNamespaceInfo(&ExpectedParentA, ParentA);
+
+  NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
+  NamespaceInfo ExpectedParentB(EmptySID);
+  ExpectedParentB.ChildNamespaces.emplace_back(EmptySID, "B",
+                                               InfoType::IT_namespace);
+  CheckNamespaceInfo(&ExpectedParentB, ParentB);
+}
+
 } // namespace doc
 } // end namespace clang




More information about the cfe-commits mailing list