[clangd] Avoid null result in FindRecordTypeAt()
[platform/upstream/llvm.git] / clang-tools-extra / clangd / unittests / TypeHierarchyTests.cpp
1 //===-- TypeHierarchyTests.cpp  ---------------------------*- C++ -*-------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-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>
39 ::testing::Matcher<TypeHierarchyItem> parents(ParentMatchers... ParentsM) {
40   return Field(&TypeHierarchyItem::parents,
41                HasValue(UnorderedElementsAre(ParentsM...)));
42 }
43 template <class... ChildMatchers>
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
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
81 TEST(FindRecordTypeAt, Nonexistent) {
82   Annotations Source(R"cpp(
83     int *wa^ldo;
84   )cpp");
85   TestTU TU = TestTU::withCode(Source.code());
86   auto AST = TU.build();
87
88   for (Position Pt : Source.points()) {
89     auto Records = findRecordTypeAt(AST, Pt);
90     ASSERT_THAT(Records, SizeIs(0));
91   }
92 }
93
94 TEST(FindRecordTypeAt, Method) {
95   Annotations Source(R"cpp(
96 struct Child2 {
97   void met^hod ();
98   void met^hod (int x);
99 };
100
101 int main() {
102   Child2 child2;
103   child2.met^hod(5);
104 }
105 )cpp");
106
107   TestTU TU = TestTU::withCode(Source.code());
108   auto AST = TU.build();
109
110   for (Position Pt : Source.points()) {
111     auto Records = findRecordTypeAt(AST, Pt);
112     ASSERT_THAT(Records, SizeIs(1));
113     EXPECT_EQ(&findDecl(AST, "Child2"),
114               static_cast<const NamedDecl *>(Records.front()));
115   }
116 }
117
118 TEST(FindRecordTypeAt, Field) {
119   Annotations Source(R"cpp(
120 struct Child2 {
121   int fi^eld;
122 };
123
124 int main() {
125   Child2 child2;
126   child2.fi^eld = 5;
127 }
128 )cpp");
129
130   TestTU TU = TestTU::withCode(Source.code());
131   auto AST = TU.build();
132
133   for (Position Pt : Source.points()) {
134     // A field does not unambiguously specify a record type
135     // (possible associated record types could be the field's type,
136     // or the type of the record that the field is a member of).
137     EXPECT_THAT(findRecordTypeAt(AST, Pt), SizeIs(0));
138   }
139 }
140
141 TEST(TypeParents, SimpleInheritance) {
142   Annotations Source(R"cpp(
143 struct Parent {
144   int a;
145 };
146
147 struct Child1 : Parent {
148   int b;
149 };
150
151 struct Child2 : Child1 {
152   int c;
153 };
154 )cpp");
155
156   TestTU TU = TestTU::withCode(Source.code());
157   auto AST = TU.build();
158
159   const CXXRecordDecl *Parent =
160       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
161   const CXXRecordDecl *Child1 =
162       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1"));
163   const CXXRecordDecl *Child2 =
164       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2"));
165
166   EXPECT_THAT(typeParents(Parent), ElementsAre());
167   EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
168   EXPECT_THAT(typeParents(Child2), ElementsAre(Child1));
169 }
170
171 TEST(TypeParents, MultipleInheritance) {
172   Annotations Source(R"cpp(
173 struct Parent1 {
174   int a;
175 };
176
177 struct Parent2 {
178   int b;
179 };
180
181 struct Parent3 : Parent2 {
182   int c;
183 };
184
185 struct Child : Parent1, Parent3 {
186   int d;
187 };
188 )cpp");
189
190   TestTU TU = TestTU::withCode(Source.code());
191   auto AST = TU.build();
192
193   const CXXRecordDecl *Parent1 =
194       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent1"));
195   const CXXRecordDecl *Parent2 =
196       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent2"));
197   const CXXRecordDecl *Parent3 =
198       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent3"));
199   const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child"));
200
201   EXPECT_THAT(typeParents(Parent1), ElementsAre());
202   EXPECT_THAT(typeParents(Parent2), ElementsAre());
203   EXPECT_THAT(typeParents(Parent3), ElementsAre(Parent2));
204   EXPECT_THAT(typeParents(Child), ElementsAre(Parent1, Parent3));
205 }
206
207 TEST(TypeParents, ClassTemplate) {
208   Annotations Source(R"cpp(
209 struct Parent {};
210
211 template <typename T>
212 struct Child : Parent {};
213 )cpp");
214
215   TestTU TU = TestTU::withCode(Source.code());
216   auto AST = TU.build();
217
218   const CXXRecordDecl *Parent =
219       dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
220   const CXXRecordDecl *Child =
221       dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
222
223   EXPECT_THAT(typeParents(Child), ElementsAre(Parent));
224 }
225
226 MATCHER_P(implicitSpecOf, ClassTemplate, "") {
227   const ClassTemplateSpecializationDecl *CTS =
228       dyn_cast<ClassTemplateSpecializationDecl>(arg);
229   return CTS &&
230          CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
231          CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
232 }
233
234 // This is similar to findDecl(AST, QName), but supports using
235 // a template-id as a query.
236 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST,
237                                           llvm::StringRef Query) {
238   return findDecl(AST, [&Query](const NamedDecl &ND) {
239     std::string QName;
240     llvm::raw_string_ostream OS(QName);
241     PrintingPolicy Policy(ND.getASTContext().getLangOpts());
242     // Use getNameForDiagnostic() which includes the template
243     // arguments in the printed name.
244     ND.getNameForDiagnostic(OS, Policy, /*Qualified=*/true);
245     OS.flush();
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(HasValue(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, HasValue(UnorderedElementsAre(
815                            AllOf(withName("Parent"),
816                                  withResolveParents(HasValue(IsEmpty()))))));
817 }
818 } // namespace
819 } // namespace clangd
820 } // namespace clang