| 
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