brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.2 KiB · 406a842 Raw
821 lines · cpp
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-exception6//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 22namespace clang {23namespace clangd {24namespace {25 26using ::testing::AllOf;27using ::testing::ElementsAre;28using ::testing::Field;29using ::testing::IsEmpty;30using ::testing::Matcher;31using ::testing::Optional;32using ::testing::SizeIs;33using ::testing::UnorderedElementsAre;34 35// GMock helpers for matching TypeHierarchyItem.36MATCHER_P(withName, N, "") { return arg.name == N; }37MATCHER_P(withKind, Kind, "") { return arg.kind == Kind; }38MATCHER_P(selectionRangeIs, R, "") { return arg.selectionRange == R; }39template <class... ParentMatchers>40::testing::Matcher<TypeHierarchyItem> parents(ParentMatchers... ParentsM) {41  return Field(&TypeHierarchyItem::parents,42               Optional(UnorderedElementsAre(ParentsM...)));43}44template <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"!50MATCHER(parentsNotResolved, "") { return !arg.parents; }51MATCHER(childrenNotResolved, "") { return !arg.children; }52MATCHER_P(withResolveID, SID, "") { return arg.symbolID.str() == SID; }53MATCHER_P(withResolveParents, M, "") {54  return testing::ExplainMatchResult(M, arg.data.parents, result_listener);55}56 57TEST(FindRecordTypeAt, TypeOrVariable) {58  Annotations Source(R"cpp(59struct Ch^ild2 {60  int c;61};62 63using A^lias = Child2;64 65int 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 82TEST(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 95TEST(FindRecordTypeAt, Method) {96  Annotations Source(R"cpp(97struct Child2 {98  void met^hod ();99  void met^hod (int x);100};101 102int 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 119TEST(FindRecordTypeAt, Field) {120  Annotations Source(R"cpp(121struct Child2 {122  int fi^eld;123};124 125int 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 type136    // (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 142TEST(TypeParents, SimpleInheritance) {143  Annotations Source(R"cpp(144struct Parent {145  int a;146};147 148struct Child1 : Parent {149  int b;150};151 152struct 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 172TEST(TypeParents, MultipleInheritance) {173  Annotations Source(R"cpp(174struct Parent1 {175  int a;176};177 178struct Parent2 {179  int b;180};181 182struct Parent3 : Parent2 {183  int c;184};185 186struct 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 208TEST(TypeParents, ClassTemplate) {209  Annotations Source(R"cpp(210struct Parent {};211 212template <typename T>213struct 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 227MATCHER_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 using236// a template-id as a query.237const 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 template244    // arguments in the printed name.245    ND.getNameForDiagnostic(OS, Policy, /*Qualified=*/true);246    return QName == Query;247  });248}249 250TEST(TypeParents, TemplateSpec1) {251  Annotations Source(R"cpp(252template <typename T>253struct Parent {};254 255template <>256struct Parent<int> {};257 258struct Child1 : Parent<float> {};259 260struct 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 279TEST(TypeParents, TemplateSpec2) {280  Annotations Source(R"cpp(281struct Parent {};282 283template <typename T>284struct Child {};285 286template <>287struct 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 304TEST(TypeParents, DependentBase) {305  Annotations Source(R"cpp(306template <typename T>307struct Parent {};308 309template <typename T>310struct Child1 : Parent<T> {};311 312template <typename T>313struct Child2 : Parent<T>::Type {};314 315template <typename T>316struct 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 339TEST(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 the352// FindRecordTypeAt.* and TypeParents.* tests above. This test exercises the353// entire operation.354TEST(TypeHierarchy, Parents) {355  Annotations Source(R"cpp(356struct $Parent1Def[[Parent1]] {357  int a;358};359 360struct $Parent2Def[[Parent2]] {361  int b;362};363 364struct $Parent3Def[[Parent3]] : Parent2 {365  int c;366};367 368struct Ch^ild : Parent1, Parent3 {369  int d;370};371 372int 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 404TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {405  Annotations Source(R"cpp(406  template <int N>407  struct $SDef[[S]] : S<N + 1> {};408 409  S^<0> s; // error-ok410  )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 the417  // 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 the423  // 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 438TEST(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 recursion457  // 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 479TEST(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 507TEST(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 529TEST(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 relationships546  //        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 557TEST(TypeHierarchy, Preamble) {558  Annotations SourceAnnotations(R"cpp(559struct Ch^ild : Parent {560  int b;561};)cpp");562 563  Annotations HeaderInPreambleAnnotations(R"cpp(564struct [[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 584SymbolID 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 602std::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 614TEST(Subtypes, SimpleInheritance) {615  Annotations Source(R"cpp(616struct Parent {};617struct Child1a : Parent {};618struct Child1b : Parent {};619struct 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 635TEST(Subtypes, MultipleInheritance) {636  Annotations Source(R"cpp(637struct Parent1 {};638struct Parent2 {};639struct Parent3 : Parent2 {};640struct 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 656TEST(Subtypes, ClassTemplate) {657  Annotations Source(R"cpp(658struct Parent {};659 660template <typename T>661struct 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 673TEST(Subtypes, TemplateSpec1) {674  Annotations Source(R"cpp(675template <typename T>676struct Parent {};677 678template <>679struct Parent<int> {};680 681struct Child1 : Parent<float> {};682 683struct 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 698TEST(Subtypes, TemplateSpec2) {699  Annotations Source(R"cpp(700struct Parent {};701 702template <typename T>703struct Child {};704 705template <>706struct 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 718TEST(Subtypes, DependentBase) {719  Annotations Source(R"cpp(720template <typename T>721struct Parent {};722 723template <typename T>724struct 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 736TEST(Subtypes, LazyResolution) {737  Annotations Source(R"cpp(738struct P^arent {};739struct Child1 : Parent {};740struct Child2a : Child1 {};741struct 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 771TEST(Standard, SubTypes) {772  Annotations Source(R"cpp(773struct Pare^nt1 {};774struct Parent2 {};775struct 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 798TEST(Standard, SuperTypes) {799  Annotations Source(R"cpp(800struct Parent {};801struct 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} // namespace819} // namespace clangd820} // namespace clang821