|  | 
| 21 | 21 | #include "clang-include-cleaner/Types.h" | 
| 22 | 22 | #include "index/Index.h" | 
| 23 | 23 | #include "index/Merge.h" | 
|  | 24 | +#include "index/Ref.h" | 
| 24 | 25 | #include "index/Relation.h" | 
| 25 | 26 | #include "index/SymbolCollector.h" | 
| 26 | 27 | #include "index/SymbolID.h" | 
|  | 
| 56 | 57 | #include "clang/Tooling/Syntax/Tokens.h" | 
| 57 | 58 | #include "llvm/ADT/ArrayRef.h" | 
| 58 | 59 | #include "llvm/ADT/DenseMap.h" | 
|  | 60 | +#include "llvm/ADT/DenseSet.h" | 
| 59 | 61 | #include "llvm/ADT/STLExtras.h" | 
| 60 | 62 | #include "llvm/ADT/ScopeExit.h" | 
| 61 | 63 | #include "llvm/ADT/SmallSet.h" | 
|  | 
| 66 | 68 | #include "llvm/Support/ErrorHandling.h" | 
| 67 | 69 | #include "llvm/Support/Path.h" | 
| 68 | 70 | #include "llvm/Support/raw_ostream.h" | 
|  | 71 | +#include <algorithm> | 
| 69 | 72 | #include <optional> | 
| 70 | 73 | #include <string> | 
| 71 | 74 | #include <vector> | 
| @@ -2350,51 +2353,64 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) { | 
| 2350 | 2353 |   // to an AST node isn't cheap, particularly when the declaration isn't | 
| 2351 | 2354 |   // in the main file. | 
| 2352 | 2355 |   // FIXME: Consider also using AST information when feasible. | 
| 2353 |  | -  RefsRequest Request; | 
| 2354 |  | -  Request.IDs.insert(*ID); | 
| 2355 |  | -  Request.WantContainer = true; | 
| 2356 |  | -  // We could restrict more specifically to calls by introducing a new RefKind, | 
| 2357 |  | -  // but non-call references (such as address-of-function) can still be | 
| 2358 |  | -  // interesting as they can indicate indirect calls. | 
| 2359 |  | -  Request.Filter = RefKind::Reference; | 
| 2360 |  | -  // Initially store the ranges in a map keyed by SymbolID of the caller. | 
| 2361 |  | -  // This allows us to group different calls with the same caller | 
| 2362 |  | -  // into the same CallHierarchyIncomingCall. | 
| 2363 |  | -  llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn; | 
| 2364 |  | -  // We can populate the ranges based on a refs request only. As we do so, we | 
| 2365 |  | -  // also accumulate the container IDs into a lookup request. | 
| 2366 |  | -  LookupRequest ContainerLookup; | 
| 2367 |  | -  Index->refs(Request, [&](const Ref &R) { | 
| 2368 |  | -    auto Loc = indexToLSPLocation(R.Location, Item.uri.file()); | 
| 2369 |  | -    if (!Loc) { | 
| 2370 |  | -      elog("incomingCalls failed to convert location: {0}", Loc.takeError()); | 
| 2371 |  | -      return; | 
| 2372 |  | -    } | 
| 2373 |  | -    CallsIn[R.Container].push_back(*Loc); | 
|  | 2356 | +  auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool MightNeverCall) { | 
|  | 2357 | +    RefsRequest Request; | 
|  | 2358 | +    Request.IDs = std::move(IDs); | 
|  | 2359 | +    Request.WantContainer = true; | 
|  | 2360 | +    // We could restrict more specifically to calls by introducing a new | 
|  | 2361 | +    // RefKind, but non-call references (such as address-of-function) can still | 
|  | 2362 | +    // be interesting as they can indicate indirect calls. | 
|  | 2363 | +    Request.Filter = RefKind::Reference; | 
|  | 2364 | +    // Initially store the ranges in a map keyed by SymbolID of the caller. | 
|  | 2365 | +    // This allows us to group different calls with the same caller | 
|  | 2366 | +    // into the same CallHierarchyIncomingCall. | 
|  | 2367 | +    llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn; | 
|  | 2368 | +    // We can populate the ranges based on a refs request only. As we do so, we | 
|  | 2369 | +    // also accumulate the container IDs into a lookup request. | 
|  | 2370 | +    LookupRequest ContainerLookup; | 
|  | 2371 | +    Index->refs(Request, [&](const Ref &R) { | 
|  | 2372 | +      auto Loc = indexToLSPLocation(R.Location, Item.uri.file()); | 
|  | 2373 | +      if (!Loc) { | 
|  | 2374 | +        elog("incomingCalls failed to convert location: {0}", Loc.takeError()); | 
|  | 2375 | +        return; | 
|  | 2376 | +      } | 
|  | 2377 | +      CallsIn[R.Container].push_back(*Loc); | 
| 2374 | 2378 | 
 | 
| 2375 |  | -    ContainerLookup.IDs.insert(R.Container); | 
| 2376 |  | -  }); | 
| 2377 |  | -  // Perform the lookup request and combine its results with CallsIn to | 
| 2378 |  | -  // get complete CallHierarchyIncomingCall objects. | 
| 2379 |  | -  Index->lookup(ContainerLookup, [&](const Symbol &Caller) { | 
| 2380 |  | -    auto It = CallsIn.find(Caller.ID); | 
| 2381 |  | -    assert(It != CallsIn.end()); | 
| 2382 |  | -    if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file())) { | 
| 2383 |  | -      std::vector<Range> FromRanges; | 
| 2384 |  | -      for (const Location &L : It->second) { | 
| 2385 |  | -        if (L.uri != CHI->uri) { | 
| 2386 |  | -          // Call location not in same file as caller. | 
| 2387 |  | -          // This can happen in some edge cases. There's not much we can do, | 
| 2388 |  | -          // since the protocol only allows returning ranges interpreted as | 
| 2389 |  | -          // being in the caller's file. | 
| 2390 |  | -          continue; | 
|  | 2379 | +      ContainerLookup.IDs.insert(R.Container); | 
|  | 2380 | +    }); | 
|  | 2381 | +    // Perform the lookup request and combine its results with CallsIn to | 
|  | 2382 | +    // get complete CallHierarchyIncomingCall objects. | 
|  | 2383 | +    Index->lookup(ContainerLookup, [&](const Symbol &Caller) { | 
|  | 2384 | +      auto It = CallsIn.find(Caller.ID); | 
|  | 2385 | +      assert(It != CallsIn.end()); | 
|  | 2386 | +      if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file())) { | 
|  | 2387 | +        std::vector<Range> FromRanges; | 
|  | 2388 | +        for (const Location &L : It->second) { | 
|  | 2389 | +          if (L.uri != CHI->uri) { | 
|  | 2390 | +            // Call location not in same file as caller. | 
|  | 2391 | +            // This can happen in some edge cases. There's not much we can do, | 
|  | 2392 | +            // since the protocol only allows returning ranges interpreted as | 
|  | 2393 | +            // being in the caller's file. | 
|  | 2394 | +            continue; | 
|  | 2395 | +          } | 
|  | 2396 | +          FromRanges.push_back(L.range); | 
| 2391 | 2397 |         } | 
| 2392 |  | -        FromRanges.push_back(L.range); | 
|  | 2398 | +        Results.push_back(CallHierarchyIncomingCall{ | 
|  | 2399 | +            std::move(*CHI), std::move(FromRanges), MightNeverCall}); | 
| 2393 | 2400 |       } | 
| 2394 |  | -      Results.push_back( | 
| 2395 |  | -          CallHierarchyIncomingCall{std::move(*CHI), std::move(FromRanges)}); | 
| 2396 |  | -    } | 
| 2397 |  | -  }); | 
|  | 2401 | +    }); | 
|  | 2402 | +  }; | 
|  | 2403 | +  QueryIndex({ID.get()}, false); | 
|  | 2404 | +  // In the case of being a virtual function we also want to return | 
|  | 2405 | +  // potential calls through the base function. | 
|  | 2406 | +  if (Item.kind == SymbolKind::Method) { | 
|  | 2407 | +    llvm::DenseSet<SymbolID> IDs; | 
|  | 2408 | +    RelationsRequest Req{{ID.get()}, RelationKind::OverriddenBy, std::nullopt}; | 
|  | 2409 | +    Index->reverseRelations(Req, [&](const SymbolID &, const Symbol &Caller) { | 
|  | 2410 | +      IDs.insert(Caller.ID); | 
|  | 2411 | +    }); | 
|  | 2412 | +    QueryIndex(std::move(IDs), true); | 
|  | 2413 | +  } | 
| 2398 | 2414 |   // Sort results by name of container. | 
| 2399 | 2415 |   llvm::sort(Results, [](const CallHierarchyIncomingCall &A, | 
| 2400 | 2416 |                          const CallHierarchyIncomingCall &B) { | 
|  | 
0 commit comments