diff options
Diffstat (limited to 'clang-tools-extra/unittests/clang-doc/SerializeTest.cpp')
| -rw-r--r-- | clang-tools-extra/unittests/clang-doc/SerializeTest.cpp | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp new file mode 100644 index 00000000000..d5bf8f11fe9 --- /dev/null +++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp @@ -0,0 +1,346 @@ +//===-- clang-doc/SerializeTest.cpp ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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) {} + + bool VisitNamespaceDecl(const NamespaceDecl *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 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; + } + + 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 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 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; + } +}; + +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() {} } }", 3, + /*Public=*/false, Infos); + + NamespaceInfo *A = InfoAsNamespace(Infos[0].get()); + NamespaceInfo ExpectedA(EmptySID, "A"); + CheckNamespaceInfo(&ExpectedA, A); + + NamespaceInfo *B = InfoAsNamespace(Infos[1].get()); + NamespaceInfo ExpectedB(EmptySID, "B"); + ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); + CheckNamespaceInfo(&ExpectedB, B); + + NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[2].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); + ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); + CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); +} + +TEST(SerializeTest, emitAnonymousNamespaceInfo) { + EmittedInfoList Infos; + ExtractInfosFromCode("namespace { }", 1, /*Public=*/false, Infos); + + NamespaceInfo *A = InfoAsNamespace(Infos[0].get()); + NamespaceInfo ExpectedA(EmptySID); + CheckNamespaceInfo(&ExpectedA, A); +} + +// Test serialization of record declarations. +TEST(SerializeTest, emitRecordInfo) { + EmittedInfoList Infos; + ExtractInfosFromCode(R"raw(class E { +public: + E() {} +protected: + void ProtectedMethod(); +};)raw", 3, /*Public=*/false, Infos); + + RecordInfo *E = InfoAsRecord(Infos[0].get()); + RecordInfo ExpectedE(EmptySID, "E"); + ExpectedE.TagType = TagTypeKind::TTK_Class; + ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + CheckRecordInfo(&ExpectedE, E); + + RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[1].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.Access = AccessSpecifier::AS_public; + EConstructor.IsMethod = true; + ExpectedRecordWithEConstructor.ChildFunctions.emplace_back( + std::move(EConstructor)); + CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor); + + RecordInfo *RecordWithMethod = InfoAsRecord(Infos[2].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.Access = AccessSpecifier::AS_protected; + Method.IsMethod = true; + ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method)); + CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod); +} + +// 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;", 1, /*Public=*/false, Infos); + + RecordInfo *E = InfoAsRecord(Infos[0].get()); + RecordInfo ExpectedE(EmptySID, "E"); + 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; };", 1, /*Public=*/false, Infos); + + RecordInfo *E = InfoAsRecord(Infos[0].get()); + RecordInfo ExpectedE(EmptySID, "E"); + 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 {}; };", 2, /*Public=*/false, Infos); + + RecordInfo *E = InfoAsRecord(Infos[0].get()); + RecordInfo ExpectedE(EmptySID, "E"); + ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + ExpectedE.TagType = TagTypeKind::TTK_Class; + CheckRecordInfo(&ExpectedE, E); + + RecordInfo *G = InfoAsRecord(Infos[1].get()); + RecordInfo ExpectedG(EmptySID, "G"); + ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + ExpectedG.TagType = TagTypeKind::TTK_Class; + ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); + 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"}); + 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"); + ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); + CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); +} + +TEST(SerializeTest, emitInheritedRecordInfo) { + EmittedInfoList Infos; + ExtractInfosFromCode( + "class F {}; class G{} ; class E : public F, virtual private G {};", 3, + /*Public=*/false, Infos); + + RecordInfo *F = InfoAsRecord(Infos[0].get()); + RecordInfo ExpectedF(EmptySID, "F"); + ExpectedF.TagType = TagTypeKind::TTK_Class; + ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + CheckRecordInfo(&ExpectedF, F); + + RecordInfo *G = InfoAsRecord(Infos[1].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 ExpectedE(EmptySID, "E"); + ExpectedE.Parents.emplace_back(EmptySID, "F", InfoType::IT_record); + ExpectedE.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record); + ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + ExpectedE.TagType = TagTypeKind::TTK_Class; + CheckRecordInfo(&ExpectedE, E); +} + +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"); + 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"); + ExpectedBWithExportedFunction.ChildFunctions.emplace_back( + std::move(ExportedF)); + CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction); +} + +} // namespace doc +} // end namespace clang |

