| //===-- 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 |