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