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