1 //===-- TypeHierarchyTests.cpp ---------------------------*- C++ -*-------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Annotations.h"
11 #include "ParsedAST.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"
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(
62 using A^lias = Child2;
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(
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(
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(
134 struct Child1 : Parent {
138 struct Child2 : Child1 {
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(
168 struct Parent3 : Parent2 {
172 struct Child : Parent1, Parent3 {
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(
198 template <typename T>
199 struct Child : Parent {};
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
);
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
) {
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);
233 return QName
== Query
;
237 TEST(TypeParents
, TemplateSpec1
) {
238 Annotations
Source(R
"cpp(
239 template <typename T>
243 struct Parent<int> {};
245 struct Child1 : Parent<float> {};
247 struct Child2 : Parent<int> {};
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(
270 template <typename T>
274 struct Child<int> : Parent {};
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>
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 {};
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());
323 EXPECT_THAT(typeParents(Child3
), ElementsAre());
326 TEST(TypeParents
, IncompleteClass
) {
327 Annotations
Source(R
"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
341 TEST(TypeHierarchy
, Parents
) {
342 Annotations
Source(R
"cpp(
343 struct $Parent1Def[[Parent1]] {
347 struct $Parent2Def[[Parent2]] {
351 struct $Parent3Def[[Parent3]] : Parent2 {
355 struct Ch^ild : Parent1, Parent3 {
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));
378 withName("Child"), withKind(SymbolKind::Struct
),
379 parents(AllOf(withName("Parent1"), withKind(SymbolKind::Struct
),
380 selectionRangeIs(Source
.range("Parent1Def")),
382 AllOf(withName("Parent3"), withKind(SymbolKind::Struct
),
383 selectionRangeIs(Source
.range("Parent3Def")),
385 withName("Parent2"), withKind(SymbolKind::Struct
),
386 selectionRangeIs(Source
.range("Parent2Def")),
391 TEST(TypeHierarchy
, RecursiveHierarchyUnbounded
) {
392 Annotations
Source(R
"cpp(
394 struct $SDef[[S]] : S<N + 1> {};
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
411 auto Result
= getTypeHierarchy(AST
, Source
.points()[0], 0,
412 TypeHierarchyDirection::Parents
);
413 ASSERT_THAT(Result
, SizeIs(1));
416 AllOf(withName("S<0>"), withKind(SymbolKind::Struct
),
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")),
425 TEST(TypeHierarchy
, RecursiveHierarchyBounded
) {
426 Annotations
Source(R
"cpp(
428 struct $SDef[[S]] : S<N - 1> {};
433 S$SRefConcrete^<2> s;
437 S$SRefDependent^<N> s;
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));
450 AllOf(withName("S<2>"), withKind(SymbolKind::Struct
),
452 withName("S<1>"), withKind(SymbolKind::Struct
),
453 selectionRangeIs(Source
.range("SDef")),
454 parents(AllOf(withName("S<0>"), withKind(SymbolKind::Struct
),
456 Result
= getTypeHierarchy(AST
, Source
.point("SRefDependent"), 0,
457 TypeHierarchyDirection::Parents
);
458 ASSERT_THAT(Result
, SizeIs(1));
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>
471 struct Child1 : Parent<int> {};
473 struct Child2 : Parent<char> {};
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*> {};
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>
521 template <typename T>
522 struct Child : Parent<T> {};
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 {
550 Annotations
HeaderInPreambleAnnotations(R
"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));
565 AllOf(withName("Child"),
566 parents(AllOf(withName("Parent"),
567 selectionRangeIs(HeaderInPreambleAnnotations
.range()),
571 SymbolID
findSymbolIDByName(SymbolIndex
*Index
, llvm::StringRef Name
,
572 llvm::StringRef TemplateArgs
= "") {
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
);
585 EXPECT_TRUE(GotResult
);
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
);
601 TEST(Subtypes
, SimpleInheritance
) {
602 Annotations
Source(R
"cpp(
604 struct Child1a : Parent {};
605 struct Child1b : Parent {};
606 struct Child2 : Child1a {};
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(
626 struct Parent3 : Parent2 {};
627 struct Child : Parent1, Parent3 {};
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(
647 template <typename T>
648 struct Child : Parent {};
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>
666 struct Parent<int> {};
668 struct Child1 : Parent<float> {};
670 struct Child2 : Parent<int> {};
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(
689 template <typename T>
693 struct Child<int> : Parent {};
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>
710 template <typename T>
711 struct Child : Parent<T> {};
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(
726 struct Child1 : Parent {};
727 struct Child2a : Child1 {};
728 struct Child2b : Child1 {};
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));
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());
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(
762 struct Child : Parent1, Parent2 {};
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.
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(
788 struct Chil^d : Parent {};
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()))))));
806 } // namespace clangd