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