clang-tools 10.0.0

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