brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.4 KiB · 6d5e7da Raw
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