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 "IncludeCleaner.h"
14 #include "ParsedAST.h"
17 #include "Selection.h"
18 #include "SourceCode.h"
20 #include "clang-include-cleaner/Analysis.h"
21 #include "clang-include-cleaner/Types.h"
22 #include "index/Index.h"
23 #include "index/Merge.h"
24 #include "index/Relation.h"
25 #include "index/SymbolCollector.h"
26 #include "index/SymbolID.h"
27 #include "index/SymbolLocation.h"
28 #include "support/Logger.h"
29 #include "clang/AST/ASTContext.h"
30 #include "clang/AST/ASTTypeTraits.h"
31 #include "clang/AST/Attr.h"
32 #include "clang/AST/Attrs.inc"
33 #include "clang/AST/Decl.h"
34 #include "clang/AST/DeclCXX.h"
35 #include "clang/AST/DeclObjC.h"
36 #include "clang/AST/DeclTemplate.h"
37 #include "clang/AST/DeclVisitor.h"
38 #include "clang/AST/ExprCXX.h"
39 #include "clang/AST/RecursiveASTVisitor.h"
40 #include "clang/AST/Stmt.h"
41 #include "clang/AST/StmtCXX.h"
42 #include "clang/AST/StmtVisitor.h"
43 #include "clang/AST/Type.h"
44 #include "clang/Basic/LLVM.h"
45 #include "clang/Basic/LangOptions.h"
46 #include "clang/Basic/SourceLocation.h"
47 #include "clang/Basic/SourceManager.h"
48 #include "clang/Basic/TokenKinds.h"
49 #include "clang/Index/IndexDataConsumer.h"
50 #include "clang/Index/IndexSymbol.h"
51 #include "clang/Index/IndexingAction.h"
52 #include "clang/Index/IndexingOptions.h"
53 #include "clang/Index/USRGeneration.h"
54 #include "clang/Lex/Lexer.h"
55 #include "clang/Sema/HeuristicResolver.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 std::optional
<Location
> toLSPLocation(const SymbolLocation
&Loc
,
125 llvm::StringRef TUPath
) {
128 auto LSPLoc
= indexToLSPLocation(Loc
, TUPath
);
130 elog("{0}", LSPLoc
.takeError());
137 SymbolLocation
toIndexLocation(const Location
&Loc
, std::string
&URIStorage
) {
138 SymbolLocation SymLoc
;
139 URIStorage
= Loc
.uri
.uri();
140 SymLoc
.FileURI
= URIStorage
.c_str();
141 SymLoc
.Start
.setLine(Loc
.range
.start
.line
);
142 SymLoc
.Start
.setColumn(Loc
.range
.start
.character
);
143 SymLoc
.End
.setLine(Loc
.range
.end
.line
);
144 SymLoc
.End
.setColumn(Loc
.range
.end
.character
);
148 // Returns the preferred location between an AST location and an index location.
149 SymbolLocation
getPreferredLocation(const Location
&ASTLoc
,
150 const SymbolLocation
&IdxLoc
,
151 std::string
&Scratch
) {
152 // Also use a mock symbol for the index location so that other fields (e.g.
153 // definition) are not factored into the preference.
154 Symbol ASTSym
, IdxSym
;
155 ASTSym
.ID
= IdxSym
.ID
= SymbolID("mock_symbol_id");
156 ASTSym
.CanonicalDeclaration
= toIndexLocation(ASTLoc
, Scratch
);
157 IdxSym
.CanonicalDeclaration
= IdxLoc
;
158 auto Merged
= mergeSymbol(ASTSym
, IdxSym
);
159 return Merged
.CanonicalDeclaration
;
162 std::vector
<std::pair
<const NamedDecl
*, DeclRelationSet
>>
163 getDeclAtPositionWithRelations(ParsedAST
&AST
, SourceLocation Pos
,
164 DeclRelationSet Relations
,
165 ASTNodeKind
*NodeKind
= nullptr) {
166 unsigned Offset
= AST
.getSourceManager().getDecomposedSpellingLoc(Pos
).second
;
167 std::vector
<std::pair
<const NamedDecl
*, DeclRelationSet
>> Result
;
168 auto ResultFromTree
= [&](SelectionTree ST
) {
169 if (const SelectionTree::Node
*N
= ST
.commonAncestor()) {
171 *NodeKind
= N
->ASTNode
.getNodeKind();
172 // Attributes don't target decls, look at the
173 // thing it's attached to.
174 // We still report the original NodeKind!
175 // This makes the `override` hack work.
176 if (N
->ASTNode
.get
<Attr
>() && N
->Parent
)
178 llvm::copy_if(allTargetDecls(N
->ASTNode
, AST
.getHeuristicResolver()),
179 std::back_inserter(Result
),
180 [&](auto &Entry
) { return !(Entry
.second
& ~Relations
); });
182 return !Result
.empty();
184 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), Offset
,
185 Offset
, ResultFromTree
);
189 std::vector
<const NamedDecl
*>
190 getDeclAtPosition(ParsedAST
&AST
, SourceLocation Pos
, DeclRelationSet Relations
,
191 ASTNodeKind
*NodeKind
= nullptr) {
192 std::vector
<const NamedDecl
*> Result
;
194 getDeclAtPositionWithRelations(AST
, Pos
, Relations
, NodeKind
))
195 Result
.push_back(Entry
.first
);
199 // Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
200 // figure out a filename.
201 std::optional
<Location
> makeLocation(const ASTContext
&AST
, SourceLocation Loc
,
202 llvm::StringRef TUPath
) {
203 const auto &SM
= AST
.getSourceManager();
204 const auto F
= SM
.getFileEntryRefForID(SM
.getFileID(Loc
));
207 auto FilePath
= getCanonicalPath(*F
, SM
.getFileManager());
209 log("failed to get path!");
213 L
.uri
= URIForFile::canonicalize(*FilePath
, TUPath
);
214 // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
215 // outside the main file.
216 auto TokLen
= Lexer::MeasureTokenLength(Loc
, SM
, AST
.getLangOpts());
217 L
.range
= halfOpenToRange(
218 SM
, CharSourceRange::getCharRange(Loc
, Loc
.getLocWithOffset(TokLen
)));
222 // Treat #included files as symbols, to enable go-to-definition on them.
223 std::optional
<LocatedSymbol
> locateFileReferent(const Position
&Pos
,
225 llvm::StringRef MainFilePath
) {
226 for (auto &Inc
: AST
.getIncludeStructure().MainFileIncludes
) {
227 if (!Inc
.Resolved
.empty() && Inc
.HashLine
== Pos
.line
) {
229 File
.Name
= std::string(llvm::sys::path::filename(Inc
.Resolved
));
230 File
.PreferredDeclaration
= {
231 URIForFile::canonicalize(Inc
.Resolved
, MainFilePath
), Range
{}};
232 File
.Definition
= File
.PreferredDeclaration
;
233 // We're not going to find any further symbols on #include lines.
240 // Macros are simple: there's no declaration/definition distinction.
241 // As a consequence, there's no need to look them up in the index either.
242 std::optional
<LocatedSymbol
>
243 locateMacroReferent(const syntax::Token
&TouchedIdentifier
, ParsedAST
&AST
,
244 llvm::StringRef MainFilePath
) {
245 if (auto M
= locateMacroAt(TouchedIdentifier
, AST
.getPreprocessor())) {
247 makeLocation(AST
.getASTContext(), M
->NameLoc
, MainFilePath
)) {
249 Macro
.Name
= std::string(M
->Name
);
250 Macro
.PreferredDeclaration
= *Loc
;
251 Macro
.Definition
= Loc
;
252 Macro
.ID
= getSymbolID(M
->Name
, M
->Info
, AST
.getSourceManager());
259 // A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
260 // definition of a canonical declaration doesn't match up to what a programmer
261 // would expect. For example, Objective-C classes can have three types of
264 // - forward declaration(s): @class MyClass;
265 // - true declaration (interface definition): @interface MyClass ... @end
266 // - true definition (implementation): @implementation MyClass ... @end
268 // Clang will consider the forward declaration to be the canonical declaration
269 // because it is first. We actually want the class definition if it is
270 // available since that is what a programmer would consider the primary
271 // declaration to be.
272 const NamedDecl
*getPreferredDecl(const NamedDecl
*D
) {
273 // FIXME: Canonical declarations of some symbols might refer to built-in
274 // decls with possibly-invalid source locations (e.g. global new operator).
275 // In such cases we should pick up a redecl with valid source location
276 // instead of failing.
277 D
= llvm::cast
<NamedDecl
>(D
->getCanonicalDecl());
279 // Prefer Objective-C class/protocol definitions over the forward declaration.
280 if (const auto *ID
= dyn_cast
<ObjCInterfaceDecl
>(D
))
281 if (const auto *DefinitionID
= ID
->getDefinition())
283 if (const auto *PD
= dyn_cast
<ObjCProtocolDecl
>(D
))
284 if (const auto *DefinitionID
= PD
->getDefinition())
290 std::vector
<LocatedSymbol
> findImplementors(llvm::DenseSet
<SymbolID
> IDs
,
291 RelationKind Predicate
,
292 const SymbolIndex
*Index
,
293 llvm::StringRef MainFilePath
) {
294 if (IDs
.empty() || !Index
)
296 static constexpr trace::Metric
FindImplementorsMetric(
297 "find_implementors", trace::Metric::Counter
, "case");
299 case RelationKind::BaseOf
:
300 FindImplementorsMetric
.record(1, "find-base");
302 case RelationKind::OverriddenBy
:
303 FindImplementorsMetric
.record(1, "find-override");
307 RelationsRequest Req
;
308 Req
.Predicate
= Predicate
;
309 Req
.Subjects
= std::move(IDs
);
310 std::vector
<LocatedSymbol
> Results
;
311 Index
->relations(Req
, [&](const SymbolID
&Subject
, const Symbol
&Object
) {
313 indexToLSPLocation(Object
.CanonicalDeclaration
, MainFilePath
);
315 elog("Find overrides: {0}", DeclLoc
.takeError());
318 Results
.emplace_back();
319 Results
.back().Name
= Object
.Name
.str();
320 Results
.back().PreferredDeclaration
= *DeclLoc
;
321 auto DefLoc
= indexToLSPLocation(Object
.Definition
, MainFilePath
);
323 elog("Failed to convert location: {0}", DefLoc
.takeError());
326 Results
.back().Definition
= *DefLoc
;
331 // Given LocatedSymbol results derived from the AST, query the index to obtain
332 // definitions and preferred declarations.
333 void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef
<LocatedSymbol
> Result
,
334 const SymbolIndex
*Index
,
335 llvm::StringRef MainFilePath
) {
336 LookupRequest QueryRequest
;
337 llvm::DenseMap
<SymbolID
, unsigned> ResultIndex
;
338 for (unsigned I
= 0; I
< Result
.size(); ++I
) {
339 if (auto ID
= Result
[I
].ID
) {
340 ResultIndex
.try_emplace(ID
, I
);
341 QueryRequest
.IDs
.insert(ID
);
344 if (!Index
|| QueryRequest
.IDs
.empty())
347 Index
->lookup(QueryRequest
, [&](const Symbol
&Sym
) {
348 auto &R
= Result
[ResultIndex
.lookup(Sym
.ID
)];
350 if (R
.Definition
) { // from AST
351 // Special case: if the AST yielded a definition, then it may not be
352 // the right *declaration*. Prefer the one from the index.
353 if (auto Loc
= toLSPLocation(Sym
.CanonicalDeclaration
, MainFilePath
))
354 R
.PreferredDeclaration
= *Loc
;
356 // We might still prefer the definition from the index, e.g. for
357 // generated symbols.
358 if (auto Loc
= toLSPLocation(
359 getPreferredLocation(*R
.Definition
, Sym
.Definition
, Scratch
),
363 R
.Definition
= toLSPLocation(Sym
.Definition
, MainFilePath
);
365 // Use merge logic to choose AST or index declaration.
366 if (auto Loc
= toLSPLocation(
367 getPreferredLocation(R
.PreferredDeclaration
,
368 Sym
.CanonicalDeclaration
, Scratch
),
370 R
.PreferredDeclaration
= *Loc
;
375 // Decls are more complicated.
376 // The AST contains at least a declaration, maybe a definition.
377 // These are up-to-date, and so generally preferred over index results.
378 // We perform a single batch index lookup to find additional definitions.
379 std::vector
<LocatedSymbol
>
380 locateASTReferent(SourceLocation CurLoc
, const syntax::Token
*TouchedIdentifier
,
381 ParsedAST
&AST
, llvm::StringRef MainFilePath
,
382 const SymbolIndex
*Index
, ASTNodeKind
&NodeKind
) {
383 const SourceManager
&SM
= AST
.getSourceManager();
384 // Results follow the order of Symbols.Decls.
385 std::vector
<LocatedSymbol
> Result
;
387 static constexpr trace::Metric
LocateASTReferentMetric(
388 "locate_ast_referent", trace::Metric::Counter
, "case");
389 auto AddResultDecl
= [&](const NamedDecl
*D
) {
390 D
= getPreferredDecl(D
);
392 makeLocation(AST
.getASTContext(), nameLocation(*D
, SM
), MainFilePath
);
396 Result
.emplace_back();
397 Result
.back().Name
= printName(AST
.getASTContext(), *D
);
398 Result
.back().PreferredDeclaration
= *Loc
;
399 Result
.back().ID
= getSymbolID(D
);
400 if (const NamedDecl
*Def
= getDefinition(D
))
401 Result
.back().Definition
= makeLocation(
402 AST
.getASTContext(), nameLocation(*Def
, SM
), MainFilePath
);
405 // Emit all symbol locations (declaration or definition) from AST.
406 DeclRelationSet Relations
=
407 DeclRelation::TemplatePattern
| DeclRelation::Alias
;
409 getDeclAtPositionWithRelations(AST
, CurLoc
, Relations
, &NodeKind
);
410 llvm::DenseSet
<SymbolID
> VirtualMethods
;
411 for (const auto &E
: Candidates
) {
412 const NamedDecl
*D
= E
.first
;
413 if (const auto *CMD
= llvm::dyn_cast
<CXXMethodDecl
>(D
)) {
414 // Special case: virtual void ^method() = 0: jump to all overrides.
415 // FIXME: extend it to ^virtual, unfortunately, virtual location is not
417 if (CMD
->isPureVirtual()) {
418 if (TouchedIdentifier
&& SM
.getSpellingLoc(CMD
->getLocation()) ==
419 TouchedIdentifier
->location()) {
420 VirtualMethods
.insert(getSymbolID(CMD
));
421 LocateASTReferentMetric
.record(1, "method-to-override");
424 // Special case: void foo() ^override: jump to the overridden method.
425 if (NodeKind
.isSame(ASTNodeKind::getFromNodeKind
<OverrideAttr
>()) ||
426 NodeKind
.isSame(ASTNodeKind::getFromNodeKind
<FinalAttr
>())) {
427 // We may be overridding multiple methods - offer them all.
428 for (const NamedDecl
*ND
: CMD
->overridden_methods())
434 // Special case: the cursor is on an alias, prefer other results.
435 // This targets "using ns::^Foo", where the target is more interesting.
436 // This does not trigger on renaming aliases:
437 // `using Foo = ^Bar` already targets Bar via a TypeLoc
438 // `using ^Foo = Bar` has no other results, as Underlying is filtered.
439 if (E
.second
& DeclRelation::Alias
&& Candidates
.size() > 1 &&
440 // beginLoc/endLoc are a token range, so rewind the identifier we're in.
441 SM
.isPointWithin(TouchedIdentifier
? TouchedIdentifier
->location()
443 D
->getBeginLoc(), D
->getEndLoc()))
446 // Special case: the point of declaration of a template specialization,
447 // it's more useful to navigate to the template declaration.
448 if (auto *CTSD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
449 if (TouchedIdentifier
&&
450 D
->getLocation() == TouchedIdentifier
->location()) {
451 LocateASTReferentMetric
.record(1, "template-specialization-to-primary");
452 AddResultDecl(CTSD
->getSpecializedTemplate());
457 // Special case: if the class name is selected, also map Objective-C
458 // categories and category implementations back to their class interface.
460 // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`
461 // instead of the `ObjCCategoryDecl` we intentionally check the contents
462 // of the locs when checking for class name equivalence.
463 if (const auto *CD
= dyn_cast
<ObjCCategoryDecl
>(D
))
464 if (const auto *ID
= CD
->getClassInterface())
465 if (TouchedIdentifier
&&
466 (CD
->getLocation() == TouchedIdentifier
->location() ||
467 ID
->getName() == TouchedIdentifier
->text(SM
))) {
468 LocateASTReferentMetric
.record(1, "objc-category-to-class");
472 LocateASTReferentMetric
.record(1, "regular");
473 // Otherwise the target declaration is the right one.
476 enhanceLocatedSymbolsFromIndex(Result
, Index
, MainFilePath
);
478 auto Overrides
= findImplementors(VirtualMethods
, RelationKind::OverriddenBy
,
479 Index
, MainFilePath
);
480 Result
.insert(Result
.end(), Overrides
.begin(), Overrides
.end());
484 std::vector
<LocatedSymbol
> locateSymbolForType(const ParsedAST
&AST
,
485 const QualType
&Type
,
486 const SymbolIndex
*Index
) {
487 const auto &SM
= AST
.getSourceManager();
488 auto MainFilePath
= AST
.tuPath();
490 // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.
491 // Likely it would be better to send it to Foo (heuristically) or to both.
492 auto Decls
= targetDecl(DynTypedNode::create(Type
.getNonReferenceType()),
493 DeclRelation::TemplatePattern
| DeclRelation::Alias
,
494 AST
.getHeuristicResolver());
498 std::vector
<LocatedSymbol
> Results
;
499 const auto &ASTContext
= AST
.getASTContext();
501 for (const NamedDecl
*D
: Decls
) {
502 D
= getPreferredDecl(D
);
504 auto Loc
= makeLocation(ASTContext
, nameLocation(*D
, SM
), MainFilePath
);
508 Results
.emplace_back();
509 Results
.back().Name
= printName(ASTContext
, *D
);
510 Results
.back().PreferredDeclaration
= *Loc
;
511 Results
.back().ID
= getSymbolID(D
);
512 if (const NamedDecl
*Def
= getDefinition(D
))
513 Results
.back().Definition
=
514 makeLocation(ASTContext
, nameLocation(*Def
, SM
), MainFilePath
);
516 enhanceLocatedSymbolsFromIndex(Results
, Index
, MainFilePath
);
521 bool tokenSpelledAt(SourceLocation SpellingLoc
, const syntax::TokenBuffer
&TB
) {
522 auto ExpandedTokens
= TB
.expandedTokens(
523 TB
.sourceManager().getMacroArgExpandedLocation(SpellingLoc
));
524 return !ExpandedTokens
.empty();
527 llvm::StringRef
sourcePrefix(SourceLocation Loc
, const SourceManager
&SM
) {
528 auto D
= SM
.getDecomposedLoc(Loc
);
529 bool Invalid
= false;
530 llvm::StringRef Buf
= SM
.getBufferData(D
.first
, &Invalid
);
531 if (Invalid
|| D
.second
> Buf
.size())
533 return Buf
.substr(0, D
.second
);
536 bool isDependentName(ASTNodeKind NodeKind
) {
537 return NodeKind
.isSame(ASTNodeKind::getFromNodeKind
<OverloadExpr
>()) ||
539 ASTNodeKind::getFromNodeKind
<CXXDependentScopeMemberExpr
>()) ||
541 ASTNodeKind::getFromNodeKind
<DependentScopeDeclRefExpr
>());
546 std::vector
<LocatedSymbol
> locateSymbolTextually(const SpelledWord
&Word
,
548 const SymbolIndex
*Index
,
549 llvm::StringRef MainFilePath
,
550 ASTNodeKind NodeKind
) {
551 // Don't use heuristics if this is a real identifier, or not an
553 // Exception: dependent names, because those may have useful textual
554 // matches that AST-based heuristics cannot find.
555 if ((Word
.ExpandedToken
&& !isDependentName(NodeKind
)) ||
556 !Word
.LikelyIdentifier
|| !Index
)
558 // We don't want to handle words in string literals. (It'd be nice to list
559 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
560 if (Word
.PartOfSpelledToken
&&
561 isStringLiteral(Word
.PartOfSpelledToken
->kind()))
564 const auto &SM
= AST
.getSourceManager();
565 // Look up the selected word in the index.
566 FuzzyFindRequest Req
;
567 Req
.Query
= Word
.Text
.str();
568 Req
.ProximityPaths
= {MainFilePath
.str()};
569 // Find the namespaces to query by lexing the file.
571 visibleNamespaces(sourcePrefix(Word
.Location
, SM
), AST
.getLangOpts());
572 // FIXME: For extra strictness, consider AnyScope=false.
574 // We limit the results to 3 further below. This limit is to avoid fetching
575 // too much data, while still likely having enough for 3 results to remain
576 // after additional filtering.
578 bool TooMany
= false;
579 using ScoredLocatedSymbol
= std::pair
<float, LocatedSymbol
>;
580 std::vector
<ScoredLocatedSymbol
> ScoredResults
;
581 Index
->fuzzyFind(Req
, [&](const Symbol
&Sym
) {
582 // Only consider exact name matches, including case.
583 // This is to avoid too many false positives.
584 // We could relax this in the future (e.g. to allow for typos) if we make
585 // the query more accurate by other means.
586 if (Sym
.Name
!= Word
.Text
)
589 // Exclude constructor results. They have the same name as the class,
590 // but we don't have enough context to prefer them over the class.
591 if (Sym
.SymInfo
.Kind
== index::SymbolKind::Constructor
)
595 indexToLSPLocation(Sym
.CanonicalDeclaration
, MainFilePath
);
597 log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc
.takeError());
600 LocatedSymbol Located
;
601 Located
.PreferredDeclaration
= *MaybeDeclLoc
;
602 Located
.Name
= (Sym
.Name
+ Sym
.TemplateSpecializationArgs
).str();
604 if (Sym
.Definition
) {
605 auto MaybeDefLoc
= indexToLSPLocation(Sym
.Definition
, MainFilePath
);
607 log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc
.takeError());
610 Located
.PreferredDeclaration
= *MaybeDefLoc
;
611 Located
.Definition
= *MaybeDefLoc
;
614 if (ScoredResults
.size() >= 5) {
615 // If we have more than 5 results, don't return anything,
616 // as confidence is too low.
617 // FIXME: Alternatively, try a stricter query?
622 SymbolQualitySignals Quality
;
624 SymbolRelevanceSignals Relevance
;
625 Relevance
.Name
= Sym
.Name
;
626 Relevance
.Query
= SymbolRelevanceSignals::Generic
;
627 Relevance
.merge(Sym
);
628 auto Score
= evaluateSymbolAndRelevance(Quality
.evaluateHeuristics(),
629 Relevance
.evaluateHeuristics());
630 dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym
.Scope
,
631 Sym
.Name
, Score
, Quality
, Relevance
);
633 ScoredResults
.push_back({Score
, std::move(Located
)});
637 vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
642 llvm::sort(ScoredResults
,
643 [](const ScoredLocatedSymbol
&A
, const ScoredLocatedSymbol
&B
) {
644 return A
.first
> B
.first
;
646 std::vector
<LocatedSymbol
> Results
;
647 for (auto &Res
: std::move(ScoredResults
))
648 Results
.push_back(std::move(Res
.second
));
650 vlog("No heuristic index definition for {0}", Word
.Text
);
652 log("Found definition heuristically in index for {0}", Word
.Text
);
656 const syntax::Token
*findNearbyIdentifier(const SpelledWord
&Word
,
657 const syntax::TokenBuffer
&TB
) {
658 // Don't use heuristics if this is a real identifier.
659 // Unlikely identifiers are OK if they were used as identifiers nearby.
660 if (Word
.ExpandedToken
)
662 // We don't want to handle words in string literals. (It'd be nice to list
663 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
664 if (Word
.PartOfSpelledToken
&&
665 isStringLiteral(Word
.PartOfSpelledToken
->kind()))
668 const SourceManager
&SM
= TB
.sourceManager();
669 // We prefer the closest possible token, line-wise. Backwards is penalized.
670 // Ties are implicitly broken by traversal order (first-one-wins).
671 auto File
= SM
.getFileID(Word
.Location
);
672 unsigned WordLine
= SM
.getSpellingLineNumber(Word
.Location
);
673 auto Cost
= [&](SourceLocation Loc
) -> unsigned {
674 assert(SM
.getFileID(Loc
) == File
&& "spelled token in wrong file?");
675 unsigned Line
= SM
.getSpellingLineNumber(Loc
);
676 return Line
>= WordLine
? Line
- WordLine
: 2 * (WordLine
- Line
);
678 const syntax::Token
*BestTok
= nullptr;
679 unsigned BestCost
= -1;
680 // Search bounds are based on word length:
681 // - forward: 2^N lines
682 // - backward: 2^(N-1) lines.
683 unsigned MaxDistance
=
684 1U << std::min
<unsigned>(Word
.Text
.size(),
685 std::numeric_limits
<unsigned>::digits
- 1);
686 // Line number for SM.translateLineCol() should be one-based, also
687 // SM.translateLineCol() can handle line number greater than
688 // number of lines in the file.
689 // - LineMin = max(1, WordLine + 1 - 2^(N-1))
690 // - LineMax = WordLine + 1 + 2^N
692 WordLine
+ 1 <= MaxDistance
/ 2 ? 1 : WordLine
+ 1 - MaxDistance
/ 2;
693 unsigned LineMax
= WordLine
+ 1 + MaxDistance
;
694 SourceLocation LocMin
= SM
.translateLineCol(File
, LineMin
, 1);
695 assert(LocMin
.isValid());
696 SourceLocation LocMax
= SM
.translateLineCol(File
, LineMax
, 1);
697 assert(LocMax
.isValid());
699 // Updates BestTok and BestCost if Tok is a good candidate.
700 // May return true if the cost is too high for this token.
701 auto Consider
= [&](const syntax::Token
&Tok
) {
702 if (Tok
.location() < LocMin
|| Tok
.location() > LocMax
)
703 return true; // we are too far from the word, break the outer loop.
704 if (!(Tok
.kind() == tok::identifier
&& Tok
.text(SM
) == Word
.Text
))
706 // No point guessing the same location we started with.
707 if (Tok
.location() == Word
.Location
)
709 // We've done cheap checks, compute cost so we can break the caller's loop.
710 unsigned TokCost
= Cost(Tok
.location());
711 if (TokCost
>= BestCost
)
712 return true; // causes the outer loop to break.
713 // Allow locations that might be part of the AST, and macros (even if empty)
714 // but not things like disabled preprocessor sections.
715 if (!(tokenSpelledAt(Tok
.location(), TB
) || TB
.expansionStartingAt(&Tok
)))
717 // We already verified this token is an improvement.
722 auto SpelledTokens
= TB
.spelledTokens(File
);
723 // Find where the word occurred in the token stream, to search forward & back.
724 auto *I
= llvm::partition_point(SpelledTokens
, [&](const syntax::Token
&T
) {
725 assert(SM
.getFileID(T
.location()) == SM
.getFileID(Word
.Location
));
726 return T
.location() < Word
.Location
; // Comparison OK: same file.
728 // Search for matches after the cursor.
729 for (const syntax::Token
&Tok
: llvm::ArrayRef(I
, SpelledTokens
.end()))
731 break; // costs of later tokens are greater...
732 // Search for matches before the cursor.
733 for (const syntax::Token
&Tok
:
734 llvm::reverse(llvm::ArrayRef(SpelledTokens
.begin(), I
)))
740 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
741 Word
.Text
, Word
.Location
.printToString(SM
),
742 BestTok
->location().printToString(SM
));
747 std::vector
<LocatedSymbol
> locateSymbolAt(ParsedAST
&AST
, Position Pos
,
748 const SymbolIndex
*Index
) {
749 const auto &SM
= AST
.getSourceManager();
750 auto MainFilePath
= AST
.tuPath();
752 if (auto File
= locateFileReferent(Pos
, AST
, MainFilePath
))
753 return {std::move(*File
)};
755 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
757 elog("locateSymbolAt failed to convert position to source location: {0}",
762 const syntax::Token
*TouchedIdentifier
= nullptr;
763 auto TokensTouchingCursor
=
764 syntax::spelledTokensTouching(*CurLoc
, AST
.getTokens());
765 for (const syntax::Token
&Tok
: TokensTouchingCursor
) {
766 if (Tok
.kind() == tok::identifier
) {
767 if (auto Macro
= locateMacroReferent(Tok
, AST
, MainFilePath
))
768 // Don't look at the AST or index if we have a macro result.
769 // (We'd just return declarations referenced from the macro's
771 return {*std::move(Macro
)};
773 TouchedIdentifier
= &Tok
;
777 if (Tok
.kind() == tok::kw_auto
|| Tok
.kind() == tok::kw_decltype
) {
778 // go-to-definition on auto should find the definition of the deduced
780 if (auto Deduced
= getDeducedType(AST
.getASTContext(), Tok
.location())) {
781 auto LocSym
= locateSymbolForType(AST
, *Deduced
, Index
);
788 ASTNodeKind NodeKind
;
789 auto ASTResults
= locateASTReferent(*CurLoc
, TouchedIdentifier
, AST
,
790 MainFilePath
, Index
, NodeKind
);
791 if (!ASTResults
.empty())
794 // If the cursor can't be resolved directly, try fallback strategies.
796 SpelledWord::touching(*CurLoc
, AST
.getTokens(), AST
.getLangOpts());
798 // Is the same word nearby a real identifier that might refer to something?
799 if (const syntax::Token
*NearbyIdent
=
800 findNearbyIdentifier(*Word
, AST
.getTokens())) {
801 if (auto Macro
= locateMacroReferent(*NearbyIdent
, AST
, MainFilePath
)) {
802 log("Found macro definition heuristically using nearby identifier {0}",
804 return {*std::move(Macro
)};
806 ASTResults
= locateASTReferent(NearbyIdent
->location(), NearbyIdent
, AST
,
807 MainFilePath
, Index
, NodeKind
);
808 if (!ASTResults
.empty()) {
809 log("Found definition heuristically using nearby identifier {0}",
810 NearbyIdent
->text(SM
));
813 vlog("No definition found using nearby identifier {0} at {1}", Word
->Text
,
814 Word
->Location
.printToString(SM
));
816 // No nearby word, or it didn't refer to anything either. Try the index.
817 auto TextualResults
=
818 locateSymbolTextually(*Word
, AST
, Index
, MainFilePath
, NodeKind
);
819 if (!TextualResults
.empty())
820 return TextualResults
;
826 std::vector
<DocumentLink
> getDocumentLinks(ParsedAST
&AST
) {
827 const auto &SM
= AST
.getSourceManager();
829 std::vector
<DocumentLink
> Result
;
830 for (auto &Inc
: AST
.getIncludeStructure().MainFileIncludes
) {
831 if (Inc
.Resolved
.empty())
833 auto HashLoc
= SM
.getComposedLoc(SM
.getMainFileID(), Inc
.HashOffset
);
834 const auto *HashTok
= AST
.getTokens().spelledTokenContaining(HashLoc
);
835 assert(HashTok
&& "got inclusion at wrong offset");
836 const auto *IncludeTok
= std::next(HashTok
);
837 const auto *FileTok
= std::next(IncludeTok
);
838 // FileTok->range is not sufficient here, as raw lexing wouldn't yield
839 // correct tokens for angled filenames. Hence we explicitly use
840 // Inc.Written's length.
842 syntax::FileRange(SM
, FileTok
->location(), Inc
.Written
.length())
846 DocumentLink({halfOpenToRange(SM
, FileRange
),
847 URIForFile::canonicalize(Inc
.Resolved
, AST
.tuPath())}));
855 /// Collects references to symbols within the main file.
856 class ReferenceFinder
: public index::IndexDataConsumer
{
859 syntax::Token SpelledTok
;
860 index::SymbolRoleSet Role
;
861 const Decl
*Container
;
863 Range
range(const SourceManager
&SM
) const {
864 return halfOpenToRange(SM
, SpelledTok
.range(SM
).toCharRange(SM
));
868 ReferenceFinder(const ParsedAST
&AST
,
869 const llvm::ArrayRef
<const NamedDecl
*> Targets
,
871 : PerToken(PerToken
), AST(AST
) {
872 for (const NamedDecl
*ND
: Targets
)
873 TargetDecls
.insert(ND
->getCanonicalDecl());
876 std::vector
<Reference
> take() && {
877 llvm::sort(References
, [](const Reference
&L
, const Reference
&R
) {
878 auto LTok
= L
.SpelledTok
.location();
879 auto RTok
= R
.SpelledTok
.location();
880 return std::tie(LTok
, L
.Role
) < std::tie(RTok
, R
.Role
);
882 // We sometimes see duplicates when parts of the AST get traversed twice.
883 References
.erase(std::unique(References
.begin(), References
.end(),
884 [](const Reference
&L
, const Reference
&R
) {
885 auto LTok
= L
.SpelledTok
.location();
886 auto RTok
= R
.SpelledTok
.location();
887 return std::tie(LTok
, L
.Role
) ==
888 std::tie(RTok
, R
.Role
);
891 return std::move(References
);
895 handleDeclOccurrence(const Decl
*D
, index::SymbolRoleSet Roles
,
896 llvm::ArrayRef
<index::SymbolRelation
> Relations
,
898 index::IndexDataConsumer::ASTNodeInfo ASTNode
) override
{
899 if (!TargetDecls
.contains(D
->getCanonicalDecl()))
901 const SourceManager
&SM
= AST
.getSourceManager();
902 if (!isInsideMainFile(Loc
, SM
))
904 const auto &TB
= AST
.getTokens();
906 llvm::SmallVector
<SourceLocation
, 1> Locs
;
908 // Check whether this is one of the few constructs where the reference
909 // can be split over several tokens.
910 if (auto *OME
= llvm::dyn_cast_or_null
<ObjCMessageExpr
>(ASTNode
.OrigE
)) {
911 OME
->getSelectorLocs(Locs
);
912 } else if (auto *OMD
=
913 llvm::dyn_cast_or_null
<ObjCMethodDecl
>(ASTNode
.OrigD
)) {
914 OMD
->getSelectorLocs(Locs
);
916 // Sanity check: we expect the *first* token to match the reported loc.
917 // Otherwise, maybe it was e.g. some other kind of reference to a Decl.
918 if (!Locs
.empty() && Locs
.front() != Loc
)
919 Locs
.clear(); // First token doesn't match, assume our guess was wrong.
924 SymbolCollector::Options CollectorOpts
;
925 CollectorOpts
.CollectMainFileSymbols
= true;
926 for (SourceLocation L
: Locs
) {
927 L
= SM
.getFileLoc(L
);
928 if (const auto *Tok
= TB
.spelledTokenContaining(L
))
929 References
.push_back(
931 SymbolCollector::getRefContainer(ASTNode
.Parent
, CollectorOpts
)});
937 bool PerToken
; // If true, report 3 references for split ObjC selector names.
938 std::vector
<Reference
> References
;
939 const ParsedAST
&AST
;
940 llvm::DenseSet
<const Decl
*> TargetDecls
;
943 std::vector
<ReferenceFinder::Reference
>
944 findRefs(const llvm::ArrayRef
<const NamedDecl
*> TargetDecls
, ParsedAST
&AST
,
946 ReferenceFinder
RefFinder(AST
, TargetDecls
, PerToken
);
947 index::IndexingOptions IndexOpts
;
948 IndexOpts
.SystemSymbolFilter
=
949 index::IndexingOptions::SystemSymbolFilterKind::All
;
950 IndexOpts
.IndexFunctionLocals
= true;
951 IndexOpts
.IndexParametersInDeclarations
= true;
952 IndexOpts
.IndexTemplateParameters
= true;
953 indexTopLevelDecls(AST
.getASTContext(), AST
.getPreprocessor(),
954 AST
.getLocalTopLevelDecls(), RefFinder
, IndexOpts
);
955 return std::move(RefFinder
).take();
958 const Stmt
*getFunctionBody(DynTypedNode N
) {
959 if (const auto *FD
= N
.get
<FunctionDecl
>())
960 return FD
->getBody();
961 if (const auto *FD
= N
.get
<BlockDecl
>())
962 return FD
->getBody();
963 if (const auto *FD
= N
.get
<LambdaExpr
>())
964 return FD
->getBody();
965 if (const auto *FD
= N
.get
<ObjCMethodDecl
>())
966 return FD
->getBody();
970 const Stmt
*getLoopBody(DynTypedNode N
) {
971 if (const auto *LS
= N
.get
<ForStmt
>())
972 return LS
->getBody();
973 if (const auto *LS
= N
.get
<CXXForRangeStmt
>())
974 return LS
->getBody();
975 if (const auto *LS
= N
.get
<WhileStmt
>())
976 return LS
->getBody();
977 if (const auto *LS
= N
.get
<DoStmt
>())
978 return LS
->getBody();
982 // AST traversal to highlight control flow statements under some root.
983 // Once we hit further control flow we prune the tree (or at least restrict
984 // what we highlight) so we capture e.g. breaks from the outer loop only.
985 class FindControlFlow
: public RecursiveASTVisitor
<FindControlFlow
> {
986 // Types of control-flow statements we might highlight.
994 All
= Break
| Continue
| Return
| Case
| Throw
| Goto
,
996 int Ignore
= 0; // bitmask of Target - what are we *not* highlighting?
997 SourceRange Bounds
; // Half-open, restricts reported targets.
998 std::vector
<SourceLocation
> &Result
;
999 const SourceManager
&SM
;
1001 // Masks out targets for a traversal into D.
1002 // Traverses the subtree using Delegate() if any targets remain.
1003 template <typename Func
>
1004 bool filterAndTraverse(DynTypedNode D
, const Func
&Delegate
) {
1005 auto RestoreIgnore
= llvm::make_scope_exit(
1006 [OldIgnore(Ignore
), this] { Ignore
= OldIgnore
; });
1007 if (getFunctionBody(D
))
1009 else if (getLoopBody(D
))
1010 Ignore
|= Continue
| Break
;
1011 else if (D
.get
<SwitchStmt
>())
1012 Ignore
|= Break
| Case
;
1013 // Prune tree if we're not looking for anything.
1014 return (Ignore
== All
) ? true : Delegate();
1017 void found(Target T
, SourceLocation Loc
) {
1020 if (SM
.isBeforeInTranslationUnit(Loc
, Bounds
.getBegin()) ||
1021 SM
.isBeforeInTranslationUnit(Bounds
.getEnd(), Loc
))
1023 Result
.push_back(Loc
);
1027 FindControlFlow(SourceRange Bounds
, std::vector
<SourceLocation
> &Result
,
1028 const SourceManager
&SM
)
1029 : Bounds(Bounds
), Result(Result
), SM(SM
) {}
1031 // When traversing function or loops, limit targets to those that still
1032 // refer to the original root.
1033 bool TraverseDecl(Decl
*D
) {
1034 return !D
|| filterAndTraverse(DynTypedNode::create(*D
), [&] {
1035 return RecursiveASTVisitor::TraverseDecl(D
);
1038 bool TraverseStmt(Stmt
*S
) {
1039 return !S
|| filterAndTraverse(DynTypedNode::create(*S
), [&] {
1040 return RecursiveASTVisitor::TraverseStmt(S
);
1044 // Add leaves that we found and want.
1045 bool VisitReturnStmt(ReturnStmt
*R
) {
1046 found(Return
, R
->getReturnLoc());
1049 bool VisitBreakStmt(BreakStmt
*B
) {
1050 found(Break
, B
->getBreakLoc());
1053 bool VisitContinueStmt(ContinueStmt
*C
) {
1054 found(Continue
, C
->getContinueLoc());
1057 bool VisitSwitchCase(SwitchCase
*C
) {
1058 found(Case
, C
->getKeywordLoc());
1061 bool VisitCXXThrowExpr(CXXThrowExpr
*T
) {
1062 found(Throw
, T
->getThrowLoc());
1065 bool VisitGotoStmt(GotoStmt
*G
) {
1066 // Goto is interesting if its target is outside the root.
1067 if (const auto *LD
= G
->getLabel()) {
1068 if (SM
.isBeforeInTranslationUnit(LD
->getLocation(), Bounds
.getBegin()) ||
1069 SM
.isBeforeInTranslationUnit(Bounds
.getEnd(), LD
->getLocation()))
1070 found(Goto
, G
->getGotoLoc());
1076 // Given a location within a switch statement, return the half-open range that
1077 // covers the case it's contained in.
1078 // We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
1079 SourceRange
findCaseBounds(const SwitchStmt
&Switch
, SourceLocation Loc
,
1080 const SourceManager
&SM
) {
1081 // Cases are not stored in order, sort them first.
1082 // (In fact they seem to be stored in reverse order, don't rely on this)
1083 std::vector
<const SwitchCase
*> Cases
;
1084 for (const SwitchCase
*Case
= Switch
.getSwitchCaseList(); Case
;
1085 Case
= Case
->getNextSwitchCase())
1086 Cases
.push_back(Case
);
1087 llvm::sort(Cases
, [&](const SwitchCase
*L
, const SwitchCase
*R
) {
1088 return SM
.isBeforeInTranslationUnit(L
->getKeywordLoc(), R
->getKeywordLoc());
1091 // Find the first case after the target location, the end of our range.
1092 auto CaseAfter
= llvm::partition_point(Cases
, [&](const SwitchCase
*C
) {
1093 return !SM
.isBeforeInTranslationUnit(Loc
, C
->getKeywordLoc());
1095 SourceLocation End
= CaseAfter
== Cases
.end() ? Switch
.getEndLoc()
1096 : (*CaseAfter
)->getKeywordLoc();
1098 // Our target can be before the first case - cases are optional!
1099 if (CaseAfter
== Cases
.begin())
1100 return SourceRange(Switch
.getBeginLoc(), End
);
1101 // The start of our range is usually the previous case, but...
1102 auto CaseBefore
= std::prev(CaseAfter
);
1103 // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
1104 while (CaseBefore
!= Cases
.begin() &&
1105 (*std::prev(CaseBefore
))->getSubStmt() == *CaseBefore
)
1107 return SourceRange((*CaseBefore
)->getKeywordLoc(), End
);
1110 // Returns the locations of control flow statements related to N. e.g.:
1111 // for => branches: break/continue/return/throw
1112 // break => controlling loop (forwhile/do), and its related control flow
1113 // return => all returns/throws from the same function
1114 // When an inner block is selected, we include branches bound to outer blocks
1115 // as these are exits from the inner block. e.g. return in a for loop.
1116 // FIXME: We don't analyze catch blocks, throw is treated the same as return.
1117 std::vector
<SourceLocation
> relatedControlFlow(const SelectionTree::Node
&N
) {
1118 const SourceManager
&SM
=
1119 N
.getDeclContext().getParentASTContext().getSourceManager();
1120 std::vector
<SourceLocation
> Result
;
1122 // First, check if we're at a node that can resolve to a root.
1123 enum class Cur
{ None
, Break
, Continue
, Return
, Case
, Throw
} Cursor
;
1124 if (N
.ASTNode
.get
<BreakStmt
>()) {
1125 Cursor
= Cur::Break
;
1126 } else if (N
.ASTNode
.get
<ContinueStmt
>()) {
1127 Cursor
= Cur::Continue
;
1128 } else if (N
.ASTNode
.get
<ReturnStmt
>()) {
1129 Cursor
= Cur::Return
;
1130 } else if (N
.ASTNode
.get
<CXXThrowExpr
>()) {
1131 Cursor
= Cur::Throw
;
1132 } else if (N
.ASTNode
.get
<SwitchCase
>()) {
1134 } else if (const GotoStmt
*GS
= N
.ASTNode
.get
<GotoStmt
>()) {
1135 // We don't know what root to associate with, but highlight the goto/label.
1136 Result
.push_back(GS
->getGotoLoc());
1137 if (const auto *LD
= GS
->getLabel())
1138 Result
.push_back(LD
->getLocation());
1144 const Stmt
*Root
= nullptr; // Loop or function body to traverse.
1146 // Look up the tree for a root (or just at this node if we didn't find a leaf)
1147 for (const auto *P
= &N
; P
; P
= P
->Parent
) {
1148 // return associates with enclosing function
1149 if (const Stmt
*FunctionBody
= getFunctionBody(P
->ASTNode
)) {
1150 if (Cursor
== Cur::Return
|| Cursor
== Cur::Throw
) {
1151 Root
= FunctionBody
;
1153 break; // other leaves don't cross functions.
1155 // break/continue associate with enclosing loop.
1156 if (const Stmt
*LoopBody
= getLoopBody(P
->ASTNode
)) {
1157 if (Cursor
== Cur::None
|| Cursor
== Cur::Break
||
1158 Cursor
== Cur::Continue
) {
1160 // Highlight the loop keyword itself.
1161 // FIXME: for do-while, this only covers the `do`..
1162 Result
.push_back(P
->ASTNode
.getSourceRange().getBegin());
1166 // For switches, users think of case statements as control flow blocks.
1167 // We highlight only occurrences surrounded by the same case.
1168 // We don't detect fallthrough (other than 'case X, case Y').
1169 if (const auto *SS
= P
->ASTNode
.get
<SwitchStmt
>()) {
1170 if (Cursor
== Cur::Break
|| Cursor
== Cur::Case
) {
1171 Result
.push_back(SS
->getSwitchLoc()); // Highlight the switch.
1172 Root
= SS
->getBody();
1173 // Limit to enclosing case, if there is one.
1174 Bounds
= findCaseBounds(*SS
, N
.ASTNode
.getSourceRange().getBegin(), SM
);
1178 // If we didn't start at some interesting node, we're done.
1179 if (Cursor
== Cur::None
)
1183 if (!Bounds
.isValid())
1184 Bounds
= Root
->getSourceRange();
1185 FindControlFlow(Bounds
, Result
, SM
).TraverseStmt(const_cast<Stmt
*>(Root
));
1190 DocumentHighlight
toHighlight(const ReferenceFinder::Reference
&Ref
,
1191 const SourceManager
&SM
) {
1192 DocumentHighlight DH
;
1193 DH
.range
= Ref
.range(SM
);
1194 if (Ref
.Role
& index::SymbolRoleSet(index::SymbolRole::Write
))
1195 DH
.kind
= DocumentHighlightKind::Write
;
1196 else if (Ref
.Role
& index::SymbolRoleSet(index::SymbolRole::Read
))
1197 DH
.kind
= DocumentHighlightKind::Read
;
1199 DH
.kind
= DocumentHighlightKind::Text
;
1203 std::optional
<DocumentHighlight
> toHighlight(SourceLocation Loc
,
1204 const syntax::TokenBuffer
&TB
) {
1205 Loc
= TB
.sourceManager().getFileLoc(Loc
);
1206 if (const auto *Tok
= TB
.spelledTokenContaining(Loc
)) {
1207 DocumentHighlight Result
;
1208 Result
.range
= halfOpenToRange(
1210 CharSourceRange::getCharRange(Tok
->location(), Tok
->endLocation()));
1213 return std::nullopt
;
1218 std::vector
<DocumentHighlight
> findDocumentHighlights(ParsedAST
&AST
,
1220 const SourceManager
&SM
= AST
.getSourceManager();
1221 // FIXME: show references to macro within file?
1222 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1224 llvm::consumeError(CurLoc
.takeError());
1227 std::vector
<DocumentHighlight
> Result
;
1228 auto TryTree
= [&](SelectionTree ST
) {
1229 if (const SelectionTree::Node
*N
= ST
.commonAncestor()) {
1230 DeclRelationSet Relations
=
1231 DeclRelation::TemplatePattern
| DeclRelation::Alias
;
1233 targetDecl(N
->ASTNode
, Relations
, AST
.getHeuristicResolver());
1234 if (!TargetDecls
.empty()) {
1235 // FIXME: we may get multiple DocumentHighlights with the same location
1236 // and different kinds, deduplicate them.
1237 for (const auto &Ref
: findRefs(TargetDecls
, AST
, /*PerToken=*/true))
1238 Result
.push_back(toHighlight(Ref
, SM
));
1241 auto ControlFlow
= relatedControlFlow(*N
);
1242 if (!ControlFlow
.empty()) {
1243 for (SourceLocation Loc
: ControlFlow
)
1244 if (auto Highlight
= toHighlight(Loc
, AST
.getTokens()))
1245 Result
.push_back(std::move(*Highlight
));
1253 AST
.getSourceManager().getDecomposedSpellingLoc(*CurLoc
).second
;
1254 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), Offset
,
1259 std::vector
<LocatedSymbol
> findImplementations(ParsedAST
&AST
, Position Pos
,
1260 const SymbolIndex
*Index
) {
1261 // We rely on index to find the implementations in subclasses.
1262 // FIXME: Index can be stale, so we may loose some latest results from the
1266 const SourceManager
&SM
= AST
.getSourceManager();
1267 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1269 elog("Failed to convert position to source location: {0}",
1270 CurLoc
.takeError());
1273 DeclRelationSet Relations
=
1274 DeclRelation::TemplatePattern
| DeclRelation::Alias
;
1275 llvm::DenseSet
<SymbolID
> IDs
;
1276 RelationKind QueryKind
= RelationKind::OverriddenBy
;
1277 for (const NamedDecl
*ND
: getDeclAtPosition(AST
, *CurLoc
, Relations
)) {
1278 if (const auto *CXXMD
= llvm::dyn_cast
<CXXMethodDecl
>(ND
)) {
1279 if (CXXMD
->isVirtual()) {
1280 IDs
.insert(getSymbolID(ND
));
1281 QueryKind
= RelationKind::OverriddenBy
;
1283 } else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(ND
)) {
1284 IDs
.insert(getSymbolID(RD
));
1285 QueryKind
= RelationKind::BaseOf
;
1288 return findImplementors(std::move(IDs
), QueryKind
, Index
, AST
.tuPath());
1292 // Recursively finds all the overridden methods of `CMD` in complete type
1294 void getOverriddenMethods(const CXXMethodDecl
*CMD
,
1295 llvm::DenseSet
<SymbolID
> &OverriddenMethods
) {
1298 for (const CXXMethodDecl
*Base
: CMD
->overridden_methods()) {
1299 if (auto ID
= getSymbolID(Base
))
1300 OverriddenMethods
.insert(ID
);
1301 getOverriddenMethods(Base
, OverriddenMethods
);
1305 std::optional
<std::string
>
1306 stringifyContainerForMainFileRef(const Decl
*Container
) {
1307 // FIXME We might also want to display the signature here
1308 // When doing so, remember to also add the Signature to index results!
1309 if (auto *ND
= llvm::dyn_cast_if_present
<NamedDecl
>(Container
))
1310 return printQualifiedName(*ND
);
1314 std::optional
<ReferencesResult
>
1315 maybeFindIncludeReferences(ParsedAST
&AST
, Position Pos
,
1316 URIForFile URIMainFile
) {
1317 const auto &Includes
= AST
.getIncludeStructure().MainFileIncludes
;
1318 auto IncludeOnLine
= llvm::find_if(Includes
, [&Pos
](const Inclusion
&Inc
) {
1319 return Inc
.HashLine
== Pos
.line
;
1321 if (IncludeOnLine
== Includes
.end())
1322 return std::nullopt
;
1324 const SourceManager
&SM
= AST
.getSourceManager();
1325 ReferencesResult Results
;
1326 auto Converted
= convertIncludes(AST
);
1327 include_cleaner::walkUsed(
1328 AST
.getLocalTopLevelDecls(), collectMacroReferences(AST
),
1329 &AST
.getPragmaIncludes(), AST
.getPreprocessor(),
1330 [&](const include_cleaner::SymbolReference
&Ref
,
1331 llvm::ArrayRef
<include_cleaner::Header
> Providers
) {
1332 if (Ref
.RT
!= include_cleaner::RefType::Explicit
||
1333 !isPreferredProvider(*IncludeOnLine
, Converted
, Providers
))
1336 auto Loc
= SM
.getFileLoc(Ref
.RefLocation
);
1337 // File locations can be outside of the main file if macro is
1338 // expanded through an #include.
1339 while (SM
.getFileID(Loc
) != SM
.getMainFileID())
1340 Loc
= SM
.getIncludeLoc(SM
.getFileID(Loc
));
1342 ReferencesResult::Reference Result
;
1343 const auto *Token
= AST
.getTokens().spelledTokenContaining(Loc
);
1344 assert(Token
&& "references expected token here");
1345 Result
.Loc
.range
= Range
{sourceLocToPosition(SM
, Token
->location()),
1346 sourceLocToPosition(SM
, Token
->endLocation())};
1347 Result
.Loc
.uri
= URIMainFile
;
1348 Results
.References
.push_back(std::move(Result
));
1350 if (Results
.References
.empty())
1351 return std::nullopt
;
1353 // Add the #include line to the references list.
1354 ReferencesResult::Reference Result
;
1355 Result
.Loc
.range
= rangeTillEOL(SM
.getBufferData(SM
.getMainFileID()),
1356 IncludeOnLine
->HashOffset
);
1357 Result
.Loc
.uri
= URIMainFile
;
1358 Results
.References
.push_back(std::move(Result
));
1363 ReferencesResult
findReferences(ParsedAST
&AST
, Position Pos
, uint32_t Limit
,
1364 const SymbolIndex
*Index
, bool AddContext
) {
1365 ReferencesResult Results
;
1366 const SourceManager
&SM
= AST
.getSourceManager();
1367 auto MainFilePath
= AST
.tuPath();
1368 auto URIMainFile
= URIForFile::canonicalize(MainFilePath
, MainFilePath
);
1369 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1371 llvm::consumeError(CurLoc
.takeError());
1375 const auto IncludeReferences
=
1376 maybeFindIncludeReferences(AST
, Pos
, URIMainFile
);
1377 if (IncludeReferences
)
1378 return *IncludeReferences
;
1380 llvm::DenseSet
<SymbolID
> IDsToQuery
, OverriddenMethods
;
1382 const auto *IdentifierAtCursor
=
1383 syntax::spelledIdentifierTouching(*CurLoc
, AST
.getTokens());
1384 std::optional
<DefinedMacro
> Macro
;
1385 if (IdentifierAtCursor
)
1386 Macro
= locateMacroAt(*IdentifierAtCursor
, AST
.getPreprocessor());
1388 // Handle references to macro.
1389 if (auto MacroSID
= getSymbolID(Macro
->Name
, Macro
->Info
, SM
)) {
1390 // Collect macro references from main file.
1391 const auto &IDToRefs
= AST
.getMacros().MacroRefs
;
1392 auto Refs
= IDToRefs
.find(MacroSID
);
1393 if (Refs
!= IDToRefs
.end()) {
1394 for (const auto &Ref
: Refs
->second
) {
1395 ReferencesResult::Reference Result
;
1396 Result
.Loc
.range
= Ref
.toRange(SM
);
1397 Result
.Loc
.uri
= URIMainFile
;
1398 if (Ref
.IsDefinition
) {
1399 Result
.Attributes
|= ReferencesResult::Declaration
;
1400 Result
.Attributes
|= ReferencesResult::Definition
;
1402 Results
.References
.push_back(std::move(Result
));
1405 IDsToQuery
.insert(MacroSID
);
1408 // Handle references to Decls.
1410 DeclRelationSet Relations
=
1411 DeclRelation::TemplatePattern
| DeclRelation::Alias
;
1412 std::vector
<const NamedDecl
*> Decls
=
1413 getDeclAtPosition(AST
, *CurLoc
, Relations
);
1414 llvm::SmallVector
<const NamedDecl
*> TargetsInMainFile
;
1415 for (const NamedDecl
*D
: Decls
) {
1416 auto ID
= getSymbolID(D
);
1419 TargetsInMainFile
.push_back(D
);
1420 // Not all symbols can be referenced from outside (e.g. function-locals).
1421 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1422 // we know this file isn't a header. The details might be tricky.
1423 if (D
->getParentFunctionOrMethod())
1425 IDsToQuery
.insert(ID
);
1428 RelationsRequest OverriddenBy
;
1430 OverriddenBy
.Predicate
= RelationKind::OverriddenBy
;
1431 for (const NamedDecl
*ND
: Decls
) {
1432 // Special case: For virtual methods, report decl/def of overrides and
1433 // references to all overridden methods in complete type hierarchy.
1434 if (const auto *CMD
= llvm::dyn_cast
<CXXMethodDecl
>(ND
)) {
1435 if (CMD
->isVirtual()) {
1436 if (auto ID
= getSymbolID(CMD
))
1437 OverriddenBy
.Subjects
.insert(ID
);
1438 getOverriddenMethods(CMD
, OverriddenMethods
);
1444 // We traverse the AST to find references in the main file.
1445 auto MainFileRefs
= findRefs(TargetsInMainFile
, AST
, /*PerToken=*/false);
1446 // We may get multiple refs with the same location and different Roles, as
1447 // cross-reference is only interested in locations, we deduplicate them
1448 // by the location to avoid emitting duplicated locations.
1449 MainFileRefs
.erase(std::unique(MainFileRefs
.begin(), MainFileRefs
.end(),
1450 [](const ReferenceFinder::Reference
&L
,
1451 const ReferenceFinder::Reference
&R
) {
1452 return L
.SpelledTok
.location() ==
1453 R
.SpelledTok
.location();
1455 MainFileRefs
.end());
1456 for (const auto &Ref
: MainFileRefs
) {
1457 ReferencesResult::Reference Result
;
1458 Result
.Loc
.range
= Ref
.range(SM
);
1459 Result
.Loc
.uri
= URIMainFile
;
1461 Result
.Loc
.containerName
=
1462 stringifyContainerForMainFileRef(Ref
.Container
);
1463 if (Ref
.Role
& static_cast<unsigned>(index::SymbolRole::Declaration
))
1464 Result
.Attributes
|= ReferencesResult::Declaration
;
1465 // clang-index doesn't report definitions as declarations, but they are.
1466 if (Ref
.Role
& static_cast<unsigned>(index::SymbolRole::Definition
))
1467 Result
.Attributes
|=
1468 ReferencesResult::Definition
| ReferencesResult::Declaration
;
1469 Results
.References
.push_back(std::move(Result
));
1471 // Add decl/def of overridding methods.
1472 if (Index
&& !OverriddenBy
.Subjects
.empty()) {
1473 LookupRequest ContainerLookup
;
1474 // Different overrides will always be contained in different classes, so
1475 // we have a one-to-one mapping between SymbolID and index here, thus we
1476 // don't need to use std::vector as the map's value type.
1477 llvm::DenseMap
<SymbolID
, size_t> RefIndexForContainer
;
1478 Index
->relations(OverriddenBy
, [&](const SymbolID
&Subject
,
1479 const Symbol
&Object
) {
1480 if (Limit
&& Results
.References
.size() >= Limit
) {
1481 Results
.HasMore
= true;
1484 const auto LSPLocDecl
=
1485 toLSPLocation(Object
.CanonicalDeclaration
, MainFilePath
);
1486 const auto LSPLocDef
= toLSPLocation(Object
.Definition
, MainFilePath
);
1487 if (LSPLocDecl
&& LSPLocDecl
!= LSPLocDef
) {
1488 ReferencesResult::Reference Result
;
1489 Result
.Loc
= {std::move(*LSPLocDecl
), std::nullopt
};
1491 ReferencesResult::Declaration
| ReferencesResult::Override
;
1492 RefIndexForContainer
.insert({Object
.ID
, Results
.References
.size()});
1493 ContainerLookup
.IDs
.insert(Object
.ID
);
1494 Results
.References
.push_back(std::move(Result
));
1497 ReferencesResult::Reference Result
;
1498 Result
.Loc
= {std::move(*LSPLocDef
), std::nullopt
};
1499 Result
.Attributes
= ReferencesResult::Declaration
|
1500 ReferencesResult::Definition
|
1501 ReferencesResult::Override
;
1502 RefIndexForContainer
.insert({Object
.ID
, Results
.References
.size()});
1503 ContainerLookup
.IDs
.insert(Object
.ID
);
1504 Results
.References
.push_back(std::move(Result
));
1508 if (!ContainerLookup
.IDs
.empty() && AddContext
)
1509 Index
->lookup(ContainerLookup
, [&](const Symbol
&Container
) {
1510 auto Ref
= RefIndexForContainer
.find(Container
.ID
);
1511 assert(Ref
!= RefIndexForContainer
.end());
1512 Results
.References
[Ref
->getSecond()].Loc
.containerName
=
1513 Container
.Scope
.str() + Container
.Name
.str();
1517 // Now query the index for references from other files.
1518 auto QueryIndex
= [&](llvm::DenseSet
<SymbolID
> IDs
, bool AllowAttributes
,
1519 bool AllowMainFileSymbols
) {
1520 if (IDs
.empty() || !Index
|| Results
.HasMore
)
1523 Req
.IDs
= std::move(IDs
);
1525 if (Limit
< Results
.References
.size()) {
1526 // We've already filled our quota, still check the index to correctly
1527 // return the `HasMore` info.
1530 // Query index only for the remaining size.
1531 Req
.Limit
= Limit
- Results
.References
.size();
1534 LookupRequest ContainerLookup
;
1535 llvm::DenseMap
<SymbolID
, std::vector
<size_t>> RefIndicesForContainer
;
1536 Results
.HasMore
|= Index
->refs(Req
, [&](const Ref
&R
) {
1537 auto LSPLoc
= toLSPLocation(R
.Location
, MainFilePath
);
1538 // Avoid indexed results for the main file - the AST is authoritative.
1540 (!AllowMainFileSymbols
&& LSPLoc
->uri
.file() == MainFilePath
))
1542 ReferencesResult::Reference Result
;
1543 Result
.Loc
= {std::move(*LSPLoc
), std::nullopt
};
1544 if (AllowAttributes
) {
1545 if ((R
.Kind
& RefKind::Declaration
) == RefKind::Declaration
)
1546 Result
.Attributes
|= ReferencesResult::Declaration
;
1547 // FIXME: our index should definitely store def | decl separately!
1548 if ((R
.Kind
& RefKind::Definition
) == RefKind::Definition
)
1549 Result
.Attributes
|=
1550 ReferencesResult::Declaration
| ReferencesResult::Definition
;
1553 SymbolID Container
= R
.Container
;
1554 ContainerLookup
.IDs
.insert(Container
);
1555 RefIndicesForContainer
[Container
].push_back(Results
.References
.size());
1557 Results
.References
.push_back(std::move(Result
));
1560 if (!ContainerLookup
.IDs
.empty() && AddContext
)
1561 Index
->lookup(ContainerLookup
, [&](const Symbol
&Container
) {
1562 auto Ref
= RefIndicesForContainer
.find(Container
.ID
);
1563 assert(Ref
!= RefIndicesForContainer
.end());
1564 auto ContainerName
= Container
.Scope
.str() + Container
.Name
.str();
1565 for (auto I
: Ref
->getSecond()) {
1566 Results
.References
[I
].Loc
.containerName
= ContainerName
;
1570 QueryIndex(std::move(IDsToQuery
), /*AllowAttributes=*/true,
1571 /*AllowMainFileSymbols=*/false);
1572 // For a virtual method: Occurrences of BaseMethod should be treated as refs
1573 // and not as decl/def. Allow symbols from main file since AST does not report
1575 QueryIndex(std::move(OverriddenMethods
), /*AllowAttributes=*/false,
1576 /*AllowMainFileSymbols=*/true);
1580 std::vector
<SymbolDetails
> getSymbolInfo(ParsedAST
&AST
, Position Pos
) {
1581 const SourceManager
&SM
= AST
.getSourceManager();
1582 auto CurLoc
= sourceLocationInMainFile(SM
, Pos
);
1584 llvm::consumeError(CurLoc
.takeError());
1587 auto MainFilePath
= AST
.tuPath();
1588 std::vector
<SymbolDetails
> Results
;
1590 // We also want the targets of using-decls, so we include
1591 // DeclRelation::Underlying.
1592 DeclRelationSet Relations
= DeclRelation::TemplatePattern
|
1593 DeclRelation::Alias
| DeclRelation::Underlying
;
1594 for (const NamedDecl
*D
: getDeclAtPosition(AST
, *CurLoc
, Relations
)) {
1595 D
= getPreferredDecl(D
);
1597 SymbolDetails NewSymbol
;
1598 std::string QName
= printQualifiedName(*D
);
1599 auto SplitQName
= splitQualifiedName(QName
);
1600 NewSymbol
.containerName
= std::string(SplitQName
.first
);
1601 NewSymbol
.name
= std::string(SplitQName
.second
);
1603 if (NewSymbol
.containerName
.empty()) {
1604 if (const auto *ParentND
=
1605 dyn_cast_or_null
<NamedDecl
>(D
->getDeclContext()))
1606 NewSymbol
.containerName
= printQualifiedName(*ParentND
);
1608 llvm::SmallString
<32> USR
;
1609 if (!index::generateUSRForDecl(D
, USR
)) {
1610 NewSymbol
.USR
= std::string(USR
);
1611 NewSymbol
.ID
= SymbolID(NewSymbol
.USR
);
1613 if (const NamedDecl
*Def
= getDefinition(D
))
1614 NewSymbol
.definitionRange
= makeLocation(
1615 AST
.getASTContext(), nameLocation(*Def
, SM
), MainFilePath
);
1616 NewSymbol
.declarationRange
=
1617 makeLocation(AST
.getASTContext(), nameLocation(*D
, SM
), MainFilePath
);
1619 Results
.push_back(std::move(NewSymbol
));
1622 const auto *IdentifierAtCursor
=
1623 syntax::spelledIdentifierTouching(*CurLoc
, AST
.getTokens());
1624 if (!IdentifierAtCursor
)
1627 if (auto M
= locateMacroAt(*IdentifierAtCursor
, AST
.getPreprocessor())) {
1628 SymbolDetails NewMacro
;
1629 NewMacro
.name
= std::string(M
->Name
);
1630 llvm::SmallString
<32> USR
;
1631 if (!index::generateUSRForMacro(NewMacro
.name
, M
->Info
->getDefinitionLoc(),
1633 NewMacro
.USR
= std::string(USR
);
1634 NewMacro
.ID
= SymbolID(NewMacro
.USR
);
1636 Results
.push_back(std::move(NewMacro
));
1642 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
, const LocatedSymbol
&S
) {
1643 OS
<< S
.Name
<< ": " << S
.PreferredDeclaration
;
1645 OS
<< " def=" << *S
.Definition
;
1649 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
,
1650 const ReferencesResult::Reference
&R
) {
1652 if (R
.Attributes
& ReferencesResult::Declaration
)
1654 if (R
.Attributes
& ReferencesResult::Definition
)
1656 if (R
.Attributes
& ReferencesResult::Override
)
1657 OS
<< " [override]";
1661 template <typename HierarchyItem
>
1662 static std::optional
<HierarchyItem
>
1663 declToHierarchyItem(const NamedDecl
&ND
, llvm::StringRef TUPath
) {
1664 ASTContext
&Ctx
= ND
.getASTContext();
1665 auto &SM
= Ctx
.getSourceManager();
1666 SourceLocation NameLoc
= nameLocation(ND
, Ctx
.getSourceManager());
1667 SourceLocation BeginLoc
= SM
.getFileLoc(ND
.getBeginLoc());
1668 SourceLocation EndLoc
= SM
.getFileLoc(ND
.getEndLoc());
1669 const auto DeclRange
=
1670 toHalfOpenFileRange(SM
, Ctx
.getLangOpts(), {BeginLoc
, EndLoc
});
1672 return std::nullopt
;
1673 const auto FE
= SM
.getFileEntryRefForID(SM
.getFileID(NameLoc
));
1675 return std::nullopt
;
1676 auto FilePath
= getCanonicalPath(*FE
, SM
.getFileManager());
1678 return std::nullopt
; // Not useful without a uri.
1680 Position NameBegin
= sourceLocToPosition(SM
, NameLoc
);
1681 Position NameEnd
= sourceLocToPosition(
1682 SM
, Lexer::getLocForEndOfToken(NameLoc
, 0, SM
, Ctx
.getLangOpts()));
1684 index::SymbolInfo SymInfo
= index::getSymbolInfo(&ND
);
1685 // FIXME: This is not classifying constructors, destructors and operators
1687 SymbolKind SK
= indexSymbolKindToSymbolKind(SymInfo
.Kind
);
1690 HI
.name
= printName(Ctx
, ND
);
1691 // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem?
1693 HI
.range
= Range
{sourceLocToPosition(SM
, DeclRange
->getBegin()),
1694 sourceLocToPosition(SM
, DeclRange
->getEnd())};
1695 HI
.selectionRange
= Range
{NameBegin
, NameEnd
};
1696 if (!HI
.range
.contains(HI
.selectionRange
)) {
1697 // 'selectionRange' must be contained in 'range', so in cases where clang
1698 // reports unrelated ranges we need to reconcile somehow.
1699 HI
.range
= HI
.selectionRange
;
1702 HI
.uri
= URIForFile::canonicalize(*FilePath
, TUPath
);
1707 static std::optional
<TypeHierarchyItem
>
1708 declToTypeHierarchyItem(const NamedDecl
&ND
, llvm::StringRef TUPath
) {
1709 auto Result
= declToHierarchyItem
<TypeHierarchyItem
>(ND
, TUPath
);
1711 Result
->deprecated
= ND
.isDeprecated();
1712 // Compute the SymbolID and store it in the 'data' field.
1713 // This allows typeHierarchy/resolve to be used to
1714 // resolve children of items returned in a previous request
1716 Result
->data
.symbolID
= getSymbolID(&ND
);
1721 static std::optional
<CallHierarchyItem
>
1722 declToCallHierarchyItem(const NamedDecl
&ND
, llvm::StringRef TUPath
) {
1723 auto Result
= declToHierarchyItem
<CallHierarchyItem
>(ND
, TUPath
);
1726 if (ND
.isDeprecated())
1727 Result
->tags
.push_back(SymbolTag::Deprecated
);
1728 if (auto ID
= getSymbolID(&ND
))
1729 Result
->data
= ID
.str();
1733 template <typename HierarchyItem
>
1734 static std::optional
<HierarchyItem
> symbolToHierarchyItem(const Symbol
&S
,
1736 auto Loc
= symbolToLocation(S
, TUPath
);
1738 elog("Failed to convert symbol to hierarchy item: {0}", Loc
.takeError());
1739 return std::nullopt
;
1742 HI
.name
= std::string(S
.Name
);
1743 HI
.detail
= (S
.Scope
+ S
.Name
).str();
1744 HI
.kind
= indexSymbolKindToSymbolKind(S
.SymInfo
.Kind
);
1745 HI
.selectionRange
= Loc
->range
;
1746 // FIXME: Populate 'range' correctly
1747 // (https://github.com/clangd/clangd/issues/59).
1748 HI
.range
= HI
.selectionRange
;
1754 static std::optional
<TypeHierarchyItem
>
1755 symbolToTypeHierarchyItem(const Symbol
&S
, PathRef TUPath
) {
1756 auto Result
= symbolToHierarchyItem
<TypeHierarchyItem
>(S
, TUPath
);
1758 Result
->deprecated
= (S
.Flags
& Symbol::Deprecated
);
1759 Result
->data
.symbolID
= S
.ID
;
1764 static std::optional
<CallHierarchyItem
>
1765 symbolToCallHierarchyItem(const Symbol
&S
, PathRef TUPath
) {
1766 auto Result
= symbolToHierarchyItem
<CallHierarchyItem
>(S
, TUPath
);
1769 Result
->data
= S
.ID
.str();
1770 if (S
.Flags
& Symbol::Deprecated
)
1771 Result
->tags
.push_back(SymbolTag::Deprecated
);
1775 static void fillSubTypes(const SymbolID
&ID
,
1776 std::vector
<TypeHierarchyItem
> &SubTypes
,
1777 const SymbolIndex
*Index
, int Levels
, PathRef TUPath
) {
1778 RelationsRequest Req
;
1779 Req
.Subjects
.insert(ID
);
1780 Req
.Predicate
= RelationKind::BaseOf
;
1781 Index
->relations(Req
, [&](const SymbolID
&Subject
, const Symbol
&Object
) {
1782 if (std::optional
<TypeHierarchyItem
> ChildSym
=
1783 symbolToTypeHierarchyItem(Object
, TUPath
)) {
1785 ChildSym
->children
.emplace();
1786 fillSubTypes(Object
.ID
, *ChildSym
->children
, Index
, Levels
- 1, TUPath
);
1788 SubTypes
.emplace_back(std::move(*ChildSym
));
1793 using RecursionProtectionSet
= llvm::SmallSet
<const CXXRecordDecl
*, 4>;
1795 // Extracts parents from AST and populates the type hierarchy item.
1796 static void fillSuperTypes(const CXXRecordDecl
&CXXRD
, llvm::StringRef TUPath
,
1797 TypeHierarchyItem
&Item
,
1798 RecursionProtectionSet
&RPSet
) {
1799 Item
.parents
.emplace();
1800 Item
.data
.parents
.emplace();
1801 // typeParents() will replace dependent template specializations
1802 // with their class template, so to avoid infinite recursion for
1803 // certain types of hierarchies, keep the templates encountered
1804 // along the parent chain in a set, and stop the recursion if one
1805 // starts to repeat.
1806 auto *Pattern
= CXXRD
.getDescribedTemplate() ? &CXXRD
: nullptr;
1808 if (!RPSet
.insert(Pattern
).second
) {
1813 for (const CXXRecordDecl
*ParentDecl
: typeParents(&CXXRD
)) {
1814 if (std::optional
<TypeHierarchyItem
> ParentSym
=
1815 declToTypeHierarchyItem(*ParentDecl
, TUPath
)) {
1816 fillSuperTypes(*ParentDecl
, TUPath
, *ParentSym
, RPSet
);
1817 Item
.data
.parents
->emplace_back(ParentSym
->data
);
1818 Item
.parents
->emplace_back(std::move(*ParentSym
));
1823 RPSet
.erase(Pattern
);
1827 std::vector
<const CXXRecordDecl
*> findRecordTypeAt(ParsedAST
&AST
,
1829 auto RecordFromNode
= [&AST
](const SelectionTree::Node
*N
) {
1830 std::vector
<const CXXRecordDecl
*> Records
;
1834 // Note: explicitReferenceTargets() will search for both template
1835 // instantiations and template patterns, and prefer the former if available
1836 // (generally, one will be available for non-dependent specializations of a
1838 auto Decls
= explicitReferenceTargets(N
->ASTNode
, DeclRelation::Underlying
,
1839 AST
.getHeuristicResolver());
1840 for (const NamedDecl
*D
: Decls
) {
1842 if (const VarDecl
*VD
= dyn_cast
<VarDecl
>(D
)) {
1843 // If this is a variable, use the type of the variable.
1844 if (const auto *RD
= VD
->getType().getTypePtr()->getAsCXXRecordDecl())
1845 Records
.push_back(RD
);
1849 if (const CXXMethodDecl
*Method
= dyn_cast
<CXXMethodDecl
>(D
)) {
1850 // If this is a method, use the type of the class.
1851 Records
.push_back(Method
->getParent());
1855 // We don't handle FieldDecl because it's not clear what behaviour
1856 // the user would expect: the enclosing class type (as with a
1857 // method), or the field's type (as with a variable).
1859 if (auto *RD
= dyn_cast
<CXXRecordDecl
>(D
))
1860 Records
.push_back(RD
);
1865 const SourceManager
&SM
= AST
.getSourceManager();
1866 std::vector
<const CXXRecordDecl
*> Result
;
1867 auto Offset
= positionToOffset(SM
.getBufferData(SM
.getMainFileID()), Pos
);
1869 llvm::consumeError(Offset
.takeError());
1872 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), *Offset
,
1873 *Offset
, [&](SelectionTree ST
) {
1874 Result
= RecordFromNode(ST
.commonAncestor());
1875 return !Result
.empty();
1880 // Return the type most associated with an AST node.
1881 // This isn't precisely defined: we want "go to type" to do something useful.
1882 static QualType
typeForNode(const SelectionTree::Node
*N
) {
1883 // If we're looking at a namespace qualifier, walk up to what it's qualifying.
1884 // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
1885 while (N
&& N
->ASTNode
.get
<NestedNameSpecifierLoc
>())
1890 // If we're pointing at a type => return it.
1891 if (const TypeLoc
*TL
= N
->ASTNode
.get
<TypeLoc
>()) {
1892 if (llvm::isa
<DeducedType
>(TL
->getTypePtr()))
1893 if (auto Deduced
= getDeducedType(
1894 N
->getDeclContext().getParentASTContext(), TL
->getBeginLoc()))
1896 // Exception: an alias => underlying type.
1897 if (llvm::isa
<TypedefType
>(TL
->getTypePtr()))
1898 return TL
->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1899 return TL
->getType();
1902 // Constructor initializers => the type of thing being initialized.
1903 if (const auto *CCI
= N
->ASTNode
.get
<CXXCtorInitializer
>()) {
1904 if (const FieldDecl
*FD
= CCI
->getAnyMember())
1905 return FD
->getType();
1906 if (const Type
*Base
= CCI
->getBaseClass())
1907 return QualType(Base
, 0);
1910 // Base specifier => the base type.
1911 if (const auto *CBS
= N
->ASTNode
.get
<CXXBaseSpecifier
>())
1912 return CBS
->getType();
1914 if (const Decl
*D
= N
->ASTNode
.get
<Decl
>()) {
1915 struct Visitor
: ConstDeclVisitor
<Visitor
, QualType
> {
1916 QualType
VisitValueDecl(const ValueDecl
*D
) { return D
->getType(); }
1917 // Declaration of a type => that type.
1918 QualType
VisitTypeDecl(const TypeDecl
*D
) {
1919 return QualType(D
->getTypeForDecl(), 0);
1921 // Exception: alias declaration => the underlying type, not the alias.
1922 QualType
VisitTypedefNameDecl(const TypedefNameDecl
*D
) {
1923 return D
->getUnderlyingType();
1925 // Look inside templates.
1926 QualType
VisitTemplateDecl(const TemplateDecl
*D
) {
1927 return Visit(D
->getTemplatedDecl());
1933 if (const Stmt
*S
= N
->ASTNode
.get
<Stmt
>()) {
1934 struct Visitor
: ConstStmtVisitor
<Visitor
, QualType
> {
1935 // Null-safe version of visit simplifies recursive calls below.
1936 QualType
type(const Stmt
*S
) { return S
? Visit(S
) : QualType(); }
1938 // In general, expressions => type of expression.
1939 QualType
VisitExpr(const Expr
*S
) {
1940 return S
->IgnoreImplicitAsWritten()->getType();
1942 QualType
VisitMemberExpr(const MemberExpr
*S
) {
1943 // The `foo` in `s.foo()` pretends not to have a real type!
1944 if (S
->getType()->isSpecificBuiltinType(BuiltinType::BoundMember
))
1945 return Expr::findBoundMemberType(S
);
1946 return VisitExpr(S
);
1948 // Exceptions for void expressions that operate on a type in some way.
1949 QualType
VisitCXXDeleteExpr(const CXXDeleteExpr
*S
) {
1950 return S
->getDestroyedType();
1952 QualType
VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr
*S
) {
1953 return S
->getDestroyedType();
1955 QualType
VisitCXXThrowExpr(const CXXThrowExpr
*S
) {
1956 return S
->getSubExpr()->getType();
1958 QualType
VisitCoyieldExpr(const CoyieldExpr
*S
) {
1959 return type(S
->getOperand());
1961 // Treat a designated initializer like a reference to the field.
1962 QualType
VisitDesignatedInitExpr(const DesignatedInitExpr
*S
) {
1963 // In .foo.bar we want to jump to bar's type, so find *last* field.
1964 for (auto &D
: llvm::reverse(S
->designators()))
1965 if (D
.isFieldDesignator())
1966 if (const auto *FD
= D
.getFieldDecl())
1967 return FD
->getType();
1971 // Control flow statements that operate on data: use the data type.
1972 QualType
VisitSwitchStmt(const SwitchStmt
*S
) {
1973 return type(S
->getCond());
1975 QualType
VisitWhileStmt(const WhileStmt
*S
) { return type(S
->getCond()); }
1976 QualType
VisitDoStmt(const DoStmt
*S
) { return type(S
->getCond()); }
1977 QualType
VisitIfStmt(const IfStmt
*S
) { return type(S
->getCond()); }
1978 QualType
VisitCaseStmt(const CaseStmt
*S
) { return type(S
->getLHS()); }
1979 QualType
VisitCXXForRangeStmt(const CXXForRangeStmt
*S
) {
1980 return S
->getLoopVariable()->getType();
1982 QualType
VisitReturnStmt(const ReturnStmt
*S
) {
1983 return type(S
->getRetValue());
1985 QualType
VisitCoreturnStmt(const CoreturnStmt
*S
) {
1986 return type(S
->getOperand());
1988 QualType
VisitCXXCatchStmt(const CXXCatchStmt
*S
) {
1989 return S
->getCaughtType();
1991 QualType
VisitObjCAtThrowStmt(const ObjCAtThrowStmt
*S
) {
1992 return type(S
->getThrowExpr());
1994 QualType
VisitObjCAtCatchStmt(const ObjCAtCatchStmt
*S
) {
1995 return S
->getCatchParamDecl() ? S
->getCatchParamDecl()->getType()
2005 // Given a type targeted by the cursor, return one or more types that are more interesting
2007 static void unwrapFindType(
2008 QualType T
, const HeuristicResolver
* H
, llvm::SmallVector
<QualType
>& Out
) {
2012 // If there's a specific type alias, point at that rather than unwrapping.
2013 if (const auto* TDT
= T
->getAs
<TypedefType
>())
2014 return Out
.push_back(QualType(TDT
, 0));
2016 // Pointers etc => pointee type.
2017 if (const auto *PT
= T
->getAs
<PointerType
>())
2018 return unwrapFindType(PT
->getPointeeType(), H
, Out
);
2019 if (const auto *RT
= T
->getAs
<ReferenceType
>())
2020 return unwrapFindType(RT
->getPointeeType(), H
, Out
);
2021 if (const auto *AT
= T
->getAsArrayTypeUnsafe())
2022 return unwrapFindType(AT
->getElementType(), H
, Out
);
2024 // Function type => return type.
2025 if (auto *FT
= T
->getAs
<FunctionType
>())
2026 return unwrapFindType(FT
->getReturnType(), H
, Out
);
2027 if (auto *CRD
= T
->getAsCXXRecordDecl()) {
2028 if (CRD
->isLambda())
2029 return unwrapFindType(CRD
->getLambdaCallOperator()->getReturnType(), H
,
2031 // FIXME: more cases we'd prefer the return type of the call operator?
2032 // std::function etc?
2035 // For smart pointer types, add the underlying type
2037 if (auto PointeeType
= H
->getPointeeType(T
.getNonReferenceType());
2038 !PointeeType
.isNull()) {
2039 unwrapFindType(PointeeType
, H
, Out
);
2040 return Out
.push_back(T
);
2043 return Out
.push_back(T
);
2046 // Convenience overload, to allow calling this without the out-parameter
2047 static llvm::SmallVector
<QualType
> unwrapFindType(
2048 QualType T
, const HeuristicResolver
* H
) {
2049 llvm::SmallVector
<QualType
> Result
;
2050 unwrapFindType(T
, H
, Result
);
2054 std::vector
<LocatedSymbol
> findType(ParsedAST
&AST
, Position Pos
,
2055 const SymbolIndex
*Index
) {
2056 const SourceManager
&SM
= AST
.getSourceManager();
2057 auto Offset
= positionToOffset(SM
.getBufferData(SM
.getMainFileID()), Pos
);
2058 std::vector
<LocatedSymbol
> Result
;
2060 elog("failed to convert position {0} for findTypes: {1}", Pos
,
2061 Offset
.takeError());
2064 // The general scheme is: position -> AST node -> type -> declaration.
2065 auto SymbolsFromNode
=
2066 [&](const SelectionTree::Node
*N
) -> std::vector
<LocatedSymbol
> {
2067 std::vector
<LocatedSymbol
> LocatedSymbols
;
2069 // NOTE: unwrapFindType might return duplicates for something like
2070 // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
2071 // information about the type you may have not known before
2072 // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
2073 for (const QualType
& Type
: unwrapFindType(typeForNode(N
), AST
.getHeuristicResolver()))
2074 llvm::copy(locateSymbolForType(AST
, Type
, Index
),
2075 std::back_inserter(LocatedSymbols
));
2077 return LocatedSymbols
;
2079 SelectionTree::createEach(AST
.getASTContext(), AST
.getTokens(), *Offset
,
2080 *Offset
, [&](SelectionTree ST
) {
2081 Result
= SymbolsFromNode(ST
.commonAncestor());
2082 return !Result
.empty();
2087 std::vector
<const CXXRecordDecl
*> typeParents(const CXXRecordDecl
*CXXRD
) {
2088 std::vector
<const CXXRecordDecl
*> Result
;
2090 // If this is an invalid instantiation, instantiation of the bases
2091 // may not have succeeded, so fall back to the template pattern.
2092 if (auto *CTSD
= dyn_cast
<ClassTemplateSpecializationDecl
>(CXXRD
)) {
2093 if (CTSD
->isInvalidDecl())
2094 CXXRD
= CTSD
->getSpecializedTemplate()->getTemplatedDecl();
2097 // Can't query bases without a definition.
2098 if (!CXXRD
->hasDefinition())
2101 for (auto Base
: CXXRD
->bases()) {
2102 const CXXRecordDecl
*ParentDecl
= nullptr;
2104 const Type
*Type
= Base
.getType().getTypePtr();
2105 if (const RecordType
*RT
= Type
->getAs
<RecordType
>()) {
2106 ParentDecl
= RT
->getAsCXXRecordDecl();
2110 // Handle a dependent base such as "Base<T>" by using the primary
2112 if (const TemplateSpecializationType
*TS
=
2113 Type
->getAs
<TemplateSpecializationType
>()) {
2114 TemplateName TN
= TS
->getTemplateName();
2115 if (TemplateDecl
*TD
= TN
.getAsTemplateDecl()) {
2116 ParentDecl
= dyn_cast
<CXXRecordDecl
>(TD
->getTemplatedDecl());
2122 Result
.push_back(ParentDecl
);
2128 std::vector
<TypeHierarchyItem
>
2129 getTypeHierarchy(ParsedAST
&AST
, Position Pos
, int ResolveLevels
,
2130 TypeHierarchyDirection Direction
, const SymbolIndex
*Index
,
2132 std::vector
<TypeHierarchyItem
> Results
;
2133 for (const auto *CXXRD
: findRecordTypeAt(AST
, Pos
)) {
2135 bool WantChildren
= Direction
== TypeHierarchyDirection::Children
||
2136 Direction
== TypeHierarchyDirection::Both
;
2138 // If we're looking for children, we're doing the lookup in the index.
2139 // The index does not store relationships between implicit
2140 // specializations, so if we have one, use the template pattern instead.
2141 // Note that this needs to be done before the declToTypeHierarchyItem(),
2142 // otherwise the type hierarchy item would misleadingly contain the
2143 // specialization parameters, while the children would involve classes
2144 // that derive from other specializations of the template.
2146 if (auto *CTSD
= dyn_cast
<ClassTemplateSpecializationDecl
>(CXXRD
))
2147 CXXRD
= CTSD
->getTemplateInstantiationPattern();
2150 std::optional
<TypeHierarchyItem
> Result
=
2151 declToTypeHierarchyItem(*CXXRD
, AST
.tuPath());
2155 RecursionProtectionSet RPSet
;
2156 fillSuperTypes(*CXXRD
, AST
.tuPath(), *Result
, RPSet
);
2158 if (WantChildren
&& ResolveLevels
> 0) {
2159 Result
->children
.emplace();
2162 if (auto ID
= getSymbolID(CXXRD
))
2163 fillSubTypes(ID
, *Result
->children
, Index
, ResolveLevels
, TUPath
);
2166 Results
.emplace_back(std::move(*Result
));
2172 std::optional
<std::vector
<TypeHierarchyItem
>>
2173 superTypes(const TypeHierarchyItem
&Item
, const SymbolIndex
*Index
) {
2174 std::vector
<TypeHierarchyItem
> Results
;
2175 if (!Item
.data
.parents
)
2176 return std::nullopt
;
2177 if (Item
.data
.parents
->empty())
2180 llvm::DenseMap
<SymbolID
, const TypeHierarchyItem::ResolveParams
*> IDToData
;
2181 for (const auto &Parent
: *Item
.data
.parents
) {
2182 Req
.IDs
.insert(Parent
.symbolID
);
2183 IDToData
[Parent
.symbolID
] = &Parent
;
2185 Index
->lookup(Req
, [&Item
, &Results
, &IDToData
](const Symbol
&S
) {
2186 if (auto THI
= symbolToTypeHierarchyItem(S
, Item
.uri
.file())) {
2187 THI
->data
= *IDToData
.lookup(S
.ID
);
2188 Results
.emplace_back(std::move(*THI
));
2194 std::vector
<TypeHierarchyItem
> subTypes(const TypeHierarchyItem
&Item
,
2195 const SymbolIndex
*Index
) {
2196 std::vector
<TypeHierarchyItem
> Results
;
2197 fillSubTypes(Item
.data
.symbolID
, Results
, Index
, 1, Item
.uri
.file());
2198 for (auto &ChildSym
: Results
)
2199 ChildSym
.data
.parents
= {Item
.data
};
2203 void resolveTypeHierarchy(TypeHierarchyItem
&Item
, int ResolveLevels
,
2204 TypeHierarchyDirection Direction
,
2205 const SymbolIndex
*Index
) {
2206 // We only support typeHierarchy/resolve for children, because for parents
2207 // we ignore ResolveLevels and return all levels of parents eagerly.
2208 if (!Index
|| Direction
== TypeHierarchyDirection::Parents
||
2212 Item
.children
.emplace();
2213 fillSubTypes(Item
.data
.symbolID
, *Item
.children
, Index
, ResolveLevels
,
2217 std::vector
<CallHierarchyItem
>
2218 prepareCallHierarchy(ParsedAST
&AST
, Position Pos
, PathRef TUPath
) {
2219 std::vector
<CallHierarchyItem
> Result
;
2220 const auto &SM
= AST
.getSourceManager();
2221 auto Loc
= sourceLocationInMainFile(SM
, Pos
);
2223 elog("prepareCallHierarchy failed to convert position to source location: "
2228 for (const NamedDecl
*Decl
: getDeclAtPosition(AST
, *Loc
, {})) {
2229 if (!(isa
<DeclContext
>(Decl
) &&
2230 cast
<DeclContext
>(Decl
)->isFunctionOrMethod()) &&
2231 Decl
->getKind() != Decl::Kind::FunctionTemplate
&&
2232 !(Decl
->getKind() == Decl::Kind::Var
&&
2233 !cast
<VarDecl
>(Decl
)->isLocalVarDecl()) &&
2234 Decl
->getKind() != Decl::Kind::Field
)
2236 if (auto CHI
= declToCallHierarchyItem(*Decl
, AST
.tuPath()))
2237 Result
.emplace_back(std::move(*CHI
));
2242 std::vector
<CallHierarchyIncomingCall
>
2243 incomingCalls(const CallHierarchyItem
&Item
, const SymbolIndex
*Index
) {
2244 std::vector
<CallHierarchyIncomingCall
> Results
;
2245 if (!Index
|| Item
.data
.empty())
2247 auto ID
= SymbolID::fromStr(Item
.data
);
2249 elog("incomingCalls failed to find symbol: {0}", ID
.takeError());
2252 // In this function, we find incoming calls based on the index only.
2253 // In principle, the AST could have more up-to-date information about
2254 // occurrences within the current file. However, going from a SymbolID
2255 // to an AST node isn't cheap, particularly when the declaration isn't
2256 // in the main file.
2257 // FIXME: Consider also using AST information when feasible.
2258 RefsRequest Request
;
2259 Request
.IDs
.insert(*ID
);
2260 Request
.WantContainer
= true;
2261 // We could restrict more specifically to calls by introducing a new RefKind,
2262 // but non-call references (such as address-of-function) can still be
2263 // interesting as they can indicate indirect calls.
2264 Request
.Filter
= RefKind::Reference
;
2265 // Initially store the ranges in a map keyed by SymbolID of the caller.
2266 // This allows us to group different calls with the same caller
2267 // into the same CallHierarchyIncomingCall.
2268 llvm::DenseMap
<SymbolID
, std::vector
<Location
>> CallsIn
;
2269 // We can populate the ranges based on a refs request only. As we do so, we
2270 // also accumulate the container IDs into a lookup request.
2271 LookupRequest ContainerLookup
;
2272 Index
->refs(Request
, [&](const Ref
&R
) {
2273 auto Loc
= indexToLSPLocation(R
.Location
, Item
.uri
.file());
2275 elog("incomingCalls failed to convert location: {0}", Loc
.takeError());
2278 CallsIn
[R
.Container
].push_back(*Loc
);
2280 ContainerLookup
.IDs
.insert(R
.Container
);
2282 // Perform the lookup request and combine its results with CallsIn to
2283 // get complete CallHierarchyIncomingCall objects.
2284 Index
->lookup(ContainerLookup
, [&](const Symbol
&Caller
) {
2285 auto It
= CallsIn
.find(Caller
.ID
);
2286 assert(It
!= CallsIn
.end());
2287 if (auto CHI
= symbolToCallHierarchyItem(Caller
, Item
.uri
.file())) {
2288 std::vector
<Range
> FromRanges
;
2289 for (const Location
&L
: It
->second
) {
2290 if (L
.uri
!= CHI
->uri
) {
2291 // Call location not in same file as caller.
2292 // This can happen in some edge cases. There's not much we can do,
2293 // since the protocol only allows returning ranges interpreted as
2294 // being in the caller's file.
2297 FromRanges
.push_back(L
.range
);
2300 CallHierarchyIncomingCall
{std::move(*CHI
), std::move(FromRanges
)});
2303 // Sort results by name of container.
2304 llvm::sort(Results
, [](const CallHierarchyIncomingCall
&A
,
2305 const CallHierarchyIncomingCall
&B
) {
2306 return A
.from
.name
< B
.from
.name
;
2311 std::vector
<CallHierarchyOutgoingCall
>
2312 outgoingCalls(const CallHierarchyItem
&Item
, const SymbolIndex
*Index
) {
2313 std::vector
<CallHierarchyOutgoingCall
> Results
;
2314 if (!Index
|| Item
.data
.empty())
2316 auto ID
= SymbolID::fromStr(Item
.data
);
2318 elog("outgoingCalls failed to find symbol: {0}", ID
.takeError());
2321 // In this function, we find outgoing calls based on the index only.
2322 ContainedRefsRequest Request
;
2324 // Initially store the ranges in a map keyed by SymbolID of the callee.
2325 // This allows us to group different calls to the same function
2326 // into the same CallHierarchyOutgoingCall.
2327 llvm::DenseMap
<SymbolID
, std::vector
<Range
>> CallsOut
;
2328 // We can populate the ranges based on a refs request only. As we do so, we
2329 // also accumulate the callee IDs into a lookup request.
2330 LookupRequest CallsOutLookup
;
2331 Index
->containedRefs(Request
, [&](const auto &R
) {
2332 auto Loc
= indexToLSPLocation(R
.Location
, Item
.uri
.file());
2334 elog("outgoingCalls failed to convert location: {0}", Loc
.takeError());
2337 auto It
= CallsOut
.try_emplace(R
.Symbol
, std::vector
<Range
>{}).first
;
2338 It
->second
.push_back(Loc
->range
);
2340 CallsOutLookup
.IDs
.insert(R
.Symbol
);
2342 // Perform the lookup request and combine its results with CallsOut to
2343 // get complete CallHierarchyOutgoingCall objects.
2344 Index
->lookup(CallsOutLookup
, [&](const Symbol
&Callee
) {
2345 // The containedRefs request should only return symbols which are
2346 // function-like, i.e. symbols for which references to them can be "calls".
2347 using SK
= index::SymbolKind
;
2348 auto Kind
= Callee
.SymInfo
.Kind
;
2349 assert(Kind
== SK::Function
|| Kind
== SK::InstanceMethod
||
2350 Kind
== SK::ClassMethod
|| Kind
== SK::StaticMethod
||
2351 Kind
== SK::Constructor
|| Kind
== SK::Destructor
||
2352 Kind
== SK::ConversionFunction
);
2356 auto It
= CallsOut
.find(Callee
.ID
);
2357 assert(It
!= CallsOut
.end());
2358 if (auto CHI
= symbolToCallHierarchyItem(Callee
, Item
.uri
.file()))
2360 CallHierarchyOutgoingCall
{std::move(*CHI
), std::move(It
->second
)});
2362 // Sort results by name of the callee.
2363 llvm::sort(Results
, [](const CallHierarchyOutgoingCall
&A
,
2364 const CallHierarchyOutgoingCall
&B
) {
2365 return A
.to
.name
< B
.to
.name
;
2370 llvm::DenseSet
<const Decl
*> getNonLocalDeclRefs(ParsedAST
&AST
,
2371 const FunctionDecl
*FD
) {
2374 llvm::DenseSet
<const Decl
*> DeclRefs
;
2375 findExplicitReferences(
2377 [&](ReferenceLoc Ref
) {
2378 for (const Decl
*D
: Ref
.Targets
) {
2379 if (!index::isFunctionLocalSymbol(D
) && !D
->isTemplateParameter() &&
2384 AST
.getHeuristicResolver());
2388 } // namespace clangd
2389 } // namespace clang