|
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