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