clang-tools  9.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 "ClangdUnit.h"
10 #include "Compiler.h"
11 #include "Matchers.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 differnt 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 int main() {
64  Ch^ild2 ch^ild2;
65  ch^ild2.c = 1;
66 }
67 )cpp");
68 
69  TestTU TU = TestTU::withCode(Source.code());
70  auto AST = TU.build();
71 
72  ASSERT_TRUE(AST.getDiagnostics().empty());
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  ASSERT_TRUE(AST.getDiagnostics().empty());
97 
98  for (Position Pt : Source.points()) {
99  const CXXRecordDecl *RD = findRecordTypeAt(AST, Pt);
100  EXPECT_EQ(&findDecl(AST, "Child2"), static_cast<const NamedDecl *>(RD));
101  }
102 }
103 
104 TEST(FindRecordTypeAt, Field) {
105  Annotations Source(R"cpp(
106 struct Child2 {
107  int fi^eld;
108 };
109 
110 int main() {
111  Child2 child2;
112  child2.fi^eld = 5;
113 }
114 )cpp");
115 
116  TestTU TU = TestTU::withCode(Source.code());
117  auto AST = TU.build();
118 
119  ASSERT_TRUE(AST.getDiagnostics().empty());
120 
121  for (Position Pt : Source.points()) {
122  const CXXRecordDecl *RD = findRecordTypeAt(AST, Pt);
123  // A field does not unambiguously specify a record type
124  // (possible associated reocrd types could be the field's type,
125  // or the type of the record that the field is a member of).
126  EXPECT_EQ(nullptr, RD);
127  }
128 }
129 
130 TEST(TypeParents, SimpleInheritance) {
131  Annotations Source(R"cpp(
132 struct Parent {
133  int a;
134 };
135 
136 struct Child1 : Parent {
137  int b;
138 };
139 
140 struct Child2 : Child1 {
141  int c;
142 };
143 )cpp");
144 
145  TestTU TU = TestTU::withCode(Source.code());
146  auto AST = TU.build();
147 
148  ASSERT_TRUE(AST.getDiagnostics().empty());
149 
150  const CXXRecordDecl *Parent =
151  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
152  const CXXRecordDecl *Child1 =
153  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1"));
154  const CXXRecordDecl *Child2 =
155  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2"));
156 
157  EXPECT_THAT(typeParents(Parent), ElementsAre());
158  EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
159  EXPECT_THAT(typeParents(Child2), ElementsAre(Child1));
160 }
161 
162 TEST(TypeParents, MultipleInheritance) {
163  Annotations Source(R"cpp(
164 struct Parent1 {
165  int a;
166 };
167 
168 struct Parent2 {
169  int b;
170 };
171 
172 struct Parent3 : Parent2 {
173  int c;
174 };
175 
176 struct Child : Parent1, Parent3 {
177  int d;
178 };
179 )cpp");
180 
181  TestTU TU = TestTU::withCode(Source.code());
182  auto AST = TU.build();
183 
184  ASSERT_TRUE(AST.getDiagnostics().empty());
185 
186  const CXXRecordDecl *Parent1 =
187  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent1"));
188  const CXXRecordDecl *Parent2 =
189  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent2"));
190  const CXXRecordDecl *Parent3 =
191  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent3"));
192  const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child"));
193 
194  EXPECT_THAT(typeParents(Parent1), ElementsAre());
195  EXPECT_THAT(typeParents(Parent2), ElementsAre());
196  EXPECT_THAT(typeParents(Parent3), ElementsAre(Parent2));
197  EXPECT_THAT(typeParents(Child), ElementsAre(Parent1, Parent3));
198 }
199 
200 TEST(TypeParents, ClassTemplate) {
201  Annotations Source(R"cpp(
202 struct Parent {};
203 
204 template <typename T>
205 struct Child : Parent {};
206 )cpp");
207 
208  TestTU TU = TestTU::withCode(Source.code());
209  auto AST = TU.build();
210 
211  ASSERT_TRUE(AST.getDiagnostics().empty());
212 
213  const CXXRecordDecl *Parent =
214  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
215  const CXXRecordDecl *Child =
216  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
217 
218  EXPECT_THAT(typeParents(Child), ElementsAre(Parent));
219 }
220 
221 MATCHER_P(ImplicitSpecOf, ClassTemplate, "") {
222  const ClassTemplateSpecializationDecl *CTS =
223  dyn_cast<ClassTemplateSpecializationDecl>(arg);
224  return CTS &&
225  CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
226  CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
227 }
228 
229 // This is similar to findDecl(AST, QName), but supports using
230 // a template-id as a query.
231 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST,
232  llvm::StringRef Query) {
233  return findDecl(AST, [&Query](const NamedDecl &ND) {
234  std::string QName;
235  llvm::raw_string_ostream OS(QName);
236  PrintingPolicy Policy(ND.getASTContext().getLangOpts());
237  // Use getNameForDiagnostic() which includes the template
238  // arguments in the printed name.
239  ND.getNameForDiagnostic(OS, Policy, /*Qualified=*/true);
240  OS.flush();
241  return QName == Query;
242  });
243 }
244 
245 TEST(TypeParents, TemplateSpec1) {
246  Annotations Source(R"cpp(
247 template <typename T>
248 struct Parent {};
249 
250 template <>
251 struct Parent<int> {};
252 
253 struct Child1 : Parent<float> {};
254 
255 struct Child2 : Parent<int> {};
256 )cpp");
257 
258  TestTU TU = TestTU::withCode(Source.code());
259  auto AST = TU.build();
260 
261  ASSERT_TRUE(AST.getDiagnostics().empty());
262 
263  const CXXRecordDecl *Parent =
264  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
265  const CXXRecordDecl *ParentSpec =
266  dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Parent<int>"));
267  const CXXRecordDecl *Child1 =
268  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child1"));
269  const CXXRecordDecl *Child2 =
270  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Child2"));
271 
272  EXPECT_THAT(typeParents(Child1), ElementsAre(ImplicitSpecOf(Parent)));
273  EXPECT_THAT(typeParents(Child2), ElementsAre(ParentSpec));
274 }
275 
276 TEST(TypeParents, TemplateSpec2) {
277  Annotations Source(R"cpp(
278 struct Parent {};
279 
280 template <typename T>
281 struct Child {};
282 
283 template <>
284 struct Child<int> : Parent {};
285 )cpp");
286 
287  TestTU TU = TestTU::withCode(Source.code());
288  auto AST = TU.build();
289 
290  ASSERT_TRUE(AST.getDiagnostics().empty());
291 
292  const CXXRecordDecl *Parent =
293  dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
294  const CXXRecordDecl *Child =
295  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child"))->getTemplatedDecl();
296  const CXXRecordDecl *ChildSpec =
297  dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST, "Child<int>"));
298 
299  EXPECT_THAT(typeParents(Child), ElementsAre());
300  EXPECT_THAT(typeParents(ChildSpec), ElementsAre(Parent));
301 }
302 
303 TEST(TypeParents, DependentBase) {
304  Annotations Source(R"cpp(
305 template <typename T>
306 struct Parent {};
307 
308 template <typename T>
309 struct Child1 : Parent<T> {};
310 
311 template <typename T>
312 struct Child2 : Parent<T>::Type {};
313 
314 template <typename T>
315 struct Child3 : T {};
316 )cpp");
317 
318  TestTU TU = TestTU::withCode(Source.code());
319  auto AST = TU.build();
320 
321  ASSERT_TRUE(AST.getDiagnostics().empty());
322 
323  const CXXRecordDecl *Parent =
324  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
325  const CXXRecordDecl *Child1 =
326  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child1"))->getTemplatedDecl();
327  const CXXRecordDecl *Child2 =
328  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child2"))->getTemplatedDecl();
329  const CXXRecordDecl *Child3 =
330  dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Child3"))->getTemplatedDecl();
331 
332  // For "Parent<T>", use the primary template as a best-effort guess.
333  EXPECT_THAT(typeParents(Child1), ElementsAre(Parent));
334  // For "Parent<T>::Type", there is nothing we can do.
335  EXPECT_THAT(typeParents(Child2), ElementsAre());
336  // Likewise for "T".
337  EXPECT_THAT(typeParents(Child3), ElementsAre());
338 }
339 
340 // Parts of getTypeHierarchy() are tested in more detail by the
341 // FindRecordTypeAt.* and TypeParents.* tests above. This test exercises the
342 // entire operation.
343 TEST(TypeHierarchy, Parents) {
344  Annotations Source(R"cpp(
345 struct $Parent1Def[[Parent1]] {
346  int a;
347 };
348 
349 struct $Parent2Def[[Parent2]] {
350  int b;
351 };
352 
353 struct $Parent3Def[[Parent3]] : Parent2 {
354  int c;
355 };
356 
357 struct Ch^ild : Parent1, Parent3 {
358  int d;
359 };
360 
361 int main() {
362  Ch^ild ch^ild;
363 
364  ch^ild.a = 1;
365 }
366 )cpp");
367 
368  TestTU TU = TestTU::withCode(Source.code());
369  auto AST = TU.build();
370 
371  for (Position Pt : Source.points()) {
372  // Set ResolveLevels to 0 because it's only used for Children;
373  // for Parents, getTypeHierarchy() always returns all levels.
374  llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
375  AST, Pt, /*ResolveLevels=*/0, TypeHierarchyDirection::Parents);
376  ASSERT_TRUE(bool(Result));
377  EXPECT_THAT(
378  *Result,
379  AllOf(
380  WithName("Child"), WithKind(SymbolKind::Struct),
381  Parents(AllOf(WithName("Parent1"), WithKind(SymbolKind::Struct),
382  SelectionRangeIs(Source.range("Parent1Def")),
383  Parents()),
384  AllOf(WithName("Parent3"), WithKind(SymbolKind::Struct),
385  SelectionRangeIs(Source.range("Parent3Def")),
386  Parents(AllOf(
387  WithName("Parent2"), WithKind(SymbolKind::Struct),
388  SelectionRangeIs(Source.range("Parent2Def")),
389  Parents()))))));
390  }
391 }
392 
393 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
394  Annotations Source(R"cpp(
395  template <int N>
396  struct $SDef[[S]] : S<N + 1> {};
397 
398  S^<0> s;
399  )cpp");
400 
401  TestTU TU = TestTU::withCode(Source.code());
402  TU.ExtraArgs.push_back("-ftemplate-depth=10");
403  auto AST = TU.build();
404 
405  // The compiler should produce a diagnostic for hitting the
406  // template instantiation depth.
407  ASSERT_TRUE(!AST.getDiagnostics().empty());
408 
409  // Make sure getTypeHierarchy() doesn't get into an infinite recursion.
410  // FIXME(nridge): It would be preferable if the type hierarchy gave us type
411  // names (e.g. "S<0>" for the child and "S<1>" for the parent) rather than
412  // template names (e.g. "S").
413  llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
414  AST, Source.points()[0], 0, TypeHierarchyDirection::Parents);
415  ASSERT_TRUE(bool(Result));
416  EXPECT_THAT(
417  *Result,
418  AllOf(WithName("S"), WithKind(SymbolKind::Struct),
419  Parents(AllOf(WithName("S"), WithKind(SymbolKind::Struct),
420  SelectionRangeIs(Source.range("SDef")), Parents()))));
421 }
422 
423 TEST(TypeHierarchy, RecursiveHierarchyBounded) {
424  Annotations Source(R"cpp(
425  template <int N>
426  struct $SDef[[S]] : S<N - 1> {};
427 
428  template <>
429  struct S<0>{};
430 
431  S$SRefConcrete^<2> s;
432 
433  template <int N>
434  struct Foo {
435  S$SRefDependent^<N> s;
436  };)cpp");
437 
438  TestTU TU = TestTU::withCode(Source.code());
439  auto AST = TU.build();
440 
441  ASSERT_TRUE(AST.getDiagnostics().empty());
442 
443  // Make sure getTypeHierarchy() doesn't get into an infinite recursion
444  // for either a concrete starting point or a dependent starting point.
445  llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
446  AST, Source.point("SRefConcrete"), 0, TypeHierarchyDirection::Parents);
447  ASSERT_TRUE(bool(Result));
448  EXPECT_THAT(
449  *Result,
450  AllOf(WithName("S"), WithKind(SymbolKind::Struct),
451  Parents(AllOf(WithName("S"), WithKind(SymbolKind::Struct),
452  SelectionRangeIs(Source.range("SDef")), Parents()))));
453  Result = getTypeHierarchy(AST, Source.point("SRefDependent"), 0,
455  ASSERT_TRUE(bool(Result));
456  EXPECT_THAT(
457  *Result,
458  AllOf(WithName("S"), WithKind(SymbolKind::Struct),
459  Parents(AllOf(WithName("S"), WithKind(SymbolKind::Struct),
460  SelectionRangeIs(Source.range("SDef")), Parents()))));
461 }
462 
463 SymbolID findSymbolIDByName(SymbolIndex *Index, llvm::StringRef Name,
464  llvm::StringRef TemplateArgs = "") {
466  FuzzyFindRequest Request;
467  Request.Query = Name;
468  Request.AnyScope = true;
469  bool GotResult = false;
470  Index->fuzzyFind(Request, [&](const Symbol &S) {
471  if (TemplateArgs == S.TemplateSpecializationArgs) {
472  EXPECT_FALSE(GotResult);
473  Result = S.ID;
474  GotResult = true;
475  }
476  });
477  EXPECT_TRUE(GotResult);
478  return Result;
479 }
480 
481 std::vector<SymbolID> collectSubtypes(SymbolID Subject, SymbolIndex *Index) {
482  std::vector<SymbolID> Result;
483  RelationsRequest Req;
484  Req.Subjects.insert(Subject);
485  Req.Predicate = index::SymbolRole::RelationBaseOf;
486  Index->relations(Req,
487  [&Result](const SymbolID &Subject, const Symbol &Object) {
488  Result.push_back(Object.ID);
489  });
490  return Result;
491 }
492 
493 TEST(Subtypes, SimpleInheritance) {
494  Annotations Source(R"cpp(
495 struct Parent {};
496 struct Child1a : Parent {};
497 struct Child1b : Parent {};
498 struct Child2 : Child1a {};
499 )cpp");
500 
501  TestTU TU = TestTU::withCode(Source.code());
502  auto Index = TU.index();
503 
504  SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
505  SymbolID Child1a = findSymbolIDByName(Index.get(), "Child1a");
506  SymbolID Child1b = findSymbolIDByName(Index.get(), "Child1b");
507  SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2");
508 
509  EXPECT_THAT(collectSubtypes(Parent, Index.get()),
510  UnorderedElementsAre(Child1a, Child1b));
511  EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
512 }
513 
514 TEST(Subtypes, MultipleInheritance) {
515  Annotations Source(R"cpp(
516 struct Parent1 {};
517 struct Parent2 {};
518 struct Parent3 : Parent2 {};
519 struct Child : Parent1, Parent3 {};
520 )cpp");
521 
522  TestTU TU = TestTU::withCode(Source.code());
523  auto Index = TU.index();
524 
525  SymbolID Parent1 = findSymbolIDByName(Index.get(), "Parent1");
526  SymbolID Parent2 = findSymbolIDByName(Index.get(), "Parent2");
527  SymbolID Parent3 = findSymbolIDByName(Index.get(), "Parent3");
528  SymbolID Child = findSymbolIDByName(Index.get(), "Child");
529 
530  EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
531  EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
532  EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
533 }
534 
535 TEST(Subtypes, ClassTemplate) {
536  Annotations Source(R"cpp(
537 struct Parent {};
538 
539 template <typename T>
540 struct Child : Parent {};
541 )cpp");
542 
543  TestTU TU = TestTU::withCode(Source.code());
544  auto Index = TU.index();
545 
546  SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
547  SymbolID Child = findSymbolIDByName(Index.get(), "Child");
548 
549  EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
550 }
551 
552 TEST(Subtypes, TemplateSpec1) {
553  Annotations Source(R"cpp(
554 template <typename T>
555 struct Parent {};
556 
557 template <>
558 struct Parent<int> {};
559 
560 struct Child1 : Parent<float> {};
561 
562 struct Child2 : Parent<int> {};
563 )cpp");
564 
565  TestTU TU = TestTU::withCode(Source.code());
566  auto Index = TU.index();
567 
568  SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
569  SymbolID ParentSpec = findSymbolIDByName(Index.get(), "Parent", "<int>");
570  SymbolID Child1 = findSymbolIDByName(Index.get(), "Child1");
571  SymbolID Child2 = findSymbolIDByName(Index.get(), "Child2");
572 
573  EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
574  EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
575 }
576 
577 TEST(Subtypes, TemplateSpec2) {
578  Annotations Source(R"cpp(
579 struct Parent {};
580 
581 template <typename T>
582 struct Child {};
583 
584 template <>
585 struct Child<int> : Parent {};
586 )cpp");
587 
588  TestTU TU = TestTU::withCode(Source.code());
589  auto Index = TU.index();
590 
591  SymbolID Parent = findSymbolIDByName(Index.get(), "Parent");
592  SymbolID ChildSpec = findSymbolIDByName(Index.get(), "Child", "<int>");
593 
594  EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
595 }
596 
597 TEST(Subtypes, DependentBase) {
598  Annotations Source(R"cpp(
599 template <typename T>
600 struct Parent {};
601 
602 template <typename T>
603 struct Child : Parent<T> {};
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, LazyResolution) {
616  Annotations Source(R"cpp(
617 struct P^arent {};
618 struct Child1 : Parent {};
619 struct Child2a : Child1 {};
620 struct Child2b : Child1 {};
621 )cpp");
622 
623  TestTU TU = TestTU::withCode(Source.code());
624  auto AST = TU.build();
625  auto Index = TU.index();
626 
627  llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
628  AST, Source.point(), /*ResolveLevels=*/1,
629  TypeHierarchyDirection::Children, Index.get(), testPath(TU.Filename));
630  ASSERT_TRUE(bool(Result));
631  EXPECT_THAT(
632  *Result,
633  AllOf(WithName("Parent"), WithKind(SymbolKind::Struct),
634  ParentsNotResolved(),
635  Children(AllOf(WithName("Child1"), WithKind(SymbolKind::Struct),
636  ParentsNotResolved(), ChildrenNotResolved()))));
637 
638  resolveTypeHierarchy((*Result->children)[0], /*ResolveLevels=*/1,
639  TypeHierarchyDirection::Children, Index.get());
640 
641  EXPECT_THAT(
642  (*Result->children)[0],
643  AllOf(WithName("Child1"), WithKind(SymbolKind::Struct),
644  ParentsNotResolved(),
645  Children(AllOf(WithName("Child2a"), WithKind(SymbolKind::Struct),
646  ParentsNotResolved(), ChildrenNotResolved()),
647  AllOf(WithName("Child2b"), WithKind(SymbolKind::Struct),
648  ParentsNotResolved(), ChildrenNotResolved()))));
649 }
650 
651 } // namespace
652 } // namespace clangd
653 } // namespace clang
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:1154
OptionalMatcher< InnerMatcher > HasValue(const InnerMatcher &inner_matcher)
ParsedAST build() const
Definition: TestTU.cpp:20
MATCHER_P(Named, N, "")
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Definition: XRefs.cpp:1255
static llvm::Optional< ParsedAST > build(std::unique_ptr< clang::CompilerInvocation > CI, std::shared_ptr< const PreambleData > Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index, const ParseOptions &Opts)
Attempts to run Clang and store parsed AST.
Definition: ClangdUnit.cpp:287
BindArgumentKind Kind
std::vector< const char * > ExtraArgs
Definition: TestTU.h:57
std::string QName
TEST(BackgroundQueueTest, Priority)
std::string testPath(PathRef File)
Definition: TestFS.cpp:82
MATCHER(Declared, "")
static constexpr llvm::StringLiteral Name
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:33
std::vector< std::unique_ptr< HTMLNode > > Children
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
Definition: XRefs.cpp:1164
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:1221
std::unique_ptr< SymbolIndex > index() const
Definition: TestTU.cpp:84
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: Rename.cpp:36
llvm::Optional< std::vector< TypeHierarchyItem > > parents
If this type hierarchy item is resolved, it contains the direct parents.
Definition: Protocol.h:1149
std::array< uint8_t, 20 > SymbolID
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
Definition: XRefs.cpp:1190
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:114
const SymbolIndex * Index
Definition: Dexp.cpp:84