clang-tools 24.0.0git
XRefs.cpp
Go to the documentation of this file.
1//===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#include "XRefs.h"
9#include "AST.h"
10#include "FindSymbols.h"
11#include "FindTarget.h"
12#include "Headers.h"
13#include "IncludeCleaner.h"
14#include "ParsedAST.h"
15#include "Protocol.h"
16#include "Quality.h"
17#include "Selection.h"
18#include "SourceCode.h"
19#include "clang-include-cleaner/Analysis.h"
20#include "clang-include-cleaner/Types.h"
21#include "index/Index.h"
22#include "index/Merge.h"
23#include "index/Ref.h"
24#include "index/Relation.h"
26#include "index/SymbolID.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/AST/TypeLoc.h"
45#include "clang/Basic/LLVM.h"
46#include "clang/Basic/Module.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/Lex/Lexer.h"
55#include "clang/Sema/HeuristicResolver.h"
56#include "clang/Tooling/Syntax/Tokens.h"
57#include "clang/UnifiedSymbolResolution/USRGeneration.h"
58#include "llvm/ADT/ArrayRef.h"
59#include "llvm/ADT/DenseMap.h"
60#include "llvm/ADT/DenseSet.h"
61#include "llvm/ADT/STLExtras.h"
62#include "llvm/ADT/ScopeExit.h"
63#include "llvm/ADT/SmallVector.h"
64#include "llvm/ADT/StringRef.h"
65#include "llvm/Support/Casting.h"
66#include "llvm/Support/Error.h"
67#include "llvm/Support/ErrorHandling.h"
68#include "llvm/Support/Path.h"
69#include "llvm/Support/raw_ostream.h"
70#include <algorithm>
71#include <optional>
72#include <string>
73#include <vector>
74
75namespace clang {
76namespace clangd {
77namespace {
78
79// Returns the single definition of the entity declared by D, if visible.
80// In particular:
81// - for non-redeclarable kinds (e.g. local vars), return D
82// - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
83// Kinds of nodes that always return nullptr here will not have definitions
84// reported by locateSymbolAt().
85const NamedDecl *getDefinition(const NamedDecl *D) {
86 assert(D);
87 // Decl has one definition that we can find.
88 if (const auto *TD = dyn_cast<TagDecl>(D))
89 return TD->getDefinition();
90 if (const auto *VD = dyn_cast<VarDecl>(D))
91 return VD->getDefinition();
92 if (const auto *FD = dyn_cast<FunctionDecl>(D))
93 return FD->getDefinition();
94 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
95 if (const auto *RD = CTD->getTemplatedDecl())
96 return RD->getDefinition();
97 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
98 if (MD->isThisDeclarationADefinition())
99 return MD;
100 // Look for the method definition inside the implementation decl.
101 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
102 if (DeclCtx->isInvalidDecl())
103 return nullptr;
104
105 if (const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
106 if (const auto *Impl = getCorrespondingObjCImpl(CD))
107 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
108 }
109 if (const auto *CD = dyn_cast<ObjCContainerDecl>(D))
110 return getCorrespondingObjCImpl(CD);
111 // Only a single declaration is allowed.
112 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
113 isa<TemplateTemplateParmDecl>(D)) // except cases above
114 return D;
115 // Multiple definitions are allowed.
116 return nullptr; // except cases above
117}
118
119void logIfOverflow(const SymbolLocation &Loc) {
120 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
121 log("Possible overflow in symbol location: {0}", Loc);
122}
123
124// Convert a SymbolLocation to LSP's Location.
125// TUPath is used to resolve the path of URI.
126std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
127 llvm::StringRef TUPath) {
128 if (!Loc)
129 return std::nullopt;
130 auto LSPLoc = indexToLSPLocation(Loc, TUPath);
131 if (!LSPLoc) {
132 elog("{0}", LSPLoc.takeError());
133 return std::nullopt;
134 }
135 logIfOverflow(Loc);
136 return *LSPLoc;
137}
138
139SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
140 SymbolLocation SymLoc;
141 URIStorage = Loc.uri.uri();
142 SymLoc.FileURI = URIStorage.c_str();
143 SymLoc.Start.setLine(Loc.range.start.line);
144 SymLoc.Start.setColumn(Loc.range.start.character);
145 SymLoc.End.setLine(Loc.range.end.line);
146 SymLoc.End.setColumn(Loc.range.end.character);
147 return SymLoc;
148}
149
150// Returns the preferred location between an AST location and an index location.
151SymbolLocation getPreferredLocation(const Location &ASTLoc,
152 const SymbolLocation &IdxLoc,
153 std::string &Scratch) {
154 // Also use a mock symbol for the index location so that other fields (e.g.
155 // definition) are not factored into the preference.
156 Symbol ASTSym, IdxSym;
157 ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
158 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
159 IdxSym.CanonicalDeclaration = IdxLoc;
160 auto Merged = mergeSymbol(ASTSym, IdxSym);
161 return Merged.CanonicalDeclaration;
162}
163
164std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
165getDeclAtPositionWithRelations(ParsedAST &AST, SourceLocation Pos,
166 DeclRelationSet Relations,
167 ASTNodeKind *NodeKind = nullptr) {
168 unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
169 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
170 auto ResultFromTree = [&](SelectionTree ST) {
171 if (const SelectionTree::Node *N = ST.commonAncestor()) {
172 if (NodeKind)
173 *NodeKind = N->ASTNode.getNodeKind();
174 // Attributes don't target decls, look at the
175 // thing it's attached to.
176 // We still report the original NodeKind!
177 // This makes the `override` hack work.
178 if (N->ASTNode.get<Attr>() && N->Parent)
179 N = N->Parent;
180 llvm::copy_if(allTargetDecls(N->ASTNode, AST.getHeuristicResolver()),
181 std::back_inserter(Result),
182 [&](auto &Entry) { return !(Entry.second & ~Relations); });
183 }
184 return !Result.empty();
185 };
186 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
187 Offset, ResultFromTree);
188 return Result;
189}
190
191std::vector<const NamedDecl *>
192getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,
193 ASTNodeKind *NodeKind = nullptr) {
194 std::vector<const NamedDecl *> Result;
195 for (auto &Entry :
196 getDeclAtPositionWithRelations(AST, Pos, Relations, NodeKind))
197 Result.push_back(Entry.first);
198 return Result;
199}
200
201// Returns the deepest CallExpr whose selection-tree commonAncestor is the call
202// itself at `Loc` (i.e. the cursor lands on the call's parens area, not on a
203// child like the callee identifier or an argument). Returns null otherwise.
204const CallExpr *findEnclosingCallAt(ParsedAST &AST, SourceLocation Loc) {
205 unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Loc).second;
206 const CallExpr *Found = nullptr;
207 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
208 Offset, [&](SelectionTree ST) {
209 if (const SelectionTree::Node *N =
210 ST.commonAncestor())
211 Found = N->ASTNode.get<CallExpr>();
212 return true;
213 });
214 return Found;
215}
216
217// Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
218// figure out a filename.
219std::optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,
220 llvm::StringRef TUPath) {
221 const auto &SM = AST.getSourceManager();
222 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
223 if (!F)
224 return std::nullopt;
225 auto FilePath = getCanonicalPath(*F, SM.getFileManager());
226 if (!FilePath) {
227 log("failed to get path!");
228 return std::nullopt;
229 }
230 Location L;
231 L.uri = URIForFile::canonicalize(*FilePath, TUPath);
232 // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
233 // outside the main file.
234 auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());
235 L.range = halfOpenToRange(
236 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
237 return L;
238}
239
240std::optional<LocatedSymbol>
241locateModuleReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
242 llvm::StringRef MainFilePath) {
243 const SourceManager &SM = AST.getSourceManager();
244 const ASTContext &Context = AST.getASTContext();
245
246 const Module *ResultModule = nullptr;
247
248 for (const ImportDecl *Import : Context.local_imports()) {
249 const Module *Imported = Import->getImportedModule();
250 ArrayRef<SourceLocation> IdentifierLocs = Import->getIdentifierLocs();
251 if (!Imported || !Imported->isNamedModule() || IdentifierLocs.empty())
252 continue;
253
254 const SourceLocation NameBegin = SM.getSpellingLoc(IdentifierLocs.front());
255 // Imports are visited in source order; bail out once we pass the cursor.
256 if (SM.isBeforeInTranslationUnit(TouchedIdentifier.location(), NameBegin))
257 break;
258
259 const std::string FullName = Imported->getFullModuleName();
260 const SourceLocation NameEnd =
261 NameBegin.getLocWithOffset(FullName.size() - 1);
262
263 if (SM.isPointWithin(TouchedIdentifier.location(), NameBegin, NameEnd)) {
264 ResultModule = Imported;
265 break;
266 }
267 }
268
269 if (!ResultModule)
270 return std::nullopt;
271
272 const SourceLocation DefinitionLoc =
273 SM.getSpellingLoc(ResultModule->DefinitionLoc);
274 auto Definition = makeLocation(Context, DefinitionLoc, MainFilePath);
275
276 if (!Definition)
277 return std::nullopt;
278
279 LocatedSymbol Result;
280 Result.Name = ResultModule->getFullModuleName();
281 Result.PreferredDeclaration = *Definition;
282 Result.Definition = *Definition;
283 return Result;
284}
285
286// Treat #included files as symbols, to enable go-to-definition on them.
287std::optional<LocatedSymbol> locateFileReferent(const Position &Pos,
288 ParsedAST &AST,
289 llvm::StringRef MainFilePath) {
290 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
291 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
293 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
294 File.PreferredDeclaration = {
295 URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
296 File.Definition = File.PreferredDeclaration;
297 // We're not going to find any further symbols on #include lines.
298 return File;
299 }
300 }
301 return std::nullopt;
302}
303
304// Macros are simple: there's no declaration/definition distinction.
305// As a consequence, there's no need to look them up in the index either.
306std::optional<LocatedSymbol>
307locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
308 llvm::StringRef MainFilePath) {
309 if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
310 if (auto Loc =
311 makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {
313 Macro.Name = std::string(M->Name);
314 Macro.PreferredDeclaration = *Loc;
315 Macro.Definition = std::move(Loc);
316 Macro.ID = getSymbolID(M->Name, M->Info, AST.getSourceManager());
317 return Macro;
318 }
319 }
320 return std::nullopt;
321}
322
323// A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
324// definition of a canonical declaration doesn't match up to what a programmer
325// would expect. For example, Objective-C classes can have three types of
326// declarations:
327//
328// - forward declaration(s): @class MyClass;
329// - true declaration (interface definition): @interface MyClass ... @end
330// - true definition (implementation): @implementation MyClass ... @end
331//
332// Clang will consider the forward declaration to be the canonical declaration
333// because it is first. We actually want the class definition if it is
334// available since that is what a programmer would consider the primary
335// declaration to be.
336const NamedDecl *getPreferredDecl(const NamedDecl *D) {
337 // FIXME: Canonical declarations of some symbols might refer to built-in
338 // decls with possibly-invalid source locations (e.g. global new operator).
339 // In such cases we should pick up a redecl with valid source location
340 // instead of failing.
341 D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
342
343 // Prefer Objective-C class/protocol definitions over the forward declaration.
344 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
345 if (const auto *DefinitionID = ID->getDefinition())
346 return DefinitionID;
347 if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
348 if (const auto *DefinitionID = PD->getDefinition())
349 return DefinitionID;
350
351 return D;
352}
353
354std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
355 RelationKind Predicate,
356 const SymbolIndex *Index,
357 llvm::StringRef MainFilePath) {
358 if (IDs.empty() || !Index)
359 return {};
360 static constexpr trace::Metric FindImplementorsMetric(
361 "find_implementors", trace::Metric::Counter, "case");
362 switch (Predicate) {
364 FindImplementorsMetric.record(1, "find-base");
365 break;
367 FindImplementorsMetric.record(1, "find-override");
368 break;
369 }
370
372 Req.Predicate = Predicate;
373 llvm::DenseSet<SymbolID> SeenIDs;
374 llvm::DenseSet<SymbolID> Queue = std::move(IDs);
375 std::vector<LocatedSymbol> Results;
376 while (!Queue.empty()) {
377 Req.Subjects = std::move(Queue);
378 Queue = {};
379 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
380 if (!SeenIDs.insert(Object.ID).second)
381 return;
382 Queue.insert(Object.ID);
383 auto DeclLoc =
384 indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
385 if (!DeclLoc) {
386 elog("Find overrides: {0}", DeclLoc.takeError());
387 return;
388 }
389 Results.emplace_back();
390 Results.back().Name = Object.Name.str();
391 Results.back().PreferredDeclaration = *DeclLoc;
392 auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
393 if (!DefLoc) {
394 elog("Failed to convert location: {0}", DefLoc.takeError());
395 return;
396 }
397 Results.back().Definition = *DefLoc;
398 });
399 }
400 return Results;
401}
402
403// Given LocatedSymbol results derived from the AST, query the index to obtain
404// definitions and preferred declarations.
405void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
406 const SymbolIndex *Index,
407 llvm::StringRef MainFilePath) {
408 LookupRequest QueryRequest;
409 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
410 for (unsigned I = 0; I < Result.size(); ++I) {
411 if (auto ID = Result[I].ID) {
412 ResultIndex.try_emplace(ID, I);
413 QueryRequest.IDs.insert(ID);
414 }
415 }
416 if (!Index || QueryRequest.IDs.empty())
417 return;
418 std::string Scratch;
419 Index->lookup(QueryRequest, [&](const Symbol &Sym) {
420 auto &R = Result[ResultIndex.lookup(Sym.ID)];
421
422 if (R.Definition) { // from AST
423 // Special case: if the AST yielded a definition, then it may not be
424 // the right *declaration*. Prefer the one from the index.
425 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
426 R.PreferredDeclaration = *Loc;
427
428 // We might still prefer the definition from the index, e.g. for
429 // generated symbols.
430 if (auto Loc = toLSPLocation(
431 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
432 MainFilePath))
433 R.Definition = *Loc;
434 } else {
435 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
436
437 // Use merge logic to choose AST or index declaration.
438 if (auto Loc = toLSPLocation(
439 getPreferredLocation(R.PreferredDeclaration,
440 Sym.CanonicalDeclaration, Scratch),
441 MainFilePath))
442 R.PreferredDeclaration = *Loc;
443 }
444 });
445}
446
447bool objcMethodIsTouched(const SourceManager &SM, const ObjCMethodDecl *OMD,
448 SourceLocation Loc) {
449 unsigned NumSels = OMD->getNumSelectorLocs();
450 for (unsigned I = 0; I < NumSels; ++I)
451 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
452 return true;
453 return false;
454}
455
456// Decls are more complicated.
457// The AST contains at least a declaration, maybe a definition.
458// These are up-to-date, and so generally preferred over index results.
459// We perform a single batch index lookup to find additional definitions.
460std::vector<LocatedSymbol>
461locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
462 ParsedAST &AST, llvm::StringRef MainFilePath,
463 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
464 const SourceManager &SM = AST.getSourceManager();
465 // Results follow the order of Symbols.Decls.
466 std::vector<LocatedSymbol> Result;
467
468 static constexpr trace::Metric LocateASTReferentMetric(
469 "locate_ast_referent", trace::Metric::Counter, "case");
470 auto AddResultDecl = [&](const NamedDecl *D) {
471 D = getPreferredDecl(D);
472 auto Loc =
473 makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
474 if (!Loc)
475 return;
476
477 Result.emplace_back();
478 Result.back().Name = printName(AST.getASTContext(), *D);
479 Result.back().PreferredDeclaration = *Loc;
480 Result.back().ID = getSymbolID(D);
481 if (const NamedDecl *Def = getDefinition(D))
482 Result.back().Definition = makeLocation(
483 AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
484 };
485
486 // Special case: if the cursor lands directly on a call expression (i.e.
487 // its enclosing SelectionTree node is the CallExpr itself, not the callee
488 // identifier or an argument), and the call invokes a forwarding wrapper
489 // such as `std::make_unique<T>(...)`, navigate to the constructor of `T`
490 // that the wrapper ultimately calls. This mirrors the existing
491 // constructor-call behaviour: `Abc^()` jumps to the constructor while
492 // `A^bc()` jumps to the type. The hook does not fire when the cursor is
493 // on the wrapper's identifier; that path continues to navigate to the
494 // wrapper itself via the candidate loop below.
495 if (const auto *CE = findEnclosingCallAt(AST, CurLoc)) {
496 if (const auto *Callee = CE->getDirectCallee()) {
497 llvm::SmallPtrSet<const CXXConstructorDecl *, 1> Seen;
498 for (const auto *Ctor :
499 getForwardedConstructors(Callee, AST.ForwardingToConstructorCache))
500 if (Seen.insert(Ctor).second) {
501 LocateASTReferentMetric.record(1, "forwarded-constructor");
502 AddResultDecl(Ctor);
503 }
504 }
505 }
506 if (!Result.empty()) {
507 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
508 return Result;
509 }
510
511 // Emit all symbol locations (declaration or definition) from AST.
512 DeclRelationSet Relations =
514 auto Candidates =
515 getDeclAtPositionWithRelations(AST, CurLoc, Relations, &NodeKind);
516 llvm::DenseSet<SymbolID> VirtualMethods;
517 for (const auto &E : Candidates) {
518 const NamedDecl *D = E.first;
519 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
520 // Special case: virtual void ^method() = 0: jump to all overrides.
521 // FIXME: extend it to ^virtual, unfortunately, virtual location is not
522 // saved in the AST.
523 if (CMD->isPureVirtual()) {
524 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
525 TouchedIdentifier->location()) {
526 VirtualMethods.insert(getSymbolID(CMD));
527 LocateASTReferentMetric.record(1, "method-to-override");
528 }
529 }
530 // Special case: void foo() ^override: jump to the overridden method.
531 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
532 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
533 // We may be overridding multiple methods - offer them all.
534 for (const NamedDecl *ND : CMD->overridden_methods())
535 AddResultDecl(ND);
536 continue;
537 }
538 }
539 // Special case: - (void)^method {} should jump to overrides, but the decl
540 // shouldn't, only the definition. Note that an Objective-C method can
541 // override a parent class or protocol.
542 //
543 // FIXME: Support jumping from a protocol decl to overrides on go-to
544 // definition.
545 if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
546 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
547 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
548 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
549 OMD->getOverriddenMethods(Overrides);
550 if (!Overrides.empty()) {
551 for (const auto *Override : Overrides)
552 AddResultDecl(Override);
553 LocateASTReferentMetric.record(1, "objc-overriden-method");
554 }
555 AddResultDecl(OMD);
556 continue;
557 }
558 }
559
560 // Special case: the cursor is on an alias, prefer other results.
561 // This targets "using ns::^Foo", where the target is more interesting.
562 // This does not trigger on renaming aliases:
563 // `using Foo = ^Bar` already targets Bar via a TypeLoc
564 // `using ^Foo = Bar` has no other results, as Underlying is filtered.
565 if (E.second & DeclRelation::Alias && Candidates.size() > 1 &&
566 // beginLoc/endLoc are a token range, so rewind the identifier we're in.
567 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
568 : CurLoc,
569 D->getBeginLoc(), D->getEndLoc()))
570 continue;
571
572 // Special case: the point of declaration of a template specialization,
573 // it's more useful to navigate to the template declaration.
574 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
575 if (TouchedIdentifier &&
576 D->getLocation() == TouchedIdentifier->location()) {
577 LocateASTReferentMetric.record(1, "template-specialization-to-primary");
578 AddResultDecl(CTSD->getSpecializedTemplate());
579 continue;
580 }
581 }
582
583 // Special case: if the class name is selected, also map Objective-C
584 // categories and category implementations back to their class interface.
585 //
586 // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`
587 // instead of the `ObjCCategoryDecl` we intentionally check the contents
588 // of the locs when checking for class name equivalence.
589 if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
590 if (const auto *ID = CD->getClassInterface())
591 if (TouchedIdentifier &&
592 (CD->getLocation() == TouchedIdentifier->location() ||
593 ID->getName() == TouchedIdentifier->text(SM))) {
594 LocateASTReferentMetric.record(1, "objc-category-to-class");
595 AddResultDecl(ID);
596 }
597
598 LocateASTReferentMetric.record(1, "regular");
599 // Otherwise the target declaration is the right one.
600 AddResultDecl(D);
601 }
602 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
603
604 auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy,
605 Index, MainFilePath);
606 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
607 return Result;
608}
609
610std::vector<LocatedSymbol> locateSymbolForType(const ParsedAST &AST,
611 const QualType &Type,
612 const SymbolIndex *Index) {
613 const auto &SM = AST.getSourceManager();
614 auto MainFilePath = AST.tuPath();
615
616 // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.
617 // Likely it would be better to send it to Foo (heuristically) or to both.
618 auto Decls = targetDecl(DynTypedNode::create(Type.getNonReferenceType()),
620 AST.getHeuristicResolver());
621 if (Decls.empty())
622 return {};
623
624 std::vector<LocatedSymbol> Results;
625 const auto &ASTContext = AST.getASTContext();
626
627 for (const NamedDecl *D : Decls) {
628 D = getPreferredDecl(D);
629
630 auto Loc = makeLocation(ASTContext, nameLocation(*D, SM), MainFilePath);
631 if (!Loc)
632 continue;
633
634 Results.emplace_back();
635 Results.back().Name = printName(ASTContext, *D);
636 Results.back().PreferredDeclaration = *Loc;
637 Results.back().ID = getSymbolID(D);
638 if (const NamedDecl *Def = getDefinition(D))
639 Results.back().Definition =
640 makeLocation(ASTContext, nameLocation(*Def, SM), MainFilePath);
641 }
642 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
643
644 return Results;
645}
646
647bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {
648 auto ExpandedTokens = TB.expandedTokens(
649 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
650 return !ExpandedTokens.empty();
651}
652
653llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {
654 auto D = SM.getDecomposedLoc(Loc);
655 bool Invalid = false;
656 llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
657 if (Invalid || D.second > Buf.size())
658 return "";
659 return Buf.substr(0, D.second);
660}
661
662bool isDependentName(ASTNodeKind NodeKind) {
663 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
664 NodeKind.isSame(
665 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
666 NodeKind.isSame(
667 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
668}
669
670} // namespace
671
672std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
673 ParsedAST &AST,
674 const SymbolIndex *Index,
675 llvm::StringRef MainFilePath,
676 ASTNodeKind NodeKind) {
677 // Don't use heuristics if this is a real identifier, or not an
678 // identifier.
679 // Exception: dependent names, because those may have useful textual
680 // matches that AST-based heuristics cannot find.
681 if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||
682 !Word.LikelyIdentifier || !Index)
683 return {};
684 // We don't want to handle words in string literals. (It'd be nice to list
685 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
686 if (Word.PartOfSpelledToken &&
687 isStringLiteral(Word.PartOfSpelledToken->kind()))
688 return {};
689
690 const auto &SM = AST.getSourceManager();
691 // Look up the selected word in the index.
693 Req.Query = Word.Text.str();
694 Req.ProximityPaths = {MainFilePath.str()};
695 // Find the namespaces to query by lexing the file.
696 Req.Scopes =
697 visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());
698 // FIXME: For extra strictness, consider AnyScope=false.
699 Req.AnyScope = true;
700 // We limit the results to 3 further below. This limit is to avoid fetching
701 // too much data, while still likely having enough for 3 results to remain
702 // after additional filtering.
703 Req.Limit = 10;
704 bool TooMany = false;
705 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
706 std::vector<ScoredLocatedSymbol> ScoredResults;
707 Index->fuzzyFind(Req, [&](const Symbol &Sym) {
708 // Only consider exact name matches, including case.
709 // This is to avoid too many false positives.
710 // We could relax this in the future (e.g. to allow for typos) if we make
711 // the query more accurate by other means.
712 if (Sym.Name != Word.Text)
713 return;
714
715 // Exclude constructor results. They have the same name as the class,
716 // but we don't have enough context to prefer them over the class.
717 if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)
718 return;
719
720 auto MaybeDeclLoc =
721 indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
722 if (!MaybeDeclLoc) {
723 log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
724 return;
725 }
726 LocatedSymbol Located;
727 Located.PreferredDeclaration = *MaybeDeclLoc;
728 Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
729 Located.ID = Sym.ID;
730 if (Sym.Definition) {
731 auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
732 if (!MaybeDefLoc) {
733 log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
734 return;
735 }
736 Located.PreferredDeclaration = *MaybeDefLoc;
737 Located.Definition = *MaybeDefLoc;
738 }
739
740 if (ScoredResults.size() >= 5) {
741 // If we have more than 5 results, don't return anything,
742 // as confidence is too low.
743 // FIXME: Alternatively, try a stricter query?
744 TooMany = true;
745 return;
746 }
747
748 SymbolQualitySignals Quality;
749 Quality.merge(Sym);
750 SymbolRelevanceSignals Relevance;
751 Relevance.Name = Sym.Name;
753 Relevance.merge(Sym);
754 auto Score = evaluateSymbolAndRelevance(Quality.evaluateHeuristics(),
755 Relevance.evaluateHeuristics());
756 dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,
757 Sym.Name, Score, Quality, Relevance);
758
759 ScoredResults.push_back({Score, std::move(Located)});
760 });
761
762 if (TooMany) {
763 vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
764 Word.Text);
765 return {};
766 }
767
768 llvm::sort(ScoredResults,
769 [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {
770 return A.first > B.first;
771 });
772 std::vector<LocatedSymbol> Results;
773 for (auto &Res : std::move(ScoredResults))
774 Results.push_back(std::move(Res.second));
775 if (Results.empty())
776 vlog("No heuristic index definition for {0}", Word.Text);
777 else
778 log("Found definition heuristically in index for {0}", Word.Text);
779 return Results;
780}
781
782const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
783 const syntax::TokenBuffer &TB) {
784 // Don't use heuristics if this is a real identifier.
785 // Unlikely identifiers are OK if they were used as identifiers nearby.
786 if (Word.ExpandedToken)
787 return nullptr;
788 // We don't want to handle words in string literals. (It'd be nice to list
789 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
790 if (Word.PartOfSpelledToken &&
791 isStringLiteral(Word.PartOfSpelledToken->kind()))
792 return {};
793
794 const SourceManager &SM = TB.sourceManager();
795 // We prefer the closest possible token, line-wise. Backwards is penalized.
796 // Ties are implicitly broken by traversal order (first-one-wins).
797 auto File = SM.getFileID(Word.Location);
798 unsigned WordLine = SM.getSpellingLineNumber(Word.Location);
799 auto Cost = [&](SourceLocation Loc) -> unsigned {
800 assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
801 unsigned Line = SM.getSpellingLineNumber(Loc);
802 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
803 };
804 const syntax::Token *BestTok = nullptr;
805 unsigned BestCost = -1;
806 // Search bounds are based on word length:
807 // - forward: 2^N lines
808 // - backward: 2^(N-1) lines.
809 unsigned MaxDistance =
810 1U << std::min<unsigned>(Word.Text.size(),
811 std::numeric_limits<unsigned>::digits - 1);
812 // Line number for SM.translateLineCol() should be one-based, also
813 // SM.translateLineCol() can handle line number greater than
814 // number of lines in the file.
815 // - LineMin = max(1, WordLine + 1 - 2^(N-1))
816 // - LineMax = WordLine + 1 + 2^N
817 unsigned LineMin =
818 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
819 unsigned LineMax = WordLine + 1 + MaxDistance;
820 SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);
821 assert(LocMin.isValid());
822 SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);
823 assert(LocMax.isValid());
824
825 // Updates BestTok and BestCost if Tok is a good candidate.
826 // May return true if the cost is too high for this token.
827 auto Consider = [&](const syntax::Token &Tok) {
828 if (Tok.location() < LocMin || Tok.location() > LocMax)
829 return true; // we are too far from the word, break the outer loop.
830 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
831 return false;
832 // No point guessing the same location we started with.
833 if (Tok.location() == Word.Location)
834 return false;
835 // We've done cheap checks, compute cost so we can break the caller's loop.
836 unsigned TokCost = Cost(Tok.location());
837 if (TokCost >= BestCost)
838 return true; // causes the outer loop to break.
839 // Allow locations that might be part of the AST, and macros (even if empty)
840 // but not things like disabled preprocessor sections.
841 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
842 return false;
843 // We already verified this token is an improvement.
844 BestCost = TokCost;
845 BestTok = &Tok;
846 return false;
847 };
848 auto SpelledTokens = TB.spelledTokens(File);
849 // Find where the word occurred in the token stream, to search forward & back.
850 auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {
851 assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));
852 return T.location() < Word.Location; // Comparison OK: same file.
853 });
854 // Search for matches after the cursor.
855 for (const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
856 if (Consider(Tok))
857 break; // costs of later tokens are greater...
858 // Search for matches before the cursor.
859 for (const syntax::Token &Tok :
860 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
861 if (Consider(Tok))
862 break;
863
864 if (BestTok)
865 vlog(
866 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
867 Word.Text, Word.Location.printToString(SM),
868 BestTok->location().printToString(SM));
869
870 return BestTok;
871}
872
873std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
874 const SymbolIndex *Index) {
875 const auto &SM = AST.getSourceManager();
876 auto MainFilePath = AST.tuPath();
877
878 if (auto File = locateFileReferent(Pos, AST, MainFilePath))
879 return {std::move(*File)};
880
881 auto CurLoc = sourceLocationInMainFile(SM, Pos);
882 if (!CurLoc) {
883 elog("locateSymbolAt failed to convert position to source location: {0}",
884 CurLoc.takeError());
885 return {};
886 }
887
888 const syntax::Token *TouchedIdentifier = nullptr;
889 auto TokensTouchingCursor =
890 syntax::spelledTokensTouching(*CurLoc, AST.getTokens());
891 for (const syntax::Token &Tok : TokensTouchingCursor) {
892 if (Tok.kind() == tok::identifier) {
893 if (auto Macro = locateMacroReferent(Tok, AST, MainFilePath))
894 // Don't look at the AST or index if we have a macro result.
895 // (We'd just return declarations referenced from the macro's
896 // expansion.)
897 return {*std::move(Macro)};
898
899 TouchedIdentifier = &Tok;
900 break;
901 }
902
903 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
904 // go-to-definition on auto should find the definition of the deduced
905 // type, if possible
906 if (auto Deduced =
907 getDeducedType(AST.getASTContext(), AST.getHeuristicResolver(),
908 Tok.location())) {
909 auto LocSym = locateSymbolForType(AST, *Deduced, Index);
910 if (!LocSym.empty())
911 return LocSym;
912 }
913 }
914 }
915
916 if (TouchedIdentifier)
917 if (auto Module =
918 locateModuleReferent(*TouchedIdentifier, AST, MainFilePath))
919 return {*std::move(Module)};
920
921 ASTNodeKind NodeKind;
922 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,
923 MainFilePath, Index, NodeKind);
924 if (!ASTResults.empty())
925 return ASTResults;
926
927 // If the cursor can't be resolved directly, try fallback strategies.
928 auto Word =
929 SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());
930 if (Word) {
931 // Is the same word nearby a real identifier that might refer to something?
932 if (const syntax::Token *NearbyIdent =
933 findNearbyIdentifier(*Word, AST.getTokens())) {
934 if (auto Macro = locateMacroReferent(*NearbyIdent, AST, MainFilePath)) {
935 log("Found macro definition heuristically using nearby identifier {0}",
936 Word->Text);
937 return {*std::move(Macro)};
938 }
939 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,
940 MainFilePath, Index, NodeKind);
941 if (!ASTResults.empty()) {
942 log("Found definition heuristically using nearby identifier {0}",
943 NearbyIdent->text(SM));
944 return ASTResults;
945 }
946 vlog("No definition found using nearby identifier {0} at {1}", Word->Text,
947 Word->Location.printToString(SM));
948 }
949 // No nearby word, or it didn't refer to anything either. Try the index.
950 auto TextualResults =
951 locateSymbolTextually(*Word, AST, Index, MainFilePath, NodeKind);
952 if (!TextualResults.empty())
953 return TextualResults;
954 }
955
956 return {};
957}
958
959std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
960 const auto &SM = AST.getSourceManager();
961
962 std::vector<DocumentLink> Result;
963 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
964 if (Inc.Resolved.empty())
965 continue;
966
967 // Get the location of the # symbole of the "#include ..." statement
968 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
969
970 // get the # Token itself, std::next to get the "include" token and the
971 // first token after (aka "File Token")
972 const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
973 assert(HashTok && "got inclusion at wrong offset");
974 const auto *IncludeTok = std::next(HashTok);
975 const auto *FileTok = std::next(IncludeTok);
976
977 // The File Token can either be of kind :
978 // "less" if using the "#include <h-char-sequence> new-line" syntax
979 // "string_literal" if using the "#include "q-char-sequence" new-line"
980 // syntax something else (most likely "identifier") if using the "#include
981 // pp-tokens new-line" syntax (#include with macro argument)
982
983 CharSourceRange FileRange;
984
985 if (FileTok->kind() == tok::TokenKind::less) {
986 // FileTok->range would only include the '<' char. Hence we explicitly use
987 // Inc.Written's length.
988 FileRange =
989 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
990 .toCharRange(SM);
991 } else if (FileTok->kind() == tok::TokenKind::string_literal) {
992 // FileTok->range includes the quotes for string literals so just return
993 // it.
994 FileRange = FileTok->range(SM).toCharRange(SM);
995 } else {
996 // FileTok is the first Token of a macro spelling
997
998 // Report the range of the first token (as it should be the macro
999 // identifier)
1000 // We could use the AST to find the last spelled token of the macro and
1001 // report a range spanning the full macro expression, but it would require
1002 // using token-buffers that are deemed too unstable and crash-prone
1003 // due to optimizations in cland
1004
1005 FileRange = FileTok->range(SM).toCharRange(SM);
1006 }
1007
1008 Result.push_back(
1009 DocumentLink({halfOpenToRange(SM, FileRange),
1010 URIForFile::canonicalize(Inc.Resolved, AST.tuPath())}));
1011 }
1012
1013 return Result;
1014}
1015
1016namespace {
1017
1018/// Returns the locations of the spelled tokens overlapping [Range.getBegin(),
1019/// Range.getEnd()], in order. Returns an empty list unless both ends of
1020/// \p Range are file locations in the same file: unlike a spelling or
1021/// expansion location, a macro location isn't something TokenBuffer (or the
1022/// FileID/offset arithmetic below) can make sense of, e.g. if part of an
1023/// operator name comes from a macro (`#define PLUS + ... operator PLUS(int)`).
1024llvm::SmallVector<SourceLocation, 4>
1025tokensSpelledInRange(const syntax::TokenBuffer &TB, const SourceManager &SM,
1026 SourceRange Range) {
1027 llvm::SmallVector<SourceLocation, 4> Locs;
1028 if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid() ||
1029 !Range.getBegin().isFileID() || !Range.getEnd().isFileID())
1030 return Locs;
1031 FileID FID = SM.getFileID(Range.getBegin());
1032 if (FID != SM.getFileID(Range.getEnd()))
1033 return Locs;
1034 unsigned EndOffset = SM.getFileOffset(Range.getEnd());
1035 llvm::ArrayRef<syntax::Token> Toks = TB.spelledTokens(FID);
1036 auto It = llvm::partition_point(Toks, [&](const syntax::Token &Tok) {
1037 return SM.getFileOffset(Tok.location()) <
1038 SM.getFileOffset(Range.getBegin());
1039 });
1040 for (; It != Toks.end() && SM.getFileOffset(It->location()) <= EndOffset;
1041 ++It)
1042 Locs.push_back(It->location());
1043 return Locs;
1044}
1045
1046/// If this occurrence is spelled as (part of) an "operator"-shaped name --
1047/// `operator+`, `operator[]`, a literal operator like `operator""_x`, or a
1048/// conversion operator like `operator int()` -- returns the location of the
1049/// `operator` keyword followed by the locations of the tokens that make up
1050/// the rest of the name, so callers can highlight (or otherwise report) the
1051/// whole name instead of just the keyword. Returns an empty list otherwise,
1052/// including when \p Loc is some other occurrence of \p D (e.g. an implicit
1053/// operator call like `a + b`, which has no `operator` token to extend).
1054llvm::SmallVector<SourceLocation, 4>
1055operatorNameTokens(const Decl *D,
1056 const index::IndexDataConsumer::ASTNodeInfo &ASTNode,
1057 SourceLocation Loc, const syntax::TokenBuffer &TB,
1058 const SourceManager &SM) {
1059 std::optional<DeclarationNameInfo> NameInfo;
1060 if (auto *ME = llvm::dyn_cast_or_null<MemberExpr>(ASTNode.OrigE))
1061 NameInfo = ME->getMemberNameInfo();
1062 else if (auto *DRE = llvm::dyn_cast_or_null<DeclRefExpr>(ASTNode.OrigE))
1063 NameInfo = DRE->getNameInfo();
1064 else if (auto *DSME = llvm::dyn_cast_or_null<CXXDependentScopeMemberExpr>(
1065 ASTNode.OrigE))
1066 NameInfo = DSME->getMemberNameInfo();
1067 else if (auto *DSDRE =
1068 llvm::dyn_cast_or_null<DependentScopeDeclRefExpr>(ASTNode.OrigE))
1069 NameInfo = DSDRE->getNameInfo();
1070 else if (auto *OE = llvm::dyn_cast_or_null<OverloadExpr>(ASTNode.OrigE))
1071 // An UnresolvedMemberExpr/UnresolvedLookupExpr: overload resolution for
1072 // this call is dependent (e.g. on a template parameter), so it reports a
1073 // reference to every candidate at the same (real, spelled) location.
1074 NameInfo = OE->getNameInfo();
1075 else if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1076 NameInfo = FD->getNameInfo();
1077 // Not every occurrence carries its own name info. Most ways of invoking an
1078 // operator without writing the `operator` keyword (e.g. `a + b`) still
1079 // reference it through a real, if implicit, MemberExpr/DeclRefExpr callee
1080 // that's handled by the cases above (and later filtered out below, since
1081 // that implicit callee has no `operator` text to report). A `new T(...)`
1082 // or `delete p;` *expression* is the odd one out: unlike a call, it has no
1083 // callee sub-expression at all -- CXXNewExpr/CXXDeleteExpr just store the
1084 // resolved FunctionDecl directly -- so indexing it passes no RefE, and we
1085 // fall through to D's info above. There, NameInfo does not actually
1086 // describe how the name is spelled at *this* occurrence -- it may belong
1087 // to a distant reference, or even a declaration in another file entirely
1088 // -- so its location won't match Loc.
1089 if (!NameInfo || NameInfo->getLoc() != Loc)
1090 return {};
1091
1092 SourceRange ExtraRange;
1093 switch (NameInfo->getName().getNameKind()) {
1094 case DeclarationName::CXXOperatorName:
1095 ExtraRange = NameInfo->getCXXOperatorNameRange();
1096 break;
1097 case DeclarationName::CXXLiteralOperatorName: {
1098 // The suffix (e.g. `_test` in `operator""_test`) is lexed as part of a
1099 // single string-literal-with-suffix token, so its location isn't a
1100 // token's own start; look up the (whole) token that contains it.
1101 SourceLocation SuffixLoc = NameInfo->getCXXLiteralOperatorNameLoc();
1102 if (SuffixLoc.isValid())
1103 if (const auto *Tok = TB.spelledTokenContaining(SM.getFileLoc(SuffixLoc)))
1104 ExtraRange = SourceRange(Tok->location(), Tok->location());
1105 break;
1106 }
1107 case DeclarationName::CXXConversionFunctionName:
1108 if (TypeSourceInfo *TInfo = NameInfo->getNamedTypeInfo())
1109 ExtraRange = TInfo->getTypeLoc().getSourceRange();
1110 break;
1111 default:
1112 break;
1113 }
1114 if (ExtraRange.getBegin().isInvalid())
1115 return {};
1116
1117 llvm::SmallVector<SourceLocation, 4> Result{Loc};
1118 llvm::append_range(Result, tokensSpelledInRange(TB, SM, ExtraRange));
1119 return Result;
1120}
1121
1122/// Collects references to symbols within the main file.
1123class ReferenceFinder : public index::IndexDataConsumer {
1124public:
1125 struct Reference {
1126 syntax::Token SpelledTok;
1127 index::SymbolRoleSet Role;
1128 const Decl *Container;
1129
1130 Range range(const SourceManager &SM) const {
1131 return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));
1132 }
1133 };
1134
1135 ReferenceFinder(ParsedAST &AST,
1136 const llvm::ArrayRef<const NamedDecl *> Targets,
1137 bool PerToken)
1138 : PerToken(PerToken), AST(AST) {
1139 for (const NamedDecl *ND : Targets) {
1140 TargetDecls.insert(ND->getCanonicalDecl());
1141 if (auto *Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
1142 TargetConstructors.insert(Constructor);
1143 }
1144 }
1145
1146 std::vector<Reference> take() && {
1147 llvm::sort(References, [](const Reference &L, const Reference &R) {
1148 auto LTok = L.SpelledTok.location();
1149 auto RTok = R.SpelledTok.location();
1150 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
1151 });
1152 // We sometimes see duplicates when parts of the AST get traversed twice.
1153 References.erase(llvm::unique(References,
1154 [](const Reference &L, const Reference &R) {
1155 auto LTok = L.SpelledTok.location();
1156 auto RTok = R.SpelledTok.location();
1157 return std::tie(LTok, L.Role) ==
1158 std::tie(RTok, R.Role);
1159 }),
1160 References.end());
1161 return std::move(References);
1162 }
1163
1164 bool forwardsToConstructor(const Decl *D) {
1165 if (TargetConstructors.empty())
1166 return false;
1167 const auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
1168 if (!FD)
1169 return false;
1170 for (const auto *Ctor :
1171 getForwardedConstructors(FD, AST.ForwardingToConstructorCache))
1172 if (TargetConstructors.contains(Ctor))
1173 return true;
1174 return false;
1175 }
1176
1177 bool
1178 handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
1179 llvm::ArrayRef<index::SymbolRelation> Relations,
1180 SourceLocation Loc,
1181 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
1182 if (!TargetDecls.contains(D->getCanonicalDecl()) &&
1183 !forwardsToConstructor(ASTNode.OrigD))
1184 return true;
1185 const SourceManager &SM = AST.getSourceManager();
1186 if (!isInsideMainFile(Loc, SM))
1187 return true;
1188 const auto &TB = AST.getTokens();
1189
1190 llvm::SmallVector<SourceLocation, 1> Locs;
1191 if (PerToken) {
1192 // Check whether this is one of the few constructs where the reference
1193 // can be split over several tokens.
1194 if (auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1195 OME->getSelectorLocs(Locs);
1196 } else if (auto *OMD =
1197 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1198 OMD->getSelectorLocs(Locs);
1199 } else {
1200 // An "operator"-shaped name (operator+, operator""_x, operator
1201 // int()) has a name that's a separate token (or tokens) from the
1202 // `operator` keyword itself; report both so the whole name gets
1203 // highlighted, not just the keyword. This covers both the
1204 // declaration and explicit references to it, e.g. `a.operator+(b)`.
1205 Locs = operatorNameTokens(D, ASTNode, Loc, TB, SM);
1206 }
1207 // Sanity check: we expect the *first* token to match the reported loc.
1208 // Otherwise, maybe it was e.g. some other kind of reference to a Decl.
1209 if (!Locs.empty() && Locs.front() != Loc)
1210 Locs.clear(); // First token doesn't match, assume our guess was wrong.
1211 }
1212 if (Locs.empty())
1213 Locs.push_back(Loc);
1214
1215 SymbolCollector::Options CollectorOpts;
1216 CollectorOpts.CollectMainFileSymbols = true;
1217 for (SourceLocation L : Locs) {
1218 L = SM.getFileLoc(L);
1219 if (const auto *Tok = TB.spelledTokenContaining(L))
1220 References.push_back(
1221 {*Tok, Roles,
1222 SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});
1223 }
1224 return true;
1225 }
1226
1227private:
1228 bool PerToken; // If true, report 3 references for split ObjC selector names.
1229 std::vector<Reference> References;
1230 ParsedAST &AST;
1231 llvm::DenseSet<const Decl *> TargetDecls;
1232 // Constructors need special handling since they can be hidden behind forwards
1233 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1234};
1235
1236std::vector<ReferenceFinder::Reference>
1237findRefs(const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &AST,
1238 bool PerToken) {
1239 ReferenceFinder RefFinder(AST, TargetDecls, PerToken);
1240 index::IndexingOptions IndexOpts;
1241 IndexOpts.SystemSymbolFilter =
1242 index::IndexingOptions::SystemSymbolFilterKind::All;
1243 IndexOpts.IndexFunctionLocals = true;
1244 IndexOpts.IndexParametersInDeclarations = true;
1245 IndexOpts.IndexTemplateParameters = true;
1246 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
1247 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1248 return std::move(RefFinder).take();
1249}
1250
1251const Stmt *getFunctionBody(DynTypedNode N) {
1252 if (const auto *FD = N.get<FunctionDecl>())
1253 return FD->getBody();
1254 if (const auto *FD = N.get<BlockDecl>())
1255 return FD->getBody();
1256 if (const auto *FD = N.get<LambdaExpr>())
1257 return FD->getBody();
1258 if (const auto *FD = N.get<ObjCMethodDecl>())
1259 return FD->getBody();
1260 return nullptr;
1261}
1262
1263const Stmt *getLoopBody(DynTypedNode N) {
1264 if (const auto *LS = N.get<ForStmt>())
1265 return LS->getBody();
1266 if (const auto *LS = N.get<CXXForRangeStmt>())
1267 return LS->getBody();
1268 if (const auto *LS = N.get<WhileStmt>())
1269 return LS->getBody();
1270 if (const auto *LS = N.get<DoStmt>())
1271 return LS->getBody();
1272 return nullptr;
1273}
1274
1275// AST traversal to highlight control flow statements under some root.
1276// Once we hit further control flow we prune the tree (or at least restrict
1277// what we highlight) so we capture e.g. breaks from the outer loop only.
1278class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {
1279 // Types of control-flow statements we might highlight.
1280 enum Target {
1281 Break = 1,
1282 Continue = 2,
1283 Return = 4,
1284 Case = 8,
1285 Throw = 16,
1286 Goto = 32,
1287 All = Break | Continue | Return | Case | Throw | Goto,
1288 };
1289 int Ignore = 0; // bitmask of Target - what are we *not* highlighting?
1290 SourceRange Bounds; // Half-open, restricts reported targets.
1291 std::vector<SourceLocation> &Result;
1292 const SourceManager &SM;
1293
1294 // Masks out targets for a traversal into D.
1295 // Traverses the subtree using Delegate() if any targets remain.
1296 template <typename Func>
1297 bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {
1298 llvm::scope_exit RestoreIgnore(
1299 [OldIgnore(Ignore), this] { Ignore = OldIgnore; });
1300 if (getFunctionBody(D))
1301 Ignore = All;
1302 else if (getLoopBody(D))
1303 Ignore |= Continue | Break;
1304 else if (D.get<SwitchStmt>())
1305 Ignore |= Break | Case;
1306 // Prune tree if we're not looking for anything.
1307 return (Ignore == All) ? true : Delegate();
1308 }
1309
1310 void found(Target T, SourceLocation Loc) {
1311 if (T & Ignore)
1312 return;
1313 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1314 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1315 return;
1316 Result.push_back(Loc);
1317 }
1318
1319public:
1320 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1321 const SourceManager &SM)
1322 : Bounds(Bounds), Result(Result), SM(SM) {}
1323
1324 // When traversing function or loops, limit targets to those that still
1325 // refer to the original root.
1326 bool TraverseDecl(Decl *D) {
1327 return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1328 return RecursiveASTVisitor::TraverseDecl(D);
1329 });
1330 }
1331 bool TraverseStmt(Stmt *S) {
1332 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1333 return RecursiveASTVisitor::TraverseStmt(S);
1334 });
1335 }
1336
1337 // Add leaves that we found and want.
1338 bool VisitReturnStmt(ReturnStmt *R) {
1339 found(Return, R->getReturnLoc());
1340 return true;
1341 }
1342 bool VisitBreakStmt(BreakStmt *B) {
1343 found(Break, B->getKwLoc());
1344 return true;
1345 }
1346 bool VisitContinueStmt(ContinueStmt *C) {
1347 found(Continue, C->getKwLoc());
1348 return true;
1349 }
1350 bool VisitSwitchCase(SwitchCase *C) {
1351 found(Case, C->getKeywordLoc());
1352 return true;
1353 }
1354 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1355 found(Throw, T->getThrowLoc());
1356 return true;
1357 }
1358 bool VisitGotoStmt(GotoStmt *G) {
1359 // Goto is interesting if its target is outside the root.
1360 if (const auto *LD = G->getLabel()) {
1361 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1362 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1363 found(Goto, G->getGotoLoc());
1364 }
1365 return true;
1366 }
1367};
1368
1369// Given a location within a switch statement, return the half-open range that
1370// covers the case it's contained in.
1371// We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
1372SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,
1373 const SourceManager &SM) {
1374 // Cases are not stored in order, sort them first.
1375 // (In fact they seem to be stored in reverse order, don't rely on this)
1376 std::vector<const SwitchCase *> Cases;
1377 for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1378 Case = Case->getNextSwitchCase())
1379 Cases.push_back(Case);
1380 llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {
1381 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1382 });
1383
1384 // Find the first case after the target location, the end of our range.
1385 auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {
1386 return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());
1387 });
1388 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1389 : (*CaseAfter)->getKeywordLoc();
1390
1391 // Our target can be before the first case - cases are optional!
1392 if (CaseAfter == Cases.begin())
1393 return SourceRange(Switch.getBeginLoc(), End);
1394 // The start of our range is usually the previous case, but...
1395 auto CaseBefore = std::prev(CaseAfter);
1396 // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
1397 while (CaseBefore != Cases.begin() &&
1398 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1399 --CaseBefore;
1400 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1401}
1402
1403// Returns the locations of control flow statements related to N. e.g.:
1404// for => branches: break/continue/return/throw
1405// break => controlling loop (forwhile/do), and its related control flow
1406// return => all returns/throws from the same function
1407// When an inner block is selected, we include branches bound to outer blocks
1408// as these are exits from the inner block. e.g. return in a for loop.
1409// FIXME: We don't analyze catch blocks, throw is treated the same as return.
1410std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {
1411 const SourceManager &SM =
1412 N.getDeclContext().getParentASTContext().getSourceManager();
1413 std::vector<SourceLocation> Result;
1414
1415 // First, check if we're at a node that can resolve to a root.
1416 enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;
1417 if (N.ASTNode.get<BreakStmt>()) {
1418 Cursor = Cur::Break;
1419 } else if (N.ASTNode.get<ContinueStmt>()) {
1420 Cursor = Cur::Continue;
1421 } else if (N.ASTNode.get<ReturnStmt>()) {
1422 Cursor = Cur::Return;
1423 } else if (N.ASTNode.get<CXXThrowExpr>()) {
1424 Cursor = Cur::Throw;
1425 } else if (N.ASTNode.get<SwitchCase>()) {
1426 Cursor = Cur::Case;
1427 } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1428 // We don't know what root to associate with, but highlight the goto/label.
1429 Result.push_back(GS->getGotoLoc());
1430 if (const auto *LD = GS->getLabel())
1431 Result.push_back(LD->getLocation());
1432 Cursor = Cur::None;
1433 } else {
1434 Cursor = Cur::None;
1435 }
1436
1437 const Stmt *Root = nullptr; // Loop or function body to traverse.
1438 SourceRange Bounds;
1439 // Look up the tree for a root (or just at this node if we didn't find a leaf)
1440 for (const auto *P = &N; P; P = P->Parent) {
1441 // return associates with enclosing function
1442 if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1443 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1444 Root = FunctionBody;
1445 }
1446 break; // other leaves don't cross functions.
1447 }
1448 // break/continue associate with enclosing loop.
1449 if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1450 if (Cursor == Cur::None || Cursor == Cur::Break ||
1451 Cursor == Cur::Continue) {
1452 Root = LoopBody;
1453 // Highlight the loop keyword itself.
1454 // FIXME: for do-while, this only covers the `do`..
1455 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1456 break;
1457 }
1458 }
1459 // For switches, users think of case statements as control flow blocks.
1460 // We highlight only occurrences surrounded by the same case.
1461 // We don't detect fallthrough (other than 'case X, case Y').
1462 if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1463 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1464 Result.push_back(SS->getSwitchLoc()); // Highlight the switch.
1465 Root = SS->getBody();
1466 // Limit to enclosing case, if there is one.
1467 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1468 break;
1469 }
1470 }
1471 // If we didn't start at some interesting node, we're done.
1472 if (Cursor == Cur::None)
1473 break;
1474 }
1475 if (Root) {
1476 if (!Bounds.isValid())
1477 Bounds = Root->getSourceRange();
1478 FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));
1479 }
1480 return Result;
1481}
1482
1483DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
1484 const SourceManager &SM) {
1486 DH.range = Ref.range(SM);
1487 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1489 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1491 else
1493 return DH;
1494}
1495
1496std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1497 const syntax::TokenBuffer &TB) {
1498 Loc = TB.sourceManager().getFileLoc(Loc);
1499 if (const auto *Tok = TB.spelledTokenContaining(Loc)) {
1500 DocumentHighlight Result;
1501 Result.range = halfOpenToRange(
1502 TB.sourceManager(),
1503 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1504 return Result;
1505 }
1506 return std::nullopt;
1507}
1508
1509} // namespace
1510
1511std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
1512 Position Pos) {
1513 const SourceManager &SM = AST.getSourceManager();
1514 // FIXME: show references to macro within file?
1515 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1516 if (!CurLoc) {
1517 llvm::consumeError(CurLoc.takeError());
1518 return {};
1519 }
1520 std::vector<DocumentHighlight> Result;
1521 auto TryTree = [&](SelectionTree ST) {
1522 if (const SelectionTree::Node *N = ST.commonAncestor()) {
1523 DeclRelationSet Relations =
1525 auto TargetDecls =
1526 targetDecl(N->ASTNode, Relations, AST.getHeuristicResolver());
1527 if (!TargetDecls.empty()) {
1528 // FIXME: we may get multiple DocumentHighlights with the same location
1529 // and different kinds, deduplicate them.
1530 for (const auto &Ref : findRefs(TargetDecls, AST, /*PerToken=*/true))
1531 Result.push_back(toHighlight(Ref, SM));
1532 return true;
1533 }
1534 auto ControlFlow = relatedControlFlow(*N);
1535 if (!ControlFlow.empty()) {
1536 for (SourceLocation Loc : ControlFlow)
1537 if (auto Highlight = toHighlight(Loc, AST.getTokens()))
1538 Result.push_back(std::move(*Highlight));
1539 return true;
1540 }
1541 }
1542 return false;
1543 };
1544
1545 unsigned Offset =
1546 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1547 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
1548 Offset, TryTree);
1549 return Result;
1550}
1551
1552std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
1553 const SymbolIndex *Index) {
1554 // We rely on index to find the implementations in subclasses.
1555 // FIXME: Index can be stale, so we may loose some latest results from the
1556 // main file.
1557 if (!Index)
1558 return {};
1559 const SourceManager &SM = AST.getSourceManager();
1560 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1561 if (!CurLoc) {
1562 elog("Failed to convert position to source location: {0}",
1563 CurLoc.takeError());
1564 return {};
1565 }
1566 DeclRelationSet Relations =
1568 llvm::DenseSet<SymbolID> IDs;
1570 for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) {
1571 if (const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1572 if (CXXMD->isVirtual()) {
1573 IDs.insert(getSymbolID(ND));
1574 QueryKind = RelationKind::OverriddenBy;
1575 }
1576 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1577 IDs.insert(getSymbolID(RD));
1578 QueryKind = RelationKind::BaseOf;
1579 } else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1580 IDs.insert(getSymbolID(OMD));
1581 QueryKind = RelationKind::OverriddenBy;
1582 } else if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1583 IDs.insert(getSymbolID(ID));
1584 QueryKind = RelationKind::BaseOf;
1585 }
1586 }
1587 return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath());
1588}
1589
1590namespace {
1591// Recursively finds all the overridden methods of `CMD` in complete type
1592// hierarchy.
1593void getOverriddenMethods(const CXXMethodDecl *CMD,
1594 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1595 if (!CMD)
1596 return;
1597 for (const CXXMethodDecl *Base : CMD->overridden_methods()) {
1598 if (auto ID = getSymbolID(Base))
1599 OverriddenMethods.insert(ID);
1600 getOverriddenMethods(Base, OverriddenMethods);
1601 }
1602}
1603
1604// Recursively finds all the overridden methods of `OMD` in complete type
1605// hierarchy.
1606void getOverriddenMethods(const ObjCMethodDecl *OMD,
1607 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1608 if (!OMD)
1609 return;
1610 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
1611 OMD->getOverriddenMethods(Overrides);
1612 for (const ObjCMethodDecl *Base : Overrides) {
1613 if (auto ID = getSymbolID(Base))
1614 OverriddenMethods.insert(ID);
1615 getOverriddenMethods(Base, OverriddenMethods);
1616 }
1617}
1618
1619std::optional<std::string>
1620stringifyContainerForMainFileRef(const Decl *Container) {
1621 // FIXME We might also want to display the signature here
1622 // When doing so, remember to also add the Signature to index results!
1623 if (auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1624 return printQualifiedName(*ND);
1625 return {};
1626}
1627
1628std::optional<ReferencesResult>
1629maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
1630 URIForFile URIMainFile) {
1631 const auto &Includes = AST.getIncludeStructure().MainFileIncludes;
1632 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](const Inclusion &Inc) {
1633 return Inc.HashLine == Pos.line;
1634 });
1635 if (IncludeOnLine == Includes.end())
1636 return std::nullopt;
1637
1638 const SourceManager &SM = AST.getSourceManager();
1639 ReferencesResult Results;
1640 auto Converted = convertIncludes(AST);
1641 include_cleaner::walkUsed(
1642 AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
1643 &AST.getPragmaIncludes(), AST.getPreprocessor(),
1644 [&](const include_cleaner::SymbolReference &Ref,
1645 llvm::ArrayRef<include_cleaner::Header> Providers) {
1646 if (Ref.RT != include_cleaner::RefType::Explicit ||
1647 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1648 return;
1649
1650 auto Loc = SM.getFileLoc(Ref.RefLocation);
1651 // File locations can be outside of the main file if macro is
1652 // expanded through an #include.
1653 while (SM.getFileID(Loc) != SM.getMainFileID())
1654 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1655
1656 ReferencesResult::Reference Result;
1657 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1658 assert(Token && "references expected token here");
1659 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1660 sourceLocToPosition(SM, Token->endLocation())};
1661 Result.Loc.uri = URIMainFile;
1662 Results.References.push_back(std::move(Result));
1663 });
1664 if (Results.References.empty())
1665 return std::nullopt;
1666
1667 // Add the #include line to the references list.
1669 Result.Loc.range = rangeTillEOL(SM.getBufferData(SM.getMainFileID()),
1670 IncludeOnLine->HashOffset);
1671 Result.Loc.uri = std::move(URIMainFile);
1672 Results.References.push_back(std::move(Result));
1673 return Results;
1674}
1675} // namespace
1676
1678 const SymbolIndex *Index, bool AddContext) {
1679 ReferencesResult Results;
1680 const SourceManager &SM = AST.getSourceManager();
1681 auto MainFilePath = AST.tuPath();
1682 auto URIMainFile = URIForFile::canonicalize(MainFilePath, MainFilePath);
1683 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1684 if (!CurLoc) {
1685 llvm::consumeError(CurLoc.takeError());
1686 return {};
1687 }
1688
1689 const auto IncludeReferences =
1690 maybeFindIncludeReferences(AST, Pos, URIMainFile);
1691 if (IncludeReferences)
1692 return *IncludeReferences;
1693
1694 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1695
1696 const auto *IdentifierAtCursor =
1697 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1698 std::optional<DefinedMacro> Macro;
1699 if (IdentifierAtCursor)
1700 Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1701 if (Macro) {
1702 // Handle references to macro.
1703 if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
1704 // Collect macro references from main file.
1705 const auto &IDToRefs = AST.getMacros().MacroRefs;
1706 auto Refs = IDToRefs.find(MacroSID);
1707 if (Refs != IDToRefs.end()) {
1708 for (const auto &Ref : Refs->second) {
1710 Result.Loc.range = Ref.toRange(SM);
1711 Result.Loc.uri = URIMainFile;
1712 if (Ref.IsDefinition) {
1715 }
1716 Results.References.push_back(std::move(Result));
1717 }
1718 }
1719 IDsToQuery.insert(MacroSID);
1720 }
1721 } else {
1722 // Handle references to Decls.
1723
1724 DeclRelationSet Relations =
1726 std::vector<const NamedDecl *> Decls =
1727 getDeclAtPosition(AST, *CurLoc, Relations);
1728 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1729 for (const NamedDecl *D : Decls) {
1730 auto ID = getSymbolID(D);
1731 if (!ID)
1732 continue;
1733 TargetsInMainFile.push_back(D);
1734 // Not all symbols can be referenced from outside (e.g. function-locals).
1735 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1736 // we know this file isn't a header. The details might be tricky.
1737 if (D->getParentFunctionOrMethod())
1738 continue;
1739 IDsToQuery.insert(ID);
1740 }
1741
1743 if (Index) {
1745 for (const NamedDecl *ND : Decls) {
1746 // Special case: For virtual methods, report decl/def of overrides and
1747 // references to all overridden methods in complete type hierarchy.
1748 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1749 if (CMD->isVirtual()) {
1750 if (auto ID = getSymbolID(CMD))
1751 OverriddenBy.Subjects.insert(ID);
1752 getOverriddenMethods(CMD, OverriddenMethods);
1753 }
1754 }
1755 // Special case: Objective-C methods can override a parent class or
1756 // protocol, we should be sure to report references to those.
1757 if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1758 OverriddenBy.Subjects.insert(getSymbolID(OMD));
1759 getOverriddenMethods(OMD, OverriddenMethods);
1760 }
1761 }
1762 }
1763
1764 // We traverse the AST to find references in the main file.
1765 auto MainFileRefs = findRefs(TargetsInMainFile, AST, /*PerToken=*/false);
1766 // We may get multiple refs with the same location and different Roles, as
1767 // cross-reference is only interested in locations, we deduplicate them
1768 // by the location to avoid emitting duplicated locations.
1769 MainFileRefs.erase(llvm::unique(MainFileRefs,
1770 [](const ReferenceFinder::Reference &L,
1771 const ReferenceFinder::Reference &R) {
1772 return L.SpelledTok.location() ==
1773 R.SpelledTok.location();
1774 }),
1775 MainFileRefs.end());
1776 for (const auto &Ref : MainFileRefs) {
1778 Result.Loc.range = Ref.range(SM);
1779 Result.Loc.uri = URIMainFile;
1780 if (AddContext)
1781 Result.Loc.containerName =
1782 stringifyContainerForMainFileRef(Ref.Container);
1783 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Declaration))
1785 // clang-index doesn't report definitions as declarations, but they are.
1786 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Definition))
1787 Result.Attributes |=
1789 Results.References.push_back(std::move(Result));
1790 }
1791 // Add decl/def of overridding methods.
1792 if (Index && !OverriddenBy.Subjects.empty()) {
1793 LookupRequest ContainerLookup;
1794 // Different overrides will always be contained in different classes, so
1795 // we have a one-to-one mapping between SymbolID and index here, thus we
1796 // don't need to use std::vector as the map's value type.
1797 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1798 Index->relations(OverriddenBy, [&](const SymbolID &Subject,
1799 const Symbol &Object) {
1800 if (Limit && Results.References.size() >= Limit) {
1801 Results.HasMore = true;
1802 return;
1803 }
1804 const auto LSPLocDecl =
1805 toLSPLocation(Object.CanonicalDeclaration, MainFilePath);
1806 const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath);
1807 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1809 Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
1810 Result.Attributes =
1812 RefIndexForContainer.insert({Object.ID, Results.References.size()});
1813 ContainerLookup.IDs.insert(Object.ID);
1814 Results.References.push_back(std::move(Result));
1815 }
1816 if (LSPLocDef) {
1818 Result.Loc = {std::move(*LSPLocDef), std::nullopt};
1822 RefIndexForContainer.insert({Object.ID, Results.References.size()});
1823 ContainerLookup.IDs.insert(Object.ID);
1824 Results.References.push_back(std::move(Result));
1825 }
1826 });
1827
1828 if (!ContainerLookup.IDs.empty() && AddContext)
1829 Index->lookup(ContainerLookup, [&](const Symbol &Container) {
1830 auto Ref = RefIndexForContainer.find(Container.ID);
1831 assert(Ref != RefIndexForContainer.end());
1832 Results.References[Ref->getSecond()].Loc.containerName =
1833 Container.Scope.str() + Container.Name.str();
1834 });
1835 }
1836 }
1837 // Now query the index for references from other files.
1838 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool AllowAttributes,
1839 bool AllowMainFileSymbols) {
1840 if (IDs.empty() || !Index || Results.HasMore)
1841 return;
1842 RefsRequest Req;
1843 Req.IDs = std::move(IDs);
1844 if (Limit) {
1845 if (Limit < Results.References.size()) {
1846 // We've already filled our quota, still check the index to correctly
1847 // return the `HasMore` info.
1848 Req.Limit = 0;
1849 } else {
1850 // Query index only for the remaining size.
1851 Req.Limit = Limit - Results.References.size();
1852 }
1853 }
1854 LookupRequest ContainerLookup;
1855 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1856 Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
1857 auto LSPLoc = toLSPLocation(R.Location, MainFilePath);
1858 // Avoid indexed results for the main file - the AST is authoritative.
1859 if (!LSPLoc ||
1860 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1861 return;
1863 Result.Loc = {std::move(*LSPLoc), std::nullopt};
1864 if (AllowAttributes) {
1867 // FIXME: our index should definitely store def | decl separately!
1869 Result.Attributes |=
1871 }
1872 if (AddContext) {
1873 SymbolID Container = R.Container;
1874 ContainerLookup.IDs.insert(Container);
1875 RefIndicesForContainer[Container].push_back(Results.References.size());
1876 }
1877 Results.References.push_back(std::move(Result));
1878 });
1879
1880 if (!ContainerLookup.IDs.empty() && AddContext)
1881 Index->lookup(ContainerLookup, [&](const Symbol &Container) {
1882 auto Ref = RefIndicesForContainer.find(Container.ID);
1883 assert(Ref != RefIndicesForContainer.end());
1884 auto ContainerName = Container.Scope.str() + Container.Name.str();
1885 for (auto I : Ref->getSecond()) {
1886 Results.References[I].Loc.containerName = ContainerName;
1887 }
1888 });
1889 };
1890 QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,
1891 /*AllowMainFileSymbols=*/false);
1892 // For a virtual method: Occurrences of BaseMethod should be treated as refs
1893 // and not as decl/def. Allow symbols from main file since AST does not report
1894 // these.
1895 QueryIndex(std::move(OverriddenMethods), /*AllowAttributes=*/false,
1896 /*AllowMainFileSymbols=*/true);
1897 return Results;
1898}
1899
1900std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
1901 const SourceManager &SM = AST.getSourceManager();
1902 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1903 if (!CurLoc) {
1904 llvm::consumeError(CurLoc.takeError());
1905 return {};
1906 }
1907 auto MainFilePath = AST.tuPath();
1908 std::vector<SymbolDetails> Results;
1909
1910 // We also want the targets of using-decls, so we include
1911 // DeclRelation::Underlying.
1914 for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1915 D = getPreferredDecl(D);
1916
1917 SymbolDetails NewSymbol;
1918 std::string QName = printQualifiedName(*D);
1919 auto SplitQName = splitQualifiedName(QName);
1920 NewSymbol.containerName = std::string(SplitQName.first);
1921 NewSymbol.name = std::string(SplitQName.second);
1922
1923 if (NewSymbol.containerName.empty()) {
1924 if (const auto *ParentND =
1925 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1926 NewSymbol.containerName = printQualifiedName(*ParentND);
1927 }
1928 llvm::SmallString<32> USR;
1929 if (!index::generateUSRForDecl(D, USR)) {
1930 NewSymbol.USR = std::string(USR);
1931 NewSymbol.ID = SymbolID(NewSymbol.USR);
1932 }
1933 if (const NamedDecl *Def = getDefinition(D))
1934 NewSymbol.definitionRange = makeLocation(
1935 AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
1936 NewSymbol.declarationRange =
1937 makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
1938
1939 Results.push_back(std::move(NewSymbol));
1940 }
1941
1942 const auto *IdentifierAtCursor =
1943 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1944 if (!IdentifierAtCursor)
1945 return Results;
1946
1947 if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1948 SymbolDetails NewMacro;
1949 NewMacro.name = std::string(M->Name);
1950 llvm::SmallString<32> USR;
1951 if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
1952 SM, USR)) {
1953 NewMacro.USR = std::string(USR);
1954 NewMacro.ID = SymbolID(NewMacro.USR);
1955 }
1956 Results.push_back(std::move(NewMacro));
1957 }
1958
1959 return Results;
1960}
1961
1962llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1963 OS << S.Name << ": " << S.PreferredDeclaration;
1964 if (S.Definition)
1965 OS << " def=" << *S.Definition;
1966 return OS;
1967}
1968
1969llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1970 const ReferencesResult::Reference &R) {
1971 OS << R.Loc;
1973 OS << " [decl]";
1975 OS << " [def]";
1977 OS << " [override]";
1978 return OS;
1979}
1980
1981template <typename HierarchyItem>
1982static std::optional<HierarchyItem>
1983declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1984 ASTContext &Ctx = ND.getASTContext();
1985 auto &SM = Ctx.getSourceManager();
1986 SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
1987 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1988 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1989 const auto DeclRange =
1990 toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});
1991 if (!DeclRange)
1992 return std::nullopt;
1993 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1994 if (!FE)
1995 return std::nullopt;
1996 auto FilePath = getCanonicalPath(*FE, SM.getFileManager());
1997 if (!FilePath)
1998 return std::nullopt; // Not useful without a uri.
1999
2000 Position NameBegin = sourceLocToPosition(SM, NameLoc);
2001 Position NameEnd = sourceLocToPosition(
2002 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
2003
2004 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
2005 // FIXME: This is not classifying constructors, destructors and operators
2006 // correctly.
2008
2009 HierarchyItem HI;
2010 HI.name = printName(Ctx, ND);
2011 HI.detail = printQualifiedName(ND);
2012 HI.kind = SK;
2013 HI.tags = getSymbolTags(ND);
2014 HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),
2015 sourceLocToPosition(SM, DeclRange->getEnd())};
2016 HI.selectionRange = Range{NameBegin, NameEnd};
2017 if (!HI.range.contains(HI.selectionRange)) {
2018 // 'selectionRange' must be contained in 'range', so in cases where clang
2019 // reports unrelated ranges we need to reconcile somehow.
2020 HI.range = HI.selectionRange;
2021 }
2022
2023 HI.uri = URIForFile::canonicalize(*FilePath, TUPath);
2024
2025 return HI;
2026}
2027
2028static std::optional<TypeHierarchyItem>
2029declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
2030 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);
2031 if (Result) {
2032 Result->deprecated = ND.isDeprecated();
2033 // Compute the SymbolID and store it in the 'data' field.
2034 // This allows typeHierarchy/resolve to be used to
2035 // resolve children of items returned in a previous request
2036 // for parents.
2037 Result->data.symbolID = getSymbolID(&ND);
2038 }
2039 return Result;
2040}
2041
2042static std::optional<CallHierarchyItem>
2043declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
2044 auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);
2045 if (!Result)
2046 return Result;
2047 if (ND.isDeprecated())
2048 Result->tags.push_back(SymbolTag::Deprecated);
2049 if (auto ID = getSymbolID(&ND))
2050 Result->data = ID.str();
2051 return Result;
2052}
2053
2054template <typename HierarchyItem>
2055static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
2056 PathRef TUPath) {
2057 auto Loc = symbolToLocation(S, TUPath);
2058 if (!Loc) {
2059 elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
2060 return std::nullopt;
2061 }
2062 HierarchyItem HI;
2063 HI.name = std::string(S.Name);
2064 HI.detail = S.Scope.empty() ? std::string()
2065 : S.Scope.drop_back(2).str(); // Trailing "::"
2067 HI.tags = getSymbolTags(S);
2068 HI.selectionRange = Loc->range;
2069 // FIXME: Populate 'range' correctly
2070 // (https://github.com/clangd/clangd/issues/59).
2071 HI.range = HI.selectionRange;
2072 HI.uri = Loc->uri;
2073
2074 return HI;
2075}
2076
2077static std::optional<TypeHierarchyItem>
2079 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
2080 if (Result) {
2081 Result->deprecated = (S.Flags & Symbol::Deprecated);
2082 Result->data.symbolID = S.ID;
2083 }
2084 return Result;
2085}
2086
2087static std::optional<CallHierarchyItem>
2089 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
2090 if (!Result)
2091 return Result;
2092 Result->data = S.ID.str();
2093 return Result;
2094}
2095
2096static void fillSubTypes(const SymbolID &ID,
2097 std::vector<TypeHierarchyItem> &SubTypes,
2098 const SymbolIndex *Index, int Levels, PathRef TUPath) {
2099 RelationsRequest Req;
2100 Req.Subjects.insert(ID);
2102 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
2103 if (std::optional<TypeHierarchyItem> ChildSym =
2105 if (Levels > 1) {
2106 ChildSym->children.emplace();
2107 fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
2108 }
2109 SubTypes.emplace_back(std::move(*ChildSym));
2110 }
2111 });
2112}
2113
2114using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;
2115
2116// Extracts parents from AST and populates the type hierarchy item.
2117static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
2118 TypeHierarchyItem &Item,
2119 RecursionProtectionSet &RPSet) {
2120 Item.parents.emplace();
2121 Item.data.parents.emplace();
2122 // typeParents() will replace dependent template specializations
2123 // with their class template, so to avoid infinite recursion for
2124 // certain types of hierarchies, keep the templates encountered
2125 // along the parent chain in a set, and stop the recursion if one
2126 // starts to repeat.
2127 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
2128 if (Pattern) {
2129 if (!RPSet.insert(Pattern).second) {
2130 return;
2131 }
2132 }
2133
2134 for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
2135 if (std::optional<TypeHierarchyItem> ParentSym =
2136 declToTypeHierarchyItem(*ParentDecl, TUPath)) {
2137 fillSuperTypes(*ParentDecl, TUPath, *ParentSym, RPSet);
2138 Item.data.parents->emplace_back(ParentSym->data);
2139 Item.parents->emplace_back(std::move(*ParentSym));
2140 }
2141 }
2142
2143 if (Pattern) {
2144 RPSet.erase(Pattern);
2145 }
2146}
2147
2148std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,
2149 Position Pos) {
2150 auto RecordFromNode = [&AST](const SelectionTree::Node *N) {
2151 std::vector<const CXXRecordDecl *> Records;
2152 if (!N)
2153 return Records;
2154
2155 // Note: explicitReferenceTargets() will search for both template
2156 // instantiations and template patterns, and prefer the former if available
2157 // (generally, one will be available for non-dependent specializations of a
2158 // class template).
2159 auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying,
2160 AST.getHeuristicResolver());
2161 for (const NamedDecl *D : Decls) {
2162
2163 if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2164 // If this is a variable, use the type of the variable.
2165 if (const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
2166 Records.push_back(RD);
2167 continue;
2168 }
2169
2170 if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
2171 // If this is a method, use the type of the class.
2172 Records.push_back(Method->getParent());
2173 continue;
2174 }
2175
2176 // We don't handle FieldDecl because it's not clear what behaviour
2177 // the user would expect: the enclosing class type (as with a
2178 // method), or the field's type (as with a variable).
2179
2180 if (auto *RD = dyn_cast<CXXRecordDecl>(D))
2181 Records.push_back(RD);
2182 }
2183 return Records;
2184 };
2185
2186 const SourceManager &SM = AST.getSourceManager();
2187 std::vector<const CXXRecordDecl *> Result;
2188 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
2189 if (!Offset) {
2190 llvm::consumeError(Offset.takeError());
2191 return Result;
2192 }
2193 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
2194 *Offset, [&](SelectionTree ST) {
2195 Result = RecordFromNode(ST.commonAncestor());
2196 return !Result.empty();
2197 });
2198 return Result;
2199}
2200
2201// Return the type most associated with an AST node.
2202// This isn't precisely defined: we want "go to type" to do something useful.
2203static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H,
2204 const SelectionTree::Node *N) {
2205 // If we're looking at a namespace qualifier, walk up to what it's qualifying.
2206 // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
2207 while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
2208 N = N->Parent;
2209 if (!N)
2210 return QualType();
2211
2212 // If we're pointing at a type => return it.
2213 if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {
2214 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2215 if (auto Deduced = getDeducedType(
2216 N->getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2217 return *Deduced;
2218 // Exception: an alias => underlying type.
2219 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2220 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2221 return TL->getType();
2222 }
2223
2224 // Constructor initializers => the type of thing being initialized.
2225 if (const auto *CCI = N->ASTNode.get<CXXCtorInitializer>()) {
2226 if (const FieldDecl *FD = CCI->getAnyMember())
2227 return FD->getType();
2228 if (const Type *Base = CCI->getBaseClass())
2229 return QualType(Base, 0);
2230 }
2231
2232 // Base specifier => the base type.
2233 if (const auto *CBS = N->ASTNode.get<CXXBaseSpecifier>())
2234 return CBS->getType();
2235
2236 if (const Decl *D = N->ASTNode.get<Decl>()) {
2237 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2238 const ASTContext &Ctx;
2239 Visitor(const ASTContext &Ctx) : Ctx(Ctx) {}
2240
2241 QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
2242 // Declaration of a type => that type.
2243 QualType VisitTypeDecl(const TypeDecl *D) {
2244 return Ctx.getTypeDeclType(D);
2245 }
2246 // Exception: alias declaration => the underlying type, not the alias.
2247 QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
2248 return D->getUnderlyingType();
2249 }
2250 // Look inside templates.
2251 QualType VisitTemplateDecl(const TemplateDecl *D) {
2252 if (const auto *TD = D->getTemplatedDecl())
2253 return Visit(TD);
2254 // ConceptDecl doesn't have any associated templates nor types.
2255 return QualType();
2256 }
2257 } V(Ctx);
2258 return V.Visit(D);
2259 }
2260
2261 if (const Stmt *S = N->ASTNode.get<Stmt>()) {
2262 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2263 // Null-safe version of visit simplifies recursive calls below.
2264 QualType type(const Stmt *S) { return S ? Visit(S) : QualType(); }
2265
2266 // In general, expressions => type of expression.
2267 QualType VisitExpr(const Expr *S) {
2268 return S->IgnoreImplicitAsWritten()->getType();
2269 }
2270 QualType VisitMemberExpr(const MemberExpr *S) {
2271 // The `foo` in `s.foo()` pretends not to have a real type!
2272 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2273 return Expr::findBoundMemberType(S);
2274 return VisitExpr(S);
2275 }
2276 // Exceptions for void expressions that operate on a type in some way.
2277 QualType VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
2278 return S->getDestroyedType();
2279 }
2280 QualType VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
2281 return S->getDestroyedType();
2282 }
2283 QualType VisitCXXThrowExpr(const CXXThrowExpr *S) {
2284 return S->getSubExpr()->getType();
2285 }
2286 QualType VisitCoyieldExpr(const CoyieldExpr *S) {
2287 return type(S->getOperand());
2288 }
2289 // Treat a designated initializer like a reference to the field.
2290 QualType VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
2291 // In .foo.bar we want to jump to bar's type, so find *last* field.
2292 for (auto &D : llvm::reverse(S->designators()))
2293 if (D.isFieldDesignator())
2294 if (const auto *FD = D.getFieldDecl())
2295 return FD->getType();
2296 return QualType();
2297 }
2298
2299 // Control flow statements that operate on data: use the data type.
2300 QualType VisitSwitchStmt(const SwitchStmt *S) {
2301 return type(S->getCond());
2302 }
2303 QualType VisitWhileStmt(const WhileStmt *S) { return type(S->getCond()); }
2304 QualType VisitDoStmt(const DoStmt *S) { return type(S->getCond()); }
2305 QualType VisitIfStmt(const IfStmt *S) { return type(S->getCond()); }
2306 QualType VisitCaseStmt(const CaseStmt *S) { return type(S->getLHS()); }
2307 QualType VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
2308 return S->getLoopVariable()->getType();
2309 }
2310 QualType VisitReturnStmt(const ReturnStmt *S) {
2311 return type(S->getRetValue());
2312 }
2313 QualType VisitCoreturnStmt(const CoreturnStmt *S) {
2314 return type(S->getOperand());
2315 }
2316 QualType VisitCXXCatchStmt(const CXXCatchStmt *S) {
2317 return S->getCaughtType();
2318 }
2319 QualType VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {
2320 return type(S->getThrowExpr());
2321 }
2322 QualType VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {
2323 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2324 : QualType();
2325 }
2326 } V;
2327 return V.Visit(S);
2328 }
2329
2330 return QualType();
2331}
2332
2333// Given a type targeted by the cursor, return one or more types that are more interesting
2334// to target.
2335static void unwrapFindType(
2336 QualType T, const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2337 if (T.isNull())
2338 return;
2339
2340 // If there's a specific type alias, point at that rather than unwrapping.
2341 if (const auto *TDT = T->getAs<TypedefType>())
2342 return Out.push_back(QualType(TDT, 0));
2343
2344 // Pointers etc => pointee type.
2345 if (const auto *PT = T->getAs<PointerType>())
2346 return unwrapFindType(PT->getPointeeType(), H, Out);
2347 if (const auto *RT = T->getAs<ReferenceType>())
2348 return unwrapFindType(RT->getPointeeType(), H, Out);
2349 if (const auto *AT = T->getAsArrayTypeUnsafe())
2350 return unwrapFindType(AT->getElementType(), H, Out);
2351
2352 // Function type => return type.
2353 if (auto *FT = T->getAs<FunctionType>())
2354 return unwrapFindType(FT->getReturnType(), H, Out);
2355 if (auto *CRD = T->getAsCXXRecordDecl()) {
2356 if (CRD->isLambda())
2357 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2358 Out);
2359 // FIXME: more cases we'd prefer the return type of the call operator?
2360 // std::function etc?
2361 }
2362
2363 // For smart pointer types, add the underlying type
2364 if (H)
2365 if (auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2366 !PointeeType.isNull()) {
2367 unwrapFindType(PointeeType, H, Out);
2368 return Out.push_back(T);
2369 }
2370
2371 return Out.push_back(T);
2372}
2373
2374// Convenience overload, to allow calling this without the out-parameter
2375static llvm::SmallVector<QualType> unwrapFindType(
2376 QualType T, const HeuristicResolver* H) {
2377 llvm::SmallVector<QualType> Result;
2378 unwrapFindType(T, H, Result);
2379 return Result;
2380}
2381
2382std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos,
2383 const SymbolIndex *Index) {
2384 const SourceManager &SM = AST.getSourceManager();
2385 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
2386 std::vector<LocatedSymbol> Result;
2387 if (!Offset) {
2388 elog("failed to convert position {0} for findTypes: {1}", Pos,
2389 Offset.takeError());
2390 return Result;
2391 }
2392 // The general scheme is: position -> AST node -> type -> declaration.
2393 auto SymbolsFromNode =
2394 [&](const SelectionTree::Node *N) -> std::vector<LocatedSymbol> {
2395 std::vector<LocatedSymbol> LocatedSymbols;
2396
2397 // NOTE: unwrapFindType might return duplicates for something like
2398 // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
2399 // information about the type you may have not known before
2400 // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
2401 for (const QualType &Type : unwrapFindType(
2402 typeForNode(AST.getASTContext(), AST.getHeuristicResolver(), N),
2403 AST.getHeuristicResolver()))
2404 llvm::copy(locateSymbolForType(AST, Type, Index),
2405 std::back_inserter(LocatedSymbols));
2406
2407 return LocatedSymbols;
2408 };
2409 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
2410 *Offset, [&](SelectionTree ST) {
2411 Result = SymbolsFromNode(ST.commonAncestor());
2412 return !Result.empty();
2413 });
2414 return Result;
2415}
2416
2417std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
2418 std::vector<const CXXRecordDecl *> Result;
2419
2420 // If this is an invalid instantiation, instantiation of the bases
2421 // may not have succeeded, so fall back to the template pattern.
2422 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2423 if (CTSD->isInvalidDecl())
2424 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2425 }
2426
2427 // Can't query bases without a definition.
2428 if (!CXXRD->hasDefinition())
2429 return Result;
2430
2431 for (auto Base : CXXRD->bases()) {
2432 const CXXRecordDecl *ParentDecl = nullptr;
2433
2434 const Type *Type = Base.getType().getTypePtr();
2435 if (const RecordType *RT = Type->getAs<RecordType>()) {
2436 ParentDecl = RT->getAsCXXRecordDecl();
2437 }
2438
2439 if (!ParentDecl) {
2440 // Handle a dependent base such as "Base<T>" by using the primary
2441 // template.
2442 if (const TemplateSpecializationType *TS =
2443 Type->getAs<TemplateSpecializationType>()) {
2444 TemplateName TN = TS->getTemplateName();
2445 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2446 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2447 }
2448 }
2449 }
2450
2451 if (ParentDecl)
2452 Result.push_back(ParentDecl);
2453 }
2454
2455 return Result;
2456}
2457
2458std::vector<TypeHierarchyItem>
2459getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
2460 TypeHierarchyDirection Direction, const SymbolIndex *Index,
2461 PathRef TUPath) {
2462 std::vector<TypeHierarchyItem> Results;
2463 for (const auto *CXXRD : findRecordTypeAt(AST, Pos)) {
2464
2465 bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2466 Direction == TypeHierarchyDirection::Both;
2467
2468 // If we're looking for children, we're doing the lookup in the index.
2469 // The index does not store relationships between implicit
2470 // specializations, so if we have one, use the template pattern instead.
2471 // Note that this needs to be done before the declToTypeHierarchyItem(),
2472 // otherwise the type hierarchy item would misleadingly contain the
2473 // specialization parameters, while the children would involve classes
2474 // that derive from other specializations of the template.
2475 if (WantChildren) {
2476 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2477 CXXRD = CTSD->getTemplateInstantiationPattern();
2478 }
2479
2480 std::optional<TypeHierarchyItem> Result =
2481 declToTypeHierarchyItem(*CXXRD, AST.tuPath());
2482 if (!Result)
2483 continue;
2484
2486 fillSuperTypes(*CXXRD, AST.tuPath(), *Result, RPSet);
2487
2488 if (WantChildren && ResolveLevels > 0) {
2489 Result->children.emplace();
2490
2491 if (Index) {
2492 if (auto ID = getSymbolID(CXXRD))
2493 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2494 }
2495 }
2496 Results.emplace_back(std::move(*Result));
2497 }
2498
2499 return Results;
2500}
2501
2502std::optional<std::vector<TypeHierarchyItem>>
2503superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {
2504 if (!Index || !Item.data.parents)
2505 return std::nullopt;
2506 LookupRequest Req;
2507 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2508 for (const auto &Parent : *Item.data.parents) {
2509 Req.IDs.insert(Parent.symbolID);
2510 IDToData[Parent.symbolID] = &Parent;
2511 }
2512 std::vector<TypeHierarchyItem> Results;
2513 Index->lookup(Req, [&Item, &Results, &IDToData](const Symbol &S) {
2514 if (auto THI = symbolToTypeHierarchyItem(S, Item.uri.file())) {
2515 THI->data = *IDToData.lookup(S.ID);
2516 Results.emplace_back(std::move(*THI));
2517 }
2518 });
2519 return Results.empty() ? std::nullopt
2520 : std::make_optional(std::move(Results));
2521}
2522
2523std::vector<TypeHierarchyItem> subTypes(const TypeHierarchyItem &Item,
2524 const SymbolIndex *Index) {
2525 std::vector<TypeHierarchyItem> Results;
2526 fillSubTypes(Item.data.symbolID, Results, Index, 1, Item.uri.file());
2527 for (auto &ChildSym : Results)
2528 ChildSym.data.parents = {Item.data};
2529 return Results;
2530}
2531
2532void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
2533 TypeHierarchyDirection Direction,
2534 const SymbolIndex *Index) {
2535 // We only support typeHierarchy/resolve for children, because for parents
2536 // we ignore ResolveLevels and return all levels of parents eagerly.
2537 if (!Index || Direction == TypeHierarchyDirection::Parents ||
2538 ResolveLevels == 0)
2539 return;
2540
2541 Item.children.emplace();
2542 fillSubTypes(Item.data.symbolID, *Item.children, Index, ResolveLevels,
2543 Item.uri.file());
2544}
2545
2546std::vector<CallHierarchyItem>
2548 std::vector<CallHierarchyItem> Result;
2549 const auto &SM = AST.getSourceManager();
2550 auto Loc = sourceLocationInMainFile(SM, Pos);
2551 if (!Loc) {
2552 elog("prepareCallHierarchy failed to convert position to source location: "
2553 "{0}",
2554 Loc.takeError());
2555 return Result;
2556 }
2557 for (const NamedDecl *Decl : getDeclAtPosition(AST, *Loc, {})) {
2558 if (!(isa<DeclContext>(Decl) &&
2559 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2560 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2561 !(Decl->getKind() == Decl::Kind::Var &&
2562 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2563 Decl->getKind() != Decl::Kind::Field &&
2564 Decl->getKind() != Decl::Kind::EnumConstant)
2565 continue;
2566 if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath()))
2567 Result.emplace_back(std::move(*CHI));
2568 }
2569 return Result;
2570}
2571
2572std::vector<CallHierarchyIncomingCall>
2573incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
2574 std::vector<CallHierarchyIncomingCall> Results;
2575 if (!Index || Item.data.empty())
2576 return Results;
2577 auto ID = SymbolID::fromStr(Item.data);
2578 if (!ID) {
2579 elog("incomingCalls failed to find symbol: {0}", ID.takeError());
2580 return Results;
2581 }
2582 // In this function, we find incoming calls based on the index only.
2583 // In principle, the AST could have more up-to-date information about
2584 // occurrences within the current file. However, going from a SymbolID
2585 // to an AST node isn't cheap, particularly when the declaration isn't
2586 // in the main file.
2587 // FIXME: Consider also using AST information when feasible.
2588 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool MightNeverCall) {
2589 RefsRequest Request;
2590 Request.IDs = std::move(IDs);
2591 Request.WantContainer = true;
2592 // We could restrict more specifically to calls by introducing a new
2593 // RefKind, but non-call references (such as address-of-function) can still
2594 // be interesting as they can indicate indirect calls.
2595 Request.Filter = RefKind::Reference;
2596 // Initially store the ranges in a map keyed by SymbolID of the caller.
2597 // This allows us to group different calls with the same caller
2598 // into the same CallHierarchyIncomingCall.
2599 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2600 // We can populate the ranges based on a refs request only. As we do so, we
2601 // also accumulate the container IDs into a lookup request.
2602 LookupRequest ContainerLookup;
2603 Index->refs(Request, [&](const Ref &R) {
2604 auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
2605 if (!Loc) {
2606 elog("incomingCalls failed to convert location: {0}", Loc.takeError());
2607 return;
2608 }
2609 CallsIn[R.Container].push_back(*Loc);
2610
2611 ContainerLookup.IDs.insert(R.Container);
2612 });
2613 // Perform the lookup request and combine its results with CallsIn to
2614 // get complete CallHierarchyIncomingCall objects.
2615 Index->lookup(ContainerLookup, [&](const Symbol &Caller) {
2616 auto It = CallsIn.find(Caller.ID);
2617 assert(It != CallsIn.end());
2618 if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file())) {
2619 std::vector<Range> FromRanges;
2620 for (const Location &L : It->second) {
2621 if (L.uri != CHI->uri) {
2622 // Call location not in same file as caller.
2623 // This can happen in some edge cases. There's not much we can do,
2624 // since the protocol only allows returning ranges interpreted as
2625 // being in the caller's file.
2626 continue;
2627 }
2628 FromRanges.push_back(L.range);
2629 }
2630 Results.push_back(CallHierarchyIncomingCall{
2631 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2632 }
2633 });
2634 };
2635 QueryIndex({ID.get()}, false);
2636 // In the case of being a virtual function we also want to return
2637 // potential calls through the base function.
2638 if (Item.kind == SymbolKind::Method) {
2639 llvm::DenseSet<SymbolID> IDs;
2640 RelationsRequest Req{{ID.get()}, RelationKind::OverriddenBy, std::nullopt};
2641 Index->reverseRelations(Req, [&](const SymbolID &, const Symbol &Caller) {
2642 IDs.insert(Caller.ID);
2643 });
2644 QueryIndex(std::move(IDs), true);
2645 }
2646 // Sort results by name of container.
2647 llvm::sort(Results, [](const CallHierarchyIncomingCall &A,
2648 const CallHierarchyIncomingCall &B) {
2649 return A.from.name < B.from.name;
2650 });
2651 return Results;
2652}
2653
2654std::vector<CallHierarchyOutgoingCall>
2655outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
2656 std::vector<CallHierarchyOutgoingCall> Results;
2657 if (!Index || Item.data.empty())
2658 return Results;
2659 auto ID = SymbolID::fromStr(Item.data);
2660 if (!ID) {
2661 elog("outgoingCalls failed to find symbol: {0}", ID.takeError());
2662 return Results;
2663 }
2664 // In this function, we find outgoing calls based on the index only.
2665 ContainedRefsRequest Request;
2666 Request.ID = *ID;
2667 // Initially store the ranges in a map keyed by SymbolID of the callee.
2668 // This allows us to group different calls to the same function
2669 // into the same CallHierarchyOutgoingCall.
2670 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2671 // We can populate the ranges based on a refs request only. As we do so, we
2672 // also accumulate the callee IDs into a lookup request.
2673 LookupRequest CallsOutLookup;
2674 Index->containedRefs(Request, [&](const auto &R) {
2675 auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
2676 if (!Loc) {
2677 elog("outgoingCalls failed to convert location: {0}", Loc.takeError());
2678 return;
2679 }
2680 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2681 It->second.push_back(*Loc);
2682
2683 CallsOutLookup.IDs.insert(R.Symbol);
2684 });
2685 // Perform the lookup request and combine its results with CallsOut to
2686 // get complete CallHierarchyOutgoingCall objects.
2687 Index->lookup(CallsOutLookup, [&](const Symbol &Callee) {
2688 // The containedRefs request should only return symbols which are
2689 // function-like, i.e. symbols for which references to them can be "calls".
2690 using SK = index::SymbolKind;
2691 auto Kind = Callee.SymInfo.Kind;
2692 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2693 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2694 Kind == SK::Constructor || Kind == SK::Destructor ||
2695 Kind == SK::ConversionFunction);
2696 (void)Kind;
2697 (void)SK::Function;
2698
2699 auto It = CallsOut.find(Callee.ID);
2700 assert(It != CallsOut.end());
2701 if (auto CHI = symbolToCallHierarchyItem(Callee, Item.uri.file())) {
2702 std::vector<Range> FromRanges;
2703 for (const Location &L : It->second) {
2704 if (L.uri != Item.uri) {
2705 // Call location not in same file as the item that outgoingCalls was
2706 // requested for. This can happen when Item is a declaration separate
2707 // from the implementation. There's not much we can do, since the
2708 // protocol only allows returning ranges interpreted as being in
2709 // Item's file.
2710 continue;
2711 }
2712 FromRanges.push_back(L.range);
2713 }
2714 Results.push_back(
2715 CallHierarchyOutgoingCall{std::move(*CHI), std::move(FromRanges)});
2716 }
2717 });
2718 // Sort results by name of the callee.
2719 llvm::sort(Results, [](const CallHierarchyOutgoingCall &A,
2720 const CallHierarchyOutgoingCall &B) {
2721 return A.to.name < B.to.name;
2722 });
2723 return Results;
2724}
2725
2726llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
2727 const FunctionDecl *FD) {
2728 if (!FD->hasBody())
2729 return {};
2730 llvm::DenseSet<const Decl *> DeclRefs;
2732 FD,
2733 [&](ReferenceLoc Ref) {
2734 for (const Decl *D : Ref.Targets) {
2735 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2736 !Ref.IsDecl)
2737 DeclRefs.insert(D);
2738 }
2739 },
2740 AST.getHeuristicResolver());
2741 return DeclRefs;
2742}
2743
2744} // namespace clangd
2745} // namespace clang
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
#define dlog(...)
Definition Logger.h:101
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for Markdown output.")
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition Context.h:69
Stores and provides access to parsed AST.
Definition ParsedAST.h:47
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static const Decl * getRefContainer(const Decl *Enclosing, const SymbolCollector::Options &Opts)
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition SymbolID.cpp:37
std::string str() const
Definition SymbolID.cpp:35
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition Index.h:134
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning.
virtual bool containedRefs(const ContainedRefsRequest &Req, llvm::function_ref< void(const ContainedRefsResult &)> Callback) const =0
Find all symbols that are referenced by a symbol and apply Callback on each result.
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol.
virtual void reverseRelations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (O, P, S) stored in the index such that S is among Req.Subjects and P is Req....
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
Definition XRefs.cpp:2523
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
Definition XRefs.cpp:2503
llvm::Expected< Location > indexToLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath)
Helper function for deriving an LSP Location from an index SymbolLocation.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
Definition XRefs.cpp:2573
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition AST.cpp:354
static std::optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath)
Definition XRefs.cpp:2078
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
static std::optional< CallHierarchyItem > symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath)
Definition XRefs.cpp:2088
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
Definition AST.cpp:248
llvm::SmallVector< std::pair< const NamedDecl *, DeclRelationSet >, 1 > allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver)
Similar to targetDecl(), however instead of applying a filter, all possible decls are returned along ...
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition XRefs.cpp:1511
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
Find declarations explicitly referenced in the source code defined by N.
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
Definition XRefs.cpp:672
std::vector< SymbolTag > getSymbolTags(const Symbol &S)
Returns the SymbolTag values for the given indexed S.
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Definition XRefs.cpp:959
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition Merge.cpp:266
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition XRefs.cpp:1900
std::vector< include_cleaner::SymbolReference > collectMacroReferences(ParsedAST &AST)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath)
Helper function for deriving an LSP Location for a Symbol.
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
Definition AST.cpp:196
void vlog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:72
include_cleaner::Includes convertIncludes(const ParsedAST &AST)
Converts the clangd include representation to include-cleaner include representation.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
Definition XRefs.cpp:2382
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H, const SelectionTree::Node *N)
Definition XRefs.cpp:2203
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
Definition XRefs.cpp:2459
static std::optional< TypeHierarchyItem > declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
Definition XRefs.cpp:2029
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, const HeuristicResolver *Resolver, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
Definition AST.cpp:624
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const DynTypedNode &N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
targetDecl() finds the declaration referred to by an AST node.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
Definition XRefs.cpp:1677
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath, TypeHierarchyItem &Item, RecursionProtectionSet &RPSet)
Definition XRefs.cpp:2117
std::optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition XRefs.cpp:873
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
static std::optional< HierarchyItem > declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
Definition XRefs.cpp:1983
std::optional< std::string > getCanonicalPath(const FileEntryRef F, FileManager &FileMgr)
Get the canonical path of F.
static void unwrapFindType(QualType T, const HeuristicResolver *H, llvm::SmallVector< QualType > &Out)
Definition XRefs.cpp:2335
static std::optional< HierarchyItem > symbolToHierarchyItem(const Symbol &S, PathRef TUPath)
Definition XRefs.cpp:2055
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
Definition XRefs.cpp:782
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
Definition XRefs.cpp:2114
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
Definition XRefs.cpp:2096
void log(const char *Fmt, Ts &&... Vals)
Definition Logger.h:67
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition Path.h:29
@ Type
An inlay hint that for a type annotation.
Definition Protocol.h:1745
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
Definition XRefs.cpp:1552
ArrayRef< const CXXConstructorDecl * > getForwardedConstructors(const FunctionDecl *FD, ForwardingToConstructorCache &Cache)
Returns the constructors that FD forwards to, if FD is a template instantiation of a likely forwardin...
Definition AST.cpp:1128
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
Definition AST.cpp:371
SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info)
Definition Protocol.cpp:306
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Definition XRefs.cpp:2532
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
Definition XRefs.cpp:2726
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
Definition Quality.cpp:534
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition AST.cpp:206
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
Definition XRefs.cpp:2655
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
Definition FindTarget.h:121
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
Definition FindTarget.h:104
@ Alias
This declaration is an alias that was referred to.
Definition FindTarget.h:112
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
Definition XRefs.cpp:2043
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
Definition XRefs.cpp:2148
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
Definition XRefs.cpp:2547
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
Definition XRefs.cpp:2417
SymbolKind
A symbol kind.
Definition Protocol.h:393
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Simplified description of a clang AST node.
Definition Protocol.h:2093
Represents an incoming call, e.g. a caller of a method or constructor.
Definition Protocol.h:1690
Represents programming constructs like functions or constructors in the context of call hierarchy.
Definition Protocol.h:1650
URIForFile uri
The resource identifier of this item.
Definition Protocol.h:1664
SymbolKind kind
The kind of this item.
Definition Protocol.h:1655
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
Definition Protocol.h:1677
Represents an outgoing call, e.g.
Definition Protocol.h:1715
A document highlight is a range inside a text document which deserves special attention.
Definition Protocol.h:1535
Range range
The range this highlight applies to.
Definition Protocol.h:1537
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
Definition Index.h:36
std::string Query
A query string for the fuzzy find.
Definition Index.h:29
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
Definition Index.h:47
bool AnyScope
If set to true, allow symbols from any scope.
Definition Index.h:39
std::optional< uint32_t > Limit
The number of top candidates to return.
Definition Index.h:42
Location PreferredDeclaration
Definition XRefs.h:45
std::optional< Location > Definition
Definition XRefs.h:47
URIForFile uri
The text document's URI.
Definition Protocol.h:214
llvm::DenseSet< SymbolID > IDs
Definition Index.h:65
Represents a symbol occurrence in the source file.
Definition Ref.h:88
RefKind Kind
Definition Ref.h:91
SymbolID Container
The ID of the symbol whose definition contains this reference.
Definition Ref.h:95
SymbolLocation Location
The source location where the symbol is named.
Definition Ref.h:90
Information about a reference written in the source code, independent of the actual AST node that thi...
Definition FindTarget.h:128
std::optional< std::string > containerName
clangd extension: contains the name of the function or class in which the reference occurs
Definition Protocol.h:237
std::vector< Reference > References
Definition XRefs.h:94
bool WantContainer
If set, populates the container of the reference.
Definition Index.h:77
llvm::DenseSet< SymbolID > IDs
Definition Index.h:69
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition Index.h:74
llvm::DenseSet< SymbolID > Subjects
Definition Index.h:94
const DeclContext & getDeclContext() const
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
const syntax::Token * ExpandedToken
Definition SourceCode.h:256
const syntax::Token * PartOfSpelledToken
Definition SourceCode.h:251
Represents information about identifier.
Definition Protocol.h:1231
std::optional< Location > definitionRange
Definition Protocol.h:1247
std::optional< Location > declarationRange
Definition Protocol.h:1245
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Definition Protocol.h:1241
Attributes of a symbol that affect how much we like it.
Definition Quality.h:56
void merge(const CodeCompletionResult &SemaCCResult)
Definition Quality.cpp:178
Attributes of a symbol-query pair that affect how much we like it.
Definition Quality.h:86
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
Definition Quality.h:88
void merge(const CodeCompletionResult &SemaResult)
Definition Quality.cpp:329
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
Ensure we have enough bits to represent all SymbolTag values.
Definition Symbol.h:49
SymbolFlag Flags
Definition Symbol.h:165
@ Deprecated
Indicates if the symbol is deprecated.
Definition Symbol.h:157
SymbolLocation Definition
The location of the symbol's definition, if one was found.
Definition Symbol.h:62
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
Definition Symbol.h:53
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition Symbol.h:57
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Definition Symbol.h:59
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
Definition Symbol.h:86
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Definition Symbol.h:71
SymbolID ID
The ID of the symbol.
Definition Symbol.h:51
std::optional< std::vector< ResolveParams > > parents
std::nullopt means parents aren't resolved and empty is no parents.
Definition Protocol.h:1604
URIForFile uri
The resource identifier of this item.
Definition Protocol.h:1590
std::optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
Definition Protocol.h:1623
std::optional< std::vector< TypeHierarchyItem > > parents
This is a clangd exntesion.
Definition Protocol.h:1617
ResolveParams data
A data entry field that is preserved between a type hierarchy prepare and supertypes or subtypes requ...
Definition Protocol.h:1610
std::string uri() const
Definition Protocol.h:108
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition Protocol.cpp:46
llvm::StringRef file() const
Retrieves absolute path to the file.
Definition Protocol.h:105
Represents measurements of clangd events, e.g.
Definition Trace.h:38
@ Counter
An aggregate number whose rate of change over time is meaningful.
Definition Trace.h:46