[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / TypeHierarchyTests.cpp
bloba73ae78766c3819c9f2367e215e6076d640a57b7
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>
22 namespace clang {
23 namespace clangd {
24 namespace {
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;
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...)));
43 template <class... ChildMatchers>
44 ::testing::Matcher<TypeHierarchyItem> children(ChildMatchers... ChildrenM) {
45 return Field(&TypeHierarchyItem::children,
46 HasValue(UnorderedElementsAre(ChildrenM...)));
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);
56 TEST(FindRecordTypeAt, TypeOrVariable) {
57 Annotations Source(R"cpp(
58 struct Ch^ild2 {
59 int c;
62 using A^lias = Child2;
64 int main() {
65 Ch^ild2 ch^ild2;
66 ch^ild2.c = 1;
68 )cpp");
70 TestTU TU = TestTU::withCode(Source.code());
71 auto AST = TU.build();
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()));
81 TEST(FindRecordTypeAt, Method) {
82 Annotations Source(R"cpp(
83 struct Child2 {
84 void met^hod ();
85 void met^hod (int x);
88 int main() {
89 Child2 child2;
90 child2.met^hod(5);
92 )cpp");
94 TestTU TU = TestTU::withCode(Source.code());
95 auto AST = TU.build();
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()));
105 TEST(FindRecordTypeAt, Field) {
106 Annotations Source(R"cpp(
107 struct Child2 {
108 int fi^eld;
111 int main() {
112 Child2 child2;
113 child2.fi^eld = 5;
115 )cpp");
117 TestTU TU = TestTU::withCode(Source.code());
118 auto AST = TU.build();
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));
128 TEST(TypeParents, SimpleInheritance) {
129 Annotations Source(R"cpp(
130 struct Parent {
131 int a;
134 struct Child1 : Parent {
135 int b;
138 struct Child2 : Child1 {
139 int c;
141 )cpp");
143 TestTU TU = TestTU::withCode(Source.code());
144 auto AST = TU.build();
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"));
153 EXPECT_THAT(typeParents(Parent), ElementsAre());
154 EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
155 EXPECT_THAT(typeParents(Child2), ElementsAre(Child1));
158 TEST(TypeParents, MultipleInheritance) {
159 Annotations Source(R"cpp(
160 struct Parent1 {
161 int a;
164 struct Parent2 {
165 int b;
168 struct Parent3 : Parent2 {
169 int c;
172 struct Child : Parent1, Parent3 {
173 int d;
175 )cpp");
177 TestTU TU = TestTU::withCode(Source.code());
178 auto AST = TU.build();
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"));
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));
194 TEST(TypeParents, ClassTemplate) {
195 Annotations Source(R"cpp(
196 struct Parent {};
198 template <typename T>
199 struct Child : Parent {};
200 )cpp");
202 TestTU TU = TestTU::withCode(Source.code());
203 auto AST = TU.build();
205 const CXXRecordDecl *Parent =
206 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
207 const CXXRecordDecl *Child =
208 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
210 EXPECT_THAT(typeParents(Child), ElementsAre(Parent));
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;
221 // This is similar to findDecl(AST, QName), but supports using
222 // a template-id as a 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;
237 TEST(TypeParents, TemplateSpec1) {
238 Annotations Source(R"cpp(
239 template <typename T>
240 struct Parent {};
242 template <>
243 struct Parent<int> {};
245 struct Child1 : Parent<float> {};
247 struct Child2 : Parent<int> {};
248 )cpp");
250 TestTU TU = TestTU::withCode(Source.code());
251 auto AST = TU.build();
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"));
262 EXPECT_THAT(typeParents(Child1), ElementsAre(implicitSpecOf(Parent)));
263 EXPECT_THAT(typeParents(Child2), ElementsAre(ParentSpec));
266 TEST(TypeParents, TemplateSpec2) {
267 Annotations Source(R"cpp(
268 struct Parent {};
270 template <typename T>
271 struct Child {};
273 template <>
274 struct Child<int> : Parent {};
275 )cpp");
277 TestTU TU = TestTU::withCode(Source.code());
278 auto AST = TU.build();
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>"));
287 EXPECT_THAT(typeParents(Child), ElementsAre());
288 EXPECT_THAT(typeParents(ChildSpec), ElementsAre(Parent));
291 TEST(TypeParents, DependentBase) {
292 Annotations Source(R"cpp(
293 template <typename T>
294 struct Parent {};
296 template <typename T>
297 struct Child1 : Parent<T> {};
299 template <typename T>
300 struct Child2 : Parent<T>::Type {};
302 template <typename T>
303 struct Child3 : T {};
304 )cpp");
306 TestTU TU = TestTU::withCode(Source.code());
307 auto AST = TU.build();
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();
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());
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();
333 const CXXRecordDecl *Incomplete =
334 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Incomplete"));
335 EXPECT_THAT(typeParents(Incomplete), IsEmpty());
338 // Parts of getTypeHierarchy() are tested in more detail by the
339 // FindRecordTypeAt.* and TypeParents.* tests above. This test exercises the
340 // entire operation.
341 TEST(TypeHierarchy, Parents) {
342 Annotations Source(R"cpp(
343 struct $Parent1Def[[Parent1]] {
344 int a;
347 struct $Parent2Def[[Parent2]] {
348 int b;
351 struct $Parent3Def[[Parent3]] : Parent2 {
352 int c;
355 struct Ch^ild : Parent1, Parent3 {
356 int d;
359 int main() {
360 Ch^ild ch^ild;
362 ch^ild.a = 1;
364 )cpp");
366 TestTU TU = TestTU::withCode(Source.code());
367 auto AST = TU.build();
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()))))));
391 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
392 Annotations Source(R"cpp(
393 template <int N>
394 struct $SDef[[S]] : S<N + 1> {};
396 S^<0> s; // error-ok
397 )cpp");
399 TestTU TU = TestTU::withCode(Source.code());
400 TU.ExtraArgs.push_back("-ftemplate-depth=10");
401 auto AST = TU.build();
403 // The compiler should produce a diagnostic for hitting the
404 // template instantiation depth.
405 ASSERT_FALSE(AST.getDiagnostics().empty());
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()))))));
425 TEST(TypeHierarchy, RecursiveHierarchyBounded) {
426 Annotations Source(R"cpp(
427 template <int N>
428 struct $SDef[[S]] : S<N - 1> {};
430 template <>
431 struct S<0>{};
433 S$SRefConcrete^<2> s;
435 template <int N>
436 struct Foo {
437 S$SRefDependent^<N> s;
438 };)cpp");
440 TestTU TU = TestTU::withCode(Source.code());
441 auto AST = TU.build();
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()))));
466 TEST(TypeHierarchy, DeriveFromImplicitSpec) {
467 Annotations Source(R"cpp(
468 template <typename T>
469 struct Parent {};
471 struct Child1 : Parent<int> {};
473 struct Child2 : Parent<char> {};
475 Parent<int> Fo^o;
476 )cpp");
478 TestTU TU = TestTU::withCode(Source.code());
479 auto AST = TU.build();
480 auto Index = TU.index();
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()))));
494 TEST(TypeHierarchy, DeriveFromPartialSpec) {
495 Annotations Source(R"cpp(
496 template <typename T> struct Parent {};
497 template <typename T> struct Parent<T*> {};
499 struct Child : Parent<int*> {};
501 Parent<int> Fo^o;
502 )cpp");
504 TestTU TU = TestTU::withCode(Source.code());
505 auto AST = TU.build();
506 auto Index = TU.index();
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()));
516 TEST(TypeHierarchy, DeriveFromTemplate) {
517 Annotations Source(R"cpp(
518 template <typename T>
519 struct Parent {};
521 template <typename T>
522 struct Child : Parent<T> {};
524 Parent<int> Fo^o;
525 )cpp");
527 TestTU TU = TestTU::withCode(Source.code());
528 auto AST = TU.build();
529 auto Index = TU.index();
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()))));
544 TEST(TypeHierarchy, Preamble) {
545 Annotations SourceAnnotations(R"cpp(
546 struct Ch^ild : Parent {
547 int b;
548 };)cpp");
550 Annotations HeaderInPreambleAnnotations(R"cpp(
551 struct [[Parent]] {
552 int a;
553 };)cpp");
555 TestTU TU = TestTU::withCode(SourceAnnotations.code());
556 TU.HeaderCode = HeaderInPreambleAnnotations.code().str();
557 auto AST = TU.build();
559 std::vector<TypeHierarchyItem> Result = getTypeHierarchy(
560 AST, SourceAnnotations.point(), 1, TypeHierarchyDirection::Parents);
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()))));
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;
585 EXPECT_TRUE(GotResult);
586 return Result;
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);
598 return Result;
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");
609 TestTU TU = TestTU::withCode(Source.code());
610 auto Index = TU.index();
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");
617 EXPECT_THAT(collectSubtypes(Parent, Index.get()),
618 UnorderedElementsAre(Child1a, Child1b));
619 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
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");
630 TestTU TU = TestTU::withCode(Source.code());
631 auto Index = TU.index();
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");
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));
643 TEST(Subtypes, ClassTemplate) {
644 Annotations Source(R"cpp(
645 struct Parent {};
647 template <typename T>
648 struct Child : Parent {};
649 )cpp");
651 TestTU TU = TestTU::withCode(Source.code());
652 auto Index = TU.index();
654 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
655 SymbolID Child = findSymbolIDByName(Index.get(), "Child");
657 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
660 TEST(Subtypes, TemplateSpec1) {
661 Annotations Source(R"cpp(
662 template <typename T>
663 struct Parent {};
665 template <>
666 struct Parent<int> {};
668 struct Child1 : Parent<float> {};
670 struct Child2 : Parent<int> {};
671 )cpp");
673 TestTU TU = TestTU::withCode(Source.code());
674 auto Index = TU.index();
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");
681 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
682 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
685 TEST(Subtypes, TemplateSpec2) {
686 Annotations Source(R"cpp(
687 struct Parent {};
689 template <typename T>
690 struct Child {};
692 template <>
693 struct Child<int> : Parent {};
694 )cpp");
696 TestTU TU = TestTU::withCode(Source.code());
697 auto Index = TU.index();
699 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
700 SymbolID ChildSpec = findSymbolIDByName(Index.get(), "Child", "<int>");
702 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
705 TEST(Subtypes, DependentBase) {
706 Annotations Source(R"cpp(
707 template <typename T>
708 struct Parent {};
710 template <typename T>
711 struct Child : Parent<T> {};
712 )cpp");
714 TestTU TU = TestTU::withCode(Source.code());
715 auto Index = TU.index();
717 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
718 SymbolID Child = findSymbolIDByName(Index.get(), "Child");
720 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
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");
731 TestTU TU = TestTU::withCode(Source.code());
732 auto AST = TU.build();
733 auto Index = TU.index();
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()))));
745 resolveTypeHierarchy((*Result.front().children)[0], /*ResolveLevels=*/1,
746 TypeHierarchyDirection::Children, Index.get());
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()))));
758 TEST(Standard, SubTypes) {
759 Annotations Source(R"cpp(
760 struct Pare^nt1 {};
761 struct Parent2 {};
762 struct Child : Parent1, Parent2 {};
763 )cpp");
765 TestTU TU = TestTU::withCode(Source.code());
766 auto AST = TU.build();
767 auto Index = TU.index();
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());
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())))))));
785 TEST(Standard, SuperTypes) {
786 Annotations Source(R"cpp(
787 struct Parent {};
788 struct Chil^d : Parent {};
789 )cpp");
791 TestTU TU = TestTU::withCode(Source.code());
792 auto AST = TU.build();
793 auto Index = TU.index();
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());
801 EXPECT_THAT(Parents, HasValue(UnorderedElementsAre(
802 AllOf(withName("Parent"),
803 withResolveParents(HasValue(IsEmpty()))))));
805 } // namespace
806 } // namespace clangd
807 } // namespace clang