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