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