xref: /llvm-project/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp (revision 61fe67a4017375fd675f75652e857e837f77fa51)
1 //===-- CallHierarchyTests.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 "ParsedAST.h"
10 #include "TestFS.h"
11 #include "TestTU.h"
12 #include "TestWorkspace.h"
13 #include "XRefs.h"
14 #include "llvm/Support/Path.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17 
18 namespace clang {
19 namespace clangd {
20 
21 llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
22                               const CallHierarchyItem &Item) {
23   return Stream << Item.name << "@" << Item.selectionRange;
24 }
25 
26 llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
27                               const CallHierarchyIncomingCall &Call) {
28   Stream << "{ from: " << Call.from << ", ranges: [";
29   for (const auto &R : Call.fromRanges) {
30     Stream << R;
31     Stream << ", ";
32   }
33   return Stream << "] }";
34 }
35 
36 namespace {
37 
38 using ::testing::AllOf;
39 using ::testing::ElementsAre;
40 using ::testing::Field;
41 using ::testing::IsEmpty;
42 using ::testing::Matcher;
43 using ::testing::UnorderedElementsAre;
44 
45 // Helpers for matching call hierarchy data structures.
46 MATCHER_P(withName, N, "") { return arg.name == N; }
47 MATCHER_P(withDetail, N, "") { return arg.detail == N; }
48 MATCHER_P(withSelectionRange, R, "") { return arg.selectionRange == R; }
49 
50 template <class ItemMatcher>
51 ::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher M) {
52   return Field(&CallHierarchyIncomingCall::from, M);
53 }
54 template <class ItemMatcher>
55 ::testing::Matcher<CallHierarchyOutgoingCall> to(ItemMatcher M) {
56   return Field(&CallHierarchyOutgoingCall::to, M);
57 }
58 template <class... RangeMatchers>
59 ::testing::Matcher<CallHierarchyIncomingCall> iFromRanges(RangeMatchers... M) {
60   return Field(&CallHierarchyIncomingCall::fromRanges,
61                UnorderedElementsAre(M...));
62 }
63 template <class... RangeMatchers>
64 ::testing::Matcher<CallHierarchyOutgoingCall> oFromRanges(RangeMatchers... M) {
65   return Field(&CallHierarchyOutgoingCall::fromRanges,
66                UnorderedElementsAre(M...));
67 }
68 
69 TEST(CallHierarchy, IncomingOneFileCpp) {
70   Annotations Source(R"cpp(
71     void call^ee(int);
72     void caller1() {
73       $Callee[[callee]](42);
74     }
75     void caller2() {
76       $Caller1A[[caller1]]();
77       $Caller1B[[caller1]]();
78     }
79     void caller3() {
80       $Caller1C[[caller1]]();
81       $Caller2[[caller2]]();
82     }
83   )cpp");
84   TestTU TU = TestTU::withCode(Source.code());
85   auto AST = TU.build();
86   auto Index = TU.index();
87 
88   std::vector<CallHierarchyItem> Items =
89       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
90   ASSERT_THAT(Items, ElementsAre(withName("callee")));
91   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
92   ASSERT_THAT(
93       IncomingLevel1,
94       ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
95                         iFromRanges(Source.range("Callee")))));
96   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
97   ASSERT_THAT(
98       IncomingLevel2,
99       ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
100                         iFromRanges(Source.range("Caller1A"),
101                                     Source.range("Caller1B"))),
102                   AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
103                         iFromRanges(Source.range("Caller1C")))));
104 
105   auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
106   ASSERT_THAT(
107       IncomingLevel3,
108       ElementsAre(AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
109                         iFromRanges(Source.range("Caller2")))));
110 
111   auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
112   EXPECT_THAT(IncomingLevel4, IsEmpty());
113 }
114 
115 TEST(CallHierarchy, IncomingOneFileObjC) {
116   Annotations Source(R"objc(
117     @implementation MyClass {}
118       +(void)call^ee {}
119       +(void) caller1 {
120         [MyClass $Callee[[callee]]];
121       }
122       +(void) caller2 {
123         [MyClass $Caller1A[[caller1]]];
124         [MyClass $Caller1B[[caller1]]];
125       }
126       +(void) caller3 {
127         [MyClass $Caller1C[[caller1]]];
128         [MyClass $Caller2[[caller2]]];
129       }
130     @end
131   )objc");
132   TestTU TU = TestTU::withCode(Source.code());
133   TU.Filename = "TestTU.m";
134   auto AST = TU.build();
135   auto Index = TU.index();
136   std::vector<CallHierarchyItem> Items =
137       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
138   ASSERT_THAT(Items, ElementsAre(withName("callee")));
139   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
140   ASSERT_THAT(IncomingLevel1,
141               ElementsAre(AllOf(from(AllOf(withName("caller1"),
142                                            withDetail("MyClass::caller1"))),
143                                 iFromRanges(Source.range("Callee")))));
144   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
145   ASSERT_THAT(IncomingLevel2,
146               ElementsAre(AllOf(from(AllOf(withName("caller2"),
147                                            withDetail("MyClass::caller2"))),
148                                 iFromRanges(Source.range("Caller1A"),
149                                             Source.range("Caller1B"))),
150                           AllOf(from(AllOf(withName("caller3"),
151                                            withDetail("MyClass::caller3"))),
152                                 iFromRanges(Source.range("Caller1C")))));
153 
154   auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
155   ASSERT_THAT(IncomingLevel3,
156               ElementsAre(AllOf(from(AllOf(withName("caller3"),
157                                            withDetail("MyClass::caller3"))),
158                                 iFromRanges(Source.range("Caller2")))));
159 
160   auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
161   EXPECT_THAT(IncomingLevel4, IsEmpty());
162 }
163 
164 TEST(CallHierarchy, MainFileOnlyRef) {
165   // In addition to testing that we store refs to main-file only symbols,
166   // this tests that anonymous namespaces do not interfere with the
167   // symbol re-identification process in callHierarchyItemToSymbo().
168   Annotations Source(R"cpp(
169     void call^ee(int);
170     namespace {
171       void caller1() {
172         $Callee[[callee]](42);
173       }
174     }
175     void caller2() {
176       $Caller1[[caller1]]();
177     }
178   )cpp");
179   TestTU TU = TestTU::withCode(Source.code());
180   auto AST = TU.build();
181   auto Index = TU.index();
182 
183   std::vector<CallHierarchyItem> Items =
184       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
185   ASSERT_THAT(Items, ElementsAre(withName("callee")));
186   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
187   ASSERT_THAT(
188       IncomingLevel1,
189       ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
190                         iFromRanges(Source.range("Callee")))));
191 
192   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
193   EXPECT_THAT(
194       IncomingLevel2,
195       ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
196                         iFromRanges(Source.range("Caller1")))));
197 }
198 
199 TEST(CallHierarchy, IncomingQualified) {
200   Annotations Source(R"cpp(
201     namespace ns {
202     struct Waldo {
203       void find();
204     };
205     void Waldo::find() {}
206     void caller1(Waldo &W) {
207       W.$Caller1[[f^ind]]();
208     }
209     void caller2(Waldo &W) {
210       W.$Caller2[[find]]();
211     }
212     }
213   )cpp");
214   TestTU TU = TestTU::withCode(Source.code());
215   auto AST = TU.build();
216   auto Index = TU.index();
217 
218   std::vector<CallHierarchyItem> Items =
219       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
220   ASSERT_THAT(Items, ElementsAre(withName("Waldo::find")));
221   auto Incoming = incomingCalls(Items[0], Index.get());
222   EXPECT_THAT(
223       Incoming,
224       ElementsAre(
225           AllOf(from(AllOf(withName("caller1"), withDetail("ns::caller1"))),
226                 iFromRanges(Source.range("Caller1"))),
227           AllOf(from(AllOf(withName("caller2"), withDetail("ns::caller2"))),
228                 iFromRanges(Source.range("Caller2")))));
229 }
230 
231 TEST(CallHierarchy, OutgoingOneFile) {
232   // Test outgoing call on the main file, with namespaces and methods
233   Annotations Source(R"cpp(
234     void callee(int);
235     namespace ns {
236       struct Foo {
237         void caller1();
238       };
239       void Foo::caller1() {
240         $Callee[[callee]](42);
241       }
242     }
243     namespace {
244       void caller2(ns::Foo& F) {
245         F.$Caller1A[[caller1]]();
246         F.$Caller1B[[caller1]]();
247       }
248     }
249     void call^er3(ns::Foo& F) {
250       F.$Caller1C[[caller1]]();
251       $Caller2[[caller2]](F);
252     }
253   )cpp");
254   TestTU TU = TestTU::withCode(Source.code());
255   auto AST = TU.build();
256   auto Index = TU.index();
257 
258   std::vector<CallHierarchyItem> Items =
259       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
260   ASSERT_THAT(Items, ElementsAre(withName("caller3")));
261   auto OugoingLevel1 = outgoingCalls(Items[0], Index.get());
262   ASSERT_THAT(
263       OugoingLevel1,
264       ElementsAre(
265           AllOf(to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
266                 oFromRanges(Source.range("Caller1C"))),
267           AllOf(to(AllOf(withName("caller2"), withDetail("caller2"))),
268                 oFromRanges(Source.range("Caller2")))));
269 
270   auto OutgoingLevel2 = outgoingCalls(OugoingLevel1[1].to, Index.get());
271   ASSERT_THAT(
272       OutgoingLevel2,
273       ElementsAre(AllOf(
274           to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
275           oFromRanges(Source.range("Caller1A"), Source.range("Caller1B")))));
276 
277   auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
278   ASSERT_THAT(
279       OutgoingLevel3,
280       ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
281                         oFromRanges(Source.range("Callee")))));
282 
283   auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
284   EXPECT_THAT(OutgoingLevel4, IsEmpty());
285 }
286 
287 TEST(CallHierarchy, MultiFileCpp) {
288   // The test uses a .hh suffix for header files to get clang
289   // to parse them in C++ mode. .h files are parsed in C mode
290   // by default, which causes problems because e.g. symbol
291   // USRs are different in C mode (do not include function signatures).
292 
293   Annotations CalleeH(R"cpp(
294     void calle^e(int);
295   )cpp");
296   Annotations CalleeC(R"cpp(
297     #include "callee.hh"
298     void calle^e(int) {}
299   )cpp");
300   Annotations Caller1H(R"cpp(
301     namespace nsa {
302       void caller1();
303     }
304   )cpp");
305   Annotations Caller1C(R"cpp(
306     #include "callee.hh"
307     #include "caller1.hh"
308     namespace nsa {
309       void caller1() {
310         [[calle^e]](42);
311       }
312     }
313   )cpp");
314   Annotations Caller2H(R"cpp(
315     namespace nsb {
316       void caller2();
317     }
318   )cpp");
319   Annotations Caller2C(R"cpp(
320     #include "caller1.hh"
321     #include "caller2.hh"
322     namespace nsb {
323       void caller2() {
324         nsa::$A[[caller1]]();
325         nsa::$B[[caller1]]();
326       }
327     }
328   )cpp");
329   Annotations Caller3H(R"cpp(
330     namespace nsa {
331       void call^er3();
332     }
333   )cpp");
334   Annotations Caller3C(R"cpp(
335     #include "caller1.hh"
336     #include "caller2.hh"
337     namespace nsa {
338       void call^er3() {
339         $Caller1[[caller1]]();
340         nsb::$Caller2[[caller2]]();
341       }
342     }
343   )cpp");
344 
345   TestWorkspace Workspace;
346   Workspace.addSource("callee.hh", CalleeH.code());
347   Workspace.addSource("caller1.hh", Caller1H.code());
348   Workspace.addSource("caller2.hh", Caller2H.code());
349   Workspace.addSource("caller3.hh", Caller3H.code());
350   Workspace.addMainFile("callee.cc", CalleeC.code());
351   Workspace.addMainFile("caller1.cc", Caller1C.code());
352   Workspace.addMainFile("caller2.cc", Caller2C.code());
353   Workspace.addMainFile("caller3.cc", Caller3C.code());
354 
355   auto Index = Workspace.index();
356 
357   auto CheckIncomingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
358     std::vector<CallHierarchyItem> Items =
359         prepareCallHierarchy(AST, Pos, TUPath);
360     ASSERT_THAT(Items, ElementsAre(withName("callee")));
361     auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
362     ASSERT_THAT(IncomingLevel1,
363                 ElementsAre(AllOf(from(AllOf(withName("caller1"),
364                                              withDetail("nsa::caller1"))),
365                                   iFromRanges(Caller1C.range()))));
366 
367     auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
368     ASSERT_THAT(
369         IncomingLevel2,
370         ElementsAre(
371             AllOf(from(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
372                   iFromRanges(Caller2C.range("A"), Caller2C.range("B"))),
373             AllOf(from(AllOf(withName("caller3"), withDetail("nsa::caller3"))),
374                   iFromRanges(Caller3C.range("Caller1")))));
375 
376     auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
377     ASSERT_THAT(IncomingLevel3,
378                 ElementsAre(AllOf(from(AllOf(withName("caller3"),
379                                              withDetail("nsa::caller3"))),
380                                   iFromRanges(Caller3C.range("Caller2")))));
381 
382     auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
383     EXPECT_THAT(IncomingLevel4, IsEmpty());
384   };
385 
386   auto CheckOutgoingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
387     std::vector<CallHierarchyItem> Items =
388         prepareCallHierarchy(AST, Pos, TUPath);
389     ASSERT_THAT(Items, ElementsAre(withName("caller3")));
390     auto OutgoingLevel1 = outgoingCalls(Items[0], Index.get());
391     ASSERT_THAT(
392         OutgoingLevel1,
393         ElementsAre(
394             AllOf(to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
395                   oFromRanges(Caller3C.range("Caller1"))),
396             AllOf(to(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
397                   oFromRanges(Caller3C.range("Caller2")))));
398 
399     auto OutgoingLevel2 = outgoingCalls(OutgoingLevel1[1].to, Index.get());
400     ASSERT_THAT(OutgoingLevel2,
401                 ElementsAre(AllOf(
402                     to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
403                     oFromRanges(Caller2C.range("A"), Caller2C.range("B")))));
404 
405     auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
406     ASSERT_THAT(
407         OutgoingLevel3,
408         ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
409                           oFromRanges(Caller1C.range()))));
410 
411     auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
412     EXPECT_THAT(OutgoingLevel4, IsEmpty());
413   };
414 
415   // Check that invoking from a call site works.
416   auto AST = Workspace.openFile("caller1.cc");
417   ASSERT_TRUE(bool(AST));
418   CheckIncomingCalls(*AST, Caller1C.point(), testPath("caller1.cc"));
419 
420   // Check that invoking from the declaration site works.
421   AST = Workspace.openFile("callee.hh");
422   ASSERT_TRUE(bool(AST));
423   CheckIncomingCalls(*AST, CalleeH.point(), testPath("callee.hh"));
424   AST = Workspace.openFile("caller3.hh");
425   ASSERT_TRUE(bool(AST));
426   CheckOutgoingCalls(*AST, Caller3H.point(), testPath("caller3.hh"));
427 
428   // Check that invoking from the definition site works.
429   AST = Workspace.openFile("callee.cc");
430   ASSERT_TRUE(bool(AST));
431   CheckIncomingCalls(*AST, CalleeC.point(), testPath("callee.cc"));
432   AST = Workspace.openFile("caller3.cc");
433   ASSERT_TRUE(bool(AST));
434   CheckOutgoingCalls(*AST, Caller3C.point(), testPath("caller3.cc"));
435 }
436 
437 TEST(CallHierarchy, IncomingMultiFileObjC) {
438   // The test uses a .mi suffix for header files to get clang
439   // to parse them in ObjC mode. .h files are parsed in C mode
440   // by default, which causes problems because e.g. symbol
441   // USRs are different in C mode (do not include function signatures).
442 
443   Annotations CalleeH(R"objc(
444     @interface CalleeClass
445       +(void)call^ee;
446     @end
447   )objc");
448   Annotations CalleeC(R"objc(
449     #import "callee.mi"
450     @implementation CalleeClass {}
451       +(void)call^ee {}
452     @end
453   )objc");
454   Annotations Caller1H(R"objc(
455     @interface Caller1Class
456       +(void)caller1;
457     @end
458   )objc");
459   Annotations Caller1C(R"objc(
460     #import "callee.mi"
461     #import "caller1.mi"
462     @implementation Caller1Class {}
463       +(void)caller1 {
464         [CalleeClass [[calle^e]]];
465       }
466     @end
467   )objc");
468   Annotations Caller2H(R"objc(
469     @interface Caller2Class
470       +(void)caller2;
471     @end
472   )objc");
473   Annotations Caller2C(R"objc(
474     #import "caller1.mi"
475     #import "caller2.mi"
476     @implementation Caller2Class {}
477       +(void)caller2 {
478         [Caller1Class $A[[caller1]]];
479         [Caller1Class $B[[caller1]]];
480       }
481     @end
482   )objc");
483   Annotations Caller3C(R"objc(
484     #import "caller1.mi"
485     #import "caller2.mi"
486     @implementation Caller3Class {}
487       +(void)caller3 {
488         [Caller1Class $Caller1[[caller1]]];
489         [Caller2Class $Caller2[[caller2]]];
490       }
491     @end
492   )objc");
493 
494   TestWorkspace Workspace;
495   Workspace.addSource("callee.mi", CalleeH.code());
496   Workspace.addSource("caller1.mi", Caller1H.code());
497   Workspace.addSource("caller2.mi", Caller2H.code());
498   Workspace.addMainFile("callee.m", CalleeC.code());
499   Workspace.addMainFile("caller1.m", Caller1C.code());
500   Workspace.addMainFile("caller2.m", Caller2C.code());
501   Workspace.addMainFile("caller3.m", Caller3C.code());
502   auto Index = Workspace.index();
503 
504   auto CheckCallHierarchy = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
505     std::vector<CallHierarchyItem> Items =
506         prepareCallHierarchy(AST, Pos, TUPath);
507     ASSERT_THAT(Items, ElementsAre(withName("callee")));
508     auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
509     ASSERT_THAT(IncomingLevel1,
510                 ElementsAre(AllOf(from(withName("caller1")),
511                                   iFromRanges(Caller1C.range()))));
512 
513     auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
514     ASSERT_THAT(IncomingLevel2,
515                 ElementsAre(AllOf(from(withName("caller2")),
516                                   iFromRanges(Caller2C.range("A"),
517                                               Caller2C.range("B"))),
518                             AllOf(from(withName("caller3")),
519                                   iFromRanges(Caller3C.range("Caller1")))));
520 
521     auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
522     ASSERT_THAT(IncomingLevel3,
523                 ElementsAre(AllOf(from(withName("caller3")),
524                                   iFromRanges(Caller3C.range("Caller2")))));
525 
526     auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
527     EXPECT_THAT(IncomingLevel4, IsEmpty());
528   };
529 
530   // Check that invoking from a call site works.
531   auto AST = Workspace.openFile("caller1.m");
532   ASSERT_TRUE(bool(AST));
533   CheckCallHierarchy(*AST, Caller1C.point(), testPath("caller1.m"));
534 
535   // Check that invoking from the declaration site works.
536   AST = Workspace.openFile("callee.mi");
537   ASSERT_TRUE(bool(AST));
538   CheckCallHierarchy(*AST, CalleeH.point(), testPath("callee.mi"));
539 
540   // Check that invoking from the definition site works.
541   AST = Workspace.openFile("callee.m");
542   ASSERT_TRUE(bool(AST));
543   CheckCallHierarchy(*AST, CalleeC.point(), testPath("callee.m"));
544 }
545 
546 TEST(CallHierarchy, CallInLocalVarDecl) {
547   // Tests that local variable declarations are not treated as callers
548   // (they're not indexed, so they can't be represented as call hierarchy
549   // items); instead, the caller should be the containing function.
550   // However, namespace-scope variable declarations should be treated as
551   // callers because those are indexed and there is no enclosing entity
552   // that would be a useful caller.
553   Annotations Source(R"cpp(
554     int call^ee();
555     void caller1() {
556       $call1[[callee]]();
557     }
558     void caller2() {
559       int localVar = $call2[[callee]]();
560     }
561     int caller3 = $call3[[callee]]();
562   )cpp");
563   TestTU TU = TestTU::withCode(Source.code());
564   auto AST = TU.build();
565   auto Index = TU.index();
566 
567   std::vector<CallHierarchyItem> Items =
568       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
569   ASSERT_THAT(Items, ElementsAre(withName("callee")));
570 
571   auto Incoming = incomingCalls(Items[0], Index.get());
572   ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName("caller1")),
573                                           iFromRanges(Source.range("call1"))),
574                                     AllOf(from(withName("caller2")),
575                                           iFromRanges(Source.range("call2"))),
576                                     AllOf(from(withName("caller3")),
577                                           iFromRanges(Source.range("call3")))));
578 }
579 
580 TEST(CallHierarchy, HierarchyOnField) {
581   // Tests that the call hierarchy works on fields.
582   Annotations Source(R"cpp(
583     struct Vars {
584       int v^ar1 = 1;
585     };
586     void caller() {
587       Vars values;
588       values.$Callee[[var1]];
589     }
590   )cpp");
591   TestTU TU = TestTU::withCode(Source.code());
592   auto AST = TU.build();
593   auto Index = TU.index();
594 
595   std::vector<CallHierarchyItem> Items =
596       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
597   ASSERT_THAT(Items, ElementsAre(withName("var1")));
598   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
599   ASSERT_THAT(IncomingLevel1,
600               ElementsAre(AllOf(from(withName("caller")),
601                                 iFromRanges(Source.range("Callee")))));
602 }
603 
604 TEST(CallHierarchy, HierarchyOnVar) {
605   // Tests that the call hierarchy works on non-local variables.
606   Annotations Source(R"cpp(
607     int v^ar = 1;
608     void caller() {
609       $Callee[[var]];
610     }
611   )cpp");
612   TestTU TU = TestTU::withCode(Source.code());
613   auto AST = TU.build();
614   auto Index = TU.index();
615 
616   std::vector<CallHierarchyItem> Items =
617       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
618   ASSERT_THAT(Items, ElementsAre(withName("var")));
619   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
620   ASSERT_THAT(IncomingLevel1,
621               ElementsAre(AllOf(from(withName("caller")),
622                                 iFromRanges(Source.range("Callee")))));
623 }
624 
625 TEST(CallHierarchy, CallInDifferentFileThanCaller) {
626   Annotations Header(R"cpp(
627     #define WALDO void caller() {
628   )cpp");
629   Annotations Source(R"cpp(
630     void call^ee();
631     WALDO
632       callee();
633     }
634   )cpp");
635   auto TU = TestTU::withCode(Source.code());
636   TU.HeaderCode = Header.code();
637   auto AST = TU.build();
638   auto Index = TU.index();
639 
640   std::vector<CallHierarchyItem> Items =
641       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
642   ASSERT_THAT(Items, ElementsAre(withName("callee")));
643 
644   auto Incoming = incomingCalls(Items[0], Index.get());
645 
646   // The only call site is in the source file, which is a different file from
647   // the declaration of the function containing the call, which is in the
648   // header. The protocol does not allow us to represent such calls, so we drop
649   // them. (The call hierarchy item itself is kept.)
650   EXPECT_THAT(Incoming,
651               ElementsAre(AllOf(from(withName("caller")), iFromRanges())));
652 }
653 
654 } // namespace
655 } // namespace clangd
656 } // namespace clang
657