xref: /llvm-project/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp (revision bc87a537d9b8117cfd63d5d9b798d6017a99097f)
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