@@ -121,31 +121,17 @@ void logIfOverflow(const SymbolLocation &Loc) {
121121
122122// Convert a SymbolLocation to LSP's Location.
123123// TUPath is used to resolve the path of URI.
124- // FIXME: figure out a good home for it, and share the implementation with
125- // FindSymbols.
126124std::optional<Location> toLSPLocation (const SymbolLocation &Loc,
127125 llvm::StringRef TUPath) {
128126 if (!Loc)
129127 return std::nullopt ;
130- auto Uri = URI::parse (Loc. FileURI );
131- if (!Uri ) {
132- elog (" Could not parse URI {0}: {1} " , Loc. FileURI , Uri .takeError ());
128+ auto LSPLoc = indexToLSPLocation (Loc, TUPath );
129+ if (!LSPLoc ) {
130+ elog (" {0}" , LSPLoc .takeError ());
133131 return std::nullopt ;
134132 }
135- auto U = URIForFile::fromURI (*Uri, TUPath);
136- if (!U) {
137- elog (" Could not resolve URI {0}: {1}" , Loc.FileURI , U.takeError ());
138- return std::nullopt ;
139- }
140-
141- Location LSPLoc;
142- LSPLoc.uri = std::move (*U);
143- LSPLoc.range .start .line = Loc.Start .line ();
144- LSPLoc.range .start .character = Loc.Start .column ();
145- LSPLoc.range .end .line = Loc.End .line ();
146- LSPLoc.range .end .character = Loc.End .column ();
147133 logIfOverflow (Loc);
148- return LSPLoc;
134+ return * LSPLoc;
149135}
150136
151137SymbolLocation toIndexLocation (const Location &Loc, std::string &URIStorage) {
@@ -1702,6 +1688,7 @@ declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
17021688
17031689 HierarchyItem HI;
17041690 HI.name = printName (Ctx, ND);
1691+ // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem?
17051692 HI.kind = SK;
17061693 HI.range = Range{sourceLocToPosition (SM, DeclRange->getBegin ()),
17071694 sourceLocToPosition (SM, DeclRange->getEnd ())};
@@ -1753,6 +1740,7 @@ static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
17531740 }
17541741 HierarchyItem HI;
17551742 HI.name = std::string (S.Name );
1743+ HI.detail = (S.Scope + S.Name ).str ();
17561744 HI.kind = indexSymbolKindToSymbolKind (S.SymInfo .Kind );
17571745 HI.selectionRange = Loc->range ;
17581746 // FIXME: Populate 'range' correctly
@@ -2319,6 +2307,65 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
23192307 return Results;
23202308}
23212309
2310+ std::vector<CallHierarchyOutgoingCall>
2311+ outgoingCalls (const CallHierarchyItem &Item, const SymbolIndex *Index) {
2312+ std::vector<CallHierarchyOutgoingCall> Results;
2313+ if (!Index || Item.data .empty ())
2314+ return Results;
2315+ auto ID = SymbolID::fromStr (Item.data );
2316+ if (!ID) {
2317+ elog (" outgoingCalls failed to find symbol: {0}" , ID.takeError ());
2318+ return Results;
2319+ }
2320+ // In this function, we find outgoing calls based on the index only.
2321+ ContainedRefsRequest Request;
2322+ Request.ID = *ID;
2323+ // Initially store the ranges in a map keyed by SymbolID of the callee.
2324+ // This allows us to group different calls to the same function
2325+ // into the same CallHierarchyOutgoingCall.
2326+ llvm::DenseMap<SymbolID, std::vector<Range>> CallsOut;
2327+ // We can populate the ranges based on a refs request only. As we do so, we
2328+ // also accumulate the callee IDs into a lookup request.
2329+ LookupRequest CallsOutLookup;
2330+ Index->containedRefs (Request, [&](const auto &R) {
2331+ auto Loc = indexToLSPLocation (R.Location , Item.uri .file ());
2332+ if (!Loc) {
2333+ elog (" outgoingCalls failed to convert location: {0}" , Loc.takeError ());
2334+ return ;
2335+ }
2336+ auto It = CallsOut.try_emplace (R.Symbol , std::vector<Range>{}).first ;
2337+ It->second .push_back (Loc->range );
2338+
2339+ CallsOutLookup.IDs .insert (R.Symbol );
2340+ });
2341+ // Perform the lookup request and combine its results with CallsOut to
2342+ // get complete CallHierarchyOutgoingCall objects.
2343+ Index->lookup (CallsOutLookup, [&](const Symbol &Callee) {
2344+ // The containedRefs request should only return symbols which are
2345+ // function-like, i.e. symbols for which references to them can be "calls".
2346+ using SK = index::SymbolKind;
2347+ auto Kind = Callee.SymInfo .Kind ;
2348+ assert (Kind == SK::Function || Kind == SK::InstanceMethod ||
2349+ Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2350+ Kind == SK::Constructor || Kind == SK::Destructor ||
2351+ Kind == SK::ConversionFunction);
2352+ (void )Kind;
2353+ (void )SK::Function;
2354+
2355+ auto It = CallsOut.find (Callee.ID );
2356+ assert (It != CallsOut.end ());
2357+ if (auto CHI = symbolToCallHierarchyItem (Callee, Item.uri .file ()))
2358+ Results.push_back (
2359+ CallHierarchyOutgoingCall{std::move (*CHI), std::move (It->second )});
2360+ });
2361+ // Sort results by name of the callee.
2362+ llvm::sort (Results, [](const CallHierarchyOutgoingCall &A,
2363+ const CallHierarchyOutgoingCall &B) {
2364+ return A.to .name < B.to .name ;
2365+ });
2366+ return Results;
2367+ }
2368+
23222369llvm::DenseSet<const Decl *> getNonLocalDeclRefs (ParsedAST &AST,
23232370 const FunctionDecl *FD) {
23242371 if (!FD->hasBody ())
0 commit comments