1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "FindSymbols.h"
11 #include "FindTarget.h"
13 #include "HeuristicResolver.h"
14 #include "IncludeCleaner.h"
15 #include "ParsedAST.h"
18 #include "Selection.h"
19 #include "SourceCode.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"
77 // Returns the single definition of the entity declared by D, if visible.
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
) {
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())
98 // Look for the method definition inside the implementation decl.
99 auto *DeclCtx
= cast
<Decl
>(MD
->getDeclContext());
100 if (DeclCtx
->isInvalidDecl())
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
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
126 std::optional
<Location
> toLSPLocation(const SymbolLocation
&Loc
,
127 llvm::StringRef TUPath
) {
130 auto Uri
= URI::parse(Loc
.FileURI
);
132 elog("Could not parse URI {0}: {1}", Loc
.FileURI
, Uri
.takeError());
135 auto U
= URIForFile::fromURI(*Uri
, TUPath
);
137 elog("Could not resolve URI {0}: {1}", Loc
.FileURI
, U
.takeError());
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();
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
);
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()) {
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
)
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
);
203 std::vector
<const NamedDecl
*>
204 getDeclAtPosition(ParsedAST
&AST
, SourceLocation Pos
, DeclRelationSet Relations
,
205 ASTNodeKind
*NodeKind
= nullptr) {
206 std::vector
<const NamedDecl
*> Result
;
208 getDeclAtPositionWithRelations(AST
, Pos
, Relations
, NodeKind
))
209 Result
.push_back(Entry
.first
);
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
));
221 auto FilePath
= getCanonicalPath(*F
, SM
.getFileManager());
223 log("failed to get path!");
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
)));
236 // Treat #included files as symbols, to enable go-to-definition on them.
237 std::optional
<LocatedSymbol
> locateFileReferent(const Position
&Pos
,
239 llvm::StringRef MainFilePath
) {
240 for (auto &Inc
: AST
.getIncludeStructure().MainFileIncludes
) {
241 if (!Inc
.Resolved
.empty() && Inc
.HashLine
== Pos
.line
) {
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.
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())) {
261 makeLocation(AST
.getASTContext(), M
->NameLoc
, MainFilePath
)) {
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());
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
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())
297 if (const auto *PD
= dyn_cast
<ObjCProtocolDecl
>(D
))
298 if (const auto *DefinitionID
= PD
->getDefinition())
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
)
310 static constexpr trace::Metric
FindImplementorsMetric(
311 "find_implementors", trace::Metric::Counter
, "case");
313 case RelationKind::BaseOf
:
314 FindImplementorsMetric
.record(1, "find-base");
316 case RelationKind::OverriddenBy
:
317 FindImplementorsMetric
.record(1, "find-override");
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
) {
327 indexToLSPLocation(Object
.CanonicalDeclaration
, MainFilePath
);
329 elog("Find overrides: {0}", DeclLoc
.takeError());
332 Results
.emplace_back();
333 Results
.back().Name
= Object
.Name
.str();
334 Results
.back().PreferredDeclaration
= *DeclLoc
;
335 auto DefLoc
= indexToLSPLocation(Object
.Definition
, MainFilePath
);
337 elog("Failed to convert location: {0}", DefLoc
.takeError());
340 Results
.back().Definition
= *DefLoc
;
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())
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
),
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
),
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
);
406 makeLocation(AST
.getASTContext(), nameLocation(*D
, SM
), MainFilePath
);
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
;
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
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())
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()
457 D
->getBeginLoc(), D
->getEndLoc()))
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());
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");
486 LocateASTReferentMetric
.record(1, "regular");
487 // Otherwise the target declaration is the right one.
490 enhanceLocatedSymbolsFromIndex(Result
, Index
, MainFilePath
);
492 auto Overrides
= findImplementors(VirtualMethods
, RelationKind::OverriddenBy
,
493 Index
, MainFilePath
);
494 Result
.insert(Result
.end(), Overrides
.begin(), Overrides
.end());
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());
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
);
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
);
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())
547 return Buf
.substr(0, D
.second
);
550 bool isDependentName(ASTNodeKind NodeKind
) {
551 return NodeKind
.isSame(ASTNodeKind::getFromNodeKind
<OverloadExpr
>()) ||
553 ASTNodeKind::getFromNodeKind
<CXXDependentScopeMemberExpr
>()) ||
555 ASTNodeKind::getFromNodeKind
<DependentScopeDeclRefExpr
>());
560 std::vector
<LocatedSymbol
> locateSymbolTextually(const SpelledWord
&Word
,
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
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
)
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()))
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.
585 visibleNamespaces(sourcePrefix(Word
.Location
, SM
), AST
.getLangOpts());
586 // FIXME: For extra strictness, consider AnyScope=false.
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.
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
)
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
)
609 indexToLSPLocation(Sym
.CanonicalDeclaration
, MainFilePath
);
611 log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc
.takeError());
614 LocatedSymbol Located
;
615 Located
.PreferredDeclaration
= *MaybeDeclLoc
;
616 Located
.Name
= (Sym
.Name
+ Sym
.TemplateSpecializationArgs
).str();
618 if (Sym
.Definition
) {
619 auto MaybeDefLoc
= indexToLSPLocation(Sym
.Definition
, MainFilePath
);
621 log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc
.takeError());
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?
636 SymbolQualitySignals Quality
;
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
)});
651 vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
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
));
664 vlog("No heuristic index definition for {0}", Word
.Text
);
666 log("Found definition heuristically in index for {0}", Word
.Text
);
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
)
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()))
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
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
))
720 // No point guessing the same location we started with.
721 if (Tok
.location() == Word
.Location
)
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
)))
731 // We already verified this token is an improvement.
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()))
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
)))
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
));
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
);
771 elog("locateSymbolAt failed to convert position to source location: {0}",
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
785 return {*std::move(Macro
)};
787 TouchedIdentifier
= &Tok
;
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
794 if (auto Deduced
= getDeducedType(AST
.getASTContext(), Tok
.location())) {
795 auto LocSym
= locateSymbolForType(AST
, *Deduced
, Index
);
802 ASTNodeKind NodeKind
;
803 auto ASTResults
= locateASTReferent(*CurLoc
, TouchedIdentifier
, AST
,
804 MainFilePath
, Index
, NodeKind
);
805 if (!ASTResults
.empty())
808 // If the cursor can't be resolved directly, try fallback strategies.
810 SpelledWord::touching(*CurLoc
, AST
.getTokens(), AST
.getLangOpts());
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}",
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
));
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
;
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())
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.
856 syntax::FileRange(SM
, FileTok
->location(), Inc
.Written
.length())
860 DocumentLink({halfOpenToRange(SM
, FileRange
),
861 URIForFile::canonicalize(Inc
.Resolved
, AST
.tuPath())}));
869 /// Collects references to symbols within the main file.
870 class ReferenceFinder
: public index::IndexDataConsumer
{
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
,
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
);
905 return std::move(References
);
909 handleDeclOccurrence(const Decl
*D
, index::SymbolRoleSet Roles
,
910 llvm::ArrayRef
<index::SymbolRelation
> Relations
,
912 index::IndexDataConsumer::ASTNodeInfo ASTNode
) override
{
913 if (!TargetDecls
.contains(D
->getCanonicalDecl()))
915 const SourceManager
&SM
= AST
.getSourceManager();
916 if (!isInsideMainFile(Loc
, SM
))
918 const auto &TB
= AST
.getTokens();
920 llvm::SmallVector
<SourceLocation
, 1> Locs
;
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.
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(
945 SymbolCollector::getRefContainer(ASTNode
.Parent
, CollectorOpts
)});
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
,
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();
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();
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.
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
))
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
) {
1034 if (SM
.isBeforeInTranslationUnit(Loc
, Bounds
.getBegin()) ||
1035 SM
.isBeforeInTranslationUnit(Bounds
.getEnd(), Loc
))
1037 Result
.push_back(Loc
);
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());
1063 bool VisitBreakStmt(BreakStmt
*B
) {
1064 found(Break
, B
->getBreakLoc());
1067 bool VisitContinueStmt(ContinueStmt
*C
) {
1068 found(Continue
, C
->getContinueLoc());
1071 bool VisitSwitchCase(SwitchCase
*C
) {
1072 found(Case
, C
->getKeywordLoc());
1075 bool VisitCXXThrowExpr(CXXThrowExpr
*T
) {
1076 found(Throw
, T
->getThrowLoc());
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());
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
)
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
>()) {
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());
1158 const Stmt
*Root
= nullptr; // Loop or function body to traverse.
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
) {
1174 // Highlight the loop keyword itself.
1175 // FIXME: for do-while, this only covers the `do`..
1176 Result
.push_back(P
->ASTNode
.getSourceRange().getBegin());
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
);
1192 // If we didn't start at some interesting node, we're done.
1193 if (Cursor
== Cur::None
)
1197 if (!Bounds
.isValid())
1198 Bounds
= Root
->getSourceRange();
1199 FindControlFlow(Bounds
, Result
, SM
).TraverseStmt(const_cast<Stmt
*>(Root
));
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
;
1213 DH
.kind
= DocumentHighlightKind::Text
;
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(
1224 CharSourceRange::getCharRange(Tok
->location(), Tok
->endLocation()));
1227 return std::nullopt
;
1232 std::vector
<DocumentHighlight
> findDocumentHighlights(ParsedAST
&AST
,
1234 const SourceManager
&SM
= AST
.getSourceManager();
1235 // FIXME: show references to macro within file?
1236 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1238 llvm::consumeError(CurLoc
.takeError());
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
;
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
));
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
));
1267 AST
.getSourceManager().getDecomposedSpellingLoc(*CurLoc
).second
;
1268 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), Offset
,
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
1280 const SourceManager
&SM
= AST
.getSourceManager();
1281 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1283 elog("Failed to convert position to source location: {0}",
1284 CurLoc
.takeError());
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());
1306 // Recursively finds all the overridden methods of `CMD` in complete type
1308 void getOverriddenMethods(const CXXMethodDecl
*CMD
,
1309 llvm::DenseSet
<SymbolID
> &OverriddenMethods
) {
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
);
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
))
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
));
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
);
1385 llvm::consumeError(CurLoc
.takeError());
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());
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
);
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
);
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())
1439 IDsToQuery
.insert(ID
);
1442 RelationsRequest OverriddenBy
;
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
;
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;
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
};
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
));
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
)
1537 Req
.IDs
= std::move(IDs
);
1539 if (Limit
< Results
.References
.size()) {
1540 // We've already filled our quota, still check the index to correctly
1541 // return the `HasMore` info.
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.
1554 (!AllowMainFileSymbols
&& LSPLoc
->uri
.file() == MainFilePath
))
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
;
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
1589 QueryIndex(std::move(OverriddenMethods
), /*AllowAttributes=*/false,
1590 /*AllowMainFileSymbols=*/true);
1594 std::vector
<SymbolDetails
> getSymbolInfo(ParsedAST
&AST
, Position Pos
) {
1595 const SourceManager
&SM
= AST
.getSourceManager();
1596 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1598 llvm::consumeError(CurLoc
.takeError());
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
)
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(),
1647 NewMacro
.USR
= std::string(USR
);
1648 NewMacro
.ID
= SymbolID(NewMacro
.USR
);
1650 Results
.push_back(std::move(NewMacro
));
1656 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
, const LocatedSymbol
&S
) {
1657 OS
<< S
.Name
<< ": " << S
.PreferredDeclaration
;
1659 OS
<< " def=" << *S
.Definition
;
1663 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
,
1664 const ReferencesResult::Reference
&R
) {
1666 if (R
.Attributes
& ReferencesResult::Declaration
)
1668 if (R
.Attributes
& ReferencesResult::Definition
)
1670 if (R
.Attributes
& ReferencesResult::Override
)
1671 OS
<< " [override]";
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
});
1686 return std::nullopt
;
1687 const auto FE
= SM
.getFileEntryRefForID(SM
.getFileID(NameLoc
));
1689 return std::nullopt
;
1690 auto FilePath
= getCanonicalPath(*FE
, SM
.getFileManager());
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
1701 SymbolKind SK
= indexSymbolKindToSymbolKind(SymInfo
.Kind
);
1704 HI
.name
= printName(Ctx
, ND
);
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
);
1720 static std::optional
<TypeHierarchyItem
>
1721 declToTypeHierarchyItem(const NamedDecl
&ND
, llvm::StringRef TUPath
) {
1722 auto Result
= declToHierarchyItem
<TypeHierarchyItem
>(ND
, TUPath
);
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
1729 Result
->data
.symbolID
= getSymbolID(&ND
);
1734 static std::optional
<CallHierarchyItem
>
1735 declToCallHierarchyItem(const NamedDecl
&ND
, llvm::StringRef TUPath
) {
1736 auto Result
= declToHierarchyItem
<CallHierarchyItem
>(ND
, TUPath
);
1739 if (ND
.isDeprecated())
1740 Result
->tags
.push_back(SymbolTag::Deprecated
);
1741 if (auto ID
= getSymbolID(&ND
))
1742 Result
->data
= ID
.str();
1746 template <typename HierarchyItem
>
1747 static std::optional
<HierarchyItem
> symbolToHierarchyItem(const Symbol
&S
,
1749 auto Loc
= symbolToLocation(S
, TUPath
);
1751 elog("Failed to convert symbol to hierarchy item: {0}", Loc
.takeError());
1752 return std::nullopt
;
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
;
1766 static std::optional
<TypeHierarchyItem
>
1767 symbolToTypeHierarchyItem(const Symbol
&S
, PathRef TUPath
) {
1768 auto Result
= symbolToHierarchyItem
<TypeHierarchyItem
>(S
, TUPath
);
1770 Result
->deprecated
= (S
.Flags
& Symbol::Deprecated
);
1771 Result
->data
.symbolID
= S
.ID
;
1776 static std::optional
<CallHierarchyItem
>
1777 symbolToCallHierarchyItem(const Symbol
&S
, PathRef TUPath
) {
1778 auto Result
= symbolToHierarchyItem
<CallHierarchyItem
>(S
, TUPath
);
1781 Result
->data
= S
.ID
.str();
1782 if (S
.Flags
& Symbol::Deprecated
)
1783 Result
->tags
.push_back(SymbolTag::Deprecated
);
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
)) {
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;
1820 if (!RPSet
.insert(Pattern
).second
) {
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
));
1835 RPSet
.erase(Pattern
);
1839 std::vector
<const CXXRecordDecl
*> findRecordTypeAt(ParsedAST
&AST
,
1841 auto RecordFromNode
= [&AST
](const SelectionTree::Node
*N
) {
1842 std::vector
<const CXXRecordDecl
*> 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
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
);
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());
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
);
1877 const SourceManager
&SM
= AST
.getSourceManager();
1878 std::vector
<const CXXRecordDecl
*> Result
;
1879 auto Offset
= positionToOffset(SM
.getBufferData(SM
.getMainFileID()), Pos
);
1881 llvm::consumeError(Offset
.takeError());
1884 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), *Offset
,
1885 *Offset
, [&](SelectionTree ST
) {
1886 Result
= RecordFromNode(ST
.commonAncestor());
1887 return !Result
.empty();
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
>())
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()))
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());
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();
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()
2017 // Given a type targeted by the cursor, return one or more types that are more interesting
2019 static void unwrapFindType(
2020 QualType T
, const HeuristicResolver
* H
, llvm::SmallVector
<QualType
>& Out
) {
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
,
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
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
);
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
;
2071 elog("failed to convert position {0} for findTypes: {1}", Pos
,
2072 Offset
.takeError());
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();
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())
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();
2121 // Handle a dependent base such as "Base<T>" by using the primary
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());
2133 Result
.push_back(ParentDecl
);
2139 std::vector
<TypeHierarchyItem
>
2140 getTypeHierarchy(ParsedAST
&AST
, Position Pos
, int ResolveLevels
,
2141 TypeHierarchyDirection Direction
, const SymbolIndex
*Index
,
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.
2157 if (auto *CTSD
= dyn_cast
<ClassTemplateSpecializationDecl
>(CXXRD
))
2158 CXXRD
= CTSD
->getTemplateInstantiationPattern();
2161 std::optional
<TypeHierarchyItem
> Result
=
2162 declToTypeHierarchyItem(*CXXRD
, AST
.tuPath());
2166 RecursionProtectionSet RPSet
;
2167 fillSuperTypes(*CXXRD
, AST
.tuPath(), *Result
, RPSet
);
2169 if (WantChildren
&& ResolveLevels
> 0) {
2170 Result
->children
.emplace();
2173 if (auto ID
= getSymbolID(CXXRD
))
2174 fillSubTypes(ID
, *Result
->children
, Index
, ResolveLevels
, TUPath
);
2177 Results
.emplace_back(std::move(*Result
));
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())
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
));
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
};
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
||
2223 Item
.children
.emplace();
2224 fillSubTypes(Item
.data
.symbolID
, *Item
.children
, Index
, ResolveLevels
,
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
);
2234 elog("prepareCallHierarchy failed to convert position to source location: "
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
)
2247 if (auto CHI
= declToCallHierarchyItem(*Decl
, AST
.tuPath()))
2248 Result
.emplace_back(std::move(*CHI
));
2253 std::vector
<CallHierarchyIncomingCall
>
2254 incomingCalls(const CallHierarchyItem
&Item
, const SymbolIndex
*Index
) {
2255 std::vector
<CallHierarchyIncomingCall
> Results
;
2256 if (!Index
|| Item
.data
.empty())
2258 auto ID
= SymbolID::fromStr(Item
.data
);
2260 elog("incomingCalls failed to find symbol: {0}", ID
.takeError());
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());
2286 elog("incomingCalls failed to convert location: {0}", Loc
.takeError());
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.
2308 FromRanges
.push_back(L
.range
);
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
;
2322 llvm::DenseSet
<const Decl
*> getNonLocalDeclRefs(ParsedAST
&AST
,
2323 const FunctionDecl
*FD
) {
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() &&
2336 AST
.getHeuristicResolver());
2340 } // namespace clangd
2341 } // namespace clang