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