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