734 lines · cpp
1//===-- clang-doc/SerializeTest.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Serialize.h"10#include "ClangDocTest.h"11#include "Representation.h"12#include "clang/AST/Comment.h"13#include "clang/AST/RecursiveASTVisitor.h"14#include "gtest/gtest.h"15 16namespace clang {17namespace doc {18 19class ClangDocSerializeTestVisitor20 : public RecursiveASTVisitor<ClangDocSerializeTestVisitor> {21 22 EmittedInfoList &EmittedInfos;23 bool Public;24 25 comments::FullComment *getComment(const NamedDecl *D) const {26 if (RawComment *Comment =27 D->getASTContext().getRawCommentForDeclNoCache(D)) {28 Comment->setAttached();29 return Comment->parse(D->getASTContext(), nullptr, D);30 }31 return nullptr;32 }33 34public:35 ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public)36 : EmittedInfos(EmittedInfos), Public(Public) {}37 38 template <typename T> bool mapDecl(const T *D) {39 Location Loc(0, 0, "test.cpp");40 auto [Child, Parent] = serialize::emitInfo(D, getComment(D), Loc, Public);41 if (Child)42 EmittedInfos.emplace_back(std::move(Child));43 if (Parent)44 EmittedInfos.emplace_back(std::move(Parent));45 return true;46 }47 48 bool VisitNamespaceDecl(const NamespaceDecl *D) { return mapDecl(D); }49 50 bool VisitFunctionDecl(const FunctionDecl *D) {51 // Don't visit CXXMethodDecls twice52 if (dyn_cast<CXXMethodDecl>(D))53 return true;54 return mapDecl(D);55 }56 57 bool VisitCXXMethodDecl(const CXXMethodDecl *D) { return mapDecl(D); }58 59 bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }60 61 bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }62 63 bool VisitTypedefDecl(const TypedefDecl *D) { return mapDecl(D); }64 65 bool VisitTypeAliasDecl(const TypeAliasDecl *D) { return mapDecl(D); }66};67 68void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,69 EmittedInfoList &EmittedInfos) {70 auto ASTUnit = clang::tooling::buildASTFromCode(Code);71 auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();72 ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);73 Visitor.TraverseTranslationUnitDecl(TU);74 ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());75}76 77void ExtractInfosFromCodeWithArgs(StringRef Code, size_t NumExpectedInfos,78 bool Public, EmittedInfoList &EmittedInfos,79 std::vector<std::string> &Args) {80 auto ASTUnit = clang::tooling::buildASTFromCodeWithArgs(Code, Args);81 auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();82 ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);83 Visitor.TraverseTranslationUnitDecl(TU);84 ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());85}86 87// Constructs a comment definition as the parser would for one comment line.88/* TODO uncomment this when the missing comment is fixed in emitRecordInfo and89 the code that calls this is re-enabled.90CommentInfo MakeOneLineCommentInfo(const std::string &Text) {91 CommentInfo TopComment;92 TopComment.Kind = "FullComment";93 TopComment.Children.emplace_back(std::make_unique<CommentInfo>());94 95 CommentInfo *Brief = TopComment.Children.back().get();96 Brief->Kind = "ParagraphComment";97 98 Brief->Children.emplace_back(std::make_unique<CommentInfo>());99 Brief->Children.back()->Kind = "TextComment";100 Brief->Children.back()->Name = "ParagraphComment";101 Brief->Children.back()->Text = Text;102 103 return TopComment;104}105*/106 107// Test serialization of namespace declarations.108TEST(SerializeTest, emitNamespaceInfo) {109 EmittedInfoList Infos;110 ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,111 /*Public=*/false, Infos);112 113 NamespaceInfo *A = InfoAsNamespace(Infos[0].get());114 NamespaceInfo ExpectedA(EmptySID, "A");115 CheckNamespaceInfo(&ExpectedA, A);116 117 NamespaceInfo *B = InfoAsNamespace(Infos[2].get());118 NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");119 ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);120 CheckNamespaceInfo(&ExpectedB, B);121 122 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());123 NamespaceInfo ExpectedBWithFunction(EmptySID);124 FunctionInfo F;125 F.Name = "f";126 F.ReturnType = TypeInfo("void");127 F.DefLoc = Location(0, 0, "test.cpp");128 F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);129 F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);130 F.Access = AccessSpecifier::AS_none;131 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));132 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);133}134 135TEST(SerializeTest, emitAnonymousNamespaceInfo) {136 EmittedInfoList Infos;137 ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos);138 139 NamespaceInfo *A = InfoAsNamespace(Infos[0].get());140 NamespaceInfo ExpectedA(EmptySID);141 ExpectedA.Name = "@nonymous_namespace";142 CheckNamespaceInfo(&ExpectedA, A);143}144 145// Test serialization of record declarations.146TEST(SerializeTest, emitRecordInfo) {147 EmittedInfoList Infos;148 ExtractInfosFromCode(R"raw(class E {149public:150 E() {}151 152 // Some docs.153 int value;154protected:155 void ProtectedMethod();156};157template <typename T>158struct F {159 void TemplateMethod();160};161template <>162void F<int>::TemplateMethod();163typedef struct {} G;)raw",164 10, /*Public=*/false, Infos);165 166 RecordInfo *E = InfoAsRecord(Infos[0].get());167 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");168 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",169 InfoType::IT_namespace);170 ExpectedE.TagType = TagTypeKind::Class;171 ExpectedE.DefLoc = Location(0, 0, "test.cpp");172 ExpectedE.Members.emplace_back(TypeInfo("int"), "value",173 AccessSpecifier::AS_public);174 // TODO the data member should have the docstring on it:175 //ExpectedE.Members.back().Description.push_back(MakeOneLineCommentInfo(" Some docs"));176 CheckRecordInfo(&ExpectedE, E);177 178 RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get());179 RecordInfo ExpectedRecordWithEConstructor(EmptySID);180 FunctionInfo EConstructor;181 EConstructor.Name = "E";182 EConstructor.Parent = Reference(EmptySID, "E", InfoType::IT_record);183 EConstructor.ReturnType = TypeInfo("void");184 EConstructor.DefLoc = Location(0, 0, "test.cpp");185 EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);186 EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace",187 InfoType::IT_namespace);188 EConstructor.Access = AccessSpecifier::AS_public;189 EConstructor.IsMethod = true;190 ExpectedRecordWithEConstructor.Children.Functions.emplace_back(191 std::move(EConstructor));192 CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);193 194 RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());195 RecordInfo ExpectedRecordWithMethod(EmptySID);196 FunctionInfo Method;197 Method.Name = "ProtectedMethod";198 Method.Parent = Reference(EmptySID, "E", InfoType::IT_record);199 Method.ReturnType = TypeInfo("void");200 Method.Loc.emplace_back(0, 0, "test.cpp");201 Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);202 Method.Namespace.emplace_back(EmptySID, "GlobalNamespace",203 InfoType::IT_namespace);204 Method.Access = AccessSpecifier::AS_protected;205 Method.IsMethod = true;206 ExpectedRecordWithMethod.Children.Functions.emplace_back(std::move(Method));207 CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);208 209 RecordInfo *F = InfoAsRecord(Infos[4].get());210 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");211 ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",212 InfoType::IT_namespace);213 ExpectedF.TagType = TagTypeKind::Struct;214 ExpectedF.DefLoc = Location(0, 0, "test.cpp");215 CheckRecordInfo(&ExpectedF, F);216 217 RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());218 RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);219 FunctionInfo TemplateMethod;220 TemplateMethod.Name = "TemplateMethod";221 TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record);222 TemplateMethod.ReturnType = TypeInfo("void");223 TemplateMethod.Loc.emplace_back(0, 0, "test.cpp");224 TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);225 TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",226 InfoType::IT_namespace);227 TemplateMethod.Access = AccessSpecifier::AS_public;228 TemplateMethod.IsMethod = true;229 ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(230 std::move(TemplateMethod));231 CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);232 233 RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());234 RecordInfo ExpectedTemplatedRecord(EmptySID);235 FunctionInfo SpecializedTemplateMethod;236 SpecializedTemplateMethod.Name = "TemplateMethod";237 SpecializedTemplateMethod.Parent =238 Reference(EmptySID, "F", InfoType::IT_record);239 SpecializedTemplateMethod.ReturnType = TypeInfo("void");240 SpecializedTemplateMethod.Loc.emplace_back(0, 0, "test.cpp");241 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F",242 InfoType::IT_record);243 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",244 InfoType::IT_namespace);245 SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;246 SpecializedTemplateMethod.IsMethod = true;247 ExpectedTemplatedRecord.Children.Functions.emplace_back(248 std::move(SpecializedTemplateMethod));249 CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);250 251 RecordInfo *G = InfoAsRecord(Infos[8].get());252 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");253 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",254 InfoType::IT_namespace);255 ExpectedG.TagType = TagTypeKind::Struct;256 ExpectedG.DefLoc = Location(0, 0, "test.cpp");257 ExpectedG.IsTypeDef = true;258 CheckRecordInfo(&ExpectedG, G);259}260 261// Test serialization of enum declarations.262TEST(SerializeTest, emitEnumInfo) {263 EmittedInfoList Infos;264 ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,265 /*Public=*/false, Infos);266 267 NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get());268 NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);269 EnumInfo E;270 E.Name = "E";271 E.DefLoc = Location(0, 0, "test.cpp");272 E.Members.emplace_back("X", "0");273 E.Members.emplace_back("Y", "1");274 ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E));275 CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);276 277 NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());278 NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);279 EnumInfo G;280 G.Name = "G";281 G.Scoped = true;282 G.DefLoc = Location(0, 0, "test.cpp");283 G.Members.emplace_back("A", "0");284 G.Members.emplace_back("B", "1");285 ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G));286 CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);287}288 289TEST(SerializeTest, emitUndefinedRecordInfo) {290 EmittedInfoList Infos;291 ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos);292 293 RecordInfo *E = InfoAsRecord(Infos[0].get());294 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");295 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",296 InfoType::IT_namespace);297 ExpectedE.TagType = TagTypeKind::Class;298 ExpectedE.Loc.emplace_back(0, 0, "test.cpp");299 CheckRecordInfo(&ExpectedE, E);300}301 302TEST(SerializeTest, emitRecordMemberInfo) {303 EmittedInfoList Infos;304 ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos);305 306 RecordInfo *E = InfoAsRecord(Infos[0].get());307 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");308 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",309 InfoType::IT_namespace);310 ExpectedE.TagType = TagTypeKind::Struct;311 ExpectedE.DefLoc = Location(0, 0, "test.cpp");312 ExpectedE.Members.emplace_back(TypeInfo("int"), "I",313 AccessSpecifier::AS_public);314 CheckRecordInfo(&ExpectedE, E);315}316 317TEST(SerializeTest, emitInternalRecordInfo) {318 EmittedInfoList Infos;319 ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos);320 321 RecordInfo *E = InfoAsRecord(Infos[0].get());322 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");323 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",324 InfoType::IT_namespace);325 ExpectedE.DefLoc = Location(0, 0, "test.cpp");326 ExpectedE.TagType = TagTypeKind::Class;327 CheckRecordInfo(&ExpectedE, E);328 329 RecordInfo *G = InfoAsRecord(Infos[2].get());330 llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");331 llvm::sys::path::native(ExpectedGPath);332 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath);333 ExpectedG.DefLoc = Location(0, 0, "test.cpp");334 ExpectedG.TagType = TagTypeKind::Class;335 ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);336 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",337 InfoType::IT_namespace);338 CheckRecordInfo(&ExpectedG, G);339}340 341TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {342 EmittedInfoList Infos;343 ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos);344}345 346TEST(SerializeTest, emitPublicFunctionInternalInfo) {347 EmittedInfoList Infos;348 ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,349 Infos);350 351 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());352 NamespaceInfo ExpectedBWithFunction(EmptySID);353 FunctionInfo F;354 F.Name = "F";355 F.ReturnType = TypeInfo("int");356 F.DefLoc = Location(0, 0, "test.cpp");357 F.Access = AccessSpecifier::AS_none;358 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));359 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);360}361 362TEST(SerializeTest, emitInlinedFunctionInfo) {363 EmittedInfoList Infos;364 ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos);365 366 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());367 NamespaceInfo ExpectedBWithFunction(EmptySID);368 FunctionInfo F;369 F.Name = "F";370 F.ReturnType = TypeInfo("void");371 F.DefLoc = Location(0, 0, "test.cpp");372 F.Params.emplace_back(TypeInfo("int"), "I");373 F.Access = AccessSpecifier::AS_none;374 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));375 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);376}377 378TEST(SerializeTest, emitInheritedRecordInfo) {379 EmittedInfoList Infos;380 ExtractInfosFromCode(R"raw(class F { protected: void set(int N); };381class G { public: int get() { return 1; } protected: int I; };382class E : public F, virtual private G {};383class H : private E {};384template <typename T>385class I {} ;386class J : public I<int> {} ;)raw",387 14, /*Public=*/false, Infos);388 389 RecordInfo *F = InfoAsRecord(Infos[0].get());390 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");391 ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",392 InfoType::IT_namespace, "");393 ExpectedF.TagType = TagTypeKind::Class;394 ExpectedF.DefLoc = Location(0, 0, "test.cpp");395 CheckRecordInfo(&ExpectedF, F);396 397 RecordInfo *G = InfoAsRecord(Infos[3].get());398 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");399 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",400 InfoType::IT_namespace);401 ExpectedG.TagType = TagTypeKind::Class;402 ExpectedG.DefLoc = Location(0, 0, "test.cpp");403 ExpectedG.Members.emplace_back(TypeInfo("int"), "I",404 AccessSpecifier::AS_protected);405 CheckRecordInfo(&ExpectedG, G);406 407 RecordInfo *E = InfoAsRecord(Infos[6].get());408 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");409 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",410 InfoType::IT_namespace);411 ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record,412 /*QualName=*/"", /*Path*=*/"GlobalNamespace");413 ExpectedE.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",414 InfoType::IT_record, /*QualName=*/"G",415 /*Path*=*/"GlobalNamespace");416 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F",417 /*Path=*/"GlobalNamespace", false,418 AccessSpecifier::AS_public, true);419 FunctionInfo FunctionSet;420 FunctionSet.Name = "set";421 FunctionSet.ReturnType = TypeInfo("void");422 FunctionSet.Loc.emplace_back();423 FunctionSet.Params.emplace_back(TypeInfo("int"), "N");424 FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);425 FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace",426 InfoType::IT_namespace);427 FunctionSet.Access = AccessSpecifier::AS_protected;428 FunctionSet.IsMethod = true;429 ExpectedE.Bases.back().Children.Functions.emplace_back(430 std::move(FunctionSet));431 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G",432 /*Path=*/"GlobalNamespace", true,433 AccessSpecifier::AS_private, true);434 FunctionInfo FunctionGet;435 FunctionGet.Name = "get";436 FunctionGet.ReturnType = TypeInfo("int");437 FunctionGet.DefLoc = Location();438 FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);439 FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace",440 InfoType::IT_namespace);441 FunctionGet.Access = AccessSpecifier::AS_private;442 FunctionGet.IsMethod = true;443 ExpectedE.Bases.back().Children.Functions.emplace_back(444 std::move(FunctionGet));445 ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I",446 AccessSpecifier::AS_private);447 ExpectedE.DefLoc = Location(0, 0, "test.cpp");448 ExpectedE.TagType = TagTypeKind::Class;449 CheckRecordInfo(&ExpectedE, E);450 451 RecordInfo *H = InfoAsRecord(Infos[8].get());452 RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");453 ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace",454 InfoType::IT_namespace);455 ExpectedH.TagType = TagTypeKind::Class;456 ExpectedH.DefLoc = Location(0, 0, "test.cpp");457 ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record,458 /*QualName=*/"E", /*Path=*/"GlobalNamespace");459 ExpectedH.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",460 InfoType::IT_record, /*QualName=*/"G",461 /*Path=*/"GlobalNamespace");462 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E",463 /*Path=*/"GlobalNamespace", false,464 AccessSpecifier::AS_private, true);465 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F",466 /*Path=*/"GlobalNamespace", false,467 AccessSpecifier::AS_private, false);468 FunctionInfo FunctionSetNew;469 FunctionSetNew.Name = "set";470 FunctionSetNew.ReturnType = TypeInfo("void");471 FunctionSetNew.Loc.emplace_back();472 FunctionSetNew.Params.emplace_back(TypeInfo("int"), "N");473 FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);474 FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",475 InfoType::IT_namespace);476 FunctionSetNew.Access = AccessSpecifier::AS_private;477 FunctionSetNew.IsMethod = true;478 ExpectedH.Bases.back().Children.Functions.emplace_back(479 std::move(FunctionSetNew));480 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",481 /*Path=*/"GlobalNamespace", true,482 AccessSpecifier::AS_private, false);483 FunctionInfo FunctionGetNew;484 FunctionGetNew.Name = "get";485 FunctionGetNew.ReturnType = TypeInfo("int");486 FunctionGetNew.DefLoc = Location();487 FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);488 FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",489 InfoType::IT_namespace);490 FunctionGetNew.Access = AccessSpecifier::AS_private;491 FunctionGetNew.IsMethod = true;492 ExpectedH.Bases.back().Children.Functions.emplace_back(493 std::move(FunctionGetNew));494 ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I",495 AccessSpecifier::AS_private);496 CheckRecordInfo(&ExpectedH, H);497 498 RecordInfo *I = InfoAsRecord(Infos[10].get());499 RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");500 ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace",501 InfoType::IT_namespace);502 ExpectedI.TagType = TagTypeKind::Class;503 ExpectedI.DefLoc = Location(0, 0, "test.cpp");504 CheckRecordInfo(&ExpectedI, I);505 506 RecordInfo *J = InfoAsRecord(Infos[12].get());507 RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");508 ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace",509 InfoType::IT_namespace);510 ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>",511 InfoType::IT_record);512 ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>",513 /*Path=*/"GlobalNamespace", false,514 AccessSpecifier::AS_public, true);515 ExpectedJ.DefLoc = Location(0, 0, "test.cpp");516 ExpectedJ.TagType = TagTypeKind::Class;517 CheckRecordInfo(&ExpectedJ, J);518}519 520TEST(SerializeTest, emitModulePublicLFunctions) {521 EmittedInfoList Infos;522 std::vector<std::string> Args;523 Args.push_back("-fmodules-ts");524 ExtractInfosFromCodeWithArgs(R"raw(export module M;525int moduleFunction(int x, double d = 3.2 - 1.0);526static int staticModuleFunction(int x);527export double exportedModuleFunction(double y);)raw",528 2, /*Public=*/true, Infos, Args);529 530 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());531 NamespaceInfo ExpectedBWithFunction(EmptySID);532 FunctionInfo F;533 F.Name = "moduleFunction";534 F.ReturnType = TypeInfo("int");535 F.Loc.emplace_back(0, 0, "test.cpp");536 F.Params.emplace_back(TypeInfo("int"), "x");537 F.Params.emplace_back(TypeInfo("double"), "d");538 F.Params.back().DefaultValue = "3.2 - 1.0";539 F.Access = AccessSpecifier::AS_none;540 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));541 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);542 543 NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());544 NamespaceInfo ExpectedBWithExportedFunction(EmptySID);545 FunctionInfo ExportedF;546 ExportedF.Name = "exportedModuleFunction";547 ExportedF.ReturnType =548 TypeInfo(Reference(EmptySID, "double", InfoType::IT_default));549 ExportedF.Loc.emplace_back(0, 0, "test.cpp");550 ExportedF.Params.emplace_back(TypeInfo("double"), "y");551 ExportedF.Access = AccessSpecifier::AS_none;552 ExpectedBWithExportedFunction.Children.Functions.emplace_back(553 std::move(ExportedF));554 CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);555}556 557// Test serialization of child records in namespaces and other records558TEST(SerializeTest, emitChildRecords) {559 EmittedInfoList Infos;560 ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,561 /*Public=*/false, Infos);562 563 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());564 NamespaceInfo ExpectedParentA(EmptySID);565 ExpectedParentA.Children.Records.emplace_back(566 EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");567 CheckNamespaceInfo(&ExpectedParentA, ParentA);568 569 RecordInfo *ParentB = InfoAsRecord(Infos[3].get());570 RecordInfo ExpectedParentB(EmptySID);571 llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");572 llvm::sys::path::native(ExpectedParentBPath);573 ExpectedParentB.Children.Records.emplace_back(574 EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);575 CheckRecordInfo(&ExpectedParentB, ParentB);576 577 NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());578 NamespaceInfo ExpectedParentC(EmptySID);579 ExpectedParentC.Children.Records.emplace_back(580 EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");581 CheckNamespaceInfo(&ExpectedParentC, ParentC);582}583 584// Test serialization of child namespaces585TEST(SerializeTest, emitChildNamespaces) {586 EmittedInfoList Infos;587 ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,588 Infos);589 590 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());591 NamespaceInfo ExpectedParentA(EmptySID);592 ExpectedParentA.Children.Namespaces.emplace_back(EmptySID, "A",593 InfoType::IT_namespace);594 CheckNamespaceInfo(&ExpectedParentA, ParentA);595 596 NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());597 NamespaceInfo ExpectedParentB(EmptySID);598 ExpectedParentB.Children.Namespaces.emplace_back(599 EmptySID, "B", InfoType::IT_namespace, "A::B", "A");600 CheckNamespaceInfo(&ExpectedParentB, ParentB);601}602 603TEST(SerializeTests, emitTypedefs) {604 EmittedInfoList Infos;605 ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,606 /*Public=*/false, Infos);607 608 // First info will be the global namespace with the typedef in it.609 NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());610 ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());611 612 const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];613 EXPECT_EQ("MyInt", FirstTD.Name);614 EXPECT_FALSE(FirstTD.IsUsing);615 EXPECT_EQ("int", FirstTD.Underlying.Type.Name);616 617 // The second will be another global namespace with the using in it (the618 // global namespace is duplicated because the items haven't been merged at the619 // serialization phase of processing).620 NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());621 ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());622 623 // Second is the "using" typedef.624 const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];625 EXPECT_EQ("MyDouble", SecondTD.Name);626 EXPECT_TRUE(SecondTD.IsUsing);627 EXPECT_EQ("double", SecondTD.Underlying.Type.Name);628}629 630TEST(SerializeTests, emitFunctionTemplate) {631 EmittedInfoList Infos;632 // A template and a specialization.633 ExtractInfosFromCode("template<typename T = int> bool GetFoo(T);\n"634 "template<> bool GetFoo<bool>(bool);",635 2,636 /*Public=*/false, Infos);637 638 // First info will be the global namespace.639 NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());640 ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());641 642 const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];643 EXPECT_EQ("GetFoo", Func1.Name);644 ASSERT_TRUE(Func1.Template);645 EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.646 647 // Template parameter.648 ASSERT_EQ(1u, Func1.Template->Params.size());649 EXPECT_EQ("typename T = int", Func1.Template->Params[0].Contents);650 651 // The second will be another global namespace with the function in it (the652 // global namespace is duplicated because the items haven't been merged at the653 // serialization phase of processing).654 NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());655 ASSERT_EQ(1u, GlobalNS2->Children.Functions.size());656 657 // This one is a template specialization.658 const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];659 EXPECT_EQ("GetFoo", Func2.Name);660 ASSERT_TRUE(Func2.Template);661 EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.662 ASSERT_TRUE(Func2.Template->Specialization);663 664 // Specialization values.665 ASSERT_EQ(1u, Func2.Template->Specialization->Params.size());666 EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents);667 EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf);668 669 EXPECT_EQ("bool", Func2.ReturnType.Type.Name);670}671 672TEST(SerializeTests, emitClassTemplate) {673 EmittedInfoList Infos;674 // This will generate 2x the number of infos: each Record will be followed by675 // a copy of the global namespace containing it (this test checks the data676 // pre-merge).677 ExtractInfosFromCode(678 "template<int I> class MyTemplate { int i[I]; };\n"679 "template<> class MyTemplate<0> {};\n"680 "template<typename T, int U = 1> class OtherTemplate {};\n"681 "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",682 8,683 /*Public=*/false, Infos);684 685 // First record.686 const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());687 EXPECT_EQ("MyTemplate", Rec1->Name);688 ASSERT_TRUE(Rec1->Template);689 EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.690 691 // First record template parameter.692 ASSERT_EQ(1u, Rec1->Template->Params.size());693 EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);694 695 // Second record.696 const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get());697 EXPECT_EQ("MyTemplate", Rec2->Name);698 ASSERT_TRUE(Rec2->Template);699 EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.700 ASSERT_TRUE(Rec2->Template->Specialization);701 702 // Second record specialization values.703 ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size());704 EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents);705 EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);706 707 // Third record.708 const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get());709 EXPECT_EQ("OtherTemplate", Rec3->Name);710 ASSERT_TRUE(Rec3->Template);711 712 // Third record template parameters.713 ASSERT_EQ(2u, Rec3->Template->Params.size());714 EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents);715 EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);716 717 // Fourth record.718 const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get());719 EXPECT_EQ("OtherTemplate", Rec3->Name);720 ASSERT_TRUE(Rec4->Template);721 ASSERT_TRUE(Rec4->Template->Specialization);722 723 // Fourth record template + specialization parameters.724 ASSERT_EQ(1u, Rec4->Template->Params.size());725 EXPECT_EQ("int U", Rec4->Template->Params[0].Contents);726 ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size());727 EXPECT_EQ("MyTemplate<0>",728 Rec4->Template->Specialization->Params[0].Contents);729 EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents);730}731 732} // namespace doc733} // end namespace clang734