|  | //===-- clang-doc/SerializeTest.cpp ---------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Serialize.h" | 
|  | #include "ClangDocTest.h" | 
|  | #include "Representation.h" | 
|  | #include "clang/AST/Comment.h" | 
|  | #include "clang/AST/RecursiveASTVisitor.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace clang { | 
|  | namespace doc { | 
|  |  | 
|  | class ClangDocSerializeTestVisitor | 
|  | : public RecursiveASTVisitor<ClangDocSerializeTestVisitor> { | 
|  |  | 
|  | EmittedInfoList &EmittedInfos; | 
|  | bool Public; | 
|  |  | 
|  | comments::FullComment *getComment(const NamedDecl *D) const { | 
|  | if (RawComment *Comment = | 
|  | D->getASTContext().getRawCommentForDeclNoCache(D)) { | 
|  | Comment->setAttached(); | 
|  | return Comment->parse(D->getASTContext(), nullptr, D); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | public: | 
|  | ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public) | 
|  | : EmittedInfos(EmittedInfos), Public(Public) {} | 
|  |  | 
|  | template <typename T> bool mapDecl(const T *D) { | 
|  | auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0, | 
|  | /*File=*/"test.cpp", true, Public); | 
|  | 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; | 
|  | return mapDecl(D); | 
|  | } | 
|  |  | 
|  | bool VisitCXXMethodDecl(const CXXMethodDecl *D) { return mapDecl(D); } | 
|  |  | 
|  | bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); } | 
|  |  | 
|  | bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); } | 
|  | }; | 
|  |  | 
|  | void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public, | 
|  | EmittedInfoList &EmittedInfos) { | 
|  | auto ASTUnit = clang::tooling::buildASTFromCode(Code); | 
|  | auto TU = ASTUnit->getASTContext().getTranslationUnitDecl(); | 
|  | ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public); | 
|  | Visitor.TraverseTranslationUnitDecl(TU); | 
|  | ASSERT_EQ(NumExpectedInfos, EmittedInfos.size()); | 
|  | } | 
|  |  | 
|  | void ExtractInfosFromCodeWithArgs(StringRef Code, size_t NumExpectedInfos, | 
|  | bool Public, EmittedInfoList &EmittedInfos, | 
|  | std::vector<std::string> &Args) { | 
|  | auto ASTUnit = clang::tooling::buildASTFromCodeWithArgs(Code, Args); | 
|  | auto TU = ASTUnit->getASTContext().getTranslationUnitDecl(); | 
|  | ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public); | 
|  | Visitor.TraverseTranslationUnitDecl(TU); | 
|  | ASSERT_EQ(NumExpectedInfos, EmittedInfos.size()); | 
|  | } | 
|  |  | 
|  | // Test serialization of namespace declarations. | 
|  | TEST(SerializeTest, emitNamespaceInfo) { | 
|  | EmittedInfoList Infos; | 
|  | 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[2].get()); | 
|  | NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A"); | 
|  | ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); | 
|  | CheckNamespaceInfo(&ExpectedB, B); | 
|  |  | 
|  | NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get()); | 
|  | NamespaceInfo ExpectedBWithFunction(EmptySID); | 
|  | FunctionInfo F; | 
|  | F.Name = "f"; | 
|  | F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace); | 
|  | F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); | 
|  | F.Access = AccessSpecifier::AS_none; | 
|  | ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); | 
|  | CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitAnonymousNamespaceInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos); | 
|  |  | 
|  | NamespaceInfo *A = InfoAsNamespace(Infos[0].get()); | 
|  | NamespaceInfo ExpectedA(EmptySID); | 
|  | ExpectedA.Name = "@nonymous_namespace"; | 
|  | CheckNamespaceInfo(&ExpectedA, A); | 
|  | } | 
|  |  | 
|  | // Test serialization of record declarations. | 
|  | TEST(SerializeTest, emitRecordInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode(R"raw(class E { | 
|  | public: | 
|  | E() {} | 
|  | protected: | 
|  | void ProtectedMethod(); | 
|  | }; | 
|  | template <typename T> | 
|  | struct F { | 
|  | void TemplateMethod(); | 
|  | }; | 
|  | template <> | 
|  | void F<int>::TemplateMethod(); | 
|  | typedef struct {} G;)raw", | 
|  | 10, /*Public=*/false, Infos); | 
|  |  | 
|  | RecordInfo *E = InfoAsRecord(Infos[0].get()); | 
|  | RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedE.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | CheckRecordInfo(&ExpectedE, E); | 
|  |  | 
|  | RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get()); | 
|  | RecordInfo ExpectedRecordWithEConstructor(EmptySID); | 
|  | FunctionInfo EConstructor; | 
|  | EConstructor.Name = "E"; | 
|  | EConstructor.Parent = Reference(EmptySID, "E", InfoType::IT_record); | 
|  | EConstructor.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | EConstructor.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); | 
|  | EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | EConstructor.Access = AccessSpecifier::AS_public; | 
|  | EConstructor.IsMethod = true; | 
|  | ExpectedRecordWithEConstructor.ChildFunctions.emplace_back( | 
|  | std::move(EConstructor)); | 
|  | CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor); | 
|  |  | 
|  | RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get()); | 
|  | RecordInfo ExpectedRecordWithMethod(EmptySID); | 
|  | FunctionInfo Method; | 
|  | Method.Name = "ProtectedMethod"; | 
|  | Method.Parent = Reference(EmptySID, "E", InfoType::IT_record); | 
|  | Method.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | Method.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); | 
|  | Method.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | Method.Access = AccessSpecifier::AS_protected; | 
|  | Method.IsMethod = true; | 
|  | ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method)); | 
|  | CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod); | 
|  |  | 
|  | RecordInfo *F = InfoAsRecord(Infos[4].get()); | 
|  | RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedF.TagType = TagTypeKind::TTK_Struct; | 
|  | ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | CheckRecordInfo(&ExpectedF, F); | 
|  |  | 
|  | RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get()); | 
|  | RecordInfo ExpectedRecordWithTemplateMethod(EmptySID); | 
|  | FunctionInfo TemplateMethod; | 
|  | TemplateMethod.Name = "TemplateMethod"; | 
|  | TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record); | 
|  | TemplateMethod.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | TemplateMethod.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); | 
|  | TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | TemplateMethod.Access = AccessSpecifier::AS_public; | 
|  | TemplateMethod.IsMethod = true; | 
|  | ExpectedRecordWithTemplateMethod.ChildFunctions.emplace_back( | 
|  | std::move(TemplateMethod)); | 
|  | CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod); | 
|  |  | 
|  | RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get()); | 
|  | RecordInfo ExpectedTemplatedRecord(EmptySID); | 
|  | FunctionInfo SpecializedTemplateMethod; | 
|  | SpecializedTemplateMethod.Name = "TemplateMethod"; | 
|  | SpecializedTemplateMethod.Parent = | 
|  | Reference(EmptySID, "F", InfoType::IT_record); | 
|  | SpecializedTemplateMethod.ReturnType = | 
|  | TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | SpecializedTemplateMethod.Loc.emplace_back(0, | 
|  | llvm::SmallString<16>{"test.cpp"}); | 
|  | SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F", | 
|  | InfoType::IT_record); | 
|  | SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | SpecializedTemplateMethod.Access = AccessSpecifier::AS_public; | 
|  | SpecializedTemplateMethod.IsMethod = true; | 
|  | ExpectedTemplatedRecord.ChildFunctions.emplace_back( | 
|  | std::move(SpecializedTemplateMethod)); | 
|  | CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord); | 
|  |  | 
|  | RecordInfo *G = InfoAsRecord(Infos[8].get()); | 
|  | RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedG.TagType = TagTypeKind::TTK_Struct; | 
|  | ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedG.IsTypeDef = true; | 
|  | CheckRecordInfo(&ExpectedG, G); | 
|  | } | 
|  |  | 
|  | // Test serialization of enum declarations. | 
|  | TEST(SerializeTest, emitEnumInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2, | 
|  | /*Public=*/false, Infos); | 
|  |  | 
|  | NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get()); | 
|  | NamespaceInfo ExpectedNamespaceWithEnum(EmptySID); | 
|  | EnumInfo E; | 
|  | E.Name = "E"; | 
|  | E.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | E.Members.emplace_back("X"); | 
|  | E.Members.emplace_back("Y"); | 
|  | ExpectedNamespaceWithEnum.ChildEnums.emplace_back(std::move(E)); | 
|  | CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum); | 
|  |  | 
|  | NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get()); | 
|  | NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID); | 
|  | EnumInfo G; | 
|  | G.Name = "G"; | 
|  | G.Scoped = true; | 
|  | G.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | G.Members.emplace_back("A"); | 
|  | G.Members.emplace_back("B"); | 
|  | ExpectedNamespaceWithScopedEnum.ChildEnums.emplace_back(std::move(G)); | 
|  | CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitUndefinedRecordInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos); | 
|  |  | 
|  | RecordInfo *E = InfoAsRecord(Infos[0].get()); | 
|  | RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedE.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedE.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | CheckRecordInfo(&ExpectedE, E); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitRecordMemberInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos); | 
|  |  | 
|  | RecordInfo *E = InfoAsRecord(Infos[0].get()); | 
|  | RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedE.TagType = TagTypeKind::TTK_Struct; | 
|  | ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedE.Members.emplace_back("int", "I", AccessSpecifier::AS_public); | 
|  | CheckRecordInfo(&ExpectedE, E); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitInternalRecordInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos); | 
|  |  | 
|  | RecordInfo *E = InfoAsRecord(Infos[0].get()); | 
|  | RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedE.TagType = TagTypeKind::TTK_Class; | 
|  | CheckRecordInfo(&ExpectedE, E); | 
|  |  | 
|  | RecordInfo *G = InfoAsRecord(Infos[2].get()); | 
|  | llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E"); | 
|  | llvm::sys::path::native(ExpectedGPath); | 
|  | RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath); | 
|  | ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedG.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); | 
|  | ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | CheckRecordInfo(&ExpectedG, G); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitPublicFunctionInternalInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true, | 
|  | Infos); | 
|  |  | 
|  | NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); | 
|  | NamespaceInfo ExpectedBWithFunction(EmptySID); | 
|  | FunctionInfo F; | 
|  | F.Name = "F"; | 
|  | F.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); | 
|  | F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | F.Access = AccessSpecifier::AS_none; | 
|  | ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); | 
|  | CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitInlinedFunctionInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos); | 
|  |  | 
|  | NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); | 
|  | NamespaceInfo ExpectedBWithFunction(EmptySID); | 
|  | FunctionInfo F; | 
|  | F.Name = "F"; | 
|  | F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | F.Params.emplace_back("int", "I"); | 
|  | F.Access = AccessSpecifier::AS_none; | 
|  | ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); | 
|  | CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitInheritedRecordInfo) { | 
|  | EmittedInfoList Infos; | 
|  | ExtractInfosFromCode(R"raw(class F { protected: void set(int N); }; | 
|  | class G { public: int get() { return 1; } protected: int I; }; | 
|  | class E : public F, virtual private G {}; | 
|  | class H : private E {}; | 
|  | template <typename T> | 
|  | class I {} ; | 
|  | class J : public I<int> {} ;)raw", | 
|  | 14, /*Public=*/false, Infos); | 
|  |  | 
|  | RecordInfo *F = InfoAsRecord(Infos[0].get()); | 
|  | RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedF.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | CheckRecordInfo(&ExpectedF, F); | 
|  |  | 
|  | RecordInfo *G = InfoAsRecord(Infos[3].get()); | 
|  | RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedG.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedG.Members.emplace_back("int", "I", AccessSpecifier::AS_protected); | 
|  | CheckRecordInfo(&ExpectedG, G); | 
|  |  | 
|  | RecordInfo *E = InfoAsRecord(Infos[6].get()); | 
|  | RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record, | 
|  | /*Path*=*/"GlobalNamespace"); | 
|  | ExpectedE.VirtualParents.emplace_back( | 
|  | EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path*=*/"GlobalNamespace"); | 
|  | ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F", | 
|  | /*Path=*/"GlobalNamespace", false, | 
|  | AccessSpecifier::AS_public, true); | 
|  | FunctionInfo FunctionSet; | 
|  | FunctionSet.Name = "set"; | 
|  | FunctionSet.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | FunctionSet.Loc.emplace_back(); | 
|  | FunctionSet.Params.emplace_back("int", "N"); | 
|  | FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); | 
|  | FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | FunctionSet.Access = AccessSpecifier::AS_protected; | 
|  | FunctionSet.IsMethod = true; | 
|  | ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSet)); | 
|  | ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G", | 
|  | /*Path=*/"GlobalNamespace", true, | 
|  | AccessSpecifier::AS_private, true); | 
|  | FunctionInfo FunctionGet; | 
|  | FunctionGet.Name = "get"; | 
|  | FunctionGet.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); | 
|  | FunctionGet.DefLoc = Location(); | 
|  | FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); | 
|  | FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | FunctionGet.Access = AccessSpecifier::AS_private; | 
|  | FunctionGet.IsMethod = true; | 
|  | ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGet)); | 
|  | ExpectedE.Bases.back().Members.emplace_back("int", "I", | 
|  | AccessSpecifier::AS_private); | 
|  | ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedE.TagType = TagTypeKind::TTK_Class; | 
|  | CheckRecordInfo(&ExpectedE, E); | 
|  |  | 
|  | RecordInfo *H = InfoAsRecord(Infos[8].get()); | 
|  | RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedH.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record, | 
|  | /*Path=*/"GlobalNamespace"); | 
|  | ExpectedH.VirtualParents.emplace_back( | 
|  | EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path=*/"GlobalNamespace"); | 
|  | ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E", | 
|  | /*Path=*/"GlobalNamespace", false, | 
|  | AccessSpecifier::AS_private, true); | 
|  | ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F", | 
|  | /*Path=*/"GlobalNamespace", false, | 
|  | AccessSpecifier::AS_private, false); | 
|  | FunctionInfo FunctionSetNew; | 
|  | FunctionSetNew.Name = "set"; | 
|  | FunctionSetNew.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); | 
|  | FunctionSetNew.Loc.emplace_back(); | 
|  | FunctionSetNew.Params.emplace_back("int", "N"); | 
|  | FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); | 
|  | FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | FunctionSetNew.Access = AccessSpecifier::AS_private; | 
|  | FunctionSetNew.IsMethod = true; | 
|  | ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSetNew)); | 
|  | ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G", | 
|  | /*Path=*/"GlobalNamespace", true, | 
|  | AccessSpecifier::AS_private, false); | 
|  | FunctionInfo FunctionGetNew; | 
|  | FunctionGetNew.Name = "get"; | 
|  | FunctionGetNew.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); | 
|  | FunctionGetNew.DefLoc = Location(); | 
|  | FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); | 
|  | FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | FunctionGetNew.Access = AccessSpecifier::AS_private; | 
|  | FunctionGetNew.IsMethod = true; | 
|  | ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGetNew)); | 
|  | ExpectedH.Bases.back().Members.emplace_back("int", "I", | 
|  | AccessSpecifier::AS_private); | 
|  | CheckRecordInfo(&ExpectedH, H); | 
|  |  | 
|  | RecordInfo *I = InfoAsRecord(Infos[10].get()); | 
|  | RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedI.TagType = TagTypeKind::TTK_Class; | 
|  | ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | CheckRecordInfo(&ExpectedI, I); | 
|  |  | 
|  | RecordInfo *J = InfoAsRecord(Infos[12].get()); | 
|  | RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace"); | 
|  | ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace", | 
|  | InfoType::IT_namespace); | 
|  | ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>", | 
|  | InfoType::IT_record); | 
|  | ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>", | 
|  | /*Path=*/"GlobalNamespace", false, | 
|  | AccessSpecifier::AS_public, true); | 
|  | ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExpectedJ.TagType = TagTypeKind::TTK_Class; | 
|  | CheckRecordInfo(&ExpectedJ, J); | 
|  | } | 
|  |  | 
|  | TEST(SerializeTest, emitModulePublicLFunctions) { | 
|  | EmittedInfoList Infos; | 
|  | std::vector<std::string> Args; | 
|  | Args.push_back("-fmodules-ts"); | 
|  | ExtractInfosFromCodeWithArgs(R"raw(export module M; | 
|  | int moduleFunction(int x); | 
|  | static int staticModuleFunction(int x); | 
|  | export double exportedModuleFunction(double y);)raw", | 
|  | 2, /*Public=*/true, Infos, Args); | 
|  |  | 
|  | NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); | 
|  | NamespaceInfo ExpectedBWithFunction(EmptySID); | 
|  | FunctionInfo F; | 
|  | F.Name = "moduleFunction"; | 
|  | F.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); | 
|  | F.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | F.Params.emplace_back("int", "x"); | 
|  | F.Access = AccessSpecifier::AS_none; | 
|  | ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); | 
|  | CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); | 
|  |  | 
|  | NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get()); | 
|  | NamespaceInfo ExpectedBWithExportedFunction(EmptySID); | 
|  | FunctionInfo ExportedF; | 
|  | ExportedF.Name = "exportedModuleFunction"; | 
|  | ExportedF.ReturnType = TypeInfo(EmptySID, "double", InfoType::IT_default); | 
|  | ExportedF.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); | 
|  | ExportedF.Params.emplace_back("double", "y"); | 
|  | ExportedF.Access = AccessSpecifier::AS_none; | 
|  | ExpectedBWithExportedFunction.ChildFunctions.emplace_back( | 
|  | std::move(ExportedF)); | 
|  | 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, | 
|  | "GlobalNamespace"); | 
|  | CheckNamespaceInfo(&ExpectedParentA, ParentA); | 
|  |  | 
|  | RecordInfo *ParentB = InfoAsRecord(Infos[3].get()); | 
|  | RecordInfo ExpectedParentB(EmptySID); | 
|  | llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A"); | 
|  | llvm::sys::path::native(ExpectedParentBPath); | 
|  | ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record, | 
|  | ExpectedParentBPath); | 
|  | CheckRecordInfo(&ExpectedParentB, ParentB); | 
|  |  | 
|  | NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get()); | 
|  | NamespaceInfo ExpectedParentC(EmptySID); | 
|  | ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record, | 
|  | "@nonymous_namespace"); | 
|  | 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, "A"); | 
|  | CheckNamespaceInfo(&ExpectedParentB, ParentB); | 
|  | } | 
|  |  | 
|  | } // namespace doc | 
|  | } // end namespace clang |