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