xref: /llvm-project/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp (revision 61fe67a4017375fd675f75652e857e837f77fa51)
13e6e6a2dSNathan Ridge //===-- CallHierarchyTests.cpp  ---------------------------*- C++ -*-------===//
23e6e6a2dSNathan Ridge //
33e6e6a2dSNathan Ridge // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43e6e6a2dSNathan Ridge // See https://llvm.org/LICENSE.txt for license information.
53e6e6a2dSNathan Ridge // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63e6e6a2dSNathan Ridge //
73e6e6a2dSNathan Ridge //===----------------------------------------------------------------------===//
83e6e6a2dSNathan Ridge #include "Annotations.h"
93e6e6a2dSNathan Ridge #include "ParsedAST.h"
103e6e6a2dSNathan Ridge #include "TestFS.h"
113e6e6a2dSNathan Ridge #include "TestTU.h"
123e6e6a2dSNathan Ridge #include "TestWorkspace.h"
133e6e6a2dSNathan Ridge #include "XRefs.h"
143e6e6a2dSNathan Ridge #include "llvm/Support/Path.h"
153e6e6a2dSNathan Ridge #include "gmock/gmock.h"
163e6e6a2dSNathan Ridge #include "gtest/gtest.h"
173e6e6a2dSNathan Ridge 
183e6e6a2dSNathan Ridge namespace clang {
193e6e6a2dSNathan Ridge namespace clangd {
20f443793dSNathan Ridge 
21f443793dSNathan Ridge llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
22f443793dSNathan Ridge                               const CallHierarchyItem &Item) {
23f443793dSNathan Ridge   return Stream << Item.name << "@" << Item.selectionRange;
24f443793dSNathan Ridge }
25f443793dSNathan Ridge 
26f443793dSNathan Ridge llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
27f443793dSNathan Ridge                               const CallHierarchyIncomingCall &Call) {
28f443793dSNathan Ridge   Stream << "{ from: " << Call.from << ", ranges: [";
29f443793dSNathan Ridge   for (const auto &R : Call.fromRanges) {
30f443793dSNathan Ridge     Stream << R;
31f443793dSNathan Ridge     Stream << ", ";
32f443793dSNathan Ridge   }
33f443793dSNathan Ridge   return Stream << "] }";
34f443793dSNathan Ridge }
35f443793dSNathan Ridge 
363e6e6a2dSNathan Ridge namespace {
373e6e6a2dSNathan Ridge 
383e6e6a2dSNathan Ridge using ::testing::AllOf;
393e6e6a2dSNathan Ridge using ::testing::ElementsAre;
403e6e6a2dSNathan Ridge using ::testing::Field;
415b6f4759SNathan Ridge using ::testing::IsEmpty;
423e6e6a2dSNathan Ridge using ::testing::Matcher;
433e6e6a2dSNathan Ridge using ::testing::UnorderedElementsAre;
443e6e6a2dSNathan Ridge 
453e6e6a2dSNathan Ridge // Helpers for matching call hierarchy data structures.
468edfc2f8SChristian Kühnel MATCHER_P(withName, N, "") { return arg.name == N; }
47*61fe67a4SNathan Ridge MATCHER_P(withDetail, N, "") { return arg.detail == N; }
488edfc2f8SChristian Kühnel MATCHER_P(withSelectionRange, R, "") { return arg.selectionRange == R; }
493e6e6a2dSNathan Ridge 
503e6e6a2dSNathan Ridge template <class ItemMatcher>
518edfc2f8SChristian Kühnel ::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher M) {
523e6e6a2dSNathan Ridge   return Field(&CallHierarchyIncomingCall::from, M);
533e6e6a2dSNathan Ridge }
54*61fe67a4SNathan Ridge template <class ItemMatcher>
55*61fe67a4SNathan Ridge ::testing::Matcher<CallHierarchyOutgoingCall> to(ItemMatcher M) {
56*61fe67a4SNathan Ridge   return Field(&CallHierarchyOutgoingCall::to, M);
57*61fe67a4SNathan Ridge }
583e6e6a2dSNathan Ridge template <class... RangeMatchers>
59*61fe67a4SNathan Ridge ::testing::Matcher<CallHierarchyIncomingCall> iFromRanges(RangeMatchers... M) {
603e6e6a2dSNathan Ridge   return Field(&CallHierarchyIncomingCall::fromRanges,
613e6e6a2dSNathan Ridge                UnorderedElementsAre(M...));
623e6e6a2dSNathan Ridge }
63*61fe67a4SNathan Ridge template <class... RangeMatchers>
64*61fe67a4SNathan Ridge ::testing::Matcher<CallHierarchyOutgoingCall> oFromRanges(RangeMatchers... M) {
65*61fe67a4SNathan Ridge   return Field(&CallHierarchyOutgoingCall::fromRanges,
66*61fe67a4SNathan Ridge                UnorderedElementsAre(M...));
67*61fe67a4SNathan Ridge }
683e6e6a2dSNathan Ridge 
69e2cad4dfSSheldon Neuberger TEST(CallHierarchy, IncomingOneFileCpp) {
703e6e6a2dSNathan Ridge   Annotations Source(R"cpp(
713e6e6a2dSNathan Ridge     void call^ee(int);
723e6e6a2dSNathan Ridge     void caller1() {
733e6e6a2dSNathan Ridge       $Callee[[callee]](42);
743e6e6a2dSNathan Ridge     }
753e6e6a2dSNathan Ridge     void caller2() {
763e6e6a2dSNathan Ridge       $Caller1A[[caller1]]();
773e6e6a2dSNathan Ridge       $Caller1B[[caller1]]();
783e6e6a2dSNathan Ridge     }
793e6e6a2dSNathan Ridge     void caller3() {
803e6e6a2dSNathan Ridge       $Caller1C[[caller1]]();
813e6e6a2dSNathan Ridge       $Caller2[[caller2]]();
823e6e6a2dSNathan Ridge     }
833e6e6a2dSNathan Ridge   )cpp");
843e6e6a2dSNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
853e6e6a2dSNathan Ridge   auto AST = TU.build();
863e6e6a2dSNathan Ridge   auto Index = TU.index();
873e6e6a2dSNathan Ridge 
883e6e6a2dSNathan Ridge   std::vector<CallHierarchyItem> Items =
893e6e6a2dSNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
908edfc2f8SChristian Kühnel   ASSERT_THAT(Items, ElementsAre(withName("callee")));
913e6e6a2dSNathan Ridge   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
92*61fe67a4SNathan Ridge   ASSERT_THAT(
93*61fe67a4SNathan Ridge       IncomingLevel1,
94*61fe67a4SNathan Ridge       ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
95*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Callee")))));
96e2cad4dfSSheldon Neuberger   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
97*61fe67a4SNathan Ridge   ASSERT_THAT(
98*61fe67a4SNathan Ridge       IncomingLevel2,
99*61fe67a4SNathan Ridge       ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
100*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Caller1A"),
101e2cad4dfSSheldon Neuberger                                     Source.range("Caller1B"))),
102*61fe67a4SNathan Ridge                   AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
103*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Caller1C")))));
1043e6e6a2dSNathan Ridge 
105e2cad4dfSSheldon Neuberger   auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
106*61fe67a4SNathan Ridge   ASSERT_THAT(
107*61fe67a4SNathan Ridge       IncomingLevel3,
108*61fe67a4SNathan Ridge       ElementsAre(AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
109*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Caller2")))));
110e2cad4dfSSheldon Neuberger 
111e2cad4dfSSheldon Neuberger   auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
112e2cad4dfSSheldon Neuberger   EXPECT_THAT(IncomingLevel4, IsEmpty());
113e2cad4dfSSheldon Neuberger }
114e2cad4dfSSheldon Neuberger 
115e2cad4dfSSheldon Neuberger TEST(CallHierarchy, IncomingOneFileObjC) {
116e2cad4dfSSheldon Neuberger   Annotations Source(R"objc(
117e2cad4dfSSheldon Neuberger     @implementation MyClass {}
118e2cad4dfSSheldon Neuberger       +(void)call^ee {}
119e2cad4dfSSheldon Neuberger       +(void) caller1 {
120e2cad4dfSSheldon Neuberger         [MyClass $Callee[[callee]]];
121e2cad4dfSSheldon Neuberger       }
122e2cad4dfSSheldon Neuberger       +(void) caller2 {
123e2cad4dfSSheldon Neuberger         [MyClass $Caller1A[[caller1]]];
124e2cad4dfSSheldon Neuberger         [MyClass $Caller1B[[caller1]]];
125e2cad4dfSSheldon Neuberger       }
126e2cad4dfSSheldon Neuberger       +(void) caller3 {
127e2cad4dfSSheldon Neuberger         [MyClass $Caller1C[[caller1]]];
128e2cad4dfSSheldon Neuberger         [MyClass $Caller2[[caller2]]];
129e2cad4dfSSheldon Neuberger       }
130e2cad4dfSSheldon Neuberger     @end
131e2cad4dfSSheldon Neuberger   )objc");
132e2cad4dfSSheldon Neuberger   TestTU TU = TestTU::withCode(Source.code());
133e2cad4dfSSheldon Neuberger   TU.Filename = "TestTU.m";
134e2cad4dfSSheldon Neuberger   auto AST = TU.build();
135e2cad4dfSSheldon Neuberger   auto Index = TU.index();
136e2cad4dfSSheldon Neuberger   std::vector<CallHierarchyItem> Items =
137e2cad4dfSSheldon Neuberger       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
1388edfc2f8SChristian Kühnel   ASSERT_THAT(Items, ElementsAre(withName("callee")));
139e2cad4dfSSheldon Neuberger   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
140e2cad4dfSSheldon Neuberger   ASSERT_THAT(IncomingLevel1,
141*61fe67a4SNathan Ridge               ElementsAre(AllOf(from(AllOf(withName("caller1"),
142*61fe67a4SNathan Ridge                                            withDetail("MyClass::caller1"))),
143*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Callee")))));
1443e6e6a2dSNathan Ridge   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
1455b6f4759SNathan Ridge   ASSERT_THAT(IncomingLevel2,
146*61fe67a4SNathan Ridge               ElementsAre(AllOf(from(AllOf(withName("caller2"),
147*61fe67a4SNathan Ridge                                            withDetail("MyClass::caller2"))),
148*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Caller1A"),
1493e6e6a2dSNathan Ridge                                             Source.range("Caller1B"))),
150*61fe67a4SNathan Ridge                           AllOf(from(AllOf(withName("caller3"),
151*61fe67a4SNathan Ridge                                            withDetail("MyClass::caller3"))),
152*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Caller1C")))));
1533e6e6a2dSNathan Ridge 
1543e6e6a2dSNathan Ridge   auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
1555b6f4759SNathan Ridge   ASSERT_THAT(IncomingLevel3,
156*61fe67a4SNathan Ridge               ElementsAre(AllOf(from(AllOf(withName("caller3"),
157*61fe67a4SNathan Ridge                                            withDetail("MyClass::caller3"))),
158*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Caller2")))));
1593e6e6a2dSNathan Ridge 
1603e6e6a2dSNathan Ridge   auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
1615b6f4759SNathan Ridge   EXPECT_THAT(IncomingLevel4, IsEmpty());
1623e6e6a2dSNathan Ridge }
1633e6e6a2dSNathan Ridge 
1643e6e6a2dSNathan Ridge TEST(CallHierarchy, MainFileOnlyRef) {
1653e6e6a2dSNathan Ridge   // In addition to testing that we store refs to main-file only symbols,
1663e6e6a2dSNathan Ridge   // this tests that anonymous namespaces do not interfere with the
1673e6e6a2dSNathan Ridge   // symbol re-identification process in callHierarchyItemToSymbo().
1683e6e6a2dSNathan Ridge   Annotations Source(R"cpp(
1693e6e6a2dSNathan Ridge     void call^ee(int);
1703e6e6a2dSNathan Ridge     namespace {
1713e6e6a2dSNathan Ridge       void caller1() {
1723e6e6a2dSNathan Ridge         $Callee[[callee]](42);
1733e6e6a2dSNathan Ridge       }
1743e6e6a2dSNathan Ridge     }
1753e6e6a2dSNathan Ridge     void caller2() {
1763e6e6a2dSNathan Ridge       $Caller1[[caller1]]();
1773e6e6a2dSNathan Ridge     }
1783e6e6a2dSNathan Ridge   )cpp");
1793e6e6a2dSNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
1803e6e6a2dSNathan Ridge   auto AST = TU.build();
1813e6e6a2dSNathan Ridge   auto Index = TU.index();
1823e6e6a2dSNathan Ridge 
1833e6e6a2dSNathan Ridge   std::vector<CallHierarchyItem> Items =
1843e6e6a2dSNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
1858edfc2f8SChristian Kühnel   ASSERT_THAT(Items, ElementsAre(withName("callee")));
1863e6e6a2dSNathan Ridge   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
187*61fe67a4SNathan Ridge   ASSERT_THAT(
188*61fe67a4SNathan Ridge       IncomingLevel1,
189*61fe67a4SNathan Ridge       ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
190*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Callee")))));
1913e6e6a2dSNathan Ridge 
1923e6e6a2dSNathan Ridge   auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
193*61fe67a4SNathan Ridge   EXPECT_THAT(
194*61fe67a4SNathan Ridge       IncomingLevel2,
195*61fe67a4SNathan Ridge       ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
196*61fe67a4SNathan Ridge                         iFromRanges(Source.range("Caller1")))));
1973e6e6a2dSNathan Ridge }
1983e6e6a2dSNathan Ridge 
1993e6e6a2dSNathan Ridge TEST(CallHierarchy, IncomingQualified) {
2003e6e6a2dSNathan Ridge   Annotations Source(R"cpp(
2013e6e6a2dSNathan Ridge     namespace ns {
2023e6e6a2dSNathan Ridge     struct Waldo {
2033e6e6a2dSNathan Ridge       void find();
2043e6e6a2dSNathan Ridge     };
2053e6e6a2dSNathan Ridge     void Waldo::find() {}
2063e6e6a2dSNathan Ridge     void caller1(Waldo &W) {
2073e6e6a2dSNathan Ridge       W.$Caller1[[f^ind]]();
2083e6e6a2dSNathan Ridge     }
2093e6e6a2dSNathan Ridge     void caller2(Waldo &W) {
2103e6e6a2dSNathan Ridge       W.$Caller2[[find]]();
2113e6e6a2dSNathan Ridge     }
2123e6e6a2dSNathan Ridge     }
2133e6e6a2dSNathan Ridge   )cpp");
2143e6e6a2dSNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
2153e6e6a2dSNathan Ridge   auto AST = TU.build();
2163e6e6a2dSNathan Ridge   auto Index = TU.index();
2173e6e6a2dSNathan Ridge 
2183e6e6a2dSNathan Ridge   std::vector<CallHierarchyItem> Items =
2193e6e6a2dSNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
2208edfc2f8SChristian Kühnel   ASSERT_THAT(Items, ElementsAre(withName("Waldo::find")));
2213e6e6a2dSNathan Ridge   auto Incoming = incomingCalls(Items[0], Index.get());
222*61fe67a4SNathan Ridge   EXPECT_THAT(
223*61fe67a4SNathan Ridge       Incoming,
224*61fe67a4SNathan Ridge       ElementsAre(
225*61fe67a4SNathan Ridge           AllOf(from(AllOf(withName("caller1"), withDetail("ns::caller1"))),
226*61fe67a4SNathan Ridge                 iFromRanges(Source.range("Caller1"))),
227*61fe67a4SNathan Ridge           AllOf(from(AllOf(withName("caller2"), withDetail("ns::caller2"))),
228*61fe67a4SNathan Ridge                 iFromRanges(Source.range("Caller2")))));
2293e6e6a2dSNathan Ridge }
2303e6e6a2dSNathan Ridge 
231*61fe67a4SNathan Ridge TEST(CallHierarchy, OutgoingOneFile) {
232*61fe67a4SNathan Ridge   // Test outgoing call on the main file, with namespaces and methods
233*61fe67a4SNathan Ridge   Annotations Source(R"cpp(
234*61fe67a4SNathan Ridge     void callee(int);
235*61fe67a4SNathan Ridge     namespace ns {
236*61fe67a4SNathan Ridge       struct Foo {
237*61fe67a4SNathan Ridge         void caller1();
238*61fe67a4SNathan Ridge       };
239*61fe67a4SNathan Ridge       void Foo::caller1() {
240*61fe67a4SNathan Ridge         $Callee[[callee]](42);
241*61fe67a4SNathan Ridge       }
242*61fe67a4SNathan Ridge     }
243*61fe67a4SNathan Ridge     namespace {
244*61fe67a4SNathan Ridge       void caller2(ns::Foo& F) {
245*61fe67a4SNathan Ridge         F.$Caller1A[[caller1]]();
246*61fe67a4SNathan Ridge         F.$Caller1B[[caller1]]();
247*61fe67a4SNathan Ridge       }
248*61fe67a4SNathan Ridge     }
249*61fe67a4SNathan Ridge     void call^er3(ns::Foo& F) {
250*61fe67a4SNathan Ridge       F.$Caller1C[[caller1]]();
251*61fe67a4SNathan Ridge       $Caller2[[caller2]](F);
252*61fe67a4SNathan Ridge     }
253*61fe67a4SNathan Ridge   )cpp");
254*61fe67a4SNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
255*61fe67a4SNathan Ridge   auto AST = TU.build();
256*61fe67a4SNathan Ridge   auto Index = TU.index();
257*61fe67a4SNathan Ridge 
258*61fe67a4SNathan Ridge   std::vector<CallHierarchyItem> Items =
259*61fe67a4SNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
260*61fe67a4SNathan Ridge   ASSERT_THAT(Items, ElementsAre(withName("caller3")));
261*61fe67a4SNathan Ridge   auto OugoingLevel1 = outgoingCalls(Items[0], Index.get());
262*61fe67a4SNathan Ridge   ASSERT_THAT(
263*61fe67a4SNathan Ridge       OugoingLevel1,
264*61fe67a4SNathan Ridge       ElementsAre(
265*61fe67a4SNathan Ridge           AllOf(to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
266*61fe67a4SNathan Ridge                 oFromRanges(Source.range("Caller1C"))),
267*61fe67a4SNathan Ridge           AllOf(to(AllOf(withName("caller2"), withDetail("caller2"))),
268*61fe67a4SNathan Ridge                 oFromRanges(Source.range("Caller2")))));
269*61fe67a4SNathan Ridge 
270*61fe67a4SNathan Ridge   auto OutgoingLevel2 = outgoingCalls(OugoingLevel1[1].to, Index.get());
271*61fe67a4SNathan Ridge   ASSERT_THAT(
272*61fe67a4SNathan Ridge       OutgoingLevel2,
273*61fe67a4SNathan Ridge       ElementsAre(AllOf(
274*61fe67a4SNathan Ridge           to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
275*61fe67a4SNathan Ridge           oFromRanges(Source.range("Caller1A"), Source.range("Caller1B")))));
276*61fe67a4SNathan Ridge 
277*61fe67a4SNathan Ridge   auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
278*61fe67a4SNathan Ridge   ASSERT_THAT(
279*61fe67a4SNathan Ridge       OutgoingLevel3,
280*61fe67a4SNathan Ridge       ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
281*61fe67a4SNathan Ridge                         oFromRanges(Source.range("Callee")))));
282*61fe67a4SNathan Ridge 
283*61fe67a4SNathan Ridge   auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
284*61fe67a4SNathan Ridge   EXPECT_THAT(OutgoingLevel4, IsEmpty());
285*61fe67a4SNathan Ridge }
286*61fe67a4SNathan Ridge 
287*61fe67a4SNathan Ridge TEST(CallHierarchy, MultiFileCpp) {
2883e6e6a2dSNathan Ridge   // The test uses a .hh suffix for header files to get clang
2893e6e6a2dSNathan Ridge   // to parse them in C++ mode. .h files are parsed in C mode
2903e6e6a2dSNathan Ridge   // by default, which causes problems because e.g. symbol
2913e6e6a2dSNathan Ridge   // USRs are different in C mode (do not include function signatures).
2923e6e6a2dSNathan Ridge 
2933e6e6a2dSNathan Ridge   Annotations CalleeH(R"cpp(
2943e6e6a2dSNathan Ridge     void calle^e(int);
2953e6e6a2dSNathan Ridge   )cpp");
2963e6e6a2dSNathan Ridge   Annotations CalleeC(R"cpp(
2973e6e6a2dSNathan Ridge     #include "callee.hh"
2983e6e6a2dSNathan Ridge     void calle^e(int) {}
2993e6e6a2dSNathan Ridge   )cpp");
3003e6e6a2dSNathan Ridge   Annotations Caller1H(R"cpp(
301*61fe67a4SNathan Ridge     namespace nsa {
3023e6e6a2dSNathan Ridge       void caller1();
303*61fe67a4SNathan Ridge     }
3043e6e6a2dSNathan Ridge   )cpp");
3053e6e6a2dSNathan Ridge   Annotations Caller1C(R"cpp(
3063e6e6a2dSNathan Ridge     #include "callee.hh"
3073e6e6a2dSNathan Ridge     #include "caller1.hh"
308*61fe67a4SNathan Ridge     namespace nsa {
3093e6e6a2dSNathan Ridge       void caller1() {
3103e6e6a2dSNathan Ridge         [[calle^e]](42);
3113e6e6a2dSNathan Ridge       }
312*61fe67a4SNathan Ridge     }
3133e6e6a2dSNathan Ridge   )cpp");
3143e6e6a2dSNathan Ridge   Annotations Caller2H(R"cpp(
315*61fe67a4SNathan Ridge     namespace nsb {
3163e6e6a2dSNathan Ridge       void caller2();
317*61fe67a4SNathan Ridge     }
3183e6e6a2dSNathan Ridge   )cpp");
3193e6e6a2dSNathan Ridge   Annotations Caller2C(R"cpp(
3203e6e6a2dSNathan Ridge     #include "caller1.hh"
3213e6e6a2dSNathan Ridge     #include "caller2.hh"
322*61fe67a4SNathan Ridge     namespace nsb {
3233e6e6a2dSNathan Ridge       void caller2() {
324*61fe67a4SNathan Ridge         nsa::$A[[caller1]]();
325*61fe67a4SNathan Ridge         nsa::$B[[caller1]]();
326*61fe67a4SNathan Ridge       }
327*61fe67a4SNathan Ridge     }
328*61fe67a4SNathan Ridge   )cpp");
329*61fe67a4SNathan Ridge   Annotations Caller3H(R"cpp(
330*61fe67a4SNathan Ridge     namespace nsa {
331*61fe67a4SNathan Ridge       void call^er3();
3323e6e6a2dSNathan Ridge     }
3333e6e6a2dSNathan Ridge   )cpp");
3343e6e6a2dSNathan Ridge   Annotations Caller3C(R"cpp(
3353e6e6a2dSNathan Ridge     #include "caller1.hh"
3363e6e6a2dSNathan Ridge     #include "caller2.hh"
337*61fe67a4SNathan Ridge     namespace nsa {
338*61fe67a4SNathan Ridge       void call^er3() {
3393e6e6a2dSNathan Ridge         $Caller1[[caller1]]();
340*61fe67a4SNathan Ridge         nsb::$Caller2[[caller2]]();
341*61fe67a4SNathan Ridge       }
3423e6e6a2dSNathan Ridge     }
3433e6e6a2dSNathan Ridge   )cpp");
3443e6e6a2dSNathan Ridge 
3453e6e6a2dSNathan Ridge   TestWorkspace Workspace;
3463e6e6a2dSNathan Ridge   Workspace.addSource("callee.hh", CalleeH.code());
3473e6e6a2dSNathan Ridge   Workspace.addSource("caller1.hh", Caller1H.code());
3483e6e6a2dSNathan Ridge   Workspace.addSource("caller2.hh", Caller2H.code());
349*61fe67a4SNathan Ridge   Workspace.addSource("caller3.hh", Caller3H.code());
3503e6e6a2dSNathan Ridge   Workspace.addMainFile("callee.cc", CalleeC.code());
3513e6e6a2dSNathan Ridge   Workspace.addMainFile("caller1.cc", Caller1C.code());
3523e6e6a2dSNathan Ridge   Workspace.addMainFile("caller2.cc", Caller2C.code());
3533e6e6a2dSNathan Ridge   Workspace.addMainFile("caller3.cc", Caller3C.code());
3543e6e6a2dSNathan Ridge 
3553e6e6a2dSNathan Ridge   auto Index = Workspace.index();
3563e6e6a2dSNathan Ridge 
357*61fe67a4SNathan Ridge   auto CheckIncomingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
3583e6e6a2dSNathan Ridge     std::vector<CallHierarchyItem> Items =
3593e6e6a2dSNathan Ridge         prepareCallHierarchy(AST, Pos, TUPath);
3608edfc2f8SChristian Kühnel     ASSERT_THAT(Items, ElementsAre(withName("callee")));
3613e6e6a2dSNathan Ridge     auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
3625b6f4759SNathan Ridge     ASSERT_THAT(IncomingLevel1,
363*61fe67a4SNathan Ridge                 ElementsAre(AllOf(from(AllOf(withName("caller1"),
364*61fe67a4SNathan Ridge                                              withDetail("nsa::caller1"))),
365*61fe67a4SNathan Ridge                                   iFromRanges(Caller1C.range()))));
3663e6e6a2dSNathan Ridge 
3673e6e6a2dSNathan Ridge     auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
3685b6f4759SNathan Ridge     ASSERT_THAT(
3695b6f4759SNathan Ridge         IncomingLevel2,
370*61fe67a4SNathan Ridge         ElementsAre(
371*61fe67a4SNathan Ridge             AllOf(from(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
372*61fe67a4SNathan Ridge                   iFromRanges(Caller2C.range("A"), Caller2C.range("B"))),
373*61fe67a4SNathan Ridge             AllOf(from(AllOf(withName("caller3"), withDetail("nsa::caller3"))),
374*61fe67a4SNathan Ridge                   iFromRanges(Caller3C.range("Caller1")))));
3753e6e6a2dSNathan Ridge 
3763e6e6a2dSNathan Ridge     auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
3775b6f4759SNathan Ridge     ASSERT_THAT(IncomingLevel3,
378*61fe67a4SNathan Ridge                 ElementsAre(AllOf(from(AllOf(withName("caller3"),
379*61fe67a4SNathan Ridge                                              withDetail("nsa::caller3"))),
380*61fe67a4SNathan Ridge                                   iFromRanges(Caller3C.range("Caller2")))));
3813e6e6a2dSNathan Ridge 
3823e6e6a2dSNathan Ridge     auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
3835b6f4759SNathan Ridge     EXPECT_THAT(IncomingLevel4, IsEmpty());
3843e6e6a2dSNathan Ridge   };
3853e6e6a2dSNathan Ridge 
386*61fe67a4SNathan Ridge   auto CheckOutgoingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
387*61fe67a4SNathan Ridge     std::vector<CallHierarchyItem> Items =
388*61fe67a4SNathan Ridge         prepareCallHierarchy(AST, Pos, TUPath);
389*61fe67a4SNathan Ridge     ASSERT_THAT(Items, ElementsAre(withName("caller3")));
390*61fe67a4SNathan Ridge     auto OutgoingLevel1 = outgoingCalls(Items[0], Index.get());
391*61fe67a4SNathan Ridge     ASSERT_THAT(
392*61fe67a4SNathan Ridge         OutgoingLevel1,
393*61fe67a4SNathan Ridge         ElementsAre(
394*61fe67a4SNathan Ridge             AllOf(to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
395*61fe67a4SNathan Ridge                   oFromRanges(Caller3C.range("Caller1"))),
396*61fe67a4SNathan Ridge             AllOf(to(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
397*61fe67a4SNathan Ridge                   oFromRanges(Caller3C.range("Caller2")))));
398*61fe67a4SNathan Ridge 
399*61fe67a4SNathan Ridge     auto OutgoingLevel2 = outgoingCalls(OutgoingLevel1[1].to, Index.get());
400*61fe67a4SNathan Ridge     ASSERT_THAT(OutgoingLevel2,
401*61fe67a4SNathan Ridge                 ElementsAre(AllOf(
402*61fe67a4SNathan Ridge                     to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
403*61fe67a4SNathan Ridge                     oFromRanges(Caller2C.range("A"), Caller2C.range("B")))));
404*61fe67a4SNathan Ridge 
405*61fe67a4SNathan Ridge     auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
406*61fe67a4SNathan Ridge     ASSERT_THAT(
407*61fe67a4SNathan Ridge         OutgoingLevel3,
408*61fe67a4SNathan Ridge         ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
409*61fe67a4SNathan Ridge                           oFromRanges(Caller1C.range()))));
410*61fe67a4SNathan Ridge 
411*61fe67a4SNathan Ridge     auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
412*61fe67a4SNathan Ridge     EXPECT_THAT(OutgoingLevel4, IsEmpty());
413*61fe67a4SNathan Ridge   };
414*61fe67a4SNathan Ridge 
4153e6e6a2dSNathan Ridge   // Check that invoking from a call site works.
4163e6e6a2dSNathan Ridge   auto AST = Workspace.openFile("caller1.cc");
4173e6e6a2dSNathan Ridge   ASSERT_TRUE(bool(AST));
418*61fe67a4SNathan Ridge   CheckIncomingCalls(*AST, Caller1C.point(), testPath("caller1.cc"));
4193e6e6a2dSNathan Ridge 
4203e6e6a2dSNathan Ridge   // Check that invoking from the declaration site works.
4213e6e6a2dSNathan Ridge   AST = Workspace.openFile("callee.hh");
4223e6e6a2dSNathan Ridge   ASSERT_TRUE(bool(AST));
423*61fe67a4SNathan Ridge   CheckIncomingCalls(*AST, CalleeH.point(), testPath("callee.hh"));
424*61fe67a4SNathan Ridge   AST = Workspace.openFile("caller3.hh");
425*61fe67a4SNathan Ridge   ASSERT_TRUE(bool(AST));
426*61fe67a4SNathan Ridge   CheckOutgoingCalls(*AST, Caller3H.point(), testPath("caller3.hh"));
4273e6e6a2dSNathan Ridge 
4283e6e6a2dSNathan Ridge   // Check that invoking from the definition site works.
4293e6e6a2dSNathan Ridge   AST = Workspace.openFile("callee.cc");
4303e6e6a2dSNathan Ridge   ASSERT_TRUE(bool(AST));
431*61fe67a4SNathan Ridge   CheckIncomingCalls(*AST, CalleeC.point(), testPath("callee.cc"));
432*61fe67a4SNathan Ridge   AST = Workspace.openFile("caller3.cc");
433*61fe67a4SNathan Ridge   ASSERT_TRUE(bool(AST));
434*61fe67a4SNathan Ridge   CheckOutgoingCalls(*AST, Caller3C.point(), testPath("caller3.cc"));
4353e6e6a2dSNathan Ridge }
4363e6e6a2dSNathan Ridge 
437e2cad4dfSSheldon Neuberger TEST(CallHierarchy, IncomingMultiFileObjC) {
438e2cad4dfSSheldon Neuberger   // The test uses a .mi suffix for header files to get clang
439e2cad4dfSSheldon Neuberger   // to parse them in ObjC mode. .h files are parsed in C mode
440e2cad4dfSSheldon Neuberger   // by default, which causes problems because e.g. symbol
441e2cad4dfSSheldon Neuberger   // USRs are different in C mode (do not include function signatures).
442e2cad4dfSSheldon Neuberger 
443e2cad4dfSSheldon Neuberger   Annotations CalleeH(R"objc(
444e2cad4dfSSheldon Neuberger     @interface CalleeClass
445e2cad4dfSSheldon Neuberger       +(void)call^ee;
446e2cad4dfSSheldon Neuberger     @end
447e2cad4dfSSheldon Neuberger   )objc");
448e2cad4dfSSheldon Neuberger   Annotations CalleeC(R"objc(
449e2cad4dfSSheldon Neuberger     #import "callee.mi"
450e2cad4dfSSheldon Neuberger     @implementation CalleeClass {}
451e2cad4dfSSheldon Neuberger       +(void)call^ee {}
452e2cad4dfSSheldon Neuberger     @end
453e2cad4dfSSheldon Neuberger   )objc");
454e2cad4dfSSheldon Neuberger   Annotations Caller1H(R"objc(
455e2cad4dfSSheldon Neuberger     @interface Caller1Class
456e2cad4dfSSheldon Neuberger       +(void)caller1;
457e2cad4dfSSheldon Neuberger     @end
458e2cad4dfSSheldon Neuberger   )objc");
459e2cad4dfSSheldon Neuberger   Annotations Caller1C(R"objc(
460e2cad4dfSSheldon Neuberger     #import "callee.mi"
461e2cad4dfSSheldon Neuberger     #import "caller1.mi"
462e2cad4dfSSheldon Neuberger     @implementation Caller1Class {}
463e2cad4dfSSheldon Neuberger       +(void)caller1 {
464e2cad4dfSSheldon Neuberger         [CalleeClass [[calle^e]]];
465e2cad4dfSSheldon Neuberger       }
466e2cad4dfSSheldon Neuberger     @end
467e2cad4dfSSheldon Neuberger   )objc");
468e2cad4dfSSheldon Neuberger   Annotations Caller2H(R"objc(
469e2cad4dfSSheldon Neuberger     @interface Caller2Class
470e2cad4dfSSheldon Neuberger       +(void)caller2;
471e2cad4dfSSheldon Neuberger     @end
472e2cad4dfSSheldon Neuberger   )objc");
473e2cad4dfSSheldon Neuberger   Annotations Caller2C(R"objc(
474e2cad4dfSSheldon Neuberger     #import "caller1.mi"
475e2cad4dfSSheldon Neuberger     #import "caller2.mi"
476e2cad4dfSSheldon Neuberger     @implementation Caller2Class {}
477e2cad4dfSSheldon Neuberger       +(void)caller2 {
478e2cad4dfSSheldon Neuberger         [Caller1Class $A[[caller1]]];
479e2cad4dfSSheldon Neuberger         [Caller1Class $B[[caller1]]];
480e2cad4dfSSheldon Neuberger       }
481e2cad4dfSSheldon Neuberger     @end
482e2cad4dfSSheldon Neuberger   )objc");
483e2cad4dfSSheldon Neuberger   Annotations Caller3C(R"objc(
484e2cad4dfSSheldon Neuberger     #import "caller1.mi"
485e2cad4dfSSheldon Neuberger     #import "caller2.mi"
486e2cad4dfSSheldon Neuberger     @implementation Caller3Class {}
487e2cad4dfSSheldon Neuberger       +(void)caller3 {
488e2cad4dfSSheldon Neuberger         [Caller1Class $Caller1[[caller1]]];
489e2cad4dfSSheldon Neuberger         [Caller2Class $Caller2[[caller2]]];
490e2cad4dfSSheldon Neuberger       }
491e2cad4dfSSheldon Neuberger     @end
492e2cad4dfSSheldon Neuberger   )objc");
493e2cad4dfSSheldon Neuberger 
494e2cad4dfSSheldon Neuberger   TestWorkspace Workspace;
495e2cad4dfSSheldon Neuberger   Workspace.addSource("callee.mi", CalleeH.code());
496e2cad4dfSSheldon Neuberger   Workspace.addSource("caller1.mi", Caller1H.code());
497e2cad4dfSSheldon Neuberger   Workspace.addSource("caller2.mi", Caller2H.code());
498e2cad4dfSSheldon Neuberger   Workspace.addMainFile("callee.m", CalleeC.code());
499e2cad4dfSSheldon Neuberger   Workspace.addMainFile("caller1.m", Caller1C.code());
500e2cad4dfSSheldon Neuberger   Workspace.addMainFile("caller2.m", Caller2C.code());
501e2cad4dfSSheldon Neuberger   Workspace.addMainFile("caller3.m", Caller3C.code());
502e2cad4dfSSheldon Neuberger   auto Index = Workspace.index();
503e2cad4dfSSheldon Neuberger 
504e2cad4dfSSheldon Neuberger   auto CheckCallHierarchy = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
505e2cad4dfSSheldon Neuberger     std::vector<CallHierarchyItem> Items =
506e2cad4dfSSheldon Neuberger         prepareCallHierarchy(AST, Pos, TUPath);
5078edfc2f8SChristian Kühnel     ASSERT_THAT(Items, ElementsAre(withName("callee")));
508e2cad4dfSSheldon Neuberger     auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
509e2cad4dfSSheldon Neuberger     ASSERT_THAT(IncomingLevel1,
5108edfc2f8SChristian Kühnel                 ElementsAre(AllOf(from(withName("caller1")),
511*61fe67a4SNathan Ridge                                   iFromRanges(Caller1C.range()))));
512e2cad4dfSSheldon Neuberger 
513e2cad4dfSSheldon Neuberger     auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
514*61fe67a4SNathan Ridge     ASSERT_THAT(IncomingLevel2,
5158edfc2f8SChristian Kühnel                 ElementsAre(AllOf(from(withName("caller2")),
516*61fe67a4SNathan Ridge                                   iFromRanges(Caller2C.range("A"),
517*61fe67a4SNathan Ridge                                               Caller2C.range("B"))),
5188edfc2f8SChristian Kühnel                             AllOf(from(withName("caller3")),
519*61fe67a4SNathan Ridge                                   iFromRanges(Caller3C.range("Caller1")))));
520e2cad4dfSSheldon Neuberger 
521e2cad4dfSSheldon Neuberger     auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
522e2cad4dfSSheldon Neuberger     ASSERT_THAT(IncomingLevel3,
5238edfc2f8SChristian Kühnel                 ElementsAre(AllOf(from(withName("caller3")),
524*61fe67a4SNathan Ridge                                   iFromRanges(Caller3C.range("Caller2")))));
525e2cad4dfSSheldon Neuberger 
526e2cad4dfSSheldon Neuberger     auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
527e2cad4dfSSheldon Neuberger     EXPECT_THAT(IncomingLevel4, IsEmpty());
528e2cad4dfSSheldon Neuberger   };
529e2cad4dfSSheldon Neuberger 
530e2cad4dfSSheldon Neuberger   // Check that invoking from a call site works.
531e2cad4dfSSheldon Neuberger   auto AST = Workspace.openFile("caller1.m");
532e2cad4dfSSheldon Neuberger   ASSERT_TRUE(bool(AST));
533e2cad4dfSSheldon Neuberger   CheckCallHierarchy(*AST, Caller1C.point(), testPath("caller1.m"));
534e2cad4dfSSheldon Neuberger 
535e2cad4dfSSheldon Neuberger   // Check that invoking from the declaration site works.
536e2cad4dfSSheldon Neuberger   AST = Workspace.openFile("callee.mi");
537e2cad4dfSSheldon Neuberger   ASSERT_TRUE(bool(AST));
538e2cad4dfSSheldon Neuberger   CheckCallHierarchy(*AST, CalleeH.point(), testPath("callee.mi"));
539e2cad4dfSSheldon Neuberger 
540e2cad4dfSSheldon Neuberger   // Check that invoking from the definition site works.
541e2cad4dfSSheldon Neuberger   AST = Workspace.openFile("callee.m");
542e2cad4dfSSheldon Neuberger   ASSERT_TRUE(bool(AST));
543e2cad4dfSSheldon Neuberger   CheckCallHierarchy(*AST, CalleeC.point(), testPath("callee.m"));
544e2cad4dfSSheldon Neuberger }
545e2cad4dfSSheldon Neuberger 
546f443793dSNathan Ridge TEST(CallHierarchy, CallInLocalVarDecl) {
547f443793dSNathan Ridge   // Tests that local variable declarations are not treated as callers
548f443793dSNathan Ridge   // (they're not indexed, so they can't be represented as call hierarchy
549f443793dSNathan Ridge   // items); instead, the caller should be the containing function.
550f443793dSNathan Ridge   // However, namespace-scope variable declarations should be treated as
551f443793dSNathan Ridge   // callers because those are indexed and there is no enclosing entity
552f443793dSNathan Ridge   // that would be a useful caller.
553f443793dSNathan Ridge   Annotations Source(R"cpp(
554f443793dSNathan Ridge     int call^ee();
555f443793dSNathan Ridge     void caller1() {
556f443793dSNathan Ridge       $call1[[callee]]();
557f443793dSNathan Ridge     }
558f443793dSNathan Ridge     void caller2() {
559f443793dSNathan Ridge       int localVar = $call2[[callee]]();
560f443793dSNathan Ridge     }
561f443793dSNathan Ridge     int caller3 = $call3[[callee]]();
562f443793dSNathan Ridge   )cpp");
563f443793dSNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
564f443793dSNathan Ridge   auto AST = TU.build();
565f443793dSNathan Ridge   auto Index = TU.index();
566f443793dSNathan Ridge 
567f443793dSNathan Ridge   std::vector<CallHierarchyItem> Items =
568f443793dSNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
5698edfc2f8SChristian Kühnel   ASSERT_THAT(Items, ElementsAre(withName("callee")));
570f443793dSNathan Ridge 
571f443793dSNathan Ridge   auto Incoming = incomingCalls(Items[0], Index.get());
572*61fe67a4SNathan Ridge   ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName("caller1")),
573*61fe67a4SNathan Ridge                                           iFromRanges(Source.range("call1"))),
574*61fe67a4SNathan Ridge                                     AllOf(from(withName("caller2")),
575*61fe67a4SNathan Ridge                                           iFromRanges(Source.range("call2"))),
576*61fe67a4SNathan Ridge                                     AllOf(from(withName("caller3")),
577*61fe67a4SNathan Ridge                                           iFromRanges(Source.range("call3")))));
578f443793dSNathan Ridge }
579f443793dSNathan Ridge 
580e102338bStimon-ul TEST(CallHierarchy, HierarchyOnField) {
581e102338bStimon-ul   // Tests that the call hierarchy works on fields.
582e102338bStimon-ul   Annotations Source(R"cpp(
583e102338bStimon-ul     struct Vars {
584e102338bStimon-ul       int v^ar1 = 1;
585e102338bStimon-ul     };
586e102338bStimon-ul     void caller() {
587e102338bStimon-ul       Vars values;
588e102338bStimon-ul       values.$Callee[[var1]];
589e102338bStimon-ul     }
590e102338bStimon-ul   )cpp");
591e102338bStimon-ul   TestTU TU = TestTU::withCode(Source.code());
592e102338bStimon-ul   auto AST = TU.build();
593e102338bStimon-ul   auto Index = TU.index();
594e102338bStimon-ul 
595e102338bStimon-ul   std::vector<CallHierarchyItem> Items =
596e102338bStimon-ul       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
597e102338bStimon-ul   ASSERT_THAT(Items, ElementsAre(withName("var1")));
598e102338bStimon-ul   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
599e102338bStimon-ul   ASSERT_THAT(IncomingLevel1,
600e102338bStimon-ul               ElementsAre(AllOf(from(withName("caller")),
601*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Callee")))));
602e102338bStimon-ul }
603e102338bStimon-ul 
604e102338bStimon-ul TEST(CallHierarchy, HierarchyOnVar) {
605e102338bStimon-ul   // Tests that the call hierarchy works on non-local variables.
606e102338bStimon-ul   Annotations Source(R"cpp(
607e102338bStimon-ul     int v^ar = 1;
608e102338bStimon-ul     void caller() {
609e102338bStimon-ul       $Callee[[var]];
610e102338bStimon-ul     }
611e102338bStimon-ul   )cpp");
612e102338bStimon-ul   TestTU TU = TestTU::withCode(Source.code());
613e102338bStimon-ul   auto AST = TU.build();
614e102338bStimon-ul   auto Index = TU.index();
615e102338bStimon-ul 
616e102338bStimon-ul   std::vector<CallHierarchyItem> Items =
617e102338bStimon-ul       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
618e102338bStimon-ul   ASSERT_THAT(Items, ElementsAre(withName("var")));
619e102338bStimon-ul   auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
620e102338bStimon-ul   ASSERT_THAT(IncomingLevel1,
621e102338bStimon-ul               ElementsAre(AllOf(from(withName("caller")),
622*61fe67a4SNathan Ridge                                 iFromRanges(Source.range("Callee")))));
623e102338bStimon-ul }
624e102338bStimon-ul 
625545917cbSNathan Ridge TEST(CallHierarchy, CallInDifferentFileThanCaller) {
626545917cbSNathan Ridge   Annotations Header(R"cpp(
627545917cbSNathan Ridge     #define WALDO void caller() {
628545917cbSNathan Ridge   )cpp");
629545917cbSNathan Ridge   Annotations Source(R"cpp(
630545917cbSNathan Ridge     void call^ee();
631545917cbSNathan Ridge     WALDO
632545917cbSNathan Ridge       callee();
633545917cbSNathan Ridge     }
634545917cbSNathan Ridge   )cpp");
635545917cbSNathan Ridge   auto TU = TestTU::withCode(Source.code());
636545917cbSNathan Ridge   TU.HeaderCode = Header.code();
637545917cbSNathan Ridge   auto AST = TU.build();
638545917cbSNathan Ridge   auto Index = TU.index();
639545917cbSNathan Ridge 
640545917cbSNathan Ridge   std::vector<CallHierarchyItem> Items =
641545917cbSNathan Ridge       prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
642545917cbSNathan Ridge   ASSERT_THAT(Items, ElementsAre(withName("callee")));
643545917cbSNathan Ridge 
644545917cbSNathan Ridge   auto Incoming = incomingCalls(Items[0], Index.get());
645545917cbSNathan Ridge 
646545917cbSNathan Ridge   // The only call site is in the source file, which is a different file from
647545917cbSNathan Ridge   // the declaration of the function containing the call, which is in the
648545917cbSNathan Ridge   // header. The protocol does not allow us to represent such calls, so we drop
649545917cbSNathan Ridge   // them. (The call hierarchy item itself is kept.)
650545917cbSNathan Ridge   EXPECT_THAT(Incoming,
651*61fe67a4SNathan Ridge               ElementsAre(AllOf(from(withName("caller")), iFromRanges())));
652545917cbSNathan Ridge }
653545917cbSNathan Ridge 
6543e6e6a2dSNathan Ridge } // namespace
6553e6e6a2dSNathan Ridge } // namespace clangd
6563e6e6a2dSNathan Ridge } // namespace clang
657