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