[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang-tools-extra / clangd / unittests / TypeHierarchyTests.cpp
blob2f82ec7444d7a9defb48bffc400f37eb945a3d11
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, Nonexistent) {
82 Annotations Source(R"cpp(
83 int *wa^ldo;
84 )cpp");
85 TestTU TU = TestTU::withCode(Source.code());
86 auto AST = TU.build();
88 for (Position Pt : Source.points()) {
89 auto Records = findRecordTypeAt(AST, Pt);
90 ASSERT_THAT(Records, SizeIs(0));
94 TEST(FindRecordTypeAt, Method) {
95 Annotations Source(R"cpp(
96 struct Child2 {
97 void met^hod ();
98 void met^hod (int x);
101 int main() {
102 Child2 child2;
103 child2.met^hod(5);
105 )cpp");
107 TestTU TU = TestTU::withCode(Source.code());
108 auto AST = TU.build();
110 for (Position Pt : Source.points()) {
111 auto Records = findRecordTypeAt(AST, Pt);
112 ASSERT_THAT(Records, SizeIs(1));
113 EXPECT_EQ(&findDecl(AST, "Child2"),
114 static_cast<const NamedDecl *>(Records.front()));
118 TEST(FindRecordTypeAt, Field) {
119 Annotations Source(R"cpp(
120 struct Child2 {
121 int fi^eld;
124 int main() {
125 Child2 child2;
126 child2.fi^eld = 5;
128 )cpp");
130 TestTU TU = TestTU::withCode(Source.code());
131 auto AST = TU.build();
133 for (Position Pt : Source.points()) {
134 // A field does not unambiguously specify a record type
135 // (possible associated record types could be the field's type,
136 // or the type of the record that the field is a member of).
137 EXPECT_THAT(findRecordTypeAt(AST, Pt), SizeIs(0));
141 TEST(TypeParents, SimpleInheritance) {
142 Annotations Source(R"cpp(
143 struct Parent {
144 int a;
147 struct Child1 : Parent {
148 int b;
151 struct Child2 : Child1 {
152 int c;
154 )cpp");
156 TestTU TU = TestTU::withCode(Source.code());
157 auto AST = TU.build();
159 const CXXRecordDecl *Parent =
160 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
161 const CXXRecordDecl *Child1 =
162 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1"));
163 const CXXRecordDecl *Child2 =
164 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2"));
166 EXPECT_THAT(typeParents(Parent), ElementsAre());
167 EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
168 EXPECT_THAT(typeParents(Child2), ElementsAre(Child1));
171 TEST(TypeParents, MultipleInheritance) {
172 Annotations Source(R"cpp(
173 struct Parent1 {
174 int a;
177 struct Parent2 {
178 int b;
181 struct Parent3 : Parent2 {
182 int c;
185 struct Child : Parent1, Parent3 {
186 int d;
188 )cpp");
190 TestTU TU = TestTU::withCode(Source.code());
191 auto AST = TU.build();
193 const CXXRecordDecl *Parent1 =
194 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent1"));
195 const CXXRecordDecl *Parent2 =
196 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent2"));
197 const CXXRecordDecl *Parent3 =
198 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent3"));
199 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child"));
201 EXPECT_THAT(typeParents(Parent1), ElementsAre());
202 EXPECT_THAT(typeParents(Parent2), ElementsAre());
203 EXPECT_THAT(typeParents(Parent3), ElementsAre(Parent2));
204 EXPECT_THAT(typeParents(Child), ElementsAre(Parent1, Parent3));
207 TEST(TypeParents, ClassTemplate) {
208 Annotations Source(R"cpp(
209 struct Parent {};
211 template <typename T>
212 struct Child : Parent {};
213 )cpp");
215 TestTU TU = TestTU::withCode(Source.code());
216 auto AST = TU.build();
218 const CXXRecordDecl *Parent =
219 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
220 const CXXRecordDecl *Child =
221 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
223 EXPECT_THAT(typeParents(Child), ElementsAre(Parent));
226 MATCHER_P(implicitSpecOf, ClassTemplate, "") {
227 const ClassTemplateSpecializationDecl *CTS =
228 dyn_cast<ClassTemplateSpecializationDecl>(arg);
229 return CTS &&
230 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
231 CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
234 // This is similar to findDecl(AST, QName), but supports using
235 // a template-id as a query.
236 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST,
237 llvm::StringRef Query) {
238 return findDecl(AST, [&Query](const NamedDecl &ND) {
239 std::string QName;
240 llvm::raw_string_ostream OS(QName);
241 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
242 // Use getNameForDiagnostic() which includes the template
243 // arguments in the printed name.
244 ND.getNameForDiagnostic(OS, Policy, /*Qualified=*/true);
245 OS.flush();
246 return QName == Query;
250 TEST(TypeParents, TemplateSpec1) {
251 Annotations Source(R"cpp(
252 template <typename T>
253 struct Parent {};
255 template <>
256 struct Parent<int> {};
258 struct Child1 : Parent<float> {};
260 struct Child2 : Parent<int> {};
261 )cpp");
263 TestTU TU = TestTU::withCode(Source.code());
264 auto AST = TU.build();
266 const CXXRecordDecl *Parent =
267 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
268 const CXXRecordDecl *ParentSpec =
269 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Parent<int>"));
270 const CXXRecordDecl *Child1 =
271 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1"));
272 const CXXRecordDecl *Child2 =
273 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2"));
275 EXPECT_THAT(typeParents(Child1), ElementsAre(implicitSpecOf(Parent)));
276 EXPECT_THAT(typeParents(Child2), ElementsAre(ParentSpec));
279 TEST(TypeParents, TemplateSpec2) {
280 Annotations Source(R"cpp(
281 struct Parent {};
283 template <typename T>
284 struct Child {};
286 template <>
287 struct Child<int> : Parent {};
288 )cpp");
290 TestTU TU = TestTU::withCode(Source.code());
291 auto AST = TU.build();
293 const CXXRecordDecl *Parent =
294 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
295 const CXXRecordDecl *Child =
296 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
297 const CXXRecordDecl *ChildSpec =
298 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Child<int>"));
300 EXPECT_THAT(typeParents(Child), ElementsAre());
301 EXPECT_THAT(typeParents(ChildSpec), ElementsAre(Parent));
304 TEST(TypeParents, DependentBase) {
305 Annotations Source(R"cpp(
306 template <typename T>
307 struct Parent {};
309 template <typename T>
310 struct Child1 : Parent<T> {};
312 template <typename T>
313 struct Child2 : Parent<T>::Type {};
315 template <typename T>
316 struct Child3 : T {};
317 )cpp");
319 TestTU TU = TestTU::withCode(Source.code());
320 auto AST = TU.build();
322 const CXXRecordDecl *Parent =
323 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
324 const CXXRecordDecl *Child1 =
325 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child1"))->getTemplatedDecl();
326 const CXXRecordDecl *Child2 =
327 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child2"))->getTemplatedDecl();
328 const CXXRecordDecl *Child3 =
329 dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child3"))->getTemplatedDecl();
331 // For "Parent<T>", use the primary template as a best-effort guess.
332 EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
333 // For "Parent<T>::Type", there is nothing we can do.
334 EXPECT_THAT(typeParents(Child2), ElementsAre());
335 // Likewise for "T".
336 EXPECT_THAT(typeParents(Child3), ElementsAre());
339 TEST(TypeParents, IncompleteClass) {
340 Annotations Source(R"cpp(
341 class Incomplete;
342 )cpp");
343 TestTU TU = TestTU::withCode(Source.code());
344 auto AST = TU.build();
346 const CXXRecordDecl *Incomplete =
347 dyn_cast<CXXRecordDecl>(&findDecl(AST, "Incomplete"));
348 EXPECT_THAT(typeParents(Incomplete), IsEmpty());
351 // Parts of getTypeHierarchy() are tested in more detail by the
352 // FindRecordTypeAt.* and TypeParents.* tests above. This test exercises the
353 // entire operation.
354 TEST(TypeHierarchy, Parents) {
355 Annotations Source(R"cpp(
356 struct $Parent1Def[[Parent1]] {
357 int a;
360 struct $Parent2Def[[Parent2]] {
361 int b;
364 struct $Parent3Def[[Parent3]] : Parent2 {
365 int c;
368 struct Ch^ild : Parent1, Parent3 {
369 int d;
372 int main() {
373 Ch^ild ch^ild;
375 ch^ild.a = 1;
377 )cpp");
379 TestTU TU = TestTU::withCode(Source.code());
380 auto AST = TU.build();
382 for (Position Pt : Source.points()) {
383 // Set ResolveLevels to 0 because it's only used for Children;
384 // for Parents, getTypeHierarchy() always returns all levels.
385 auto Result = getTypeHierarchy(AST, Pt, /*ResolveLevels=*/0,
386 TypeHierarchyDirection::Parents);
387 ASSERT_THAT(Result, SizeIs(1));
388 EXPECT_THAT(
389 Result.front(),
390 AllOf(
391 withName("Child"), withKind(SymbolKind::Struct),
392 parents(AllOf(withName("Parent1"), withKind(SymbolKind::Struct),
393 selectionRangeIs(Source.range("Parent1Def")),
394 parents()),
395 AllOf(withName("Parent3"), withKind(SymbolKind::Struct),
396 selectionRangeIs(Source.range("Parent3Def")),
397 parents(AllOf(
398 withName("Parent2"), withKind(SymbolKind::Struct),
399 selectionRangeIs(Source.range("Parent2Def")),
400 parents()))))));
404 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
405 Annotations Source(R"cpp(
406 template <int N>
407 struct $SDef[[S]] : S<N + 1> {};
409 S^<0> s; // error-ok
410 )cpp");
412 TestTU TU = TestTU::withCode(Source.code());
413 TU.ExtraArgs.push_back("-ftemplate-depth=10");
414 auto AST = TU.build();
416 // The compiler should produce a diagnostic for hitting the
417 // template instantiation depth.
418 ASSERT_FALSE(AST.getDiagnostics().empty());
420 // Make sure getTypeHierarchy() doesn't get into an infinite recursion.
421 // The parent is reported as "S" because "S<0>" is an invalid instantiation.
422 // We then iterate once more and find "S" again before detecting the
423 // recursion.
424 auto Result = getTypeHierarchy(AST, Source.points()[0], 0,
425 TypeHierarchyDirection::Parents);
426 ASSERT_THAT(Result, SizeIs(1));
427 EXPECT_THAT(
428 Result.front(),
429 AllOf(withName("S<0>"), withKind(SymbolKind::Struct),
430 parents(
431 AllOf(withName("S"), withKind(SymbolKind::Struct),
432 selectionRangeIs(Source.range("SDef")),
433 parents(AllOf(withName("S"), withKind(SymbolKind::Struct),
434 selectionRangeIs(Source.range("SDef")),
435 parents()))))));
438 TEST(TypeHierarchy, RecursiveHierarchyBounded) {
439 Annotations Source(R"cpp(
440 template <int N>
441 struct $SDef[[S]] : S<N - 1> {};
443 template <>
444 struct S<0>{};
446 S$SRefConcrete^<2> s;
448 template <int N>
449 struct Foo {
450 S$SRefDependent^<N> s;
451 };)cpp");
453 TestTU TU = TestTU::withCode(Source.code());
454 auto AST = TU.build();
456 // Make sure getTypeHierarchy() doesn't get into an infinite recursion
457 // for either a concrete starting point or a dependent starting point.
458 auto Result = getTypeHierarchy(AST, Source.point("SRefConcrete"), 0,
459 TypeHierarchyDirection::Parents);
460 ASSERT_THAT(Result, SizeIs(1));
461 EXPECT_THAT(
462 Result.front(),
463 AllOf(withName("S<2>"), withKind(SymbolKind::Struct),
464 parents(AllOf(
465 withName("S<1>"), withKind(SymbolKind::Struct),
466 selectionRangeIs(Source.range("SDef")),
467 parents(AllOf(withName("S<0>"), withKind(SymbolKind::Struct),
468 parents()))))));
469 Result = getTypeHierarchy(AST, Source.point("SRefDependent"), 0,
470 TypeHierarchyDirection::Parents);
471 ASSERT_THAT(Result, SizeIs(1));
472 EXPECT_THAT(
473 Result.front(),
474 AllOf(withName("S"), withKind(SymbolKind::Struct),
475 parents(AllOf(withName("S"), withKind(SymbolKind::Struct),
476 selectionRangeIs(Source.range("SDef")), parents()))));
479 TEST(TypeHierarchy, DeriveFromImplicitSpec) {
480 Annotations Source(R"cpp(
481 template <typename T>
482 struct Parent {};
484 struct Child1 : Parent<int> {};
486 struct Child2 : Parent<char> {};
488 Parent<int> Fo^o;
489 )cpp");
491 TestTU TU = TestTU::withCode(Source.code());
492 auto AST = TU.build();
493 auto Index = TU.index();
495 auto Result = getTypeHierarchy(AST, Source.points()[0], 2,
496 TypeHierarchyDirection::Children, Index.get(),
497 testPath(TU.Filename));
498 ASSERT_THAT(Result, SizeIs(1));
499 EXPECT_THAT(Result.front(),
500 AllOf(withName("Parent"), withKind(SymbolKind::Struct),
501 children(AllOf(withName("Child1"),
502 withKind(SymbolKind::Struct), children()),
503 AllOf(withName("Child2"),
504 withKind(SymbolKind::Struct), children()))));
507 TEST(TypeHierarchy, DeriveFromPartialSpec) {
508 Annotations Source(R"cpp(
509 template <typename T> struct Parent {};
510 template <typename T> struct Parent<T*> {};
512 struct Child : Parent<int*> {};
514 Parent<int> Fo^o;
515 )cpp");
517 TestTU TU = TestTU::withCode(Source.code());
518 auto AST = TU.build();
519 auto Index = TU.index();
521 auto Result = getTypeHierarchy(AST, Source.points()[0], 2,
522 TypeHierarchyDirection::Children, Index.get(),
523 testPath(TU.Filename));
524 ASSERT_THAT(Result, SizeIs(1));
525 EXPECT_THAT(Result.front(), AllOf(withName("Parent"),
526 withKind(SymbolKind::Struct), children()));
529 TEST(TypeHierarchy, DeriveFromTemplate) {
530 Annotations Source(R"cpp(
531 template <typename T>
532 struct Parent {};
534 template <typename T>
535 struct Child : Parent<T> {};
537 Parent<int> Fo^o;
538 )cpp");
540 TestTU TU = TestTU::withCode(Source.code());
541 auto AST = TU.build();
542 auto Index = TU.index();
544 // FIXME: We'd like this to show the implicit specializations Parent<int>
545 // and Child<int>, but currently libIndex does not expose relationships
546 // between implicit specializations.
547 auto Result = getTypeHierarchy(AST, Source.points()[0], 2,
548 TypeHierarchyDirection::Children, Index.get(),
549 testPath(TU.Filename));
550 ASSERT_THAT(Result, SizeIs(1));
551 EXPECT_THAT(Result.front(),
552 AllOf(withName("Parent"), withKind(SymbolKind::Struct),
553 children(AllOf(withName("Child"),
554 withKind(SymbolKind::Struct), children()))));
557 TEST(TypeHierarchy, Preamble) {
558 Annotations SourceAnnotations(R"cpp(
559 struct Ch^ild : Parent {
560 int b;
561 };)cpp");
563 Annotations HeaderInPreambleAnnotations(R"cpp(
564 struct [[Parent]] {
565 int a;
566 };)cpp");
568 TestTU TU = TestTU::withCode(SourceAnnotations.code());
569 TU.HeaderCode = HeaderInPreambleAnnotations.code().str();
570 auto AST = TU.build();
572 std::vector<TypeHierarchyItem> Result = getTypeHierarchy(
573 AST, SourceAnnotations.point(), 1, TypeHierarchyDirection::Parents);
575 ASSERT_THAT(Result, SizeIs(1));
576 EXPECT_THAT(
577 Result.front(),
578 AllOf(withName("Child"),
579 parents(AllOf(withName("Parent"),
580 selectionRangeIs(HeaderInPreambleAnnotations.range()),
581 parents()))));
584 SymbolID findSymbolIDByName(SymbolIndex *Index, llvm::StringRef Name,
585 llvm::StringRef TemplateArgs = "") {
586 SymbolID Result;
587 FuzzyFindRequest Request;
588 Request.Query = std::string(Name);
589 Request.AnyScope = true;
590 bool GotResult = false;
591 Index->fuzzyFind(Request, [&](const Symbol &S) {
592 if (TemplateArgs == S.TemplateSpecializationArgs) {
593 EXPECT_FALSE(GotResult);
594 Result = S.ID;
595 GotResult = true;
598 EXPECT_TRUE(GotResult);
599 return Result;
602 std::vector<SymbolID> collectSubtypes(SymbolID Subject, SymbolIndex *Index) {
603 std::vector<SymbolID> Result;
604 RelationsRequest Req;
605 Req.Subjects.insert(Subject);
606 Req.Predicate = RelationKind::BaseOf;
607 Index->relations(Req,
608 [&Result](const SymbolID &Subject, const Symbol &Object) {
609 Result.push_back(Object.ID);
611 return Result;
614 TEST(Subtypes, SimpleInheritance) {
615 Annotations Source(R"cpp(
616 struct Parent {};
617 struct Child1a : Parent {};
618 struct Child1b : Parent {};
619 struct Child2 : Child1a {};
620 )cpp");
622 TestTU TU = TestTU::withCode(Source.code());
623 auto Index = TU.index();
625 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
626 SymbolID Child1a = findSymbolIDByName(Index.get(), "Child1a");
627 SymbolID Child1b = findSymbolIDByName(Index.get(), "Child1b");
628 SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2");
630 EXPECT_THAT(collectSubtypes(Parent, Index.get()),
631 UnorderedElementsAre(Child1a, Child1b));
632 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
635 TEST(Subtypes, MultipleInheritance) {
636 Annotations Source(R"cpp(
637 struct Parent1 {};
638 struct Parent2 {};
639 struct Parent3 : Parent2 {};
640 struct Child : Parent1, Parent3 {};
641 )cpp");
643 TestTU TU = TestTU::withCode(Source.code());
644 auto Index = TU.index();
646 SymbolID Parent1 = findSymbolIDByName(Index.get(), "Parent1");
647 SymbolID Parent2 = findSymbolIDByName(Index.get(), "Parent2");
648 SymbolID Parent3 = findSymbolIDByName(Index.get(), "Parent3");
649 SymbolID Child = findSymbolIDByName(Index.get(), "Child");
651 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
652 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
653 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
656 TEST(Subtypes, ClassTemplate) {
657 Annotations Source(R"cpp(
658 struct Parent {};
660 template <typename T>
661 struct Child : Parent {};
662 )cpp");
664 TestTU TU = TestTU::withCode(Source.code());
665 auto Index = TU.index();
667 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
668 SymbolID Child = findSymbolIDByName(Index.get(), "Child");
670 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
673 TEST(Subtypes, TemplateSpec1) {
674 Annotations Source(R"cpp(
675 template <typename T>
676 struct Parent {};
678 template <>
679 struct Parent<int> {};
681 struct Child1 : Parent<float> {};
683 struct Child2 : Parent<int> {};
684 )cpp");
686 TestTU TU = TestTU::withCode(Source.code());
687 auto Index = TU.index();
689 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
690 SymbolID ParentSpec = findSymbolIDByName(Index.get(), "Parent", "<int>");
691 SymbolID Child1 = findSymbolIDByName(Index.get(), "Child1");
692 SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2");
694 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
695 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
698 TEST(Subtypes, TemplateSpec2) {
699 Annotations Source(R"cpp(
700 struct Parent {};
702 template <typename T>
703 struct Child {};
705 template <>
706 struct Child<int> : Parent {};
707 )cpp");
709 TestTU TU = TestTU::withCode(Source.code());
710 auto Index = TU.index();
712 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
713 SymbolID ChildSpec = findSymbolIDByName(Index.get(), "Child", "<int>");
715 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
718 TEST(Subtypes, DependentBase) {
719 Annotations Source(R"cpp(
720 template <typename T>
721 struct Parent {};
723 template <typename T>
724 struct Child : Parent<T> {};
725 )cpp");
727 TestTU TU = TestTU::withCode(Source.code());
728 auto Index = TU.index();
730 SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
731 SymbolID Child = findSymbolIDByName(Index.get(), "Child");
733 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
736 TEST(Subtypes, LazyResolution) {
737 Annotations Source(R"cpp(
738 struct P^arent {};
739 struct Child1 : Parent {};
740 struct Child2a : Child1 {};
741 struct Child2b : Child1 {};
742 )cpp");
744 TestTU TU = TestTU::withCode(Source.code());
745 auto AST = TU.build();
746 auto Index = TU.index();
748 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1,
749 TypeHierarchyDirection::Children, Index.get(),
750 testPath(TU.Filename));
751 ASSERT_THAT(Result, SizeIs(1));
752 EXPECT_THAT(
753 Result.front(),
754 AllOf(withName("Parent"), withKind(SymbolKind::Struct), parents(),
755 children(AllOf(withName("Child1"), withKind(SymbolKind::Struct),
756 parentsNotResolved(), childrenNotResolved()))));
758 resolveTypeHierarchy((*Result.front().children)[0], /*ResolveLevels=*/1,
759 TypeHierarchyDirection::Children, Index.get());
761 EXPECT_THAT(
762 (*Result.front().children)[0],
763 AllOf(withName("Child1"), withKind(SymbolKind::Struct),
764 parentsNotResolved(),
765 children(AllOf(withName("Child2a"), withKind(SymbolKind::Struct),
766 parentsNotResolved(), childrenNotResolved()),
767 AllOf(withName("Child2b"), withKind(SymbolKind::Struct),
768 parentsNotResolved(), childrenNotResolved()))));
771 TEST(Standard, SubTypes) {
772 Annotations Source(R"cpp(
773 struct Pare^nt1 {};
774 struct Parent2 {};
775 struct Child : Parent1, Parent2 {};
776 )cpp");
778 TestTU TU = TestTU::withCode(Source.code());
779 auto AST = TU.build();
780 auto Index = TU.index();
782 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1,
783 TypeHierarchyDirection::Children, Index.get(),
784 testPath(TU.Filename));
785 ASSERT_THAT(Result, SizeIs(1));
786 auto Children = subTypes(Result.front(), Index.get());
788 // Make sure parents are populated when getting children.
789 // FIXME: This is partial.
790 EXPECT_THAT(
791 Children,
792 UnorderedElementsAre(
793 AllOf(withName("Child"),
794 withResolveParents(HasValue(UnorderedElementsAre(withResolveID(
795 getSymbolID(&findDecl(AST, "Parent1")).str())))))));
798 TEST(Standard, SuperTypes) {
799 Annotations Source(R"cpp(
800 struct Parent {};
801 struct Chil^d : Parent {};
802 )cpp");
804 TestTU TU = TestTU::withCode(Source.code());
805 auto AST = TU.build();
806 auto Index = TU.index();
808 auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1,
809 TypeHierarchyDirection::Children, Index.get(),
810 testPath(TU.Filename));
811 ASSERT_THAT(Result, SizeIs(1));
812 auto Parents = superTypes(Result.front(), Index.get());
814 EXPECT_THAT(Parents, HasValue(UnorderedElementsAre(
815 AllOf(withName("Parent"),
816 withResolveParents(HasValue(IsEmpty()))))));
818 } // namespace
819 } // namespace clangd
820 } // namespace clang