1 //===-- TypeHierarchyTests.cpp ---------------------------*- C++ -*-------===// 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 #include "AST.h" 9 #include "Annotations.h" 10 #include "Matchers.h" 11 #include "ParsedAST.h" 12 #include "TestFS.h" 13 #include "TestTU.h" 14 #include "XRefs.h" 15 #include "clang/AST/DeclCXX.h" 16 #include "clang/AST/DeclTemplate.h" 17 #include "llvm/Support/Path.h" 18 #include "gmock/gmock.h" 19 #include "gtest/gtest.h" 20 #include <vector> 21 22 namespace clang { 23 namespace clangd { 24 namespace { 25 26 using ::testing::AllOf; 27 using ::testing::ElementsAre; 28 using ::testing::Field; 29 using ::testing::IsEmpty; 30 using ::testing::Matcher; 31 using ::testing::Optional; 32 using ::testing::SizeIs; 33 using ::testing::UnorderedElementsAre; 34 35 // GMock helpers for matching TypeHierarchyItem. 36 MATCHER_P(withName, N, "") { return arg.name == N; } 37 MATCHER_P(withKind, Kind, "") { return arg.kind == Kind; } 38 MATCHER_P(selectionRangeIs, R, "") { return arg.selectionRange == R; } 39 template <class... ParentMatchers> 40 ::testing::Matcher<TypeHierarchyItem> parents(ParentMatchers... ParentsM) { 41 return Field(&TypeHierarchyItem::parents, 42 Optional(UnorderedElementsAre(ParentsM...))); 43 } 44 template <class... ChildMatchers> 45 ::testing::Matcher<TypeHierarchyItem> children(ChildMatchers... ChildrenM) { 46 return Field(&TypeHierarchyItem::children, 47 Optional(UnorderedElementsAre(ChildrenM...))); 48 } 49 // Note: "not resolved" is different from "resolved but empty"! 50 MATCHER(parentsNotResolved, "") { return !arg.parents; } 51 MATCHER(childrenNotResolved, "") { return !arg.children; } 52 MATCHER_P(withResolveID, SID, "") { return arg.symbolID.str() == SID; } 53 MATCHER_P(withResolveParents, M, "") { 54 return testing::ExplainMatchResult(M, arg.data.parents, result_listener); 55 } 56 57 TEST(FindRecordTypeAt, TypeOrVariable) { 58 Annotations Source(R"cpp( 59 struct Ch^ild2 { 60 int c; 61 }; 62 63 using A^lias = Child2; 64 65 int main() { 66 Ch^ild2 ch^ild2; 67 ch^ild2.c = 1; 68 } 69 )cpp"); 70 71 TestTU TU = TestTU::withCode(Source.code()); 72 auto AST = TU.build(); 73 74 for (Position Pt : Source.points()) { 75 auto Records = findRecordTypeAt(AST, Pt); 76 ASSERT_THAT(Records, SizeIs(1)); 77 EXPECT_EQ(&findDecl(AST, "Child2"), 78 static_cast<const NamedDecl *>(Records.front())); 79 } 80 } 81 82 TEST(FindRecordTypeAt, Nonexistent) { 83 Annotations Source(R"cpp( 84 int *wa^ldo; 85 )cpp"); 86 TestTU TU = TestTU::withCode(Source.code()); 87 auto AST = TU.build(); 88 89 for (Position Pt : Source.points()) { 90 auto Records = findRecordTypeAt(AST, Pt); 91 ASSERT_THAT(Records, SizeIs(0)); 92 } 93 } 94 95 TEST(FindRecordTypeAt, Method) { 96 Annotations Source(R"cpp( 97 struct Child2 { 98 void met^hod (); 99 void met^hod (int x); 100 }; 101 102 int main() { 103 Child2 child2; 104 child2.met^hod(5); 105 } 106 )cpp"); 107 108 TestTU TU = TestTU::withCode(Source.code()); 109 auto AST = TU.build(); 110 111 for (Position Pt : Source.points()) { 112 auto Records = findRecordTypeAt(AST, Pt); 113 ASSERT_THAT(Records, SizeIs(1)); 114 EXPECT_EQ(&findDecl(AST, "Child2"), 115 static_cast<const NamedDecl *>(Records.front())); 116 } 117 } 118 119 TEST(FindRecordTypeAt, Field) { 120 Annotations Source(R"cpp( 121 struct Child2 { 122 int fi^eld; 123 }; 124 125 int main() { 126 Child2 child2; 127 child2.fi^eld = 5; 128 } 129 )cpp"); 130 131 TestTU TU = TestTU::withCode(Source.code()); 132 auto AST = TU.build(); 133 134 for (Position Pt : Source.points()) { 135 // A field does not unambiguously specify a record type 136 // (possible associated record types could be the field's type, 137 // or the type of the record that the field is a member of). 138 EXPECT_THAT(findRecordTypeAt(AST, Pt), SizeIs(0)); 139 } 140 } 141 142 TEST(TypeParents, SimpleInheritance) { 143 Annotations Source(R"cpp( 144 struct Parent { 145 int a; 146 }; 147 148 struct Child1 : Parent { 149 int b; 150 }; 151 152 struct Child2 : Child1 { 153 int c; 154 }; 155 )cpp"); 156 157 TestTU TU = TestTU::withCode(Source.code()); 158 auto AST = TU.build(); 159 160 const CXXRecordDecl *Parent = 161 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent")); 162 const CXXRecordDecl *Child1 = 163 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1")); 164 const CXXRecordDecl *Child2 = 165 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2")); 166 167 EXPECT_THAT(typeParents(Parent), ElementsAre()); 168 EXPECT_THAT(typeParents(Child1), ElementsAre(Parent)); 169 EXPECT_THAT(typeParents(Child2), ElementsAre(Child1)); 170 } 171 172 TEST(TypeParents, MultipleInheritance) { 173 Annotations Source(R"cpp( 174 struct Parent1 { 175 int a; 176 }; 177 178 struct Parent2 { 179 int b; 180 }; 181 182 struct Parent3 : Parent2 { 183 int c; 184 }; 185 186 struct Child : Parent1, Parent3 { 187 int d; 188 }; 189 )cpp"); 190 191 TestTU TU = TestTU::withCode(Source.code()); 192 auto AST = TU.build(); 193 194 const CXXRecordDecl *Parent1 = 195 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent1")); 196 const CXXRecordDecl *Parent2 = 197 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent2")); 198 const CXXRecordDecl *Parent3 = 199 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent3")); 200 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child")); 201 202 EXPECT_THAT(typeParents(Parent1), ElementsAre()); 203 EXPECT_THAT(typeParents(Parent2), ElementsAre()); 204 EXPECT_THAT(typeParents(Parent3), ElementsAre(Parent2)); 205 EXPECT_THAT(typeParents(Child), ElementsAre(Parent1, Parent3)); 206 } 207 208 TEST(TypeParents, ClassTemplate) { 209 Annotations Source(R"cpp( 210 struct Parent {}; 211 212 template <typename T> 213 struct Child : Parent {}; 214 )cpp"); 215 216 TestTU TU = TestTU::withCode(Source.code()); 217 auto AST = TU.build(); 218 219 const CXXRecordDecl *Parent = 220 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent")); 221 const CXXRecordDecl *Child = 222 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl(); 223 224 EXPECT_THAT(typeParents(Child), ElementsAre(Parent)); 225 } 226 227 MATCHER_P(implicitSpecOf, ClassTemplate, "") { 228 const ClassTemplateSpecializationDecl *CTS = 229 dyn_cast<ClassTemplateSpecializationDecl>(arg); 230 return CTS && 231 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate && 232 CTS->getSpecializationKind() == TSK_ImplicitInstantiation; 233 } 234 235 // This is similar to findDecl(AST, QName), but supports using 236 // a template-id as a query. 237 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST, 238 llvm::StringRef Query) { 239 return findDecl(AST, [&Query](const NamedDecl &ND) { 240 std::string QName; 241 llvm::raw_string_ostream OS(QName); 242 PrintingPolicy Policy(ND.getASTContext().getLangOpts()); 243 // Use getNameForDiagnostic() which includes the template 244 // arguments in the printed name. 245 ND.getNameForDiagnostic(OS, Policy, /*Qualified=*/true); 246 return QName == Query; 247 }); 248 } 249 250 TEST(TypeParents, TemplateSpec1) { 251 Annotations Source(R"cpp( 252 template <typename T> 253 struct Parent {}; 254 255 template <> 256 struct Parent<int> {}; 257 258 struct Child1 : Parent<float> {}; 259 260 struct Child2 : Parent<int> {}; 261 )cpp"); 262 263 TestTU TU = TestTU::withCode(Source.code()); 264 auto AST = TU.build(); 265 266 const CXXRecordDecl *Parent = 267 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl(); 268 const CXXRecordDecl *ParentSpec = 269 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Parent<int>")); 270 const CXXRecordDecl *Child1 = 271 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1")); 272 const CXXRecordDecl *Child2 = 273 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2")); 274 275 EXPECT_THAT(typeParents(Child1), ElementsAre(implicitSpecOf(Parent))); 276 EXPECT_THAT(typeParents(Child2), ElementsAre(ParentSpec)); 277 } 278 279 TEST(TypeParents, TemplateSpec2) { 280 Annotations Source(R"cpp( 281 struct Parent {}; 282 283 template <typename T> 284 struct Child {}; 285 286 template <> 287 struct Child<int> : Parent {}; 288 )cpp"); 289 290 TestTU TU = TestTU::withCode(Source.code()); 291 auto AST = TU.build(); 292 293 const CXXRecordDecl *Parent = 294 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent")); 295 const CXXRecordDecl *Child = 296 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl(); 297 const CXXRecordDecl *ChildSpec = 298 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Child<int>")); 299 300 EXPECT_THAT(typeParents(Child), ElementsAre()); 301 EXPECT_THAT(typeParents(ChildSpec), ElementsAre(Parent)); 302 } 303 304 TEST(TypeParents, DependentBase) { 305 Annotations Source(R"cpp( 306 template <typename T> 307 struct Parent {}; 308 309 template <typename T> 310 struct Child1 : Parent<T> {}; 311 312 template <typename T> 313 struct Child2 : Parent<T>::Type {}; 314 315 template <typename T> 316 struct Child3 : T {}; 317 )cpp"); 318 319 TestTU TU = TestTU::withCode(Source.code()); 320 auto AST = TU.build(); 321 322 const CXXRecordDecl *Parent = 323 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl(); 324 const CXXRecordDecl *Child1 = 325 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child1"))->getTemplatedDecl(); 326 const CXXRecordDecl *Child2 = 327 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child2"))->getTemplatedDecl(); 328 const CXXRecordDecl *Child3 = 329 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child3"))->getTemplatedDecl(); 330 331 // For "Parent<T>", use the primary template as a best-effort guess. 332 EXPECT_THAT(typeParents(Child1), ElementsAre(Parent)); 333 // For "Parent<T>::Type", there is nothing we can do. 334 EXPECT_THAT(typeParents(Child2), ElementsAre()); 335 // Likewise for "T". 336 EXPECT_THAT(typeParents(Child3), ElementsAre()); 337 } 338 339 TEST(TypeParents, IncompleteClass) { 340 Annotations Source(R"cpp( 341 class Incomplete; 342 )cpp"); 343 TestTU TU = TestTU::withCode(Source.code()); 344 auto AST = TU.build(); 345 346 const CXXRecordDecl *Incomplete = 347 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Incomplete")); 348 EXPECT_THAT(typeParents(Incomplete), IsEmpty()); 349 } 350 351 // Parts of getTypeHierarchy() are tested in more detail by the 352 // FindRecordTypeAt.* and TypeParents.* tests above. This test exercises the 353 // entire operation. 354 TEST(TypeHierarchy, Parents) { 355 Annotations Source(R"cpp( 356 struct $Parent1Def[[Parent1]] { 357 int a; 358 }; 359 360 struct $Parent2Def[[Parent2]] { 361 int b; 362 }; 363 364 struct $Parent3Def[[Parent3]] : Parent2 { 365 int c; 366 }; 367 368 struct Ch^ild : Parent1, Parent3 { 369 int d; 370 }; 371 372 int main() { 373 Ch^ild ch^ild; 374 375 ch^ild.a = 1; 376 } 377 )cpp"); 378 379 TestTU TU = TestTU::withCode(Source.code()); 380 auto AST = TU.build(); 381 382 for (Position Pt : Source.points()) { 383 // Set ResolveLevels to 0 because it's only used for Children; 384 // for Parents, getTypeHierarchy() always returns all levels. 385 auto Result = getTypeHierarchy(AST, Pt, /*ResolveLevels=*/0, 386 TypeHierarchyDirection::Parents); 387 ASSERT_THAT(Result, SizeIs(1)); 388 EXPECT_THAT( 389 Result.front(), 390 AllOf( 391 withName("Child"), withKind(SymbolKind::Struct), 392 parents(AllOf(withName("Parent1"), withKind(SymbolKind::Struct), 393 selectionRangeIs(Source.range("Parent1Def")), 394 parents()), 395 AllOf(withName("Parent3"), withKind(SymbolKind::Struct), 396 selectionRangeIs(Source.range("Parent3Def")), 397 parents(AllOf( 398 withName("Parent2"), withKind(SymbolKind::Struct), 399 selectionRangeIs(Source.range("Parent2Def")), 400 parents())))))); 401 } 402 } 403 404 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) { 405 Annotations Source(R"cpp( 406 template <int N> 407 struct $SDef[[S]] : S<N + 1> {}; 408 409 S^<0> s; // error-ok 410 )cpp"); 411 412 TestTU TU = TestTU::withCode(Source.code()); 413 TU.ExtraArgs.push_back("-ftemplate-depth=10"); 414 auto AST = TU.build(); 415 416 // The compiler should produce a diagnostic for hitting the 417 // template instantiation depth. 418 ASSERT_FALSE(AST.getDiagnostics().empty()); 419 420 // Make sure getTypeHierarchy() doesn't get into an infinite recursion. 421 // The parent is reported as "S" because "S<0>" is an invalid instantiation. 422 // We then iterate once more and find "S" again before detecting the 423 // recursion. 424 auto Result = getTypeHierarchy(AST, Source.points()[0], 0, 425 TypeHierarchyDirection::Parents); 426 ASSERT_THAT(Result, SizeIs(1)); 427 EXPECT_THAT( 428 Result.front(), 429 AllOf(withName("S<0>"), withKind(SymbolKind::Struct), 430 parents( 431 AllOf(withName("S"), withKind(SymbolKind::Struct), 432 selectionRangeIs(Source.range("SDef")), 433 parents(AllOf(withName("S"), withKind(SymbolKind::Struct), 434 selectionRangeIs(Source.range("SDef")), 435 parents())))))); 436 } 437 438 TEST(TypeHierarchy, RecursiveHierarchyBounded) { 439 Annotations Source(R"cpp( 440 template <int N> 441 struct $SDef[[S]] : S<N - 1> {}; 442 443 template <> 444 struct S<0>{}; 445 446 S$SRefConcrete^<2> s; 447 448 template <int N> 449 struct Foo { 450 S$SRefDependent^<N> s; 451 };)cpp"); 452 453 TestTU TU = TestTU::withCode(Source.code()); 454 auto AST = TU.build(); 455 456 // Make sure getTypeHierarchy() doesn't get into an infinite recursion 457 // for either a concrete starting point or a dependent starting point. 458 auto Result = getTypeHierarchy(AST, Source.point("SRefConcrete"), 0, 459 TypeHierarchyDirection::Parents); 460 ASSERT_THAT(Result, SizeIs(1)); 461 EXPECT_THAT( 462 Result.front(), 463 AllOf(withName("S<2>"), withKind(SymbolKind::Struct), 464 parents(AllOf( 465 withName("S<1>"), withKind(SymbolKind::Struct), 466 selectionRangeIs(Source.range("SDef")), 467 parents(AllOf(withName("S<0>"), withKind(SymbolKind::Struct), 468 parents())))))); 469 Result = getTypeHierarchy(AST, Source.point("SRefDependent"), 0, 470 TypeHierarchyDirection::Parents); 471 ASSERT_THAT(Result, SizeIs(1)); 472 EXPECT_THAT( 473 Result.front(), 474 AllOf(withName("S"), withKind(SymbolKind::Struct), 475 parents(AllOf(withName("S"), withKind(SymbolKind::Struct), 476 selectionRangeIs(Source.range("SDef")), parents())))); 477 } 478 479 TEST(TypeHierarchy, DeriveFromImplicitSpec) { 480 Annotations Source(R"cpp( 481 template <typename T> 482 struct Parent {}; 483 484 struct Child1 : Parent<int> {}; 485 486 struct Child2 : Parent<char> {}; 487 488 Parent<int> Fo^o; 489 )cpp"); 490 491 TestTU TU = TestTU::withCode(Source.code()); 492 auto AST = TU.build(); 493 auto Index = TU.index(); 494 495 auto Result = getTypeHierarchy(AST, Source.points()[0], 2, 496 TypeHierarchyDirection::Children, Index.get(), 497 testPath(TU.Filename)); 498 ASSERT_THAT(Result, SizeIs(1)); 499 EXPECT_THAT(Result.front(), 500 AllOf(withName("Parent"), withKind(SymbolKind::Struct), 501 children(AllOf(withName("Child1"), 502 withKind(SymbolKind::Struct), children()), 503 AllOf(withName("Child2"), 504 withKind(SymbolKind::Struct), children())))); 505 } 506 507 TEST(TypeHierarchy, DeriveFromPartialSpec) { 508 Annotations Source(R"cpp( 509 template <typename T> struct Parent {}; 510 template <typename T> struct Parent<T*> {}; 511 512 struct Child : Parent<int*> {}; 513 514 Parent<int> Fo^o; 515 )cpp"); 516 517 TestTU TU = TestTU::withCode(Source.code()); 518 auto AST = TU.build(); 519 auto Index = TU.index(); 520 521 auto Result = getTypeHierarchy(AST, Source.points()[0], 2, 522 TypeHierarchyDirection::Children, Index.get(), 523 testPath(TU.Filename)); 524 ASSERT_THAT(Result, SizeIs(1)); 525 EXPECT_THAT(Result.front(), AllOf(withName("Parent"), 526 withKind(SymbolKind::Struct), children())); 527 } 528 529 TEST(TypeHierarchy, DeriveFromTemplate) { 530 Annotations Source(R"cpp( 531 template <typename T> 532 struct Parent {}; 533 534 template <typename T> 535 struct Child : Parent<T> {}; 536 537 Parent<int> Fo^o; 538 )cpp"); 539 540 TestTU TU = TestTU::withCode(Source.code()); 541 auto AST = TU.build(); 542 auto Index = TU.index(); 543 544 // FIXME: We'd like this to show the implicit specializations Parent<int> 545 // and Child<int>, but currently libIndex does not expose relationships 546 // between implicit specializations. 547 auto Result = getTypeHierarchy(AST, Source.points()[0], 2, 548 TypeHierarchyDirection::Children, Index.get(), 549 testPath(TU.Filename)); 550 ASSERT_THAT(Result, SizeIs(1)); 551 EXPECT_THAT(Result.front(), 552 AllOf(withName("Parent"), withKind(SymbolKind::Struct), 553 children(AllOf(withName("Child"), 554 withKind(SymbolKind::Struct), children())))); 555 } 556 557 TEST(TypeHierarchy, Preamble) { 558 Annotations SourceAnnotations(R"cpp( 559 struct Ch^ild : Parent { 560 int b; 561 };)cpp"); 562 563 Annotations HeaderInPreambleAnnotations(R"cpp( 564 struct [[Parent]] { 565 int a; 566 };)cpp"); 567 568 TestTU TU = TestTU::withCode(SourceAnnotations.code()); 569 TU.HeaderCode = HeaderInPreambleAnnotations.code().str(); 570 auto AST = TU.build(); 571 572 std::vector<TypeHierarchyItem> Result = getTypeHierarchy( 573 AST, SourceAnnotations.point(), 1, TypeHierarchyDirection::Parents); 574 575 ASSERT_THAT(Result, SizeIs(1)); 576 EXPECT_THAT( 577 Result.front(), 578 AllOf(withName("Child"), 579 parents(AllOf(withName("Parent"), 580 selectionRangeIs(HeaderInPreambleAnnotations.range()), 581 parents())))); 582 } 583 584 SymbolID findSymbolIDByName(SymbolIndex *Index, llvm::StringRef Name, 585 llvm::StringRef TemplateArgs = "") { 586 SymbolID Result; 587 FuzzyFindRequest Request; 588 Request.Query = std::string(Name); 589 Request.AnyScope = true; 590 bool GotResult = false; 591 Index->fuzzyFind(Request, [&](const Symbol &S) { 592 if (TemplateArgs == S.TemplateSpecializationArgs) { 593 EXPECT_FALSE(GotResult); 594 Result = S.ID; 595 GotResult = true; 596 } 597 }); 598 EXPECT_TRUE(GotResult); 599 return Result; 600 } 601 602 std::vector<SymbolID> collectSubtypes(SymbolID Subject, SymbolIndex *Index) { 603 std::vector<SymbolID> Result; 604 RelationsRequest Req; 605 Req.Subjects.insert(Subject); 606 Req.Predicate = RelationKind::BaseOf; 607 Index->relations(Req, 608 [&Result](const SymbolID &Subject, const Symbol &Object) { 609 Result.push_back(Object.ID); 610 }); 611 return Result; 612 } 613 614 TEST(Subtypes, SimpleInheritance) { 615 Annotations Source(R"cpp( 616 struct Parent {}; 617 struct Child1a : Parent {}; 618 struct Child1b : Parent {}; 619 struct Child2 : Child1a {}; 620 )cpp"); 621 622 TestTU TU = TestTU::withCode(Source.code()); 623 auto Index = TU.index(); 624 625 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent"); 626 SymbolID Child1a = findSymbolIDByName(Index.get(), "Child1a"); 627 SymbolID Child1b = findSymbolIDByName(Index.get(), "Child1b"); 628 SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2"); 629 630 EXPECT_THAT(collectSubtypes(Parent, Index.get()), 631 UnorderedElementsAre(Child1a, Child1b)); 632 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2)); 633 } 634 635 TEST(Subtypes, MultipleInheritance) { 636 Annotations Source(R"cpp( 637 struct Parent1 {}; 638 struct Parent2 {}; 639 struct Parent3 : Parent2 {}; 640 struct Child : Parent1, Parent3 {}; 641 )cpp"); 642 643 TestTU TU = TestTU::withCode(Source.code()); 644 auto Index = TU.index(); 645 646 SymbolID Parent1 = findSymbolIDByName(Index.get(), "Parent1"); 647 SymbolID Parent2 = findSymbolIDByName(Index.get(), "Parent2"); 648 SymbolID Parent3 = findSymbolIDByName(Index.get(), "Parent3"); 649 SymbolID Child = findSymbolIDByName(Index.get(), "Child"); 650 651 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child)); 652 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3)); 653 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child)); 654 } 655 656 TEST(Subtypes, ClassTemplate) { 657 Annotations Source(R"cpp( 658 struct Parent {}; 659 660 template <typename T> 661 struct Child : Parent {}; 662 )cpp"); 663 664 TestTU TU = TestTU::withCode(Source.code()); 665 auto Index = TU.index(); 666 667 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent"); 668 SymbolID Child = findSymbolIDByName(Index.get(), "Child"); 669 670 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child)); 671 } 672 673 TEST(Subtypes, TemplateSpec1) { 674 Annotations Source(R"cpp( 675 template <typename T> 676 struct Parent {}; 677 678 template <> 679 struct Parent<int> {}; 680 681 struct Child1 : Parent<float> {}; 682 683 struct Child2 : Parent<int> {}; 684 )cpp"); 685 686 TestTU TU = TestTU::withCode(Source.code()); 687 auto Index = TU.index(); 688 689 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent"); 690 SymbolID ParentSpec = findSymbolIDByName(Index.get(), "Parent", "<int>"); 691 SymbolID Child1 = findSymbolIDByName(Index.get(), "Child1"); 692 SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2"); 693 694 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1)); 695 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2)); 696 } 697 698 TEST(Subtypes, TemplateSpec2) { 699 Annotations Source(R"cpp( 700 struct Parent {}; 701 702 template <typename T> 703 struct Child {}; 704 705 template <> 706 struct Child<int> : Parent {}; 707 )cpp"); 708 709 TestTU TU = TestTU::withCode(Source.code()); 710 auto Index = TU.index(); 711 712 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent"); 713 SymbolID ChildSpec = findSymbolIDByName(Index.get(), "Child", "<int>"); 714 715 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec)); 716 } 717 718 TEST(Subtypes, DependentBase) { 719 Annotations Source(R"cpp( 720 template <typename T> 721 struct Parent {}; 722 723 template <typename T> 724 struct Child : Parent<T> {}; 725 )cpp"); 726 727 TestTU TU = TestTU::withCode(Source.code()); 728 auto Index = TU.index(); 729 730 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent"); 731 SymbolID Child = findSymbolIDByName(Index.get(), "Child"); 732 733 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child)); 734 } 735 736 TEST(Subtypes, LazyResolution) { 737 Annotations Source(R"cpp( 738 struct P^arent {}; 739 struct Child1 : Parent {}; 740 struct Child2a : Child1 {}; 741 struct Child2b : Child1 {}; 742 )cpp"); 743 744 TestTU TU = TestTU::withCode(Source.code()); 745 auto AST = TU.build(); 746 auto Index = TU.index(); 747 748 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1, 749 TypeHierarchyDirection::Children, Index.get(), 750 testPath(TU.Filename)); 751 ASSERT_THAT(Result, SizeIs(1)); 752 EXPECT_THAT( 753 Result.front(), 754 AllOf(withName("Parent"), withKind(SymbolKind::Struct), parents(), 755 children(AllOf(withName("Child1"), withKind(SymbolKind::Struct), 756 parentsNotResolved(), childrenNotResolved())))); 757 758 resolveTypeHierarchy((*Result.front().children)[0], /*ResolveLevels=*/1, 759 TypeHierarchyDirection::Children, Index.get()); 760 761 EXPECT_THAT( 762 (*Result.front().children)[0], 763 AllOf(withName("Child1"), withKind(SymbolKind::Struct), 764 parentsNotResolved(), 765 children(AllOf(withName("Child2a"), withKind(SymbolKind::Struct), 766 parentsNotResolved(), childrenNotResolved()), 767 AllOf(withName("Child2b"), withKind(SymbolKind::Struct), 768 parentsNotResolved(), childrenNotResolved())))); 769 } 770 771 TEST(Standard, SubTypes) { 772 Annotations Source(R"cpp( 773 struct Pare^nt1 {}; 774 struct Parent2 {}; 775 struct Child : Parent1, Parent2 {}; 776 )cpp"); 777 778 TestTU TU = TestTU::withCode(Source.code()); 779 auto AST = TU.build(); 780 auto Index = TU.index(); 781 782 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1, 783 TypeHierarchyDirection::Children, Index.get(), 784 testPath(TU.Filename)); 785 ASSERT_THAT(Result, SizeIs(1)); 786 auto Children = subTypes(Result.front(), Index.get()); 787 788 // Make sure parents are populated when getting children. 789 // FIXME: This is partial. 790 EXPECT_THAT( 791 Children, 792 UnorderedElementsAre( 793 AllOf(withName("Child"), 794 withResolveParents(Optional(UnorderedElementsAre(withResolveID( 795 getSymbolID(&findDecl(AST, "Parent1")).str()))))))); 796 } 797 798 TEST(Standard, SuperTypes) { 799 Annotations Source(R"cpp( 800 struct Parent {}; 801 struct Chil^d : Parent {}; 802 )cpp"); 803 804 TestTU TU = TestTU::withCode(Source.code()); 805 auto AST = TU.build(); 806 auto Index = TU.index(); 807 808 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1, 809 TypeHierarchyDirection::Children, Index.get(), 810 testPath(TU.Filename)); 811 ASSERT_THAT(Result, SizeIs(1)); 812 auto Parents = superTypes(Result.front(), Index.get()); 813 814 EXPECT_THAT(Parents, Optional(UnorderedElementsAre( 815 AllOf(withName("Parent"), 816 withResolveParents(Optional(IsEmpty())))))); 817 } 818 } // namespace 819 } // namespace clangd 820 } // namespace clang 821