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-exception 6 // 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 16 namespace clang { 17 namespace doc { 18 19 class ClangDocSerializeTestVisitor 20 : 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 34 public: 35 ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public) 36 : EmittedInfos(EmittedInfos), Public(Public) {} 37 38 template <typename T> bool mapDecl(const T *D) { 39 auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0, 40 /*File=*/"test.cpp", true, Public); 41 if (I.first) 42 EmittedInfos.emplace_back(std::move(I.first)); 43 if (I.second) 44 EmittedInfos.emplace_back(std::move(I.second)); 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 twice 52 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 68 void 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 77 void 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 and 89 the code that calls this is re-enabled. 90 CommentInfo 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. 108 TEST(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, llvm::SmallString<16>{"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 135 TEST(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. 146 TEST(SerializeTest, emitRecordInfo) { 147 EmittedInfoList Infos; 148 ExtractInfosFromCode(R"raw(class E { 149 public: 150 E() {} 151 152 // Some docs. 153 int value; 154 protected: 155 void ProtectedMethod(); 156 }; 157 template <typename T> 158 struct F { 159 void TemplateMethod(); 160 }; 161 template <> 162 void F<int>::TemplateMethod(); 163 typedef 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, llvm::SmallString<16>{"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, llvm::SmallString<16>{"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, llvm::SmallString<16>{"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, llvm::SmallString<16>{"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, llvm::SmallString<16>{"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, 241 llvm::SmallString<16>{"test.cpp"}); 242 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F", 243 InfoType::IT_record); 244 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace", 245 InfoType::IT_namespace); 246 SpecializedTemplateMethod.Access = AccessSpecifier::AS_public; 247 SpecializedTemplateMethod.IsMethod = true; 248 ExpectedTemplatedRecord.Children.Functions.emplace_back( 249 std::move(SpecializedTemplateMethod)); 250 CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord); 251 252 RecordInfo *G = InfoAsRecord(Infos[8].get()); 253 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace"); 254 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", 255 InfoType::IT_namespace); 256 ExpectedG.TagType = TagTypeKind::Struct; 257 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 258 ExpectedG.IsTypeDef = true; 259 CheckRecordInfo(&ExpectedG, G); 260 } 261 262 // Test serialization of enum declarations. 263 TEST(SerializeTest, emitEnumInfo) { 264 EmittedInfoList Infos; 265 ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2, 266 /*Public=*/false, Infos); 267 268 NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get()); 269 NamespaceInfo ExpectedNamespaceWithEnum(EmptySID); 270 EnumInfo E; 271 E.Name = "E"; 272 E.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 273 E.Members.emplace_back("X", "0"); 274 E.Members.emplace_back("Y", "1"); 275 ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E)); 276 CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum); 277 278 NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get()); 279 NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID); 280 EnumInfo G; 281 G.Name = "G"; 282 G.Scoped = true; 283 G.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 284 G.Members.emplace_back("A", "0"); 285 G.Members.emplace_back("B", "1"); 286 ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G)); 287 CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum); 288 } 289 290 TEST(SerializeTest, emitUndefinedRecordInfo) { 291 EmittedInfoList Infos; 292 ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos); 293 294 RecordInfo *E = InfoAsRecord(Infos[0].get()); 295 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); 296 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", 297 InfoType::IT_namespace); 298 ExpectedE.TagType = TagTypeKind::Class; 299 ExpectedE.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); 300 CheckRecordInfo(&ExpectedE, E); 301 } 302 303 TEST(SerializeTest, emitRecordMemberInfo) { 304 EmittedInfoList Infos; 305 ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos); 306 307 RecordInfo *E = InfoAsRecord(Infos[0].get()); 308 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); 309 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", 310 InfoType::IT_namespace); 311 ExpectedE.TagType = TagTypeKind::Struct; 312 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 313 ExpectedE.Members.emplace_back(TypeInfo("int"), "I", 314 AccessSpecifier::AS_public); 315 CheckRecordInfo(&ExpectedE, E); 316 } 317 318 TEST(SerializeTest, emitInternalRecordInfo) { 319 EmittedInfoList Infos; 320 ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos); 321 322 RecordInfo *E = InfoAsRecord(Infos[0].get()); 323 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); 324 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", 325 InfoType::IT_namespace); 326 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 327 ExpectedE.TagType = TagTypeKind::Class; 328 CheckRecordInfo(&ExpectedE, E); 329 330 RecordInfo *G = InfoAsRecord(Infos[2].get()); 331 llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E"); 332 llvm::sys::path::native(ExpectedGPath); 333 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath); 334 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 335 ExpectedG.TagType = TagTypeKind::Class; 336 ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); 337 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", 338 InfoType::IT_namespace); 339 CheckRecordInfo(&ExpectedG, G); 340 } 341 342 TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) { 343 EmittedInfoList Infos; 344 ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos); 345 } 346 347 TEST(SerializeTest, emitPublicFunctionInternalInfo) { 348 EmittedInfoList Infos; 349 ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true, 350 Infos); 351 352 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); 353 NamespaceInfo ExpectedBWithFunction(EmptySID); 354 FunctionInfo F; 355 F.Name = "F"; 356 F.ReturnType = TypeInfo("int"); 357 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 358 F.Access = AccessSpecifier::AS_none; 359 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F)); 360 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); 361 } 362 363 TEST(SerializeTest, emitInlinedFunctionInfo) { 364 EmittedInfoList Infos; 365 ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos); 366 367 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); 368 NamespaceInfo ExpectedBWithFunction(EmptySID); 369 FunctionInfo F; 370 F.Name = "F"; 371 F.ReturnType = TypeInfo("void"); 372 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 373 F.Params.emplace_back(TypeInfo("int"), "I"); 374 F.Access = AccessSpecifier::AS_none; 375 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F)); 376 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); 377 } 378 379 TEST(SerializeTest, emitInheritedRecordInfo) { 380 EmittedInfoList Infos; 381 ExtractInfosFromCode(R"raw(class F { protected: void set(int N); }; 382 class G { public: int get() { return 1; } protected: int I; }; 383 class E : public F, virtual private G {}; 384 class H : private E {}; 385 template <typename T> 386 class I {} ; 387 class J : public I<int> {} ;)raw", 388 14, /*Public=*/false, Infos); 389 390 RecordInfo *F = InfoAsRecord(Infos[0].get()); 391 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace"); 392 ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace", 393 InfoType::IT_namespace, ""); 394 ExpectedF.TagType = TagTypeKind::Class; 395 ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 396 CheckRecordInfo(&ExpectedF, F); 397 398 RecordInfo *G = InfoAsRecord(Infos[3].get()); 399 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace"); 400 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", 401 InfoType::IT_namespace); 402 ExpectedG.TagType = TagTypeKind::Class; 403 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 404 ExpectedG.Members.emplace_back(TypeInfo("int"), "I", 405 AccessSpecifier::AS_protected); 406 CheckRecordInfo(&ExpectedG, G); 407 408 RecordInfo *E = InfoAsRecord(Infos[6].get()); 409 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); 410 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", 411 InfoType::IT_namespace); 412 ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record, 413 /*QualName=*/"", /*Path*=*/"GlobalNamespace"); 414 ExpectedE.VirtualParents.emplace_back(EmptySID, /*Name=*/"G", 415 InfoType::IT_record, /*QualName=*/"G", 416 /*Path*=*/"GlobalNamespace"); 417 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F", 418 /*Path=*/"GlobalNamespace", false, 419 AccessSpecifier::AS_public, true); 420 FunctionInfo FunctionSet; 421 FunctionSet.Name = "set"; 422 FunctionSet.ReturnType = TypeInfo("void"); 423 FunctionSet.Loc.emplace_back(); 424 FunctionSet.Params.emplace_back(TypeInfo("int"), "N"); 425 FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); 426 FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace", 427 InfoType::IT_namespace); 428 FunctionSet.Access = AccessSpecifier::AS_protected; 429 FunctionSet.IsMethod = true; 430 ExpectedE.Bases.back().Children.Functions.emplace_back( 431 std::move(FunctionSet)); 432 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G", 433 /*Path=*/"GlobalNamespace", true, 434 AccessSpecifier::AS_private, true); 435 FunctionInfo FunctionGet; 436 FunctionGet.Name = "get"; 437 FunctionGet.ReturnType = TypeInfo("int"); 438 FunctionGet.DefLoc = Location(); 439 FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); 440 FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace", 441 InfoType::IT_namespace); 442 FunctionGet.Access = AccessSpecifier::AS_private; 443 FunctionGet.IsMethod = true; 444 ExpectedE.Bases.back().Children.Functions.emplace_back( 445 std::move(FunctionGet)); 446 ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I", 447 AccessSpecifier::AS_private); 448 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 449 ExpectedE.TagType = TagTypeKind::Class; 450 CheckRecordInfo(&ExpectedE, E); 451 452 RecordInfo *H = InfoAsRecord(Infos[8].get()); 453 RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace"); 454 ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace", 455 InfoType::IT_namespace); 456 ExpectedH.TagType = TagTypeKind::Class; 457 ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 458 ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record, 459 /*QualName=*/"E", /*Path=*/"GlobalNamespace"); 460 ExpectedH.VirtualParents.emplace_back(EmptySID, /*Name=*/"G", 461 InfoType::IT_record, /*QualName=*/"G", 462 /*Path=*/"GlobalNamespace"); 463 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E", 464 /*Path=*/"GlobalNamespace", false, 465 AccessSpecifier::AS_private, true); 466 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F", 467 /*Path=*/"GlobalNamespace", false, 468 AccessSpecifier::AS_private, false); 469 FunctionInfo FunctionSetNew; 470 FunctionSetNew.Name = "set"; 471 FunctionSetNew.ReturnType = TypeInfo("void"); 472 FunctionSetNew.Loc.emplace_back(); 473 FunctionSetNew.Params.emplace_back(TypeInfo("int"), "N"); 474 FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); 475 FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", 476 InfoType::IT_namespace); 477 FunctionSetNew.Access = AccessSpecifier::AS_private; 478 FunctionSetNew.IsMethod = true; 479 ExpectedH.Bases.back().Children.Functions.emplace_back( 480 std::move(FunctionSetNew)); 481 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G", 482 /*Path=*/"GlobalNamespace", true, 483 AccessSpecifier::AS_private, false); 484 FunctionInfo FunctionGetNew; 485 FunctionGetNew.Name = "get"; 486 FunctionGetNew.ReturnType = TypeInfo("int"); 487 FunctionGetNew.DefLoc = Location(); 488 FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); 489 FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", 490 InfoType::IT_namespace); 491 FunctionGetNew.Access = AccessSpecifier::AS_private; 492 FunctionGetNew.IsMethod = true; 493 ExpectedH.Bases.back().Children.Functions.emplace_back( 494 std::move(FunctionGetNew)); 495 ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I", 496 AccessSpecifier::AS_private); 497 CheckRecordInfo(&ExpectedH, H); 498 499 RecordInfo *I = InfoAsRecord(Infos[10].get()); 500 RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace"); 501 ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace", 502 InfoType::IT_namespace); 503 ExpectedI.TagType = TagTypeKind::Class; 504 ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 505 CheckRecordInfo(&ExpectedI, I); 506 507 RecordInfo *J = InfoAsRecord(Infos[12].get()); 508 RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace"); 509 ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace", 510 InfoType::IT_namespace); 511 ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>", 512 InfoType::IT_record); 513 ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>", 514 /*Path=*/"GlobalNamespace", false, 515 AccessSpecifier::AS_public, true); 516 ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); 517 ExpectedJ.TagType = TagTypeKind::Class; 518 CheckRecordInfo(&ExpectedJ, J); 519 } 520 521 TEST(SerializeTest, emitModulePublicLFunctions) { 522 EmittedInfoList Infos; 523 std::vector<std::string> Args; 524 Args.push_back("-fmodules-ts"); 525 ExtractInfosFromCodeWithArgs(R"raw(export module M; 526 int moduleFunction(int x, double d = 3.2 - 1.0); 527 static int staticModuleFunction(int x); 528 export double exportedModuleFunction(double y);)raw", 529 2, /*Public=*/true, Infos, Args); 530 531 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get()); 532 NamespaceInfo ExpectedBWithFunction(EmptySID); 533 FunctionInfo F; 534 F.Name = "moduleFunction"; 535 F.ReturnType = TypeInfo("int"); 536 F.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); 537 F.Params.emplace_back(TypeInfo("int"), "x"); 538 F.Params.emplace_back(TypeInfo("double"), "d"); 539 F.Params.back().DefaultValue = "3.2 - 1.0"; 540 F.Access = AccessSpecifier::AS_none; 541 ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F)); 542 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); 543 544 NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get()); 545 NamespaceInfo ExpectedBWithExportedFunction(EmptySID); 546 FunctionInfo ExportedF; 547 ExportedF.Name = "exportedModuleFunction"; 548 ExportedF.ReturnType = 549 TypeInfo(Reference(EmptySID, "double", InfoType::IT_default)); 550 ExportedF.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); 551 ExportedF.Params.emplace_back(TypeInfo("double"), "y"); 552 ExportedF.Access = AccessSpecifier::AS_none; 553 ExpectedBWithExportedFunction.Children.Functions.emplace_back( 554 std::move(ExportedF)); 555 CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction); 556 } 557 558 // Test serialization of child records in namespaces and other records 559 TEST(SerializeTest, emitChildRecords) { 560 EmittedInfoList Infos; 561 ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8, 562 /*Public=*/false, Infos); 563 564 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get()); 565 NamespaceInfo ExpectedParentA(EmptySID); 566 ExpectedParentA.Children.Records.emplace_back( 567 EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace"); 568 CheckNamespaceInfo(&ExpectedParentA, ParentA); 569 570 RecordInfo *ParentB = InfoAsRecord(Infos[3].get()); 571 RecordInfo ExpectedParentB(EmptySID); 572 llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A"); 573 llvm::sys::path::native(ExpectedParentBPath); 574 ExpectedParentB.Children.Records.emplace_back( 575 EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath); 576 CheckRecordInfo(&ExpectedParentB, ParentB); 577 578 NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get()); 579 NamespaceInfo ExpectedParentC(EmptySID); 580 ExpectedParentC.Children.Records.emplace_back( 581 EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace"); 582 CheckNamespaceInfo(&ExpectedParentC, ParentC); 583 } 584 585 // Test serialization of child namespaces 586 TEST(SerializeTest, emitChildNamespaces) { 587 EmittedInfoList Infos; 588 ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false, 589 Infos); 590 591 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get()); 592 NamespaceInfo ExpectedParentA(EmptySID); 593 ExpectedParentA.Children.Namespaces.emplace_back(EmptySID, "A", 594 InfoType::IT_namespace); 595 CheckNamespaceInfo(&ExpectedParentA, ParentA); 596 597 NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get()); 598 NamespaceInfo ExpectedParentB(EmptySID); 599 ExpectedParentB.Children.Namespaces.emplace_back( 600 EmptySID, "B", InfoType::IT_namespace, "A::B", "A"); 601 CheckNamespaceInfo(&ExpectedParentB, ParentB); 602 } 603 604 TEST(SerializeTests, emitTypedefs) { 605 EmittedInfoList Infos; 606 ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2, 607 /*Public=*/false, Infos); 608 609 // First info will be the global namespace with the typedef in it. 610 NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get()); 611 ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size()); 612 613 const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0]; 614 EXPECT_EQ("MyInt", FirstTD.Name); 615 EXPECT_FALSE(FirstTD.IsUsing); 616 EXPECT_EQ("int", FirstTD.Underlying.Type.Name); 617 618 // The second will be another global namespace with the using in it (the 619 // global namespace is duplicated because the items haven't been merged at the 620 // serialization phase of processing). 621 NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get()); 622 ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size()); 623 624 // Second is the "using" typedef. 625 const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0]; 626 EXPECT_EQ("MyDouble", SecondTD.Name); 627 EXPECT_TRUE(SecondTD.IsUsing); 628 EXPECT_EQ("double", SecondTD.Underlying.Type.Name); 629 } 630 631 TEST(SerializeTests, emitFunctionTemplate) { 632 EmittedInfoList Infos; 633 // A template and a specialization. 634 ExtractInfosFromCode("template<typename T = int> bool GetFoo(T);\n" 635 "template<> bool GetFoo<bool>(bool);", 636 2, 637 /*Public=*/false, Infos); 638 639 // First info will be the global namespace. 640 NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get()); 641 ASSERT_EQ(1u, GlobalNS1->Children.Functions.size()); 642 643 const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0]; 644 EXPECT_EQ("GetFoo", Func1.Name); 645 ASSERT_TRUE(Func1.Template); 646 EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization. 647 648 // Template parameter. 649 ASSERT_EQ(1u, Func1.Template->Params.size()); 650 EXPECT_EQ("typename T = int", Func1.Template->Params[0].Contents); 651 652 // The second will be another global namespace with the function in it (the 653 // global namespace is duplicated because the items haven't been merged at the 654 // serialization phase of processing). 655 NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get()); 656 ASSERT_EQ(1u, GlobalNS2->Children.Functions.size()); 657 658 // This one is a template specialization. 659 const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0]; 660 EXPECT_EQ("GetFoo", Func2.Name); 661 ASSERT_TRUE(Func2.Template); 662 EXPECT_TRUE(Func2.Template->Params.empty()); // No template params. 663 ASSERT_TRUE(Func2.Template->Specialization); 664 665 // Specialization values. 666 ASSERT_EQ(1u, Func2.Template->Specialization->Params.size()); 667 EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents); 668 EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf); 669 670 EXPECT_EQ("bool", Func2.ReturnType.Type.Name); 671 } 672 673 TEST(SerializeTests, emitClassTemplate) { 674 EmittedInfoList Infos; 675 // This will generate 2x the number of infos: each Record will be followed by 676 // a copy of the global namespace containing it (this test checks the data 677 // pre-merge). 678 ExtractInfosFromCode( 679 "template<int I> class MyTemplate { int i[I]; };\n" 680 "template<> class MyTemplate<0> {};\n" 681 "template<typename T, int U = 1> class OtherTemplate {};\n" 682 "template<int U> class OtherTemplate<MyTemplate<0>, U> {};", 683 8, 684 /*Public=*/false, Infos); 685 686 // First record. 687 const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get()); 688 EXPECT_EQ("MyTemplate", Rec1->Name); 689 ASSERT_TRUE(Rec1->Template); 690 EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization. 691 692 // First record template parameter. 693 ASSERT_EQ(1u, Rec1->Template->Params.size()); 694 EXPECT_EQ("int I", Rec1->Template->Params[0].Contents); 695 696 // Second record. 697 const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get()); 698 EXPECT_EQ("MyTemplate", Rec2->Name); 699 ASSERT_TRUE(Rec2->Template); 700 EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params. 701 ASSERT_TRUE(Rec2->Template->Specialization); 702 703 // Second record specialization values. 704 ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size()); 705 EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents); 706 EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf); 707 708 // Third record. 709 const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get()); 710 EXPECT_EQ("OtherTemplate", Rec3->Name); 711 ASSERT_TRUE(Rec3->Template); 712 713 // Third record template parameters. 714 ASSERT_EQ(2u, Rec3->Template->Params.size()); 715 EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents); 716 EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents); 717 718 // Fourth record. 719 const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get()); 720 EXPECT_EQ("OtherTemplate", Rec3->Name); 721 ASSERT_TRUE(Rec4->Template); 722 ASSERT_TRUE(Rec4->Template->Specialization); 723 724 // Fourth record template + specialization parameters. 725 ASSERT_EQ(1u, Rec4->Template->Params.size()); 726 EXPECT_EQ("int U", Rec4->Template->Params[0].Contents); 727 ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size()); 728 EXPECT_EQ("MyTemplate<0>", 729 Rec4->Template->Specialization->Params[0].Contents); 730 EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents); 731 } 732 733 } // namespace doc 734 } // end namespace clang 735