@@ -1702,6 +1702,7 @@ declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1702
1702
1703
1703
HierarchyItem HI;
1704
1704
HI.name = printName (Ctx, ND);
1705
+ // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem?
1705
1706
HI.kind = SK;
1706
1707
HI.range = Range{sourceLocToPosition (SM, DeclRange->getBegin ()),
1707
1708
sourceLocToPosition (SM, DeclRange->getEnd ())};
@@ -1753,6 +1754,7 @@ static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
1753
1754
}
1754
1755
HierarchyItem HI;
1755
1756
HI.name = std::string (S.Name );
1757
+ HI.detail = (S.Scope + S.Name ).str ();
1756
1758
HI.kind = indexSymbolKindToSymbolKind (S.SymInfo .Kind );
1757
1759
HI.selectionRange = Loc->range ;
1758
1760
// FIXME: Populate 'range' correctly
@@ -2319,6 +2321,63 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
2319
2321
return Results;
2320
2322
}
2321
2323
2324
+ std::vector<CallHierarchyOutgoingCall>
2325
+ outgoingCalls (const CallHierarchyItem &Item, const SymbolIndex *Index) {
2326
+ std::vector<CallHierarchyOutgoingCall> Results;
2327
+ if (!Index || Item.data .empty ())
2328
+ return Results;
2329
+ auto ID = SymbolID::fromStr (Item.data );
2330
+ if (!ID) {
2331
+ elog (" outgoingCalls failed to find symbol: {0}" , ID.takeError ());
2332
+ return Results;
2333
+ }
2334
+ // In this function, we find outgoing calls based on the index only.
2335
+ ContainedRefsRequest Request;
2336
+ Request.ID = *ID;
2337
+ // Initially store the ranges in a map keyed by SymbolID of the callee.
2338
+ // This allows us to group different calls to the same function
2339
+ // into the same CallHierarchyOutgoingCall.
2340
+ llvm::DenseMap<SymbolID, std::vector<Range>> CallsOut;
2341
+ // We can populate the ranges based on a refs request only. As we do so, we
2342
+ // also accumulate the callee IDs into a lookup request.
2343
+ LookupRequest CallsOutLookup;
2344
+ Index->containedRefs (Request, [&](const auto &R) {
2345
+ auto Loc = indexToLSPLocation (R.Location , Item.uri .file ());
2346
+ if (!Loc) {
2347
+ elog (" outgoingCalls failed to convert location: {0}" , Loc.takeError ());
2348
+ return ;
2349
+ }
2350
+ auto It = CallsOut.try_emplace (R.Symbol , std::vector<Range>{}).first ;
2351
+ It->second .push_back (Loc->range );
2352
+
2353
+ CallsOutLookup.IDs .insert (R.Symbol );
2354
+ });
2355
+ // Perform the lookup request and combine its results with CallsOut to
2356
+ // get complete CallHierarchyOutgoingCall objects.
2357
+ Index->lookup (CallsOutLookup, [&](const Symbol &Callee) {
2358
+ // The containedRefs request should only return symbols which are
2359
+ // function-like, i.e. symbols for which references to them can be "calls".
2360
+ using SK = index ::SymbolKind;
2361
+ auto Kind = Callee.SymInfo .Kind ;
2362
+ assert (Kind == SK::Function || Kind == SK::InstanceMethod ||
2363
+ Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2364
+ Kind == SK::Constructor || Kind == SK::Destructor ||
2365
+ Kind == SK::ConversionFunction);
2366
+
2367
+ auto It = CallsOut.find (Callee.ID );
2368
+ assert (It != CallsOut.end ());
2369
+ if (auto CHI = symbolToCallHierarchyItem (Callee, Item.uri .file ()))
2370
+ Results.push_back (
2371
+ CallHierarchyOutgoingCall{std::move (*CHI), std::move (It->second )});
2372
+ });
2373
+ // Sort results by name of the callee.
2374
+ llvm::sort (Results, [](const CallHierarchyOutgoingCall &A,
2375
+ const CallHierarchyOutgoingCall &B) {
2376
+ return A.to .name < B.to .name ;
2377
+ });
2378
+ return Results;
2379
+ }
2380
+
2322
2381
llvm::DenseSet<const Decl *> getNonLocalDeclRefs (ParsedAST &AST,
2323
2382
const FunctionDecl *FD) {
2324
2383
if (!FD->hasBody ())
0 commit comments