summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clang-doc/Mapper.cpp9
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp96
-rw-r--r--clang-tools-extra/clang-doc/Serialize.h34
-rw-r--r--clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp7
-rw-r--r--clang-tools-extra/unittests/clang-doc/SerializeTest.cpp123
5 files changed, 176 insertions, 93 deletions
diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp
index 654096d8590..9bf2015d6a0 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -43,9 +43,12 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
// 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;
}
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 462918bae85..4962fa04456 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -335,30 +335,39 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
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 RecordDecl *D, const FullComment *FC,
}
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 FunctionDecl *D, const FullComment *FC,
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 CXXMethodDecl *D, const FullComment *FC,
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 EnumDecl *D, const FullComment *FC,
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 EnumDecl *D, const FullComment *FC,
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
diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h
index 3a2c93dfd20..1301e439a4f 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -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
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index 75767986e63..064ec28651f 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -130,11 +130,12 @@ void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual) {
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 *Expected, RecordInfo *Actual) {
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)
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 44cc9125a86..9384fabe652 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -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(StringRef Code, size_t NumExpectedInfos,
// 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, emitUndefinedRecordInfo) {
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, emitInternalRecordInfo) {
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, emitInlinedFunctionInfo) {
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(double y);)raw",
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
OpenPOWER on IntegriCloud