[RISCV] Add shrinkwrap test cases showing gaps in current impl
[llvm-project.git] / clang-tools-extra / clangd / XRefs.cpp
blob61fa66180376cd1e7194091626ffd1acbe9a1759
1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "XRefs.h"
9 #include "AST.h"
10 #include "FindSymbols.h"
11 #include "FindTarget.h"
12 #include "Headers.h"
13 #include "HeuristicResolver.h"
14 #include "IncludeCleaner.h"
15 #include "ParsedAST.h"
16 #include "Protocol.h"
17 #include "Quality.h"
18 #include "Selection.h"
19 #include "SourceCode.h"
20 #include "URI.h"
21 #include "clang-include-cleaner/Analysis.h"
22 #include "clang-include-cleaner/Types.h"
23 #include "index/Index.h"
24 #include "index/Merge.h"
25 #include "index/Relation.h"
26 #include "index/SymbolCollector.h"
27 #include "index/SymbolID.h"
28 #include "index/SymbolLocation.h"
29 #include "support/Logger.h"
30 #include "clang/AST/ASTContext.h"
31 #include "clang/AST/ASTTypeTraits.h"
32 #include "clang/AST/Attr.h"
33 #include "clang/AST/Attrs.inc"
34 #include "clang/AST/Decl.h"
35 #include "clang/AST/DeclCXX.h"
36 #include "clang/AST/DeclObjC.h"
37 #include "clang/AST/DeclTemplate.h"
38 #include "clang/AST/DeclVisitor.h"
39 #include "clang/AST/ExprCXX.h"
40 #include "clang/AST/RecursiveASTVisitor.h"
41 #include "clang/AST/Stmt.h"
42 #include "clang/AST/StmtCXX.h"
43 #include "clang/AST/StmtVisitor.h"
44 #include "clang/AST/Type.h"
45 #include "clang/Basic/LLVM.h"
46 #include "clang/Basic/LangOptions.h"
47 #include "clang/Basic/SourceLocation.h"
48 #include "clang/Basic/SourceManager.h"
49 #include "clang/Basic/TokenKinds.h"
50 #include "clang/Index/IndexDataConsumer.h"
51 #include "clang/Index/IndexSymbol.h"
52 #include "clang/Index/IndexingAction.h"
53 #include "clang/Index/IndexingOptions.h"
54 #include "clang/Index/USRGeneration.h"
55 #include "clang/Lex/Lexer.h"
56 #include "clang/Tooling/Syntax/Tokens.h"
57 #include "llvm/ADT/ArrayRef.h"
58 #include "llvm/ADT/DenseMap.h"
59 #include "llvm/ADT/STLExtras.h"
60 #include "llvm/ADT/ScopeExit.h"
61 #include "llvm/ADT/SmallSet.h"
62 #include "llvm/ADT/SmallVector.h"
63 #include "llvm/ADT/StringRef.h"
64 #include "llvm/Support/Casting.h"
65 #include "llvm/Support/Error.h"
66 #include "llvm/Support/ErrorHandling.h"
67 #include "llvm/Support/Path.h"
68 #include "llvm/Support/raw_ostream.h"
69 #include <optional>
70 #include <string>
71 #include <vector>
73 namespace clang {
74 namespace clangd {
75 namespace {
77 // Returns the single definition of the entity declared by D, if visible.
78 // In particular:
79 // - for non-redeclarable kinds (e.g. local vars), return D
80 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
81 // Kinds of nodes that always return nullptr here will not have definitions
82 // reported by locateSymbolAt().
83 const NamedDecl *getDefinition(const NamedDecl *D) {
84 assert(D);
85 // Decl has one definition that we can find.
86 if (const auto *TD = dyn_cast<TagDecl>(D))
87 return TD->getDefinition();
88 if (const auto *VD = dyn_cast<VarDecl>(D))
89 return VD->getDefinition();
90 if (const auto *FD = dyn_cast<FunctionDecl>(D))
91 return FD->getDefinition();
92 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
93 if (const auto *RD = CTD->getTemplatedDecl())
94 return RD->getDefinition();
95 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
96 if (MD->isThisDeclarationADefinition())
97 return MD;
98 // Look for the method definition inside the implementation decl.
99 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
100 if (DeclCtx->isInvalidDecl())
101 return nullptr;
103 if (const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
104 if (const auto *Impl = getCorrespondingObjCImpl(CD))
105 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
107 if (const auto *CD = dyn_cast<ObjCContainerDecl>(D))
108 return getCorrespondingObjCImpl(CD);
109 // Only a single declaration is allowed.
110 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
111 isa<TemplateTemplateParmDecl>(D)) // except cases above
112 return D;
113 // Multiple definitions are allowed.
114 return nullptr; // except cases above
117 void logIfOverflow(const SymbolLocation &Loc) {
118 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
119 log("Possible overflow in symbol location: {0}", Loc);
122 // Convert a SymbolLocation to LSP's Location.
123 // 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.
126 std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
127 llvm::StringRef TUPath) {
128 if (!Loc)
129 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());
133 return std::nullopt;
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;
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();
147 logIfOverflow(Loc);
148 return LSPLoc;
151 SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
152 SymbolLocation SymLoc;
153 URIStorage = Loc.uri.uri();
154 SymLoc.FileURI = URIStorage.c_str();
155 SymLoc.Start.setLine(Loc.range.start.line);
156 SymLoc.Start.setColumn(Loc.range.start.character);
157 SymLoc.End.setLine(Loc.range.end.line);
158 SymLoc.End.setColumn(Loc.range.end.character);
159 return SymLoc;
162 // Returns the preferred location between an AST location and an index location.
163 SymbolLocation getPreferredLocation(const Location &ASTLoc,
164 const SymbolLocation &IdxLoc,
165 std::string &Scratch) {
166 // Also use a mock symbol for the index location so that other fields (e.g.
167 // definition) are not factored into the preference.
168 Symbol ASTSym, IdxSym;
169 ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
170 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
171 IdxSym.CanonicalDeclaration = IdxLoc;
172 auto Merged = mergeSymbol(ASTSym, IdxSym);
173 return Merged.CanonicalDeclaration;
176 std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
177 getDeclAtPositionWithRelations(ParsedAST &AST, SourceLocation Pos,
178 DeclRelationSet Relations,
179 ASTNodeKind *NodeKind = nullptr) {
180 unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
181 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
182 auto ResultFromTree = [&](SelectionTree ST) {
183 if (const SelectionTree::Node *N = ST.commonAncestor()) {
184 if (NodeKind)
185 *NodeKind = N->ASTNode.getNodeKind();
186 // Attributes don't target decls, look at the
187 // thing it's attached to.
188 // We still report the original NodeKind!
189 // This makes the `override` hack work.
190 if (N->ASTNode.get<Attr>() && N->Parent)
191 N = N->Parent;
192 llvm::copy_if(allTargetDecls(N->ASTNode, AST.getHeuristicResolver()),
193 std::back_inserter(Result),
194 [&](auto &Entry) { return !(Entry.second & ~Relations); });
196 return !Result.empty();
198 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
199 Offset, ResultFromTree);
200 return Result;
203 std::vector<const NamedDecl *>
204 getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,
205 ASTNodeKind *NodeKind = nullptr) {
206 std::vector<const NamedDecl *> Result;
207 for (auto &Entry :
208 getDeclAtPositionWithRelations(AST, Pos, Relations, NodeKind))
209 Result.push_back(Entry.first);
210 return Result;
213 // Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
214 // figure out a filename.
215 std::optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,
216 llvm::StringRef TUPath) {
217 const auto &SM = AST.getSourceManager();
218 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
219 if (!F)
220 return std::nullopt;
221 auto FilePath = getCanonicalPath(*F, SM.getFileManager());
222 if (!FilePath) {
223 log("failed to get path!");
224 return std::nullopt;
226 Location L;
227 L.uri = URIForFile::canonicalize(*FilePath, TUPath);
228 // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
229 // outside the main file.
230 auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());
231 L.range = halfOpenToRange(
232 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
233 return L;
236 // Treat #included files as symbols, to enable go-to-definition on them.
237 std::optional<LocatedSymbol> locateFileReferent(const Position &Pos,
238 ParsedAST &AST,
239 llvm::StringRef MainFilePath) {
240 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
241 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
242 LocatedSymbol File;
243 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
244 File.PreferredDeclaration = {
245 URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
246 File.Definition = File.PreferredDeclaration;
247 // We're not going to find any further symbols on #include lines.
248 return File;
251 return std::nullopt;
254 // Macros are simple: there's no declaration/definition distinction.
255 // As a consequence, there's no need to look them up in the index either.
256 std::optional<LocatedSymbol>
257 locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
258 llvm::StringRef MainFilePath) {
259 if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
260 if (auto Loc =
261 makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {
262 LocatedSymbol Macro;
263 Macro.Name = std::string(M->Name);
264 Macro.PreferredDeclaration = *Loc;
265 Macro.Definition = Loc;
266 Macro.ID = getSymbolID(M->Name, M->Info, AST.getSourceManager());
267 return Macro;
270 return std::nullopt;
273 // A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
274 // definition of a canonical declaration doesn't match up to what a programmer
275 // would expect. For example, Objective-C classes can have three types of
276 // declarations:
278 // - forward declaration(s): @class MyClass;
279 // - true declaration (interface definition): @interface MyClass ... @end
280 // - true definition (implementation): @implementation MyClass ... @end
282 // Clang will consider the forward declaration to be the canonical declaration
283 // because it is first. We actually want the class definition if it is
284 // available since that is what a programmer would consider the primary
285 // declaration to be.
286 const NamedDecl *getPreferredDecl(const NamedDecl *D) {
287 // FIXME: Canonical declarations of some symbols might refer to built-in
288 // decls with possibly-invalid source locations (e.g. global new operator).
289 // In such cases we should pick up a redecl with valid source location
290 // instead of failing.
291 D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
293 // Prefer Objective-C class/protocol definitions over the forward declaration.
294 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
295 if (const auto *DefinitionID = ID->getDefinition())
296 return DefinitionID;
297 if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
298 if (const auto *DefinitionID = PD->getDefinition())
299 return DefinitionID;
301 return D;
304 std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
305 RelationKind Predicate,
306 const SymbolIndex *Index,
307 llvm::StringRef MainFilePath) {
308 if (IDs.empty() || !Index)
309 return {};
310 static constexpr trace::Metric FindImplementorsMetric(
311 "find_implementors", trace::Metric::Counter, "case");
312 switch (Predicate) {
313 case RelationKind::BaseOf:
314 FindImplementorsMetric.record(1, "find-base");
315 break;
316 case RelationKind::OverriddenBy:
317 FindImplementorsMetric.record(1, "find-override");
318 break;
321 RelationsRequest Req;
322 Req.Predicate = Predicate;
323 Req.Subjects = std::move(IDs);
324 std::vector<LocatedSymbol> Results;
325 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
326 auto DeclLoc =
327 indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
328 if (!DeclLoc) {
329 elog("Find overrides: {0}", DeclLoc.takeError());
330 return;
332 Results.emplace_back();
333 Results.back().Name = Object.Name.str();
334 Results.back().PreferredDeclaration = *DeclLoc;
335 auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
336 if (!DefLoc) {
337 elog("Failed to convert location: {0}", DefLoc.takeError());
338 return;
340 Results.back().Definition = *DefLoc;
342 return Results;
345 // Given LocatedSymbol results derived from the AST, query the index to obtain
346 // definitions and preferred declarations.
347 void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
348 const SymbolIndex *Index,
349 llvm::StringRef MainFilePath) {
350 LookupRequest QueryRequest;
351 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
352 for (unsigned I = 0; I < Result.size(); ++I) {
353 if (auto ID = Result[I].ID) {
354 ResultIndex.try_emplace(ID, I);
355 QueryRequest.IDs.insert(ID);
358 if (!Index || QueryRequest.IDs.empty())
359 return;
360 std::string Scratch;
361 Index->lookup(QueryRequest, [&](const Symbol &Sym) {
362 auto &R = Result[ResultIndex.lookup(Sym.ID)];
364 if (R.Definition) { // from AST
365 // Special case: if the AST yielded a definition, then it may not be
366 // the right *declaration*. Prefer the one from the index.
367 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
368 R.PreferredDeclaration = *Loc;
370 // We might still prefer the definition from the index, e.g. for
371 // generated symbols.
372 if (auto Loc = toLSPLocation(
373 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
374 MainFilePath))
375 R.Definition = *Loc;
376 } else {
377 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
379 // Use merge logic to choose AST or index declaration.
380 if (auto Loc = toLSPLocation(
381 getPreferredLocation(R.PreferredDeclaration,
382 Sym.CanonicalDeclaration, Scratch),
383 MainFilePath))
384 R.PreferredDeclaration = *Loc;
389 // Decls are more complicated.
390 // The AST contains at least a declaration, maybe a definition.
391 // These are up-to-date, and so generally preferred over index results.
392 // We perform a single batch index lookup to find additional definitions.
393 std::vector<LocatedSymbol>
394 locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
395 ParsedAST &AST, llvm::StringRef MainFilePath,
396 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
397 const SourceManager &SM = AST.getSourceManager();
398 // Results follow the order of Symbols.Decls.
399 std::vector<LocatedSymbol> Result;
401 static constexpr trace::Metric LocateASTReferentMetric(
402 "locate_ast_referent", trace::Metric::Counter, "case");
403 auto AddResultDecl = [&](const NamedDecl *D) {
404 D = getPreferredDecl(D);
405 auto Loc =
406 makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
407 if (!Loc)
408 return;
410 Result.emplace_back();
411 Result.back().Name = printName(AST.getASTContext(), *D);
412 Result.back().PreferredDeclaration = *Loc;
413 Result.back().ID = getSymbolID(D);
414 if (const NamedDecl *Def = getDefinition(D))
415 Result.back().Definition = makeLocation(
416 AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
419 // Emit all symbol locations (declaration or definition) from AST.
420 DeclRelationSet Relations =
421 DeclRelation::TemplatePattern | DeclRelation::Alias;
422 auto Candidates =
423 getDeclAtPositionWithRelations(AST, CurLoc, Relations, &NodeKind);
424 llvm::DenseSet<SymbolID> VirtualMethods;
425 for (const auto &E : Candidates) {
426 const NamedDecl *D = E.first;
427 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
428 // Special case: virtual void ^method() = 0: jump to all overrides.
429 // FIXME: extend it to ^virtual, unfortunately, virtual location is not
430 // saved in the AST.
431 if (CMD->isPureVirtual()) {
432 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
433 TouchedIdentifier->location()) {
434 VirtualMethods.insert(getSymbolID(CMD));
435 LocateASTReferentMetric.record(1, "method-to-override");
438 // Special case: void foo() ^override: jump to the overridden method.
439 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
440 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
441 // We may be overridding multiple methods - offer them all.
442 for (const NamedDecl *ND : CMD->overridden_methods())
443 AddResultDecl(ND);
444 continue;
448 // Special case: the cursor is on an alias, prefer other results.
449 // This targets "using ns::^Foo", where the target is more interesting.
450 // This does not trigger on renaming aliases:
451 // `using Foo = ^Bar` already targets Bar via a TypeLoc
452 // `using ^Foo = Bar` has no other results, as Underlying is filtered.
453 if (E.second & DeclRelation::Alias && Candidates.size() > 1 &&
454 // beginLoc/endLoc are a token range, so rewind the identifier we're in.
455 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
456 : CurLoc,
457 D->getBeginLoc(), D->getEndLoc()))
458 continue;
460 // Special case: the point of declaration of a template specialization,
461 // it's more useful to navigate to the template declaration.
462 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
463 if (TouchedIdentifier &&
464 D->getLocation() == TouchedIdentifier->location()) {
465 LocateASTReferentMetric.record(1, "template-specialization-to-primary");
466 AddResultDecl(CTSD->getSpecializedTemplate());
467 continue;
471 // Special case: if the class name is selected, also map Objective-C
472 // categories and category implementations back to their class interface.
474 // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`
475 // instead of the `ObjCCategoryDecl` we intentionally check the contents
476 // of the locs when checking for class name equivalence.
477 if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
478 if (const auto *ID = CD->getClassInterface())
479 if (TouchedIdentifier &&
480 (CD->getLocation() == TouchedIdentifier->location() ||
481 ID->getName() == TouchedIdentifier->text(SM))) {
482 LocateASTReferentMetric.record(1, "objc-category-to-class");
483 AddResultDecl(ID);
486 LocateASTReferentMetric.record(1, "regular");
487 // Otherwise the target declaration is the right one.
488 AddResultDecl(D);
490 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
492 auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy,
493 Index, MainFilePath);
494 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
495 return Result;
498 std::vector<LocatedSymbol> locateSymbolForType(const ParsedAST &AST,
499 const QualType &Type,
500 const SymbolIndex *Index) {
501 const auto &SM = AST.getSourceManager();
502 auto MainFilePath = AST.tuPath();
504 // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.
505 // Likely it would be better to send it to Foo (heuristically) or to both.
506 auto Decls = targetDecl(DynTypedNode::create(Type.getNonReferenceType()),
507 DeclRelation::TemplatePattern | DeclRelation::Alias,
508 AST.getHeuristicResolver());
509 if (Decls.empty())
510 return {};
512 std::vector<LocatedSymbol> Results;
513 const auto &ASTContext = AST.getASTContext();
515 for (const NamedDecl *D : Decls) {
516 D = getPreferredDecl(D);
518 auto Loc = makeLocation(ASTContext, nameLocation(*D, SM), MainFilePath);
519 if (!Loc)
520 continue;
522 Results.emplace_back();
523 Results.back().Name = printName(ASTContext, *D);
524 Results.back().PreferredDeclaration = *Loc;
525 Results.back().ID = getSymbolID(D);
526 if (const NamedDecl *Def = getDefinition(D))
527 Results.back().Definition =
528 makeLocation(ASTContext, nameLocation(*Def, SM), MainFilePath);
530 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
532 return Results;
535 bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {
536 auto ExpandedTokens = TB.expandedTokens(
537 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
538 return !ExpandedTokens.empty();
541 llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {
542 auto D = SM.getDecomposedLoc(Loc);
543 bool Invalid = false;
544 llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
545 if (Invalid || D.second > Buf.size())
546 return "";
547 return Buf.substr(0, D.second);
550 bool isDependentName(ASTNodeKind NodeKind) {
551 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
552 NodeKind.isSame(
553 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
554 NodeKind.isSame(
555 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
558 } // namespace
560 std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
561 ParsedAST &AST,
562 const SymbolIndex *Index,
563 llvm::StringRef MainFilePath,
564 ASTNodeKind NodeKind) {
565 // Don't use heuristics if this is a real identifier, or not an
566 // identifier.
567 // Exception: dependent names, because those may have useful textual
568 // matches that AST-based heuristics cannot find.
569 if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||
570 !Word.LikelyIdentifier || !Index)
571 return {};
572 // We don't want to handle words in string literals. (It'd be nice to list
573 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
574 if (Word.PartOfSpelledToken &&
575 isStringLiteral(Word.PartOfSpelledToken->kind()))
576 return {};
578 const auto &SM = AST.getSourceManager();
579 // Look up the selected word in the index.
580 FuzzyFindRequest Req;
581 Req.Query = Word.Text.str();
582 Req.ProximityPaths = {MainFilePath.str()};
583 // Find the namespaces to query by lexing the file.
584 Req.Scopes =
585 visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());
586 // FIXME: For extra strictness, consider AnyScope=false.
587 Req.AnyScope = true;
588 // We limit the results to 3 further below. This limit is to avoid fetching
589 // too much data, while still likely having enough for 3 results to remain
590 // after additional filtering.
591 Req.Limit = 10;
592 bool TooMany = false;
593 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
594 std::vector<ScoredLocatedSymbol> ScoredResults;
595 Index->fuzzyFind(Req, [&](const Symbol &Sym) {
596 // Only consider exact name matches, including case.
597 // This is to avoid too many false positives.
598 // We could relax this in the future (e.g. to allow for typos) if we make
599 // the query more accurate by other means.
600 if (Sym.Name != Word.Text)
601 return;
603 // Exclude constructor results. They have the same name as the class,
604 // but we don't have enough context to prefer them over the class.
605 if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)
606 return;
608 auto MaybeDeclLoc =
609 indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
610 if (!MaybeDeclLoc) {
611 log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
612 return;
614 LocatedSymbol Located;
615 Located.PreferredDeclaration = *MaybeDeclLoc;
616 Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
617 Located.ID = Sym.ID;
618 if (Sym.Definition) {
619 auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
620 if (!MaybeDefLoc) {
621 log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
622 return;
624 Located.PreferredDeclaration = *MaybeDefLoc;
625 Located.Definition = *MaybeDefLoc;
628 if (ScoredResults.size() >= 5) {
629 // If we have more than 5 results, don't return anything,
630 // as confidence is too low.
631 // FIXME: Alternatively, try a stricter query?
632 TooMany = true;
633 return;
636 SymbolQualitySignals Quality;
637 Quality.merge(Sym);
638 SymbolRelevanceSignals Relevance;
639 Relevance.Name = Sym.Name;
640 Relevance.Query = SymbolRelevanceSignals::Generic;
641 Relevance.merge(Sym);
642 auto Score = evaluateSymbolAndRelevance(Quality.evaluateHeuristics(),
643 Relevance.evaluateHeuristics());
644 dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,
645 Sym.Name, Score, Quality, Relevance);
647 ScoredResults.push_back({Score, std::move(Located)});
650 if (TooMany) {
651 vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
652 Word.Text);
653 return {};
656 llvm::sort(ScoredResults,
657 [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {
658 return A.first > B.first;
660 std::vector<LocatedSymbol> Results;
661 for (auto &Res : std::move(ScoredResults))
662 Results.push_back(std::move(Res.second));
663 if (Results.empty())
664 vlog("No heuristic index definition for {0}", Word.Text);
665 else
666 log("Found definition heuristically in index for {0}", Word.Text);
667 return Results;
670 const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
671 const syntax::TokenBuffer &TB) {
672 // Don't use heuristics if this is a real identifier.
673 // Unlikely identifiers are OK if they were used as identifiers nearby.
674 if (Word.ExpandedToken)
675 return nullptr;
676 // We don't want to handle words in string literals. (It'd be nice to list
677 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
678 if (Word.PartOfSpelledToken &&
679 isStringLiteral(Word.PartOfSpelledToken->kind()))
680 return {};
682 const SourceManager &SM = TB.sourceManager();
683 // We prefer the closest possible token, line-wise. Backwards is penalized.
684 // Ties are implicitly broken by traversal order (first-one-wins).
685 auto File = SM.getFileID(Word.Location);
686 unsigned WordLine = SM.getSpellingLineNumber(Word.Location);
687 auto Cost = [&](SourceLocation Loc) -> unsigned {
688 assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
689 unsigned Line = SM.getSpellingLineNumber(Loc);
690 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
692 const syntax::Token *BestTok = nullptr;
693 unsigned BestCost = -1;
694 // Search bounds are based on word length:
695 // - forward: 2^N lines
696 // - backward: 2^(N-1) lines.
697 unsigned MaxDistance =
698 1U << std::min<unsigned>(Word.Text.size(),
699 std::numeric_limits<unsigned>::digits - 1);
700 // Line number for SM.translateLineCol() should be one-based, also
701 // SM.translateLineCol() can handle line number greater than
702 // number of lines in the file.
703 // - LineMin = max(1, WordLine + 1 - 2^(N-1))
704 // - LineMax = WordLine + 1 + 2^N
705 unsigned LineMin =
706 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
707 unsigned LineMax = WordLine + 1 + MaxDistance;
708 SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);
709 assert(LocMin.isValid());
710 SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);
711 assert(LocMax.isValid());
713 // Updates BestTok and BestCost if Tok is a good candidate.
714 // May return true if the cost is too high for this token.
715 auto Consider = [&](const syntax::Token &Tok) {
716 if (Tok.location() < LocMin || Tok.location() > LocMax)
717 return true; // we are too far from the word, break the outer loop.
718 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
719 return false;
720 // No point guessing the same location we started with.
721 if (Tok.location() == Word.Location)
722 return false;
723 // We've done cheap checks, compute cost so we can break the caller's loop.
724 unsigned TokCost = Cost(Tok.location());
725 if (TokCost >= BestCost)
726 return true; // causes the outer loop to break.
727 // Allow locations that might be part of the AST, and macros (even if empty)
728 // but not things like disabled preprocessor sections.
729 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
730 return false;
731 // We already verified this token is an improvement.
732 BestCost = TokCost;
733 BestTok = &Tok;
734 return false;
736 auto SpelledTokens = TB.spelledTokens(File);
737 // Find where the word occurred in the token stream, to search forward & back.
738 auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {
739 assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));
740 return T.location() < Word.Location; // Comparison OK: same file.
742 // Search for matches after the cursor.
743 for (const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
744 if (Consider(Tok))
745 break; // costs of later tokens are greater...
746 // Search for matches before the cursor.
747 for (const syntax::Token &Tok :
748 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
749 if (Consider(Tok))
750 break;
752 if (BestTok)
753 vlog(
754 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
755 Word.Text, Word.Location.printToString(SM),
756 BestTok->location().printToString(SM));
758 return BestTok;
761 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
762 const SymbolIndex *Index) {
763 const auto &SM = AST.getSourceManager();
764 auto MainFilePath = AST.tuPath();
766 if (auto File = locateFileReferent(Pos, AST, MainFilePath))
767 return {std::move(*File)};
769 auto CurLoc = sourceLocationInMainFile(SM, Pos);
770 if (!CurLoc) {
771 elog("locateSymbolAt failed to convert position to source location: {0}",
772 CurLoc.takeError());
773 return {};
776 const syntax::Token *TouchedIdentifier = nullptr;
777 auto TokensTouchingCursor =
778 syntax::spelledTokensTouching(*CurLoc, AST.getTokens());
779 for (const syntax::Token &Tok : TokensTouchingCursor) {
780 if (Tok.kind() == tok::identifier) {
781 if (auto Macro = locateMacroReferent(Tok, AST, MainFilePath))
782 // Don't look at the AST or index if we have a macro result.
783 // (We'd just return declarations referenced from the macro's
784 // expansion.)
785 return {*std::move(Macro)};
787 TouchedIdentifier = &Tok;
788 break;
791 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
792 // go-to-definition on auto should find the definition of the deduced
793 // type, if possible
794 if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
795 auto LocSym = locateSymbolForType(AST, *Deduced, Index);
796 if (!LocSym.empty())
797 return LocSym;
802 ASTNodeKind NodeKind;
803 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,
804 MainFilePath, Index, NodeKind);
805 if (!ASTResults.empty())
806 return ASTResults;
808 // If the cursor can't be resolved directly, try fallback strategies.
809 auto Word =
810 SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());
811 if (Word) {
812 // Is the same word nearby a real identifier that might refer to something?
813 if (const syntax::Token *NearbyIdent =
814 findNearbyIdentifier(*Word, AST.getTokens())) {
815 if (auto Macro = locateMacroReferent(*NearbyIdent, AST, MainFilePath)) {
816 log("Found macro definition heuristically using nearby identifier {0}",
817 Word->Text);
818 return {*std::move(Macro)};
820 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,
821 MainFilePath, Index, NodeKind);
822 if (!ASTResults.empty()) {
823 log("Found definition heuristically using nearby identifier {0}",
824 NearbyIdent->text(SM));
825 return ASTResults;
827 vlog("No definition found using nearby identifier {0} at {1}", Word->Text,
828 Word->Location.printToString(SM));
830 // No nearby word, or it didn't refer to anything either. Try the index.
831 auto TextualResults =
832 locateSymbolTextually(*Word, AST, Index, MainFilePath, NodeKind);
833 if (!TextualResults.empty())
834 return TextualResults;
837 return {};
840 std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
841 const auto &SM = AST.getSourceManager();
843 std::vector<DocumentLink> Result;
844 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
845 if (Inc.Resolved.empty())
846 continue;
847 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
848 const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
849 assert(HashTok && "got inclusion at wrong offset");
850 const auto *IncludeTok = std::next(HashTok);
851 const auto *FileTok = std::next(IncludeTok);
852 // FileTok->range is not sufficient here, as raw lexing wouldn't yield
853 // correct tokens for angled filenames. Hence we explicitly use
854 // Inc.Written's length.
855 auto FileRange =
856 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
857 .toCharRange(SM);
859 Result.push_back(
860 DocumentLink({halfOpenToRange(SM, FileRange),
861 URIForFile::canonicalize(Inc.Resolved, AST.tuPath())}));
864 return Result;
867 namespace {
869 /// Collects references to symbols within the main file.
870 class ReferenceFinder : public index::IndexDataConsumer {
871 public:
872 struct Reference {
873 syntax::Token SpelledTok;
874 index::SymbolRoleSet Role;
875 const Decl *Container;
877 Range range(const SourceManager &SM) const {
878 return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));
882 ReferenceFinder(const ParsedAST &AST,
883 const llvm::ArrayRef<const NamedDecl *> Targets,
884 bool PerToken)
885 : PerToken(PerToken), AST(AST) {
886 for (const NamedDecl *ND : Targets)
887 TargetDecls.insert(ND->getCanonicalDecl());
890 std::vector<Reference> take() && {
891 llvm::sort(References, [](const Reference &L, const Reference &R) {
892 auto LTok = L.SpelledTok.location();
893 auto RTok = R.SpelledTok.location();
894 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
896 // We sometimes see duplicates when parts of the AST get traversed twice.
897 References.erase(std::unique(References.begin(), References.end(),
898 [](const Reference &L, const Reference &R) {
899 auto LTok = L.SpelledTok.location();
900 auto RTok = R.SpelledTok.location();
901 return std::tie(LTok, L.Role) ==
902 std::tie(RTok, R.Role);
904 References.end());
905 return std::move(References);
908 bool
909 handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
910 llvm::ArrayRef<index::SymbolRelation> Relations,
911 SourceLocation Loc,
912 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
913 if (!TargetDecls.contains(D->getCanonicalDecl()))
914 return true;
915 const SourceManager &SM = AST.getSourceManager();
916 if (!isInsideMainFile(Loc, SM))
917 return true;
918 const auto &TB = AST.getTokens();
920 llvm::SmallVector<SourceLocation, 1> Locs;
921 if (PerToken) {
922 // Check whether this is one of the few constructs where the reference
923 // can be split over several tokens.
924 if (auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
925 OME->getSelectorLocs(Locs);
926 } else if (auto *OMD =
927 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
928 OMD->getSelectorLocs(Locs);
930 // Sanity check: we expect the *first* token to match the reported loc.
931 // Otherwise, maybe it was e.g. some other kind of reference to a Decl.
932 if (!Locs.empty() && Locs.front() != Loc)
933 Locs.clear(); // First token doesn't match, assume our guess was wrong.
935 if (Locs.empty())
936 Locs.push_back(Loc);
938 SymbolCollector::Options CollectorOpts;
939 CollectorOpts.CollectMainFileSymbols = true;
940 for (SourceLocation L : Locs) {
941 L = SM.getFileLoc(L);
942 if (const auto *Tok = TB.spelledTokenContaining(L))
943 References.push_back(
944 {*Tok, Roles,
945 SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});
947 return true;
950 private:
951 bool PerToken; // If true, report 3 references for split ObjC selector names.
952 std::vector<Reference> References;
953 const ParsedAST &AST;
954 llvm::DenseSet<const Decl *> TargetDecls;
957 std::vector<ReferenceFinder::Reference>
958 findRefs(const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &AST,
959 bool PerToken) {
960 ReferenceFinder RefFinder(AST, TargetDecls, PerToken);
961 index::IndexingOptions IndexOpts;
962 IndexOpts.SystemSymbolFilter =
963 index::IndexingOptions::SystemSymbolFilterKind::All;
964 IndexOpts.IndexFunctionLocals = true;
965 IndexOpts.IndexParametersInDeclarations = true;
966 IndexOpts.IndexTemplateParameters = true;
967 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
968 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
969 return std::move(RefFinder).take();
972 const Stmt *getFunctionBody(DynTypedNode N) {
973 if (const auto *FD = N.get<FunctionDecl>())
974 return FD->getBody();
975 if (const auto *FD = N.get<BlockDecl>())
976 return FD->getBody();
977 if (const auto *FD = N.get<LambdaExpr>())
978 return FD->getBody();
979 if (const auto *FD = N.get<ObjCMethodDecl>())
980 return FD->getBody();
981 return nullptr;
984 const Stmt *getLoopBody(DynTypedNode N) {
985 if (const auto *LS = N.get<ForStmt>())
986 return LS->getBody();
987 if (const auto *LS = N.get<CXXForRangeStmt>())
988 return LS->getBody();
989 if (const auto *LS = N.get<WhileStmt>())
990 return LS->getBody();
991 if (const auto *LS = N.get<DoStmt>())
992 return LS->getBody();
993 return nullptr;
996 // AST traversal to highlight control flow statements under some root.
997 // Once we hit further control flow we prune the tree (or at least restrict
998 // what we highlight) so we capture e.g. breaks from the outer loop only.
999 class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {
1000 // Types of control-flow statements we might highlight.
1001 enum Target {
1002 Break = 1,
1003 Continue = 2,
1004 Return = 4,
1005 Case = 8,
1006 Throw = 16,
1007 Goto = 32,
1008 All = Break | Continue | Return | Case | Throw | Goto,
1010 int Ignore = 0; // bitmask of Target - what are we *not* highlighting?
1011 SourceRange Bounds; // Half-open, restricts reported targets.
1012 std::vector<SourceLocation> &Result;
1013 const SourceManager &SM;
1015 // Masks out targets for a traversal into D.
1016 // Traverses the subtree using Delegate() if any targets remain.
1017 template <typename Func>
1018 bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {
1019 auto RestoreIgnore = llvm::make_scope_exit(
1020 [OldIgnore(Ignore), this] { Ignore = OldIgnore; });
1021 if (getFunctionBody(D))
1022 Ignore = All;
1023 else if (getLoopBody(D))
1024 Ignore |= Continue | Break;
1025 else if (D.get<SwitchStmt>())
1026 Ignore |= Break | Case;
1027 // Prune tree if we're not looking for anything.
1028 return (Ignore == All) ? true : Delegate();
1031 void found(Target T, SourceLocation Loc) {
1032 if (T & Ignore)
1033 return;
1034 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1035 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1036 return;
1037 Result.push_back(Loc);
1040 public:
1041 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1042 const SourceManager &SM)
1043 : Bounds(Bounds), Result(Result), SM(SM) {}
1045 // When traversing function or loops, limit targets to those that still
1046 // refer to the original root.
1047 bool TraverseDecl(Decl *D) {
1048 return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1049 return RecursiveASTVisitor::TraverseDecl(D);
1052 bool TraverseStmt(Stmt *S) {
1053 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1054 return RecursiveASTVisitor::TraverseStmt(S);
1058 // Add leaves that we found and want.
1059 bool VisitReturnStmt(ReturnStmt *R) {
1060 found(Return, R->getReturnLoc());
1061 return true;
1063 bool VisitBreakStmt(BreakStmt *B) {
1064 found(Break, B->getBreakLoc());
1065 return true;
1067 bool VisitContinueStmt(ContinueStmt *C) {
1068 found(Continue, C->getContinueLoc());
1069 return true;
1071 bool VisitSwitchCase(SwitchCase *C) {
1072 found(Case, C->getKeywordLoc());
1073 return true;
1075 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1076 found(Throw, T->getThrowLoc());
1077 return true;
1079 bool VisitGotoStmt(GotoStmt *G) {
1080 // Goto is interesting if its target is outside the root.
1081 if (const auto *LD = G->getLabel()) {
1082 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1083 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1084 found(Goto, G->getGotoLoc());
1086 return true;
1090 // Given a location within a switch statement, return the half-open range that
1091 // covers the case it's contained in.
1092 // We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
1093 SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,
1094 const SourceManager &SM) {
1095 // Cases are not stored in order, sort them first.
1096 // (In fact they seem to be stored in reverse order, don't rely on this)
1097 std::vector<const SwitchCase *> Cases;
1098 for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1099 Case = Case->getNextSwitchCase())
1100 Cases.push_back(Case);
1101 llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {
1102 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1105 // Find the first case after the target location, the end of our range.
1106 auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {
1107 return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());
1109 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1110 : (*CaseAfter)->getKeywordLoc();
1112 // Our target can be before the first case - cases are optional!
1113 if (CaseAfter == Cases.begin())
1114 return SourceRange(Switch.getBeginLoc(), End);
1115 // The start of our range is usually the previous case, but...
1116 auto CaseBefore = std::prev(CaseAfter);
1117 // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
1118 while (CaseBefore != Cases.begin() &&
1119 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1120 --CaseBefore;
1121 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1124 // Returns the locations of control flow statements related to N. e.g.:
1125 // for => branches: break/continue/return/throw
1126 // break => controlling loop (forwhile/do), and its related control flow
1127 // return => all returns/throws from the same function
1128 // When an inner block is selected, we include branches bound to outer blocks
1129 // as these are exits from the inner block. e.g. return in a for loop.
1130 // FIXME: We don't analyze catch blocks, throw is treated the same as return.
1131 std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {
1132 const SourceManager &SM =
1133 N.getDeclContext().getParentASTContext().getSourceManager();
1134 std::vector<SourceLocation> Result;
1136 // First, check if we're at a node that can resolve to a root.
1137 enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;
1138 if (N.ASTNode.get<BreakStmt>()) {
1139 Cursor = Cur::Break;
1140 } else if (N.ASTNode.get<ContinueStmt>()) {
1141 Cursor = Cur::Continue;
1142 } else if (N.ASTNode.get<ReturnStmt>()) {
1143 Cursor = Cur::Return;
1144 } else if (N.ASTNode.get<CXXThrowExpr>()) {
1145 Cursor = Cur::Throw;
1146 } else if (N.ASTNode.get<SwitchCase>()) {
1147 Cursor = Cur::Case;
1148 } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1149 // We don't know what root to associate with, but highlight the goto/label.
1150 Result.push_back(GS->getGotoLoc());
1151 if (const auto *LD = GS->getLabel())
1152 Result.push_back(LD->getLocation());
1153 Cursor = Cur::None;
1154 } else {
1155 Cursor = Cur::None;
1158 const Stmt *Root = nullptr; // Loop or function body to traverse.
1159 SourceRange Bounds;
1160 // Look up the tree for a root (or just at this node if we didn't find a leaf)
1161 for (const auto *P = &N; P; P = P->Parent) {
1162 // return associates with enclosing function
1163 if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1164 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1165 Root = FunctionBody;
1167 break; // other leaves don't cross functions.
1169 // break/continue associate with enclosing loop.
1170 if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1171 if (Cursor == Cur::None || Cursor == Cur::Break ||
1172 Cursor == Cur::Continue) {
1173 Root = LoopBody;
1174 // Highlight the loop keyword itself.
1175 // FIXME: for do-while, this only covers the `do`..
1176 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1177 break;
1180 // For switches, users think of case statements as control flow blocks.
1181 // We highlight only occurrences surrounded by the same case.
1182 // We don't detect fallthrough (other than 'case X, case Y').
1183 if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1184 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1185 Result.push_back(SS->getSwitchLoc()); // Highlight the switch.
1186 Root = SS->getBody();
1187 // Limit to enclosing case, if there is one.
1188 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1189 break;
1192 // If we didn't start at some interesting node, we're done.
1193 if (Cursor == Cur::None)
1194 break;
1196 if (Root) {
1197 if (!Bounds.isValid())
1198 Bounds = Root->getSourceRange();
1199 FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));
1201 return Result;
1204 DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
1205 const SourceManager &SM) {
1206 DocumentHighlight DH;
1207 DH.range = Ref.range(SM);
1208 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1209 DH.kind = DocumentHighlightKind::Write;
1210 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1211 DH.kind = DocumentHighlightKind::Read;
1212 else
1213 DH.kind = DocumentHighlightKind::Text;
1214 return DH;
1217 std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1218 const syntax::TokenBuffer &TB) {
1219 Loc = TB.sourceManager().getFileLoc(Loc);
1220 if (const auto *Tok = TB.spelledTokenContaining(Loc)) {
1221 DocumentHighlight Result;
1222 Result.range = halfOpenToRange(
1223 TB.sourceManager(),
1224 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1225 return Result;
1227 return std::nullopt;
1230 } // namespace
1232 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
1233 Position Pos) {
1234 const SourceManager &SM = AST.getSourceManager();
1235 // FIXME: show references to macro within file?
1236 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1237 if (!CurLoc) {
1238 llvm::consumeError(CurLoc.takeError());
1239 return {};
1241 std::vector<DocumentHighlight> Result;
1242 auto TryTree = [&](SelectionTree ST) {
1243 if (const SelectionTree::Node *N = ST.commonAncestor()) {
1244 DeclRelationSet Relations =
1245 DeclRelation::TemplatePattern | DeclRelation::Alias;
1246 auto TargetDecls =
1247 targetDecl(N->ASTNode, Relations, AST.getHeuristicResolver());
1248 if (!TargetDecls.empty()) {
1249 // FIXME: we may get multiple DocumentHighlights with the same location
1250 // and different kinds, deduplicate them.
1251 for (const auto &Ref : findRefs(TargetDecls, AST, /*PerToken=*/true))
1252 Result.push_back(toHighlight(Ref, SM));
1253 return true;
1255 auto ControlFlow = relatedControlFlow(*N);
1256 if (!ControlFlow.empty()) {
1257 for (SourceLocation Loc : ControlFlow)
1258 if (auto Highlight = toHighlight(Loc, AST.getTokens()))
1259 Result.push_back(std::move(*Highlight));
1260 return true;
1263 return false;
1266 unsigned Offset =
1267 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1268 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
1269 Offset, TryTree);
1270 return Result;
1273 std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
1274 const SymbolIndex *Index) {
1275 // We rely on index to find the implementations in subclasses.
1276 // FIXME: Index can be stale, so we may loose some latest results from the
1277 // main file.
1278 if (!Index)
1279 return {};
1280 const SourceManager &SM = AST.getSourceManager();
1281 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1282 if (!CurLoc) {
1283 elog("Failed to convert position to source location: {0}",
1284 CurLoc.takeError());
1285 return {};
1287 DeclRelationSet Relations =
1288 DeclRelation::TemplatePattern | DeclRelation::Alias;
1289 llvm::DenseSet<SymbolID> IDs;
1290 RelationKind QueryKind = RelationKind::OverriddenBy;
1291 for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) {
1292 if (const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1293 if (CXXMD->isVirtual()) {
1294 IDs.insert(getSymbolID(ND));
1295 QueryKind = RelationKind::OverriddenBy;
1297 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1298 IDs.insert(getSymbolID(RD));
1299 QueryKind = RelationKind::BaseOf;
1302 return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath());
1305 namespace {
1306 // Recursively finds all the overridden methods of `CMD` in complete type
1307 // hierarchy.
1308 void getOverriddenMethods(const CXXMethodDecl *CMD,
1309 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1310 if (!CMD)
1311 return;
1312 for (const CXXMethodDecl *Base : CMD->overridden_methods()) {
1313 if (auto ID = getSymbolID(Base))
1314 OverriddenMethods.insert(ID);
1315 getOverriddenMethods(Base, OverriddenMethods);
1319 std::optional<std::string>
1320 stringifyContainerForMainFileRef(const Decl *Container) {
1321 // FIXME We might also want to display the signature here
1322 // When doing so, remember to also add the Signature to index results!
1323 if (auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1324 return printQualifiedName(*ND);
1325 return {};
1328 std::optional<ReferencesResult>
1329 maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
1330 URIForFile URIMainFile) {
1331 const auto &Includes = AST.getIncludeStructure().MainFileIncludes;
1332 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](const Inclusion &Inc) {
1333 return Inc.HashLine == Pos.line;
1335 if (IncludeOnLine == Includes.end())
1336 return std::nullopt;
1338 const SourceManager &SM = AST.getSourceManager();
1339 ReferencesResult Results;
1340 auto Converted = convertIncludes(AST);
1341 include_cleaner::walkUsed(
1342 AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
1343 &AST.getPragmaIncludes(), AST.getPreprocessor(),
1344 [&](const include_cleaner::SymbolReference &Ref,
1345 llvm::ArrayRef<include_cleaner::Header> Providers) {
1346 if (Ref.RT != include_cleaner::RefType::Explicit ||
1347 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1348 return;
1350 auto Loc = SM.getFileLoc(Ref.RefLocation);
1351 // File locations can be outside of the main file if macro is
1352 // expanded through an #include.
1353 while (SM.getFileID(Loc) != SM.getMainFileID())
1354 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1356 ReferencesResult::Reference Result;
1357 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1358 assert(Token && "references expected token here");
1359 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1360 sourceLocToPosition(SM, Token->endLocation())};
1361 Result.Loc.uri = URIMainFile;
1362 Results.References.push_back(std::move(Result));
1364 if (Results.References.empty())
1365 return std::nullopt;
1367 // Add the #include line to the references list.
1368 ReferencesResult::Reference Result;
1369 Result.Loc.range = rangeTillEOL(SM.getBufferData(SM.getMainFileID()),
1370 IncludeOnLine->HashOffset);
1371 Result.Loc.uri = URIMainFile;
1372 Results.References.push_back(std::move(Result));
1373 return Results;
1375 } // namespace
1377 ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
1378 const SymbolIndex *Index, bool AddContext) {
1379 ReferencesResult Results;
1380 const SourceManager &SM = AST.getSourceManager();
1381 auto MainFilePath = AST.tuPath();
1382 auto URIMainFile = URIForFile::canonicalize(MainFilePath, MainFilePath);
1383 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1384 if (!CurLoc) {
1385 llvm::consumeError(CurLoc.takeError());
1386 return {};
1389 const auto IncludeReferences =
1390 maybeFindIncludeReferences(AST, Pos, URIMainFile);
1391 if (IncludeReferences)
1392 return *IncludeReferences;
1394 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1396 const auto *IdentifierAtCursor =
1397 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1398 std::optional<DefinedMacro> Macro;
1399 if (IdentifierAtCursor)
1400 Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1401 if (Macro) {
1402 // Handle references to macro.
1403 if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
1404 // Collect macro references from main file.
1405 const auto &IDToRefs = AST.getMacros().MacroRefs;
1406 auto Refs = IDToRefs.find(MacroSID);
1407 if (Refs != IDToRefs.end()) {
1408 for (const auto &Ref : Refs->second) {
1409 ReferencesResult::Reference Result;
1410 Result.Loc.range = Ref.toRange(SM);
1411 Result.Loc.uri = URIMainFile;
1412 if (Ref.IsDefinition) {
1413 Result.Attributes |= ReferencesResult::Declaration;
1414 Result.Attributes |= ReferencesResult::Definition;
1416 Results.References.push_back(std::move(Result));
1419 IDsToQuery.insert(MacroSID);
1421 } else {
1422 // Handle references to Decls.
1424 DeclRelationSet Relations =
1425 DeclRelation::TemplatePattern | DeclRelation::Alias;
1426 std::vector<const NamedDecl *> Decls =
1427 getDeclAtPosition(AST, *CurLoc, Relations);
1428 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1429 for (const NamedDecl *D : Decls) {
1430 auto ID = getSymbolID(D);
1431 if (!ID)
1432 continue;
1433 TargetsInMainFile.push_back(D);
1434 // Not all symbols can be referenced from outside (e.g. function-locals).
1435 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1436 // we know this file isn't a header. The details might be tricky.
1437 if (D->getParentFunctionOrMethod())
1438 continue;
1439 IDsToQuery.insert(ID);
1442 RelationsRequest OverriddenBy;
1443 if (Index) {
1444 OverriddenBy.Predicate = RelationKind::OverriddenBy;
1445 for (const NamedDecl *ND : Decls) {
1446 // Special case: For virtual methods, report decl/def of overrides and
1447 // references to all overridden methods in complete type hierarchy.
1448 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1449 if (CMD->isVirtual()) {
1450 if (auto ID = getSymbolID(CMD))
1451 OverriddenBy.Subjects.insert(ID);
1452 getOverriddenMethods(CMD, OverriddenMethods);
1458 // We traverse the AST to find references in the main file.
1459 auto MainFileRefs = findRefs(TargetsInMainFile, AST, /*PerToken=*/false);
1460 // We may get multiple refs with the same location and different Roles, as
1461 // cross-reference is only interested in locations, we deduplicate them
1462 // by the location to avoid emitting duplicated locations.
1463 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1464 [](const ReferenceFinder::Reference &L,
1465 const ReferenceFinder::Reference &R) {
1466 return L.SpelledTok.location() ==
1467 R.SpelledTok.location();
1469 MainFileRefs.end());
1470 for (const auto &Ref : MainFileRefs) {
1471 ReferencesResult::Reference Result;
1472 Result.Loc.range = Ref.range(SM);
1473 Result.Loc.uri = URIMainFile;
1474 if (AddContext)
1475 Result.Loc.containerName =
1476 stringifyContainerForMainFileRef(Ref.Container);
1477 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Declaration))
1478 Result.Attributes |= ReferencesResult::Declaration;
1479 // clang-index doesn't report definitions as declarations, but they are.
1480 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Definition))
1481 Result.Attributes |=
1482 ReferencesResult::Definition | ReferencesResult::Declaration;
1483 Results.References.push_back(std::move(Result));
1485 // Add decl/def of overridding methods.
1486 if (Index && !OverriddenBy.Subjects.empty()) {
1487 LookupRequest ContainerLookup;
1488 // Different overrides will always be contained in different classes, so
1489 // we have a one-to-one mapping between SymbolID and index here, thus we
1490 // don't need to use std::vector as the map's value type.
1491 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1492 Index->relations(OverriddenBy, [&](const SymbolID &Subject,
1493 const Symbol &Object) {
1494 if (Limit && Results.References.size() >= Limit) {
1495 Results.HasMore = true;
1496 return;
1498 const auto LSPLocDecl =
1499 toLSPLocation(Object.CanonicalDeclaration, MainFilePath);
1500 const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath);
1501 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1502 ReferencesResult::Reference Result;
1503 Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
1504 Result.Attributes =
1505 ReferencesResult::Declaration | ReferencesResult::Override;
1506 RefIndexForContainer.insert({Object.ID, Results.References.size()});
1507 ContainerLookup.IDs.insert(Object.ID);
1508 Results.References.push_back(std::move(Result));
1510 if (LSPLocDef) {
1511 ReferencesResult::Reference Result;
1512 Result.Loc = {std::move(*LSPLocDef), std::nullopt};
1513 Result.Attributes = ReferencesResult::Declaration |
1514 ReferencesResult::Definition |
1515 ReferencesResult::Override;
1516 RefIndexForContainer.insert({Object.ID, Results.References.size()});
1517 ContainerLookup.IDs.insert(Object.ID);
1518 Results.References.push_back(std::move(Result));
1522 if (!ContainerLookup.IDs.empty() && AddContext)
1523 Index->lookup(ContainerLookup, [&](const Symbol &Container) {
1524 auto Ref = RefIndexForContainer.find(Container.ID);
1525 assert(Ref != RefIndexForContainer.end());
1526 Results.References[Ref->getSecond()].Loc.containerName =
1527 Container.Scope.str() + Container.Name.str();
1531 // Now query the index for references from other files.
1532 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool AllowAttributes,
1533 bool AllowMainFileSymbols) {
1534 if (IDs.empty() || !Index || Results.HasMore)
1535 return;
1536 RefsRequest Req;
1537 Req.IDs = std::move(IDs);
1538 if (Limit) {
1539 if (Limit < Results.References.size()) {
1540 // We've already filled our quota, still check the index to correctly
1541 // return the `HasMore` info.
1542 Req.Limit = 0;
1543 } else {
1544 // Query index only for the remaining size.
1545 Req.Limit = Limit - Results.References.size();
1548 LookupRequest ContainerLookup;
1549 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1550 Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
1551 auto LSPLoc = toLSPLocation(R.Location, MainFilePath);
1552 // Avoid indexed results for the main file - the AST is authoritative.
1553 if (!LSPLoc ||
1554 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1555 return;
1556 ReferencesResult::Reference Result;
1557 Result.Loc = {std::move(*LSPLoc), std::nullopt};
1558 if (AllowAttributes) {
1559 if ((R.Kind & RefKind::Declaration) == RefKind::Declaration)
1560 Result.Attributes |= ReferencesResult::Declaration;
1561 // FIXME: our index should definitely store def | decl separately!
1562 if ((R.Kind & RefKind::Definition) == RefKind::Definition)
1563 Result.Attributes |=
1564 ReferencesResult::Declaration | ReferencesResult::Definition;
1566 if (AddContext) {
1567 SymbolID Container = R.Container;
1568 ContainerLookup.IDs.insert(Container);
1569 RefIndicesForContainer[Container].push_back(Results.References.size());
1571 Results.References.push_back(std::move(Result));
1574 if (!ContainerLookup.IDs.empty() && AddContext)
1575 Index->lookup(ContainerLookup, [&](const Symbol &Container) {
1576 auto Ref = RefIndicesForContainer.find(Container.ID);
1577 assert(Ref != RefIndicesForContainer.end());
1578 auto ContainerName = Container.Scope.str() + Container.Name.str();
1579 for (auto I : Ref->getSecond()) {
1580 Results.References[I].Loc.containerName = ContainerName;
1584 QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,
1585 /*AllowMainFileSymbols=*/false);
1586 // For a virtual method: Occurrences of BaseMethod should be treated as refs
1587 // and not as decl/def. Allow symbols from main file since AST does not report
1588 // these.
1589 QueryIndex(std::move(OverriddenMethods), /*AllowAttributes=*/false,
1590 /*AllowMainFileSymbols=*/true);
1591 return Results;
1594 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
1595 const SourceManager &SM = AST.getSourceManager();
1596 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1597 if (!CurLoc) {
1598 llvm::consumeError(CurLoc.takeError());
1599 return {};
1601 auto MainFilePath = AST.tuPath();
1602 std::vector<SymbolDetails> Results;
1604 // We also want the targets of using-decls, so we include
1605 // DeclRelation::Underlying.
1606 DeclRelationSet Relations = DeclRelation::TemplatePattern |
1607 DeclRelation::Alias | DeclRelation::Underlying;
1608 for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1609 D = getPreferredDecl(D);
1611 SymbolDetails NewSymbol;
1612 std::string QName = printQualifiedName(*D);
1613 auto SplitQName = splitQualifiedName(QName);
1614 NewSymbol.containerName = std::string(SplitQName.first);
1615 NewSymbol.name = std::string(SplitQName.second);
1617 if (NewSymbol.containerName.empty()) {
1618 if (const auto *ParentND =
1619 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1620 NewSymbol.containerName = printQualifiedName(*ParentND);
1622 llvm::SmallString<32> USR;
1623 if (!index::generateUSRForDecl(D, USR)) {
1624 NewSymbol.USR = std::string(USR);
1625 NewSymbol.ID = SymbolID(NewSymbol.USR);
1627 if (const NamedDecl *Def = getDefinition(D))
1628 NewSymbol.definitionRange = makeLocation(
1629 AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
1630 NewSymbol.declarationRange =
1631 makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
1633 Results.push_back(std::move(NewSymbol));
1636 const auto *IdentifierAtCursor =
1637 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1638 if (!IdentifierAtCursor)
1639 return Results;
1641 if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1642 SymbolDetails NewMacro;
1643 NewMacro.name = std::string(M->Name);
1644 llvm::SmallString<32> USR;
1645 if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
1646 SM, USR)) {
1647 NewMacro.USR = std::string(USR);
1648 NewMacro.ID = SymbolID(NewMacro.USR);
1650 Results.push_back(std::move(NewMacro));
1653 return Results;
1656 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1657 OS << S.Name << ": " << S.PreferredDeclaration;
1658 if (S.Definition)
1659 OS << " def=" << *S.Definition;
1660 return OS;
1663 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1664 const ReferencesResult::Reference &R) {
1665 OS << R.Loc;
1666 if (R.Attributes & ReferencesResult::Declaration)
1667 OS << " [decl]";
1668 if (R.Attributes & ReferencesResult::Definition)
1669 OS << " [def]";
1670 if (R.Attributes & ReferencesResult::Override)
1671 OS << " [override]";
1672 return OS;
1675 template <typename HierarchyItem>
1676 static std::optional<HierarchyItem>
1677 declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1678 ASTContext &Ctx = ND.getASTContext();
1679 auto &SM = Ctx.getSourceManager();
1680 SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
1681 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1682 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1683 const auto DeclRange =
1684 toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});
1685 if (!DeclRange)
1686 return std::nullopt;
1687 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1688 if (!FE)
1689 return std::nullopt;
1690 auto FilePath = getCanonicalPath(*FE, SM.getFileManager());
1691 if (!FilePath)
1692 return std::nullopt; // Not useful without a uri.
1694 Position NameBegin = sourceLocToPosition(SM, NameLoc);
1695 Position NameEnd = sourceLocToPosition(
1696 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1698 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1699 // FIXME: This is not classifying constructors, destructors and operators
1700 // correctly.
1701 SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
1703 HierarchyItem HI;
1704 HI.name = printName(Ctx, ND);
1705 HI.kind = SK;
1706 HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),
1707 sourceLocToPosition(SM, DeclRange->getEnd())};
1708 HI.selectionRange = Range{NameBegin, NameEnd};
1709 if (!HI.range.contains(HI.selectionRange)) {
1710 // 'selectionRange' must be contained in 'range', so in cases where clang
1711 // reports unrelated ranges we need to reconcile somehow.
1712 HI.range = HI.selectionRange;
1715 HI.uri = URIForFile::canonicalize(*FilePath, TUPath);
1717 return HI;
1720 static std::optional<TypeHierarchyItem>
1721 declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1722 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);
1723 if (Result) {
1724 Result->deprecated = ND.isDeprecated();
1725 // Compute the SymbolID and store it in the 'data' field.
1726 // This allows typeHierarchy/resolve to be used to
1727 // resolve children of items returned in a previous request
1728 // for parents.
1729 Result->data.symbolID = getSymbolID(&ND);
1731 return Result;
1734 static std::optional<CallHierarchyItem>
1735 declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1736 auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);
1737 if (!Result)
1738 return Result;
1739 if (ND.isDeprecated())
1740 Result->tags.push_back(SymbolTag::Deprecated);
1741 if (auto ID = getSymbolID(&ND))
1742 Result->data = ID.str();
1743 return Result;
1746 template <typename HierarchyItem>
1747 static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
1748 PathRef TUPath) {
1749 auto Loc = symbolToLocation(S, TUPath);
1750 if (!Loc) {
1751 elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1752 return std::nullopt;
1754 HierarchyItem HI;
1755 HI.name = std::string(S.Name);
1756 HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1757 HI.selectionRange = Loc->range;
1758 // FIXME: Populate 'range' correctly
1759 // (https://github.com/clangd/clangd/issues/59).
1760 HI.range = HI.selectionRange;
1761 HI.uri = Loc->uri;
1763 return HI;
1766 static std::optional<TypeHierarchyItem>
1767 symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath) {
1768 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1769 if (Result) {
1770 Result->deprecated = (S.Flags & Symbol::Deprecated);
1771 Result->data.symbolID = S.ID;
1773 return Result;
1776 static std::optional<CallHierarchyItem>
1777 symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath) {
1778 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1779 if (!Result)
1780 return Result;
1781 Result->data = S.ID.str();
1782 if (S.Flags & Symbol::Deprecated)
1783 Result->tags.push_back(SymbolTag::Deprecated);
1784 return Result;
1787 static void fillSubTypes(const SymbolID &ID,
1788 std::vector<TypeHierarchyItem> &SubTypes,
1789 const SymbolIndex *Index, int Levels, PathRef TUPath) {
1790 RelationsRequest Req;
1791 Req.Subjects.insert(ID);
1792 Req.Predicate = RelationKind::BaseOf;
1793 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
1794 if (std::optional<TypeHierarchyItem> ChildSym =
1795 symbolToTypeHierarchyItem(Object, TUPath)) {
1796 if (Levels > 1) {
1797 ChildSym->children.emplace();
1798 fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
1800 SubTypes.emplace_back(std::move(*ChildSym));
1805 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
1807 // Extracts parents from AST and populates the type hierarchy item.
1808 static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
1809 TypeHierarchyItem &Item,
1810 RecursionProtectionSet &RPSet) {
1811 Item.parents.emplace();
1812 Item.data.parents.emplace();
1813 // typeParents() will replace dependent template specializations
1814 // with their class template, so to avoid infinite recursion for
1815 // certain types of hierarchies, keep the templates encountered
1816 // along the parent chain in a set, and stop the recursion if one
1817 // starts to repeat.
1818 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
1819 if (Pattern) {
1820 if (!RPSet.insert(Pattern).second) {
1821 return;
1825 for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
1826 if (std::optional<TypeHierarchyItem> ParentSym =
1827 declToTypeHierarchyItem(*ParentDecl, TUPath)) {
1828 fillSuperTypes(*ParentDecl, TUPath, *ParentSym, RPSet);
1829 Item.data.parents->emplace_back(ParentSym->data);
1830 Item.parents->emplace_back(std::move(*ParentSym));
1834 if (Pattern) {
1835 RPSet.erase(Pattern);
1839 std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,
1840 Position Pos) {
1841 auto RecordFromNode = [&AST](const SelectionTree::Node *N) {
1842 std::vector<const CXXRecordDecl *> Records;
1843 if (!N)
1844 return Records;
1846 // Note: explicitReferenceTargets() will search for both template
1847 // instantiations and template patterns, and prefer the former if available
1848 // (generally, one will be available for non-dependent specializations of a
1849 // class template).
1850 auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying,
1851 AST.getHeuristicResolver());
1852 for (const NamedDecl *D : Decls) {
1854 if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1855 // If this is a variable, use the type of the variable.
1856 if (const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1857 Records.push_back(RD);
1858 continue;
1861 if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
1862 // If this is a method, use the type of the class.
1863 Records.push_back(Method->getParent());
1864 continue;
1867 // We don't handle FieldDecl because it's not clear what behaviour
1868 // the user would expect: the enclosing class type (as with a
1869 // method), or the field's type (as with a variable).
1871 if (auto *RD = dyn_cast<CXXRecordDecl>(D))
1872 Records.push_back(RD);
1874 return Records;
1877 const SourceManager &SM = AST.getSourceManager();
1878 std::vector<const CXXRecordDecl *> Result;
1879 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1880 if (!Offset) {
1881 llvm::consumeError(Offset.takeError());
1882 return Result;
1884 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
1885 *Offset, [&](SelectionTree ST) {
1886 Result = RecordFromNode(ST.commonAncestor());
1887 return !Result.empty();
1889 return Result;
1892 // Return the type most associated with an AST node.
1893 // This isn't precisely defined: we want "go to type" to do something useful.
1894 static QualType typeForNode(const SelectionTree::Node *N) {
1895 // If we're looking at a namespace qualifier, walk up to what it's qualifying.
1896 // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
1897 while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
1898 N = N->Parent;
1899 if (!N)
1900 return QualType();
1902 // If we're pointing at a type => return it.
1903 if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {
1904 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1905 if (auto Deduced = getDeducedType(
1906 N->getDeclContext().getParentASTContext(), TL->getBeginLoc()))
1907 return *Deduced;
1908 // Exception: an alias => underlying type.
1909 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1910 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1911 return TL->getType();
1914 // Constructor initializers => the type of thing being initialized.
1915 if (const auto *CCI = N->ASTNode.get<CXXCtorInitializer>()) {
1916 if (const FieldDecl *FD = CCI->getAnyMember())
1917 return FD->getType();
1918 if (const Type *Base = CCI->getBaseClass())
1919 return QualType(Base, 0);
1922 // Base specifier => the base type.
1923 if (const auto *CBS = N->ASTNode.get<CXXBaseSpecifier>())
1924 return CBS->getType();
1926 if (const Decl *D = N->ASTNode.get<Decl>()) {
1927 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1928 QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
1929 // Declaration of a type => that type.
1930 QualType VisitTypeDecl(const TypeDecl *D) {
1931 return QualType(D->getTypeForDecl(), 0);
1933 // Exception: alias declaration => the underlying type, not the alias.
1934 QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
1935 return D->getUnderlyingType();
1937 // Look inside templates.
1938 QualType VisitTemplateDecl(const TemplateDecl *D) {
1939 return Visit(D->getTemplatedDecl());
1941 } V;
1942 return V.Visit(D);
1945 if (const Stmt *S = N->ASTNode.get<Stmt>()) {
1946 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1947 // Null-safe version of visit simplifies recursive calls below.
1948 QualType type(const Stmt *S) { return S ? Visit(S) : QualType(); }
1950 // In general, expressions => type of expression.
1951 QualType VisitExpr(const Expr *S) {
1952 return S->IgnoreImplicitAsWritten()->getType();
1954 QualType VisitMemberExpr(const MemberExpr *S) {
1955 // The `foo` in `s.foo()` pretends not to have a real type!
1956 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
1957 return Expr::findBoundMemberType(S);
1958 return VisitExpr(S);
1960 // Exceptions for void expressions that operate on a type in some way.
1961 QualType VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
1962 return S->getDestroyedType();
1964 QualType VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
1965 return S->getDestroyedType();
1967 QualType VisitCXXThrowExpr(const CXXThrowExpr *S) {
1968 return S->getSubExpr()->getType();
1970 QualType VisitCoyieldExpr(const CoyieldExpr *S) {
1971 return type(S->getOperand());
1973 // Treat a designated initializer like a reference to the field.
1974 QualType VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
1975 // In .foo.bar we want to jump to bar's type, so find *last* field.
1976 for (auto &D : llvm::reverse(S->designators()))
1977 if (D.isFieldDesignator())
1978 if (const auto *FD = D.getFieldDecl())
1979 return FD->getType();
1980 return QualType();
1983 // Control flow statements that operate on data: use the data type.
1984 QualType VisitSwitchStmt(const SwitchStmt *S) {
1985 return type(S->getCond());
1987 QualType VisitWhileStmt(const WhileStmt *S) { return type(S->getCond()); }
1988 QualType VisitDoStmt(const DoStmt *S) { return type(S->getCond()); }
1989 QualType VisitIfStmt(const IfStmt *S) { return type(S->getCond()); }
1990 QualType VisitCaseStmt(const CaseStmt *S) { return type(S->getLHS()); }
1991 QualType VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1992 return S->getLoopVariable()->getType();
1994 QualType VisitReturnStmt(const ReturnStmt *S) {
1995 return type(S->getRetValue());
1997 QualType VisitCoreturnStmt(const CoreturnStmt *S) {
1998 return type(S->getOperand());
2000 QualType VisitCXXCatchStmt(const CXXCatchStmt *S) {
2001 return S->getCaughtType();
2003 QualType VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {
2004 return type(S->getThrowExpr());
2006 QualType VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {
2007 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2008 : QualType();
2010 } V;
2011 return V.Visit(S);
2014 return QualType();
2017 // Given a type targeted by the cursor, return one or more types that are more interesting
2018 // to target.
2019 static void unwrapFindType(
2020 QualType T, const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2021 if (T.isNull())
2022 return;
2024 // If there's a specific type alias, point at that rather than unwrapping.
2025 if (const auto* TDT = T->getAs<TypedefType>())
2026 return Out.push_back(QualType(TDT, 0));
2028 // Pointers etc => pointee type.
2029 if (const auto *PT = T->getAs<PointerType>())
2030 return unwrapFindType(PT->getPointeeType(), H, Out);
2031 if (const auto *RT = T->getAs<ReferenceType>())
2032 return unwrapFindType(RT->getPointeeType(), H, Out);
2033 if (const auto *AT = T->getAsArrayTypeUnsafe())
2034 return unwrapFindType(AT->getElementType(), H, Out);
2036 // Function type => return type.
2037 if (auto *FT = T->getAs<FunctionType>())
2038 return unwrapFindType(FT->getReturnType(), H, Out);
2039 if (auto *CRD = T->getAsCXXRecordDecl()) {
2040 if (CRD->isLambda())
2041 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2042 Out);
2043 // FIXME: more cases we'd prefer the return type of the call operator?
2044 // std::function etc?
2047 // For smart pointer types, add the underlying type
2048 if (H)
2049 if (const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) {
2050 unwrapFindType(QualType(PointeeType, 0), H, Out);
2051 return Out.push_back(T);
2054 return Out.push_back(T);
2057 // Convenience overload, to allow calling this without the out-parameter
2058 static llvm::SmallVector<QualType> unwrapFindType(
2059 QualType T, const HeuristicResolver* H) {
2060 llvm::SmallVector<QualType> Result;
2061 unwrapFindType(T, H, Result);
2062 return Result;
2065 std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos,
2066 const SymbolIndex *Index) {
2067 const SourceManager &SM = AST.getSourceManager();
2068 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
2069 std::vector<LocatedSymbol> Result;
2070 if (!Offset) {
2071 elog("failed to convert position {0} for findTypes: {1}", Pos,
2072 Offset.takeError());
2073 return Result;
2075 // The general scheme is: position -> AST node -> type -> declaration.
2076 auto SymbolsFromNode =
2077 [&](const SelectionTree::Node *N) -> std::vector<LocatedSymbol> {
2078 std::vector<LocatedSymbol> LocatedSymbols;
2080 // NOTE: unwrapFindType might return duplicates for something like
2081 // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
2082 // information about the type you may have not known before
2083 // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
2084 for (const QualType& Type : unwrapFindType(typeForNode(N), AST.getHeuristicResolver()))
2085 llvm::copy(locateSymbolForType(AST, Type, Index),
2086 std::back_inserter(LocatedSymbols));
2088 return LocatedSymbols;
2090 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
2091 *Offset, [&](SelectionTree ST) {
2092 Result = SymbolsFromNode(ST.commonAncestor());
2093 return !Result.empty();
2095 return Result;
2098 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
2099 std::vector<const CXXRecordDecl *> Result;
2101 // If this is an invalid instantiation, instantiation of the bases
2102 // may not have succeeded, so fall back to the template pattern.
2103 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2104 if (CTSD->isInvalidDecl())
2105 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2108 // Can't query bases without a definition.
2109 if (!CXXRD->hasDefinition())
2110 return Result;
2112 for (auto Base : CXXRD->bases()) {
2113 const CXXRecordDecl *ParentDecl = nullptr;
2115 const Type *Type = Base.getType().getTypePtr();
2116 if (const RecordType *RT = Type->getAs<RecordType>()) {
2117 ParentDecl = RT->getAsCXXRecordDecl();
2120 if (!ParentDecl) {
2121 // Handle a dependent base such as "Base<T>" by using the primary
2122 // template.
2123 if (const TemplateSpecializationType *TS =
2124 Type->getAs<TemplateSpecializationType>()) {
2125 TemplateName TN = TS->getTemplateName();
2126 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2127 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2132 if (ParentDecl)
2133 Result.push_back(ParentDecl);
2136 return Result;
2139 std::vector<TypeHierarchyItem>
2140 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
2141 TypeHierarchyDirection Direction, const SymbolIndex *Index,
2142 PathRef TUPath) {
2143 std::vector<TypeHierarchyItem> Results;
2144 for (const auto *CXXRD : findRecordTypeAt(AST, Pos)) {
2146 bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2147 Direction == TypeHierarchyDirection::Both;
2149 // If we're looking for children, we're doing the lookup in the index.
2150 // The index does not store relationships between implicit
2151 // specializations, so if we have one, use the template pattern instead.
2152 // Note that this needs to be done before the declToTypeHierarchyItem(),
2153 // otherwise the type hierarchy item would misleadingly contain the
2154 // specialization parameters, while the children would involve classes
2155 // that derive from other specializations of the template.
2156 if (WantChildren) {
2157 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2158 CXXRD = CTSD->getTemplateInstantiationPattern();
2161 std::optional<TypeHierarchyItem> Result =
2162 declToTypeHierarchyItem(*CXXRD, AST.tuPath());
2163 if (!Result)
2164 continue;
2166 RecursionProtectionSet RPSet;
2167 fillSuperTypes(*CXXRD, AST.tuPath(), *Result, RPSet);
2169 if (WantChildren && ResolveLevels > 0) {
2170 Result->children.emplace();
2172 if (Index) {
2173 if (auto ID = getSymbolID(CXXRD))
2174 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2177 Results.emplace_back(std::move(*Result));
2180 return Results;
2183 std::optional<std::vector<TypeHierarchyItem>>
2184 superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {
2185 std::vector<TypeHierarchyItem> Results;
2186 if (!Item.data.parents)
2187 return std::nullopt;
2188 if (Item.data.parents->empty())
2189 return Results;
2190 LookupRequest Req;
2191 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2192 for (const auto &Parent : *Item.data.parents) {
2193 Req.IDs.insert(Parent.symbolID);
2194 IDToData[Parent.symbolID] = &Parent;
2196 Index->lookup(Req, [&Item, &Results, &IDToData](const Symbol &S) {
2197 if (auto THI = symbolToTypeHierarchyItem(S, Item.uri.file())) {
2198 THI->data = *IDToData.lookup(S.ID);
2199 Results.emplace_back(std::move(*THI));
2202 return Results;
2205 std::vector<TypeHierarchyItem> subTypes(const TypeHierarchyItem &Item,
2206 const SymbolIndex *Index) {
2207 std::vector<TypeHierarchyItem> Results;
2208 fillSubTypes(Item.data.symbolID, Results, Index, 1, Item.uri.file());
2209 for (auto &ChildSym : Results)
2210 ChildSym.data.parents = {Item.data};
2211 return Results;
2214 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
2215 TypeHierarchyDirection Direction,
2216 const SymbolIndex *Index) {
2217 // We only support typeHierarchy/resolve for children, because for parents
2218 // we ignore ResolveLevels and return all levels of parents eagerly.
2219 if (!Index || Direction == TypeHierarchyDirection::Parents ||
2220 ResolveLevels == 0)
2221 return;
2223 Item.children.emplace();
2224 fillSubTypes(Item.data.symbolID, *Item.children, Index, ResolveLevels,
2225 Item.uri.file());
2228 std::vector<CallHierarchyItem>
2229 prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath) {
2230 std::vector<CallHierarchyItem> Result;
2231 const auto &SM = AST.getSourceManager();
2232 auto Loc = sourceLocationInMainFile(SM, Pos);
2233 if (!Loc) {
2234 elog("prepareCallHierarchy failed to convert position to source location: "
2235 "{0}",
2236 Loc.takeError());
2237 return Result;
2239 for (const NamedDecl *Decl : getDeclAtPosition(AST, *Loc, {})) {
2240 if (!(isa<DeclContext>(Decl) &&
2241 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2242 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2243 !(Decl->getKind() == Decl::Kind::Var &&
2244 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2245 Decl->getKind() != Decl::Kind::Field)
2246 continue;
2247 if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath()))
2248 Result.emplace_back(std::move(*CHI));
2250 return Result;
2253 std::vector<CallHierarchyIncomingCall>
2254 incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
2255 std::vector<CallHierarchyIncomingCall> Results;
2256 if (!Index || Item.data.empty())
2257 return Results;
2258 auto ID = SymbolID::fromStr(Item.data);
2259 if (!ID) {
2260 elog("incomingCalls failed to find symbol: {0}", ID.takeError());
2261 return Results;
2263 // In this function, we find incoming calls based on the index only.
2264 // In principle, the AST could have more up-to-date information about
2265 // occurrences within the current file. However, going from a SymbolID
2266 // to an AST node isn't cheap, particularly when the declaration isn't
2267 // in the main file.
2268 // FIXME: Consider also using AST information when feasible.
2269 RefsRequest Request;
2270 Request.IDs.insert(*ID);
2271 Request.WantContainer = true;
2272 // We could restrict more specifically to calls by introducing a new RefKind,
2273 // but non-call references (such as address-of-function) can still be
2274 // interesting as they can indicate indirect calls.
2275 Request.Filter = RefKind::Reference;
2276 // Initially store the ranges in a map keyed by SymbolID of the caller.
2277 // This allows us to group different calls with the same caller
2278 // into the same CallHierarchyIncomingCall.
2279 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2280 // We can populate the ranges based on a refs request only. As we do so, we
2281 // also accumulate the container IDs into a lookup request.
2282 LookupRequest ContainerLookup;
2283 Index->refs(Request, [&](const Ref &R) {
2284 auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
2285 if (!Loc) {
2286 elog("incomingCalls failed to convert location: {0}", Loc.takeError());
2287 return;
2289 CallsIn[R.Container].push_back(*Loc);
2291 ContainerLookup.IDs.insert(R.Container);
2293 // Perform the lookup request and combine its results with CallsIn to
2294 // get complete CallHierarchyIncomingCall objects.
2295 Index->lookup(ContainerLookup, [&](const Symbol &Caller) {
2296 auto It = CallsIn.find(Caller.ID);
2297 assert(It != CallsIn.end());
2298 if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file())) {
2299 std::vector<Range> FromRanges;
2300 for (const Location &L : It->second) {
2301 if (L.uri != CHI->uri) {
2302 // Call location not in same file as caller.
2303 // This can happen in some edge cases. There's not much we can do,
2304 // since the protocol only allows returning ranges interpreted as
2305 // being in the caller's file.
2306 continue;
2308 FromRanges.push_back(L.range);
2310 Results.push_back(
2311 CallHierarchyIncomingCall{std::move(*CHI), std::move(FromRanges)});
2314 // Sort results by name of container.
2315 llvm::sort(Results, [](const CallHierarchyIncomingCall &A,
2316 const CallHierarchyIncomingCall &B) {
2317 return A.from.name < B.from.name;
2319 return Results;
2322 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
2323 const FunctionDecl *FD) {
2324 if (!FD->hasBody())
2325 return {};
2326 llvm::DenseSet<const Decl *> DeclRefs;
2327 findExplicitReferences(
2329 [&](ReferenceLoc Ref) {
2330 for (const Decl *D : Ref.Targets) {
2331 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2332 !Ref.IsDecl)
2333 DeclRefs.insert(D);
2336 AST.getHeuristicResolver());
2337 return DeclRefs;
2340 } // namespace clangd
2341 } // namespace clang