clang-tools  14.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 "CodeCompletionStrings.h"
11 #include "FindSymbols.h"
12 #include "FindTarget.h"
13 #include "ParsedAST.h"
14 #include "Protocol.h"
15 #include "Quality.h"
16 #include "Selection.h"
17 #include "SourceCode.h"
18 #include "URI.h"
19 #include "index/Index.h"
20 #include "index/Merge.h"
21 #include "index/Relation.h"
22 #include "index/SymbolLocation.h"
23 #include "support/Logger.h"
24 #include "clang/AST/ASTContext.h"
25 #include "clang/AST/ASTTypeTraits.h"
26 #include "clang/AST/Attr.h"
27 #include "clang/AST/Attrs.inc"
28 #include "clang/AST/Decl.h"
29 #include "clang/AST/DeclCXX.h"
30 #include "clang/AST/DeclObjC.h"
31 #include "clang/AST/DeclTemplate.h"
32 #include "clang/AST/DeclVisitor.h"
33 #include "clang/AST/ExprCXX.h"
34 #include "clang/AST/ExternalASTSource.h"
35 #include "clang/AST/RecursiveASTVisitor.h"
36 #include "clang/AST/Stmt.h"
37 #include "clang/AST/StmtCXX.h"
38 #include "clang/AST/StmtVisitor.h"
39 #include "clang/AST/Type.h"
40 #include "clang/Basic/CharInfo.h"
41 #include "clang/Basic/LLVM.h"
42 #include "clang/Basic/LangOptions.h"
43 #include "clang/Basic/SourceLocation.h"
44 #include "clang/Basic/SourceManager.h"
45 #include "clang/Basic/TokenKinds.h"
46 #include "clang/Index/IndexDataConsumer.h"
47 #include "clang/Index/IndexSymbol.h"
48 #include "clang/Index/IndexingAction.h"
49 #include "clang/Index/IndexingOptions.h"
50 #include "clang/Index/USRGeneration.h"
51 #include "clang/Tooling/Syntax/Tokens.h"
52 #include "llvm/ADT/ArrayRef.h"
53 #include "llvm/ADT/MapVector.h"
54 #include "llvm/ADT/None.h"
55 #include "llvm/ADT/STLExtras.h"
56 #include "llvm/ADT/ScopeExit.h"
57 #include "llvm/ADT/SmallSet.h"
58 #include "llvm/ADT/StringExtras.h"
59 #include "llvm/ADT/StringRef.h"
60 #include "llvm/Support/Casting.h"
61 #include "llvm/Support/Error.h"
62 #include "llvm/Support/MathExtras.h"
63 #include "llvm/Support/Path.h"
64 #include "llvm/Support/raw_ostream.h"
65 
66 namespace clang {
67 namespace clangd {
68 namespace {
69 
70 // Returns the single definition of the entity declared by D, if visible.
71 // In particular:
72 // - for non-redeclarable kinds (e.g. local vars), return D
73 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
74 // Kinds of nodes that always return nullptr here will not have definitions
75 // reported by locateSymbolAt().
76 const NamedDecl *getDefinition(const NamedDecl *D) {
77  assert(D);
78  // Decl has one definition that we can find.
79  if (const auto *TD = dyn_cast<TagDecl>(D))
80  return TD->getDefinition();
81  if (const auto *VD = dyn_cast<VarDecl>(D))
82  return VD->getDefinition();
83  if (const auto *FD = dyn_cast<FunctionDecl>(D))
84  return FD->getDefinition();
85  if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
86  if (const auto *RD = CTD->getTemplatedDecl())
87  return RD->getDefinition();
88  // Objective-C classes can have three types of declarations:
89  //
90  // - forward declaration: @class MyClass;
91  // - true declaration (interface definition): @interface MyClass ... @end
92  // - true definition (implementation): @implementation MyClass ... @end
93  //
94  // Objective-C categories are extensions are on classes:
95  //
96  // - declaration: @interface MyClass (Ext) ... @end
97  // - definition: @implementation MyClass (Ext) ... @end
98  //
99  // With one special case, a class extension, which is normally used to keep
100  // some declarations internal to a file without exposing them in a header.
101  //
102  // - class extension declaration: @interface MyClass () ... @end
103  // - which really links to class definition: @implementation MyClass ... @end
104  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
105  return ID->getImplementation();
106  if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D)) {
107  if (CD->IsClassExtension()) {
108  if (const auto *ID = CD->getClassInterface())
109  return ID->getImplementation();
110  return nullptr;
111  }
112  return CD->getImplementation();
113  }
114  // Only a single declaration is allowed.
115  if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
116  isa<TemplateTemplateParmDecl>(D)) // except cases above
117  return D;
118  // Multiple definitions are allowed.
119  return nullptr; // except cases above
120 }
121 
122 void logIfOverflow(const SymbolLocation &Loc) {
123  if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
124  log("Possible overflow in symbol location: {0}", Loc);
125 }
126 
127 // Convert a SymbolLocation to LSP's Location.
128 // TUPath is used to resolve the path of URI.
129 // FIXME: figure out a good home for it, and share the implementation with
130 // FindSymbols.
131 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
132  llvm::StringRef TUPath) {
133  if (!Loc)
134  return None;
135  auto Uri = URI::parse(Loc.FileURI);
136  if (!Uri) {
137  elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
138  return None;
139  }
140  auto U = URIForFile::fromURI(*Uri, TUPath);
141  if (!U) {
142  elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
143  return None;
144  }
145 
146  Location LSPLoc;
147  LSPLoc.uri = std::move(*U);
148  LSPLoc.range.start.line = Loc.Start.line();
149  LSPLoc.range.start.character = Loc.Start.column();
150  LSPLoc.range.end.line = Loc.End.line();
151  LSPLoc.range.end.character = Loc.End.column();
152  logIfOverflow(Loc);
153  return LSPLoc;
154 }
155 
156 SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
157  SymbolLocation SymLoc;
158  URIStorage = Loc.uri.uri();
159  SymLoc.FileURI = URIStorage.c_str();
160  SymLoc.Start.setLine(Loc.range.start.line);
161  SymLoc.Start.setColumn(Loc.range.start.character);
162  SymLoc.End.setLine(Loc.range.end.line);
163  SymLoc.End.setColumn(Loc.range.end.character);
164  return SymLoc;
165 }
166 
167 // Returns the preferred location between an AST location and an index location.
168 SymbolLocation getPreferredLocation(const Location &ASTLoc,
169  const SymbolLocation &IdxLoc,
170  std::string &Scratch) {
171  // Also use a mock symbol for the index location so that other fields (e.g.
172  // definition) are not factored into the preference.
173  Symbol ASTSym, IdxSym;
174  ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
175  ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
176  IdxSym.CanonicalDeclaration = IdxLoc;
177  auto Merged = mergeSymbol(ASTSym, IdxSym);
178  return Merged.CanonicalDeclaration;
179 }
180 
181 std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
182 getDeclAtPositionWithRelations(ParsedAST &AST, SourceLocation Pos,
183  DeclRelationSet Relations,
184  ASTNodeKind *NodeKind = nullptr) {
185  unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
186  std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
187  auto ResultFromTree = [&](SelectionTree ST) {
188  if (const SelectionTree::Node *N = ST.commonAncestor()) {
189  if (NodeKind)
190  *NodeKind = N->ASTNode.getNodeKind();
191  // Attributes don't target decls, look at the
192  // thing it's attached to.
193  // We still report the original NodeKind!
194  // This makes the `override` hack work.
195  if (N->ASTNode.get<Attr>() && N->Parent)
196  N = N->Parent;
197  llvm::copy_if(allTargetDecls(N->ASTNode, AST.getHeuristicResolver()),
198  std::back_inserter(Result),
199  [&](auto &Entry) { return !(Entry.second & ~Relations); });
200  }
201  return !Result.empty();
202  };
204  Offset, ResultFromTree);
205  return Result;
206 }
207 
208 std::vector<const NamedDecl *>
209 getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,
210  ASTNodeKind *NodeKind = nullptr) {
211  std::vector<const NamedDecl *> Result;
212  for (auto &Entry :
213  getDeclAtPositionWithRelations(AST, Pos, Relations, NodeKind))
214  Result.push_back(Entry.first);
215  return Result;
216 }
217 
218 // Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
219 // figure out a filename.
220 llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,
221  llvm::StringRef TUPath) {
222  const auto &SM = AST.getSourceManager();
223  const FileEntry *F = SM.getFileEntryForID(SM.getFileID(Loc));
224  if (!F)
225  return None;
226  auto FilePath = getCanonicalPath(F, SM);
227  if (!FilePath) {
228  log("failed to get path!");
229  return None;
230  }
231  Location L;
232  L.uri = URIForFile::canonicalize(*FilePath, TUPath);
233  // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
234  // outside the main file.
235  auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());
236  L.range = halfOpenToRange(
237  SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
238  return L;
239 }
240 
241 // Treat #included files as symbols, to enable go-to-definition on them.
242 llvm::Optional<LocatedSymbol> locateFileReferent(const Position &Pos,
243  ParsedAST &AST,
244  llvm::StringRef MainFilePath) {
245  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
246  if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
247  LocatedSymbol File;
248  File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
249  File.PreferredDeclaration = {
250  URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
251  File.Definition = File.PreferredDeclaration;
252  // We're not going to find any further symbols on #include lines.
253  return File;
254  }
255  }
256  return llvm::None;
257 }
258 
259 // Macros are simple: there's no declaration/definition distinction.
260 // As a consequence, there's no need to look them up in the index either.
261 llvm::Optional<LocatedSymbol>
262 locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
263  llvm::StringRef MainFilePath) {
264  if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
265  if (auto Loc =
266  makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {
267  LocatedSymbol Macro;
268  Macro.Name = std::string(M->Name);
269  Macro.PreferredDeclaration = *Loc;
270  Macro.Definition = Loc;
271  Macro.ID = getSymbolID(M->Name, M->Info, AST.getSourceManager());
272  return Macro;
273  }
274  }
275  return llvm::None;
276 }
277 
278 // A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
279 // definition of a canonical declaration doesn't match up to what a programmer
280 // would expect. For example, Objective-C classes can have three types of
281 // declarations:
282 //
283 // - forward declaration(s): @class MyClass;
284 // - true declaration (interface definition): @interface MyClass ... @end
285 // - true definition (implementation): @implementation MyClass ... @end
286 //
287 // Clang will consider the forward declaration to be the canonical declaration
288 // because it is first. We actually want the class definition if it is
289 // available since that is what a programmer would consider the primary
290 // declaration to be.
291 const NamedDecl *getPreferredDecl(const NamedDecl *D) {
292  // FIXME: Canonical declarations of some symbols might refer to built-in
293  // decls with possibly-invalid source locations (e.g. global new operator).
294  // In such cases we should pick up a redecl with valid source location
295  // instead of failing.
296  D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
297 
298  // Prefer Objective-C class/protocol definitions over the forward declaration.
299  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
300  if (const auto *DefinitionID = ID->getDefinition())
301  return DefinitionID;
302  if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
303  if (const auto *DefinitionID = PD->getDefinition())
304  return DefinitionID;
305 
306  return D;
307 }
308 
309 std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
310  RelationKind Predicate,
311  const SymbolIndex *Index,
312  llvm::StringRef MainFilePath) {
313  if (IDs.empty() || !Index)
314  return {};
315  static constexpr trace::Metric FindImplementorsMetric(
316  "find_implementors", trace::Metric::Counter, "case");
317  switch (Predicate) {
319  FindImplementorsMetric.record(1, "find-base");
320  break;
322  FindImplementorsMetric.record(1, "find-override");
323  break;
324  }
325 
326  RelationsRequest Req;
327  Req.Predicate = Predicate;
328  Req.Subjects = std::move(IDs);
329  std::vector<LocatedSymbol> Results;
330  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
331  auto DeclLoc =
332  indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
333  if (!DeclLoc) {
334  elog("Find overrides: {0}", DeclLoc.takeError());
335  return;
336  }
337  Results.emplace_back();
338  Results.back().Name = Object.Name.str();
339  Results.back().PreferredDeclaration = *DeclLoc;
340  auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
341  if (!DefLoc) {
342  elog("Failed to convert location: {0}", DefLoc.takeError());
343  return;
344  }
345  Results.back().Definition = *DefLoc;
346  });
347  return Results;
348 }
349 
350 // Decls are more complicated.
351 // The AST contains at least a declaration, maybe a definition.
352 // These are up-to-date, and so generally preferred over index results.
353 // We perform a single batch index lookup to find additional definitions.
354 std::vector<LocatedSymbol>
355 locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
356  ParsedAST &AST, llvm::StringRef MainFilePath,
357  const SymbolIndex *Index, ASTNodeKind &NodeKind) {
358  const SourceManager &SM = AST.getSourceManager();
359  // Results follow the order of Symbols.Decls.
360  std::vector<LocatedSymbol> Result;
361  // Keep track of SymbolID -> index mapping, to fill in index data later.
362  llvm::DenseMap<SymbolID, size_t> ResultIndex;
363 
364  static constexpr trace::Metric LocateASTReferentMetric(
365  "locate_ast_referent", trace::Metric::Counter, "case");
366  auto AddResultDecl = [&](const NamedDecl *D) {
367  D = getPreferredDecl(D);
368  auto Loc =
369  makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
370  if (!Loc)
371  return;
372 
373  Result.emplace_back();
374  Result.back().Name = printName(AST.getASTContext(), *D);
375  Result.back().PreferredDeclaration = *Loc;
376  Result.back().ID = getSymbolID(D);
377  if (const NamedDecl *Def = getDefinition(D))
378  Result.back().Definition = makeLocation(
379  AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
380 
381  // Record SymbolID for index lookup later.
382  if (auto ID = getSymbolID(D))
383  ResultIndex[ID] = Result.size() - 1;
384  };
385 
386  // Emit all symbol locations (declaration or definition) from AST.
387  DeclRelationSet Relations =
389  auto Candidates =
390  getDeclAtPositionWithRelations(AST, CurLoc, Relations, &NodeKind);
391  llvm::DenseSet<SymbolID> VirtualMethods;
392  for (const auto &E : Candidates) {
393  const NamedDecl *D = E.first;
394  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
395  // Special case: virtual void ^method() = 0: jump to all overrides.
396  // FIXME: extend it to ^virtual, unfortunately, virtual location is not
397  // saved in the AST.
398  if (CMD->isPure()) {
399  if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
400  TouchedIdentifier->location()) {
401  VirtualMethods.insert(getSymbolID(CMD));
402  LocateASTReferentMetric.record(1, "method-to-override");
403  }
404  }
405  // Special case: void foo() ^override: jump to the overridden method.
406  if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
407  NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
408  // We may be overridding multiple methods - offer them all.
409  for (const NamedDecl *ND : CMD->overridden_methods())
410  AddResultDecl(ND);
411  continue;
412  }
413  }
414 
415  // Special case: the cursor is on an alias, prefer other results.
416  // This targets "using ns::^Foo", where the target is more interesting.
417  // This does not trigger on renaming aliases:
418  // `using Foo = ^Bar` already targets Bar via a TypeLoc
419  // `using ^Foo = Bar` has no other results, as Underlying is filtered.
420  if (E.second & DeclRelation::Alias && Candidates.size() > 1 &&
421  // beginLoc/endLoc are a token range, so rewind the identifier we're in.
422  SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
423  : CurLoc,
424  D->getBeginLoc(), D->getEndLoc()))
425  continue;
426 
427  // Special case: the point of declaration of a template specialization,
428  // it's more useful to navigate to the template declaration.
429  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
430  if (TouchedIdentifier &&
431  D->getLocation() == TouchedIdentifier->location()) {
432  LocateASTReferentMetric.record(1, "template-specialization-to-primary");
433  AddResultDecl(CTSD->getSpecializedTemplate());
434  continue;
435  }
436  }
437 
438  // Special case: if the class name is selected, also map Objective-C
439  // categories and category implementations back to their class interface.
440  //
441  // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`
442  // instead of the `ObjCCategoryDecl` we intentionally check the contents
443  // of the locs when checking for class name equivalence.
444  if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
445  if (const auto *ID = CD->getClassInterface())
446  if (TouchedIdentifier &&
447  (CD->getLocation() == TouchedIdentifier->location() ||
448  ID->getName() == TouchedIdentifier->text(SM))) {
449  LocateASTReferentMetric.record(1, "objc-category-to-class");
450  AddResultDecl(ID);
451  }
452 
453  LocateASTReferentMetric.record(1, "regular");
454  // Otherwise the target declaration is the right one.
455  AddResultDecl(D);
456  }
457 
458  // Now query the index for all Symbol IDs we found in the AST.
459  if (Index && !ResultIndex.empty()) {
460  LookupRequest QueryRequest;
461  for (auto It : ResultIndex)
462  QueryRequest.IDs.insert(It.first);
463  std::string Scratch;
464  Index->lookup(QueryRequest, [&](const Symbol &Sym) {
465  auto &R = Result[ResultIndex.lookup(Sym.ID)];
466 
467  if (R.Definition) { // from AST
468  // Special case: if the AST yielded a definition, then it may not be
469  // the right *declaration*. Prefer the one from the index.
470  if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
471  R.PreferredDeclaration = *Loc;
472 
473  // We might still prefer the definition from the index, e.g. for
474  // generated symbols.
475  if (auto Loc = toLSPLocation(
476  getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
477  MainFilePath))
478  R.Definition = *Loc;
479  } else {
480  R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
481 
482  // Use merge logic to choose AST or index declaration.
483  if (auto Loc = toLSPLocation(
484  getPreferredLocation(R.PreferredDeclaration,
485  Sym.CanonicalDeclaration, Scratch),
486  MainFilePath))
487  R.PreferredDeclaration = *Loc;
488  }
489  });
490  }
491 
492  auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy,
493  Index, MainFilePath);
494  Result.insert(Result.end(), Overrides.begin(), Overrides.end());
495  return Result;
496 }
497 
498 std::vector<LocatedSymbol> locateSymbolForType(const ParsedAST &AST,
499  const QualType &Type) {
500  const auto &SM = AST.getSourceManager();
501  auto MainFilePath =
502  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
503  if (!MainFilePath) {
504  elog("Failed to get a path for the main file, so no symbol.");
505  return {};
506  }
507 
508  // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.
509  // Likely it would be better to send it to Foo (heuristically) or to both.
510  auto Decls = targetDecl(DynTypedNode::create(Type.getNonReferenceType()),
512  AST.getHeuristicResolver());
513  if (Decls.empty())
514  return {};
515 
516  std::vector<LocatedSymbol> Results;
517  const auto &ASTContext = AST.getASTContext();
518 
519  for (const NamedDecl *D : Decls) {
520  D = getPreferredDecl(D);
521 
522  auto Loc = makeLocation(ASTContext, nameLocation(*D, SM), *MainFilePath);
523  if (!Loc)
524  continue;
525 
526  Results.emplace_back();
527  Results.back().Name = printName(ASTContext, *D);
528  Results.back().PreferredDeclaration = *Loc;
529  Results.back().ID = getSymbolID(D);
530  if (const NamedDecl *Def = getDefinition(D))
531  Results.back().Definition =
532  makeLocation(ASTContext, nameLocation(*Def, SM), *MainFilePath);
533  }
534 
535  return Results;
536 }
537 
538 bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {
539  auto ExpandedTokens = TB.expandedTokens(
540  TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
541  return !ExpandedTokens.empty();
542 }
543 
544 llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {
545  auto D = SM.getDecomposedLoc(Loc);
546  bool Invalid = false;
547  llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
548  if (Invalid || D.second > Buf.size())
549  return "";
550  return Buf.substr(0, D.second);
551 }
552 
553 bool isDependentName(ASTNodeKind NodeKind) {
554  return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
555  NodeKind.isSame(
556  ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
557  NodeKind.isSame(
558  ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
559 }
560 
561 } // namespace
562 
563 std::vector<LocatedSymbol>
565  const SymbolIndex *Index, const std::string &MainFilePath,
566  ASTNodeKind NodeKind) {
567  // Don't use heuristics if this is a real identifier, or not an
568  // identifier.
569  // Exception: dependent names, because those may have useful textual
570  // matches that AST-based heuristics cannot find.
571  if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||
572  !Word.LikelyIdentifier || !Index)
573  return {};
574  // We don't want to handle words in string literals. (It'd be nice to list
575  // *allowed* token kinds explicitly, but comment Tokens aren't retained).
576  if (Word.PartOfSpelledToken &&
577  isStringLiteral(Word.PartOfSpelledToken->kind()))
578  return {};
579 
580  const auto &SM = AST.getSourceManager();
581  // Look up the selected word in the index.
582  FuzzyFindRequest Req;
583  Req.Query = Word.Text.str();
584  Req.ProximityPaths = {MainFilePath};
585  // Find the namespaces to query by lexing the file.
586  Req.Scopes =
587  visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());
588  // FIXME: For extra strictness, consider AnyScope=false.
589  Req.AnyScope = true;
590  // We limit the results to 3 further below. This limit is to avoid fetching
591  // too much data, while still likely having enough for 3 results to remain
592  // after additional filtering.
593  Req.Limit = 10;
594  bool TooMany = false;
595  using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
596  std::vector<ScoredLocatedSymbol> ScoredResults;
597  Index->fuzzyFind(Req, [&](const Symbol &Sym) {
598  // Only consider exact name matches, including case.
599  // This is to avoid too many false positives.
600  // We could relax this in the future (e.g. to allow for typos) if we make
601  // the query more accurate by other means.
602  if (Sym.Name != Word.Text)
603  return;
604 
605  // Exclude constructor results. They have the same name as the class,
606  // but we don't have enough context to prefer them over the class.
607  if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)
608  return;
609 
610  auto MaybeDeclLoc =
611  indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
612  if (!MaybeDeclLoc) {
613  log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
614  return;
615  }
616  LocatedSymbol Located;
617  Located.PreferredDeclaration = *MaybeDeclLoc;
618  Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
619  Located.ID = Sym.ID;
620  if (Sym.Definition) {
621  auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
622  if (!MaybeDefLoc) {
623  log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
624  return;
625  }
626  Located.PreferredDeclaration = *MaybeDefLoc;
627  Located.Definition = *MaybeDefLoc;
628  }
629 
630  if (ScoredResults.size() >= 5) {
631  // If we have more than 5 results, don't return anything,
632  // as confidence is too low.
633  // FIXME: Alternatively, try a stricter query?
634  TooMany = true;
635  return;
636  }
637 
639  Quality.merge(Sym);
640  SymbolRelevanceSignals Relevance;
641  Relevance.Name = Sym.Name;
643  Relevance.merge(Sym);
644  auto Score = evaluateSymbolAndRelevance(Quality.evaluateHeuristics(),
645  Relevance.evaluateHeuristics());
646  dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,
647  Sym.Name, Score, Quality, Relevance);
648 
649  ScoredResults.push_back({Score, std::move(Located)});
650  });
651 
652  if (TooMany) {
653  vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
654  Word.Text);
655  return {};
656  }
657 
658  llvm::sort(ScoredResults,
659  [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {
660  return A.first > B.first;
661  });
662  std::vector<LocatedSymbol> Results;
663  for (auto &Res : std::move(ScoredResults))
664  Results.push_back(std::move(Res.second));
665  if (Results.empty())
666  vlog("No heuristic index definition for {0}", Word.Text);
667  else
668  log("Found definition heuristically in index for {0}", Word.Text);
669  return Results;
670 }
671 
672 const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
673  const syntax::TokenBuffer &TB) {
674  // Don't use heuristics if this is a real identifier.
675  // Unlikely identifiers are OK if they were used as identifiers nearby.
676  if (Word.ExpandedToken)
677  return nullptr;
678  // We don't want to handle words in string literals. (It'd be nice to list
679  // *allowed* token kinds explicitly, but comment Tokens aren't retained).
680  if (Word.PartOfSpelledToken &&
681  isStringLiteral(Word.PartOfSpelledToken->kind()))
682  return {};
683 
684  const SourceManager &SM = TB.sourceManager();
685  // We prefer the closest possible token, line-wise. Backwards is penalized.
686  // Ties are implicitly broken by traversal order (first-one-wins).
687  auto File = SM.getFileID(Word.Location);
688  unsigned WordLine = SM.getSpellingLineNumber(Word.Location);
689  auto Cost = [&](SourceLocation Loc) -> unsigned {
690  assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
691  unsigned Line = SM.getSpellingLineNumber(Loc);
692  return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
693  };
694  const syntax::Token *BestTok = nullptr;
695  unsigned BestCost = -1;
696  // Search bounds are based on word length:
697  // - forward: 2^N lines
698  // - backward: 2^(N-1) lines.
699  unsigned MaxDistance =
700  1U << std::min<unsigned>(Word.Text.size(),
701  std::numeric_limits<unsigned>::digits - 1);
702  // Line number for SM.translateLineCol() should be one-based, also
703  // SM.translateLineCol() can handle line number greater than
704  // number of lines in the file.
705  // - LineMin = max(1, WordLine + 1 - 2^(N-1))
706  // - LineMax = WordLine + 1 + 2^N
707  unsigned LineMin =
708  WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
709  unsigned LineMax = WordLine + 1 + MaxDistance;
710  SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);
711  assert(LocMin.isValid());
712  SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);
713  assert(LocMax.isValid());
714 
715  // Updates BestTok and BestCost if Tok is a good candidate.
716  // May return true if the cost is too high for this token.
717  auto Consider = [&](const syntax::Token &Tok) {
718  if (Tok.location() < LocMin || Tok.location() > LocMax)
719  return true; // we are too far from the word, break the outer loop.
720  if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
721  return false;
722  // No point guessing the same location we started with.
723  if (Tok.location() == Word.Location)
724  return false;
725  // We've done cheap checks, compute cost so we can break the caller's loop.
726  unsigned TokCost = Cost(Tok.location());
727  if (TokCost >= BestCost)
728  return true; // causes the outer loop to break.
729  // Allow locations that might be part of the AST, and macros (even if empty)
730  // but not things like disabled preprocessor sections.
731  if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
732  return false;
733  // We already verified this token is an improvement.
734  BestCost = TokCost;
735  BestTok = &Tok;
736  return false;
737  };
738  auto SpelledTokens = TB.spelledTokens(File);
739  // Find where the word occurred in the token stream, to search forward & back.
740  auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {
741  assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));
742  return T.location() < Word.Location; // Comparison OK: same file.
743  });
744  // Search for matches after the cursor.
745  for (const syntax::Token &Tok : llvm::makeArrayRef(I, SpelledTokens.end()))
746  if (Consider(Tok))
747  break; // costs of later tokens are greater...
748  // Search for matches before the cursor.
749  for (const syntax::Token &Tok :
750  llvm::reverse(llvm::makeArrayRef(SpelledTokens.begin(), I)))
751  if (Consider(Tok))
752  break;
753 
754  if (BestTok)
755  vlog(
756  "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
757  Word.Text, Word.Location.printToString(SM),
758  BestTok->location().printToString(SM));
759 
760  return BestTok;
761 }
762 
763 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
764  const SymbolIndex *Index) {
765  const auto &SM = AST.getSourceManager();
766  auto MainFilePath =
767  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
768  if (!MainFilePath) {
769  elog("Failed to get a path for the main file, so no references");
770  return {};
771  }
772 
773  if (auto File = locateFileReferent(Pos, AST, *MainFilePath))
774  return {std::move(*File)};
775 
776  auto CurLoc = sourceLocationInMainFile(SM, Pos);
777  if (!CurLoc) {
778  elog("locateSymbolAt failed to convert position to source location: {0}",
779  CurLoc.takeError());
780  return {};
781  }
782 
783  const syntax::Token *TouchedIdentifier = nullptr;
784  auto TokensTouchingCursor =
785  syntax::spelledTokensTouching(*CurLoc, AST.getTokens());
786  for (const syntax::Token &Tok : TokensTouchingCursor) {
787  if (Tok.kind() == tok::identifier) {
788  if (auto Macro = locateMacroReferent(Tok, AST, *MainFilePath))
789  // Don't look at the AST or index if we have a macro result.
790  // (We'd just return declarations referenced from the macro's
791  // expansion.)
792  return {*std::move(Macro)};
793 
794  TouchedIdentifier = &Tok;
795  break;
796  }
797 
798  if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
799  // go-to-definition on auto should find the definition of the deduced
800  // type, if possible
801  if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
802  auto LocSym = locateSymbolForType(AST, *Deduced);
803  if (!LocSym.empty())
804  return LocSym;
805  }
806  }
807  }
808 
809  ASTNodeKind NodeKind;
810  auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,
811  *MainFilePath, Index, NodeKind);
812  if (!ASTResults.empty())
813  return ASTResults;
814 
815  // If the cursor can't be resolved directly, try fallback strategies.
816  auto Word =
817  SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());
818  if (Word) {
819  // Is the same word nearby a real identifier that might refer to something?
820  if (const syntax::Token *NearbyIdent =
822  if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) {
823  log("Found macro definition heuristically using nearby identifier {0}",
824  Word->Text);
825  return {*std::move(Macro)};
826  }
827  ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,
828  *MainFilePath, Index, NodeKind);
829  if (!ASTResults.empty()) {
830  log("Found definition heuristically using nearby identifier {0}",
831  NearbyIdent->text(SM));
832  return ASTResults;
833  }
834  vlog("No definition found using nearby identifier {0} at {1}", Word->Text,
835  Word->Location.printToString(SM));
836  }
837  // No nearby word, or it didn't refer to anything either. Try the index.
838  auto TextualResults =
839  locateSymbolTextually(*Word, AST, Index, *MainFilePath, NodeKind);
840  if (!TextualResults.empty())
841  return TextualResults;
842  }
843 
844  return {};
845 }
846 
847 std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
848  const auto &SM = AST.getSourceManager();
849  auto MainFilePath =
850  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
851  if (!MainFilePath) {
852  elog("Failed to get a path for the main file, so no links");
853  return {};
854  }
855 
856  std::vector<DocumentLink> Result;
857  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
858  if (Inc.Resolved.empty())
859  continue;
860  auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
861  const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
862  assert(HashTok && "got inclusion at wrong offset");
863  const auto *IncludeTok = std::next(HashTok);
864  const auto *FileTok = std::next(IncludeTok);
865  // FileTok->range is not sufficient here, as raw lexing wouldn't yield
866  // correct tokens for angled filenames. Hence we explicitly use
867  // Inc.Written's length.
868  auto FileRange =
869  syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
870  .toCharRange(SM);
871 
872  Result.push_back(
873  DocumentLink({halfOpenToRange(SM, FileRange),
874  URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
875  }
876 
877  return Result;
878 }
879 
880 namespace {
881 
882 /// Collects references to symbols within the main file.
883 class ReferenceFinder : public index::IndexDataConsumer {
884 public:
885  struct Reference {
886  syntax::Token SpelledTok;
887  index::SymbolRoleSet Role;
889 
890  Range range(const SourceManager &SM) const {
891  return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));
892  }
893  };
894 
895  ReferenceFinder(const ParsedAST &AST,
896  const llvm::DenseSet<SymbolID> &TargetIDs, bool PerToken)
897  : PerToken(PerToken), AST(AST), TargetIDs(TargetIDs) {}
898 
899  std::vector<Reference> take() && {
900  llvm::sort(References, [](const Reference &L, const Reference &R) {
901  auto LTok = L.SpelledTok.location();
902  auto RTok = R.SpelledTok.location();
903  return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
904  });
905  // We sometimes see duplicates when parts of the AST get traversed twice.
906  References.erase(std::unique(References.begin(), References.end(),
907  [](const Reference &L, const Reference &R) {
908  auto LTok = L.SpelledTok.location();
909  auto RTok = R.SpelledTok.location();
910  return std::tie(LTok, L.Role) ==
911  std::tie(RTok, R.Role);
912  }),
913  References.end());
914  return std::move(References);
915  }
916 
917  bool
918  handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
919  llvm::ArrayRef<index::SymbolRelation> Relations,
920  SourceLocation Loc,
921  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
922  const SourceManager &SM = AST.getSourceManager();
923  if (!isInsideMainFile(Loc, SM))
924  return true;
926  if (!TargetIDs.contains(ID))
927  return true;
928  const auto &TB = AST.getTokens();
929 
930  llvm::SmallVector<SourceLocation, 1> Locs;
931  if (PerToken) {
932  // Check whether this is one of the few constructs where the reference
933  // can be split over several tokens.
934  if (auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
935  OME->getSelectorLocs(Locs);
936  } else if (auto *OMD =
937  llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
938  OMD->getSelectorLocs(Locs);
939  }
940  // Sanity check: we expect the *first* token to match the reported loc.
941  // Otherwise, maybe it was e.g. some other kind of reference to a Decl.
942  if (!Locs.empty() && Locs.front() != Loc)
943  Locs.clear(); // First token doesn't match, assume our guess was wrong.
944  }
945  if (Locs.empty())
946  Locs.push_back(Loc);
947 
948  for (SourceLocation L : Locs) {
949  L = SM.getFileLoc(L);
950  if (const auto *Tok = TB.spelledTokenAt(L))
951  References.push_back({*Tok, Roles, ID});
952  }
953  return true;
954  }
955 
956 private:
957  bool PerToken; // If true, report 3 references for split ObjC selector names.
958  std::vector<Reference> References;
959  const ParsedAST &AST;
960  const llvm::DenseSet<SymbolID> &TargetIDs;
961 };
962 
963 std::vector<ReferenceFinder::Reference>
964 findRefs(const llvm::DenseSet<SymbolID> &IDs, ParsedAST &AST, bool PerToken) {
965  ReferenceFinder RefFinder(AST, IDs, PerToken);
966  index::IndexingOptions IndexOpts;
967  IndexOpts.SystemSymbolFilter =
968  index::IndexingOptions::SystemSymbolFilterKind::All;
969  IndexOpts.IndexFunctionLocals = true;
970  IndexOpts.IndexParametersInDeclarations = true;
971  IndexOpts.IndexTemplateParameters = true;
972  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
973  AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
974  return std::move(RefFinder).take();
975 }
976 
977 const Stmt *getFunctionBody(DynTypedNode N) {
978  if (const auto *FD = N.get<FunctionDecl>())
979  return FD->getBody();
980  if (const auto *FD = N.get<BlockDecl>())
981  return FD->getBody();
982  if (const auto *FD = N.get<LambdaExpr>())
983  return FD->getBody();
984  if (const auto *FD = N.get<ObjCMethodDecl>())
985  return FD->getBody();
986  return nullptr;
987 }
988 
989 const Stmt *getLoopBody(DynTypedNode N) {
990  if (const auto *LS = N.get<ForStmt>())
991  return LS->getBody();
992  if (const auto *LS = N.get<CXXForRangeStmt>())
993  return LS->getBody();
994  if (const auto *LS = N.get<WhileStmt>())
995  return LS->getBody();
996  if (const auto *LS = N.get<DoStmt>())
997  return LS->getBody();
998  return nullptr;
999 }
1000 
1001 // AST traversal to highlight control flow statements under some root.
1002 // Once we hit further control flow we prune the tree (or at least restrict
1003 // what we highlight) so we capture e.g. breaks from the outer loop only.
1004 class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {
1005  // Types of control-flow statements we might highlight.
1006  enum Target {
1007  Break = 1,
1008  Continue = 2,
1009  Return = 4,
1010  Case = 8,
1011  Throw = 16,
1012  Goto = 32,
1013  All = Break | Continue | Return | Case | Throw | Goto,
1014  };
1015  int Ignore = 0; // bitmask of Target - what are we *not* highlighting?
1016  SourceRange Bounds; // Half-open, restricts reported targets.
1017  std::vector<SourceLocation> &Result;
1018  const SourceManager &SM;
1019 
1020  // Masks out targets for a traversal into D.
1021  // Traverses the subtree using Delegate() if any targets remain.
1022  template <typename Func>
1023  bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {
1024  auto RestoreIgnore = llvm::make_scope_exit(
1025  [OldIgnore(Ignore), this] { Ignore = OldIgnore; });
1026  if (getFunctionBody(D))
1027  Ignore = All;
1028  else if (getLoopBody(D))
1029  Ignore |= Continue | Break;
1030  else if (D.get<SwitchStmt>())
1031  Ignore |= Break | Case;
1032  // Prune tree if we're not looking for anything.
1033  return (Ignore == All) ? true : Delegate();
1034  }
1035 
1036  void found(Target T, SourceLocation Loc) {
1037  if (T & Ignore)
1038  return;
1039  if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1040  SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1041  return;
1042  Result.push_back(Loc);
1043  }
1044 
1045 public:
1046  FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1047  const SourceManager &SM)
1048  : Bounds(Bounds), Result(Result), SM(SM) {}
1049 
1050  // When traversing function or loops, limit targets to those that still
1051  // refer to the original root.
1052  bool TraverseDecl(Decl *D) {
1053  return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1054  return RecursiveASTVisitor::TraverseDecl(D);
1055  });
1056  }
1057  bool TraverseStmt(Stmt *S) {
1058  return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1059  return RecursiveASTVisitor::TraverseStmt(S);
1060  });
1061  }
1062 
1063  // Add leaves that we found and want.
1064  bool VisitReturnStmt(ReturnStmt *R) {
1065  found(Return, R->getReturnLoc());
1066  return true;
1067  }
1068  bool VisitBreakStmt(BreakStmt *B) {
1069  found(Break, B->getBreakLoc());
1070  return true;
1071  }
1072  bool VisitContinueStmt(ContinueStmt *C) {
1073  found(Continue, C->getContinueLoc());
1074  return true;
1075  }
1076  bool VisitSwitchCase(SwitchCase *C) {
1077  found(Case, C->getKeywordLoc());
1078  return true;
1079  }
1080  bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1081  found(Throw, T->getThrowLoc());
1082  return true;
1083  }
1084  bool VisitGotoStmt(GotoStmt *G) {
1085  // Goto is interesting if its target is outside the root.
1086  if (const auto *LD = G->getLabel()) {
1087  if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1088  SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1089  found(Goto, G->getGotoLoc());
1090  }
1091  return true;
1092  }
1093 };
1094 
1095 // Given a location within a switch statement, return the half-open range that
1096 // covers the case it's contained in.
1097 // We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
1098 SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,
1099  const SourceManager &SM) {
1100  // Cases are not stored in order, sort them first.
1101  // (In fact they seem to be stored in reverse order, don't rely on this)
1102  std::vector<const SwitchCase *> Cases;
1103  for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1104  Case = Case->getNextSwitchCase())
1105  Cases.push_back(Case);
1106  llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {
1107  return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1108  });
1109 
1110  // Find the first case after the target location, the end of our range.
1111  auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {
1112  return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());
1113  });
1114  SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1115  : (*CaseAfter)->getKeywordLoc();
1116 
1117  // Our target can be before the first case - cases are optional!
1118  if (CaseAfter == Cases.begin())
1119  return SourceRange(Switch.getBeginLoc(), End);
1120  // The start of our range is usually the previous case, but...
1121  auto CaseBefore = std::prev(CaseAfter);
1122  // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
1123  while (CaseBefore != Cases.begin() &&
1124  (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1125  --CaseBefore;
1126  return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1127 }
1128 
1129 // Returns the locations of control flow statements related to N. e.g.:
1130 // for => branches: break/continue/return/throw
1131 // break => controlling loop (forwhile/do), and its related control flow
1132 // return => all returns/throws from the same function
1133 // When an inner block is selected, we include branches bound to outer blocks
1134 // as these are exits from the inner block. e.g. return in a for loop.
1135 // FIXME: We don't analyze catch blocks, throw is treated the same as return.
1136 std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {
1137  const SourceManager &SM =
1138  N.getDeclContext().getParentASTContext().getSourceManager();
1139  std::vector<SourceLocation> Result;
1140 
1141  // First, check if we're at a node that can resolve to a root.
1142  enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;
1143  if (N.ASTNode.get<BreakStmt>()) {
1144  Cursor = Cur::Break;
1145  } else if (N.ASTNode.get<ContinueStmt>()) {
1146  Cursor = Cur::Continue;
1147  } else if (N.ASTNode.get<ReturnStmt>()) {
1148  Cursor = Cur::Return;
1149  } else if (N.ASTNode.get<CXXThrowExpr>()) {
1150  Cursor = Cur::Throw;
1151  } else if (N.ASTNode.get<SwitchCase>()) {
1152  Cursor = Cur::Case;
1153  } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1154  // We don't know what root to associate with, but highlight the goto/label.
1155  Result.push_back(GS->getGotoLoc());
1156  if (const auto *LD = GS->getLabel())
1157  Result.push_back(LD->getLocation());
1158  Cursor = Cur::None;
1159  } else {
1160  Cursor = Cur::None;
1161  }
1162 
1163  const Stmt *Root = nullptr; // Loop or function body to traverse.
1164  SourceRange Bounds;
1165  // Look up the tree for a root (or just at this node if we didn't find a leaf)
1166  for (const auto *P = &N; P; P = P->Parent) {
1167  // return associates with enclosing function
1168  if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1169  if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1170  Root = FunctionBody;
1171  }
1172  break; // other leaves don't cross functions.
1173  }
1174  // break/continue associate with enclosing loop.
1175  if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1176  if (Cursor == Cur::None || Cursor == Cur::Break ||
1177  Cursor == Cur::Continue) {
1178  Root = LoopBody;
1179  // Highlight the loop keyword itself.
1180  // FIXME: for do-while, this only covers the `do`..
1181  Result.push_back(P->ASTNode.getSourceRange().getBegin());
1182  break;
1183  }
1184  }
1185  // For switches, users think of case statements as control flow blocks.
1186  // We highlight only occurrences surrounded by the same case.
1187  // We don't detect fallthrough (other than 'case X, case Y').
1188  if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1189  if (Cursor == Cur::Break || Cursor == Cur::Case) {
1190  Result.push_back(SS->getSwitchLoc()); // Highlight the switch.
1191  Root = SS->getBody();
1192  // Limit to enclosing case, if there is one.
1193  Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1194  break;
1195  }
1196  }
1197  // If we didn't start at some interesting node, we're done.
1198  if (Cursor == Cur::None)
1199  break;
1200  }
1201  if (Root) {
1202  if (!Bounds.isValid())
1203  Bounds = Root->getSourceRange();
1204  FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));
1205  }
1206  return Result;
1207 }
1208 
1209 DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
1210  const SourceManager &SM) {
1211  DocumentHighlight DH;
1212  DH.range = Ref.range(SM);
1213  if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1214  DH.kind = DocumentHighlightKind::Write;
1215  else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1216  DH.kind = DocumentHighlightKind::Read;
1217  else
1218  DH.kind = DocumentHighlightKind::Text;
1219  return DH;
1220 }
1221 
1222 llvm::Optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1223  const syntax::TokenBuffer &TB) {
1224  Loc = TB.sourceManager().getFileLoc(Loc);
1225  if (const auto *Tok = TB.spelledTokenAt(Loc)) {
1226  DocumentHighlight Result;
1227  Result.range = halfOpenToRange(
1228  TB.sourceManager(),
1229  CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1230  return Result;
1231  }
1232  return llvm::None;
1233 }
1234 
1235 } // namespace
1236 
1237 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
1238  Position Pos) {
1239  const SourceManager &SM = AST.getSourceManager();
1240  // FIXME: show references to macro within file?
1241  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1242  if (!CurLoc) {
1243  llvm::consumeError(CurLoc.takeError());
1244  return {};
1245  }
1246  std::vector<DocumentHighlight> Result;
1247  auto TryTree = [&](SelectionTree ST) {
1248  if (const SelectionTree::Node *N = ST.commonAncestor()) {
1249  DeclRelationSet Relations =
1251  auto Decls =
1252  targetDecl(N->ASTNode, Relations, AST.getHeuristicResolver());
1253  if (!Decls.empty()) {
1254  // FIXME: we may get multiple DocumentHighlights with the same location
1255  // and different kinds, deduplicate them.
1256  llvm::DenseSet<SymbolID> Targets;
1257  for (const NamedDecl *ND : Decls)
1258  if (auto ID = getSymbolID(ND))
1259  Targets.insert(ID);
1260  for (const auto &Ref : findRefs(Targets, AST, /*PerToken=*/true))
1261  Result.push_back(toHighlight(Ref, SM));
1262  return true;
1263  }
1264  auto ControlFlow = relatedControlFlow(*N);
1265  if (!ControlFlow.empty()) {
1266  for (SourceLocation Loc : ControlFlow)
1267  if (auto Highlight = toHighlight(Loc, AST.getTokens()))
1268  Result.push_back(std::move(*Highlight));
1269  return true;
1270  }
1271  }
1272  return false;
1273  };
1274 
1275  unsigned Offset =
1276  AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1278  Offset, TryTree);
1279  return Result;
1280 }
1281 
1282 std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
1283  const SymbolIndex *Index) {
1284  // We rely on index to find the implementations in subclasses.
1285  // FIXME: Index can be stale, so we may loose some latest results from the
1286  // main file.
1287  if (!Index)
1288  return {};
1289  const SourceManager &SM = AST.getSourceManager();
1290  auto MainFilePath =
1291  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1292  if (!MainFilePath) {
1293  elog("Failed to get a path for the main file, so no implementations.");
1294  return {};
1295  }
1296  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1297  if (!CurLoc) {
1298  elog("Failed to convert position to source location: {0}",
1299  CurLoc.takeError());
1300  return {};
1301  }
1302  DeclRelationSet Relations =
1304  llvm::DenseSet<SymbolID> IDs;
1306  for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) {
1307  if (const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1308  if (CXXMD->isVirtual()) {
1309  IDs.insert(getSymbolID(ND));
1311  }
1312  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1313  IDs.insert(getSymbolID(RD));
1315  }
1316  }
1317  return findImplementors(std::move(IDs), QueryKind, Index, *MainFilePath);
1318 }
1319 
1320 namespace {
1321 // Recursively finds all the overridden methods of `CMD` in complete type
1322 // hierarchy.
1323 void getOverriddenMethods(const CXXMethodDecl *CMD,
1324  llvm::DenseSet<SymbolID> &OverriddenMethods) {
1325  if (!CMD)
1326  return;
1327  for (const CXXMethodDecl *Base : CMD->overridden_methods()) {
1328  if (auto ID = getSymbolID(Base))
1329  OverriddenMethods.insert(ID);
1330  getOverriddenMethods(Base, OverriddenMethods);
1331  }
1332 }
1333 } // namespace
1334 
1336  const SymbolIndex *Index) {
1338  const SourceManager &SM = AST.getSourceManager();
1339  auto MainFilePath =
1340  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1341  if (!MainFilePath) {
1342  elog("Failed to get a path for the main file, so no references");
1343  return Results;
1344  }
1345  auto URIMainFile = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
1346  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1347  if (!CurLoc) {
1348  llvm::consumeError(CurLoc.takeError());
1349  return {};
1350  }
1351 
1352  llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1353 
1354  const auto *IdentifierAtCursor =
1355  syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1356  llvm::Optional<DefinedMacro> Macro;
1357  if (IdentifierAtCursor)
1358  Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1359  if (Macro) {
1360  // Handle references to macro.
1361  if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
1362  // Collect macro references from main file.
1363  const auto &IDToRefs = AST.getMacros().MacroRefs;
1364  auto Refs = IDToRefs.find(MacroSID);
1365  if (Refs != IDToRefs.end()) {
1366  for (const auto &Ref : Refs->second) {
1368  Result.Loc.range = Ref.Rng;
1369  Result.Loc.uri = URIMainFile;
1370  if (Ref.IsDefinition) {
1371  Result.Attributes |= ReferencesResult::Declaration;
1372  Result.Attributes |= ReferencesResult::Definition;
1373  }
1374  Results.References.push_back(std::move(Result));
1375  }
1376  }
1377  IDsToQuery.insert(MacroSID);
1378  }
1379  } else {
1380  // Handle references to Decls.
1381 
1382  DeclRelationSet Relations =
1384  std::vector<const NamedDecl *> Decls =
1385  getDeclAtPosition(AST, *CurLoc, Relations);
1386  llvm::DenseSet<SymbolID> TargetsInMainFile;
1387  for (const NamedDecl *D : Decls) {
1388  auto ID = getSymbolID(D);
1389  if (!ID)
1390  continue;
1391  TargetsInMainFile.insert(ID);
1392  // Not all symbols can be referenced from outside (e.g. function-locals).
1393  // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1394  // we know this file isn't a header. The details might be tricky.
1395  if (D->getParentFunctionOrMethod())
1396  continue;
1397  IDsToQuery.insert(ID);
1398  }
1399 
1401  if (Index) {
1403  for (const NamedDecl *ND : Decls) {
1404  // Special case: For virtual methods, report decl/def of overrides and
1405  // references to all overridden methods in complete type hierarchy.
1406  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1407  if (CMD->isVirtual()) {
1408  if (auto ID = getSymbolID(CMD))
1409  OverriddenBy.Subjects.insert(ID);
1410  getOverriddenMethods(CMD, OverriddenMethods);
1411  }
1412  }
1413  }
1414  }
1415 
1416  // We traverse the AST to find references in the main file.
1417  auto MainFileRefs = findRefs(TargetsInMainFile, AST, /*PerToken=*/false);
1418  // We may get multiple refs with the same location and different Roles, as
1419  // cross-reference is only interested in locations, we deduplicate them
1420  // by the location to avoid emitting duplicated locations.
1421  MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1422  [](const ReferenceFinder::Reference &L,
1423  const ReferenceFinder::Reference &R) {
1424  return L.SpelledTok.location() ==
1425  R.SpelledTok.location();
1426  }),
1427  MainFileRefs.end());
1428  for (const auto &Ref : MainFileRefs) {
1430  Result.Loc.range = Ref.range(SM);
1431  Result.Loc.uri = URIMainFile;
1432  if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Declaration))
1433  Result.Attributes |= ReferencesResult::Declaration;
1434  // clang-index doesn't report definitions as declarations, but they are.
1435  if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Definition))
1436  Result.Attributes |=
1438  Results.References.push_back(std::move(Result));
1439  }
1440  // Add decl/def of overridding methods.
1441  if (Index && !OverriddenBy.Subjects.empty()) {
1442  Index->relations(OverriddenBy, [&](const SymbolID &Subject,
1443  const Symbol &Object) {
1444  if (Limit && Results.References.size() >= Limit) {
1445  Results.HasMore = true;
1446  return;
1447  }
1448  const auto LSPLocDecl =
1449  toLSPLocation(Object.CanonicalDeclaration, *MainFilePath);
1450  const auto LSPLocDef = toLSPLocation(Object.Definition, *MainFilePath);
1451  if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1453  Result.Loc = std::move(*LSPLocDecl);
1454  Result.Attributes =
1456  Results.References.push_back(std::move(Result));
1457  }
1458  if (LSPLocDef) {
1460  Result.Loc = std::move(*LSPLocDef);
1461  Result.Attributes = ReferencesResult::Declaration |
1464  Results.References.push_back(std::move(Result));
1465  }
1466  });
1467  }
1468  }
1469  // Now query the index for references from other files.
1470  auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool AllowAttributes,
1471  bool AllowMainFileSymbols) {
1472  if (IDs.empty() || !Index || Results.HasMore)
1473  return;
1474  RefsRequest Req;
1475  Req.IDs = std::move(IDs);
1476  if (Limit) {
1477  if (Limit < Results.References.size()) {
1478  // We've already filled our quota, still check the index to correctly
1479  // return the `HasMore` info.
1480  Req.Limit = 0;
1481  } else {
1482  // Query index only for the remaining size.
1483  Req.Limit = Limit - Results.References.size();
1484  }
1485  }
1486  Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
1487  auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
1488  // Avoid indexed results for the main file - the AST is authoritative.
1489  if (!LSPLoc ||
1490  (!AllowMainFileSymbols && LSPLoc->uri.file() == *MainFilePath))
1491  return;
1493  Result.Loc = std::move(*LSPLoc);
1494  if (AllowAttributes) {
1496  Result.Attributes |= ReferencesResult::Declaration;
1497  // FIXME: our index should definitely store def | decl separately!
1499  Result.Attributes |=
1501  }
1502  Results.References.push_back(std::move(Result));
1503  });
1504  };
1505  QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,
1506  /*AllowMainFileSymbols=*/false);
1507  // For a virtual method: Occurrences of BaseMethod should be treated as refs
1508  // and not as decl/def. Allow symbols from main file since AST does not report
1509  // these.
1510  QueryIndex(std::move(OverriddenMethods), /*AllowAttributes=*/false,
1511  /*AllowMainFileSymbols=*/true);
1512  return Results;
1513 }
1514 
1515 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
1516  const SourceManager &SM = AST.getSourceManager();
1517  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1518  if (!CurLoc) {
1519  llvm::consumeError(CurLoc.takeError());
1520  return {};
1521  }
1522 
1523  std::vector<SymbolDetails> Results;
1524 
1525  // We also want the targets of using-decls, so we include
1526  // DeclRelation::Underlying.
1529  for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1530  SymbolDetails NewSymbol;
1531  std::string QName = printQualifiedName(*D);
1532  auto SplitQName = splitQualifiedName(QName);
1533  NewSymbol.containerName = std::string(SplitQName.first);
1534  NewSymbol.name = std::string(SplitQName.second);
1535 
1536  if (NewSymbol.containerName.empty()) {
1537  if (const auto *ParentND =
1538  dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1539  NewSymbol.containerName = printQualifiedName(*ParentND);
1540  }
1541  llvm::SmallString<32> USR;
1542  if (!index::generateUSRForDecl(D, USR)) {
1543  NewSymbol.USR = std::string(USR.str());
1544  NewSymbol.ID = SymbolID(NewSymbol.USR);
1545  }
1546  Results.push_back(std::move(NewSymbol));
1547  }
1548 
1549  const auto *IdentifierAtCursor =
1550  syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1551  if (!IdentifierAtCursor)
1552  return Results;
1553 
1554  if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1555  SymbolDetails NewMacro;
1556  NewMacro.name = std::string(M->Name);
1557  llvm::SmallString<32> USR;
1558  if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
1559  SM, USR)) {
1560  NewMacro.USR = std::string(USR.str());
1561  NewMacro.ID = SymbolID(NewMacro.USR);
1562  }
1563  Results.push_back(std::move(NewMacro));
1564  }
1565 
1566  return Results;
1567 }
1568 
1569 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1570  OS << S.Name << ": " << S.PreferredDeclaration;
1571  if (S.Definition)
1572  OS << " def=" << *S.Definition;
1573  return OS;
1574 }
1575 
1576 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1577  const ReferencesResult::Reference &R) {
1578  OS << R.Loc;
1580  OS << " [decl]";
1582  OS << " [def]";
1584  OS << " [override]";
1585  return OS;
1586 }
1587 
1588 template <typename HierarchyItem>
1589 static llvm::Optional<HierarchyItem> declToHierarchyItem(const NamedDecl &ND) {
1590  ASTContext &Ctx = ND.getASTContext();
1591  auto &SM = Ctx.getSourceManager();
1592  SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
1593  SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
1594  SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
1595  const auto DeclRange =
1596  toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});
1597  if (!DeclRange)
1598  return llvm::None;
1599  auto FilePath =
1600  getCanonicalPath(SM.getFileEntryForID(SM.getFileID(NameLoc)), SM);
1601  auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1602  if (!FilePath || !TUPath)
1603  return llvm::None; // Not useful without a uri.
1604 
1605  Position NameBegin = sourceLocToPosition(SM, NameLoc);
1606  Position NameEnd = sourceLocToPosition(
1607  SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1608 
1609  index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1610  // FIXME: This is not classifying constructors, destructors and operators
1611  // correctly.
1612  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
1613 
1614  HierarchyItem HI;
1615  HI.name = printName(Ctx, ND);
1616  HI.kind = SK;
1617  HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),
1618  sourceLocToPosition(SM, DeclRange->getEnd())};
1619  HI.selectionRange = Range{NameBegin, NameEnd};
1620  if (!HI.range.contains(HI.selectionRange)) {
1621  // 'selectionRange' must be contained in 'range', so in cases where clang
1622  // reports unrelated ranges we need to reconcile somehow.
1623  HI.range = HI.selectionRange;
1624  }
1625 
1626  HI.uri = URIForFile::canonicalize(*FilePath, *TUPath);
1627 
1628  // Compute the SymbolID and store it in the 'data' field.
1629  // This allows typeHierarchy/resolve to be used to
1630  // resolve children of items returned in a previous request
1631  // for parents.
1632  if (auto ID = getSymbolID(&ND))
1633  HI.data = ID.str();
1634 
1635  return HI;
1636 }
1637 
1638 static llvm::Optional<TypeHierarchyItem>
1639 declToTypeHierarchyItem(const NamedDecl &ND) {
1640  auto Result = declToHierarchyItem<TypeHierarchyItem>(ND);
1641  if (Result)
1642  Result->deprecated = ND.isDeprecated();
1643  return Result;
1644 }
1645 
1646 static llvm::Optional<CallHierarchyItem>
1647 declToCallHierarchyItem(const NamedDecl &ND) {
1648  auto Result = declToHierarchyItem<CallHierarchyItem>(ND);
1649  if (Result && ND.isDeprecated())
1650  Result->tags.push_back(SymbolTag::Deprecated);
1651  return Result;
1652 }
1653 
1654 template <typename HierarchyItem>
1655 static llvm::Optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
1656  PathRef TUPath) {
1657  auto Loc = symbolToLocation(S, TUPath);
1658  if (!Loc) {
1659  elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1660  return llvm::None;
1661  }
1662  HierarchyItem HI;
1663  HI.name = std::string(S.Name);
1664  HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1665  HI.selectionRange = Loc->range;
1666  // FIXME: Populate 'range' correctly
1667  // (https://github.com/clangd/clangd/issues/59).
1668  HI.range = HI.selectionRange;
1669  HI.uri = Loc->uri;
1670  // Store the SymbolID in the 'data' field. The client will
1671  // send this back in requests to resolve additional levels
1672  // of the hierarchy.
1673  HI.data = S.ID.str();
1674 
1675  return HI;
1676 }
1677 
1678 static llvm::Optional<TypeHierarchyItem>
1680  auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1681  if (Result)
1682  Result->deprecated = (S.Flags & Symbol::Deprecated);
1683  return Result;
1684 }
1685 
1686 static llvm::Optional<CallHierarchyItem>
1688  auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1689  if (Result && (S.Flags & Symbol::Deprecated))
1690  Result->tags.push_back(SymbolTag::Deprecated);
1691  return Result;
1692 }
1693 
1694 static void fillSubTypes(const SymbolID &ID,
1695  std::vector<TypeHierarchyItem> &SubTypes,
1696  const SymbolIndex *Index, int Levels, PathRef TUPath) {
1697  RelationsRequest Req;
1698  Req.Subjects.insert(ID);
1700  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
1701  if (Optional<TypeHierarchyItem> ChildSym =
1702  symbolToTypeHierarchyItem(Object, TUPath)) {
1703  if (Levels > 1) {
1704  ChildSym->children.emplace();
1705  fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
1706  }
1707  SubTypes.emplace_back(std::move(*ChildSym));
1708  }
1709  });
1710 }
1711 
1712 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
1713 
1714 static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx,
1715  std::vector<TypeHierarchyItem> &SuperTypes,
1716  RecursionProtectionSet &RPSet) {
1717  // typeParents() will replace dependent template specializations
1718  // with their class template, so to avoid infinite recursion for
1719  // certain types of hierarchies, keep the templates encountered
1720  // along the parent chain in a set, and stop the recursion if one
1721  // starts to repeat.
1722  auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
1723  if (Pattern) {
1724  if (!RPSet.insert(Pattern).second) {
1725  return;
1726  }
1727  }
1728 
1729  for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
1730  if (Optional<TypeHierarchyItem> ParentSym =
1731  declToTypeHierarchyItem(*ParentDecl)) {
1732  ParentSym->parents.emplace();
1733  fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet);
1734  SuperTypes.emplace_back(std::move(*ParentSym));
1735  }
1736  }
1737 
1738  if (Pattern) {
1739  RPSet.erase(Pattern);
1740  }
1741 }
1742 
1743 const CXXRecordDecl *findRecordTypeAt(ParsedAST &AST, Position Pos) {
1744  auto RecordFromNode =
1745  [&AST](const SelectionTree::Node *N) -> const CXXRecordDecl * {
1746  if (!N)
1747  return nullptr;
1748 
1749  // Note: explicitReferenceTargets() will search for both template
1750  // instantiations and template patterns, and prefer the former if available
1751  // (generally, one will be available for non-dependent specializations of a
1752  // class template).
1753  auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying,
1754  AST.getHeuristicResolver());
1755  if (Decls.empty())
1756  return nullptr;
1757 
1758  const NamedDecl *D = Decls[0];
1759 
1760  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1761  // If this is a variable, use the type of the variable.
1762  return VD->getType().getTypePtr()->getAsCXXRecordDecl();
1763  }
1764 
1765  if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
1766  // If this is a method, use the type of the class.
1767  return Method->getParent();
1768  }
1769 
1770  // We don't handle FieldDecl because it's not clear what behaviour
1771  // the user would expect: the enclosing class type (as with a
1772  // method), or the field's type (as with a variable).
1773 
1774  return dyn_cast<CXXRecordDecl>(D);
1775  };
1776 
1777  const SourceManager &SM = AST.getSourceManager();
1778  const CXXRecordDecl *Result = nullptr;
1779  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1780  if (!Offset) {
1781  llvm::consumeError(Offset.takeError());
1782  return Result;
1783  }
1785  *Offset, [&](SelectionTree ST) {
1786  Result = RecordFromNode(ST.commonAncestor());
1787  return Result != nullptr;
1788  });
1789  return Result;
1790 }
1791 
1792 // Return the type most associated with an AST node.
1793 // This isn't precisely defined: we want "go to type" to do something useful.
1794 static QualType typeForNode(const SelectionTree::Node *N) {
1795  // If we're looking at a namespace qualifier, walk up to what it's qualifying.
1796  // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
1797  while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
1798  N = N->Parent;
1799  if (!N)
1800  return QualType();
1801 
1802  // If we're pointing at a type => return it.
1803  if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {
1804  if (llvm::isa<DeducedType>(TL->getTypePtr()))
1805  if (auto Deduced = getDeducedType(
1806  N->getDeclContext().getParentASTContext(), TL->getBeginLoc()))
1807  return *Deduced;
1808  // Exception: an alias => underlying type.
1809  if (llvm::isa<TypedefType>(TL->getTypePtr()))
1810  return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1811  return TL->getType();
1812  }
1813 
1814  // Constructor initializers => the type of thing being initialized.
1815  if (const auto *CCI = N->ASTNode.get<CXXCtorInitializer>()) {
1816  if (const FieldDecl *FD = CCI->getAnyMember())
1817  return FD->getType();
1818  if (const Type *Base = CCI->getBaseClass())
1819  return QualType(Base, 0);
1820  }
1821 
1822  // Base specifier => the base type.
1823  if (const auto *CBS = N->ASTNode.get<CXXBaseSpecifier>())
1824  return CBS->getType();
1825 
1826  if (const Decl *D = N->ASTNode.get<Decl>()) {
1827  struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1828  QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
1829  // Declaration of a type => that type.
1830  QualType VisitTypeDecl(const TypeDecl *D) {
1831  return QualType(D->getTypeForDecl(), 0);
1832  }
1833  // Exception: alias declaration => the underlying type, not the alias.
1834  QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
1835  return D->getUnderlyingType();
1836  }
1837  // Look inside templates.
1838  QualType VisitTemplateDecl(const TemplateDecl *D) {
1839  return Visit(D->getTemplatedDecl());
1840  }
1841  } V;
1842  return V.Visit(D);
1843  }
1844 
1845  if (const Stmt *S = N->ASTNode.get<Stmt>()) {
1846  struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1847  // Null-safe version of visit simplifies recursive calls below.
1848  QualType type(const Stmt *S) { return S ? Visit(S) : QualType(); }
1849 
1850  // In general, expressions => type of expression.
1851  QualType VisitExpr(const Expr *S) {
1852  return S->IgnoreImplicitAsWritten()->getType();
1853  }
1854  // Exceptions for void expressions that operate on a type in some way.
1855  QualType VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
1856  return S->getDestroyedType();
1857  }
1858  QualType VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
1859  return S->getDestroyedType();
1860  }
1861  QualType VisitCXXThrowExpr(const CXXThrowExpr *S) {
1862  return S->getSubExpr()->getType();
1863  }
1864  QualType VisitCoyieldStmt(const CoyieldExpr *S) {
1865  return type(S->getOperand());
1866  }
1867  // Treat a designated initializer like a reference to the field.
1868  QualType VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
1869  // In .foo.bar we want to jump to bar's type, so find *last* field.
1870  for (auto &D : llvm::reverse(S->designators()))
1871  if (D.isFieldDesignator())
1872  if (const auto *FD = D.getField())
1873  return FD->getType();
1874  return QualType();
1875  }
1876 
1877  // Control flow statements that operate on data: use the data type.
1878  QualType VisitSwitchStmt(const SwitchStmt *S) {
1879  return type(S->getCond());
1880  }
1881  QualType VisitWhileStmt(const WhileStmt *S) { return type(S->getCond()); }
1882  QualType VisitDoStmt(const DoStmt *S) { return type(S->getCond()); }
1883  QualType VisitIfStmt(const IfStmt *S) { return type(S->getCond()); }
1884  QualType VisitCaseStmt(const CaseStmt *S) { return type(S->getLHS()); }
1885  QualType VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1886  return S->getLoopVariable()->getType();
1887  }
1888  QualType VisitReturnStmt(const ReturnStmt *S) {
1889  return type(S->getRetValue());
1890  }
1891  QualType VisitCoreturnStmt(const CoreturnStmt *S) {
1892  return type(S->getOperand());
1893  }
1894  QualType VisitCXXCatchStmt(const CXXCatchStmt *S) {
1895  return S->getCaughtType();
1896  }
1897  QualType VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {
1898  return type(S->getThrowExpr());
1899  }
1900  QualType VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {
1901  return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
1902  : QualType();
1903  }
1904  } V;
1905  return V.Visit(S);
1906  }
1907 
1908  return QualType();
1909 }
1910 
1911 // Given a type targeted by the cursor, return a type that's more interesting
1912 // to target.
1913 static QualType unwrapFindType(QualType T) {
1914  if (T.isNull())
1915  return T;
1916 
1917  // If there's a specific type alias, point at that rather than unwrapping.
1918  if (const auto* TDT = T->getAs<TypedefType>())
1919  return QualType(TDT, 0);
1920 
1921  // Pointers etc => pointee type.
1922  if (const auto *PT = T->getAs<PointerType>())
1923  return unwrapFindType(PT->getPointeeType());
1924  if (const auto *RT = T->getAs<ReferenceType>())
1925  return unwrapFindType(RT->getPointeeType());
1926  if (const auto *AT = T->getAsArrayTypeUnsafe())
1927  return unwrapFindType(AT->getElementType());
1928  // FIXME: use HeuristicResolver to unwrap smart pointers?
1929 
1930  // Function type => return type.
1931  if (auto FT = T->getAs<FunctionType>())
1932  return unwrapFindType(FT->getReturnType());
1933  if (auto CRD = T->getAsCXXRecordDecl()) {
1934  if (CRD->isLambda())
1935  return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType());
1936  // FIXME: more cases we'd prefer the return type of the call operator?
1937  // std::function etc?
1938  }
1939 
1940  return T;
1941 }
1942 
1943 std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos) {
1944  const SourceManager &SM = AST.getSourceManager();
1945  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1946  std::vector<LocatedSymbol> Result;
1947  if (!Offset) {
1948  elog("failed to convert position {0} for findTypes: {1}", Pos,
1949  Offset.takeError());
1950  return Result;
1951  }
1952  // The general scheme is: position -> AST node -> type -> declaration.
1953  auto SymbolsFromNode =
1954  [&AST](const SelectionTree::Node *N) -> std::vector<LocatedSymbol> {
1955  QualType Type = unwrapFindType(typeForNode(N));
1956  if (Type.isNull())
1957  return {};
1958  return locateSymbolForType(AST, Type);
1959  };
1961  *Offset, [&](SelectionTree ST) {
1962  Result = SymbolsFromNode(ST.commonAncestor());
1963  return !Result.empty();
1964  });
1965  return Result;
1966 }
1967 
1968 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
1969  std::vector<const CXXRecordDecl *> Result;
1970 
1971  // If this is an invalid instantiation, instantiation of the bases
1972  // may not have succeeded, so fall back to the template pattern.
1973  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
1974  if (CTSD->isInvalidDecl())
1975  CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
1976  }
1977 
1978  // Can't query bases without a definition.
1979  if (!CXXRD->hasDefinition())
1980  return Result;
1981 
1982  for (auto Base : CXXRD->bases()) {
1983  const CXXRecordDecl *ParentDecl = nullptr;
1984 
1985  const Type *Type = Base.getType().getTypePtr();
1986  if (const RecordType *RT = Type->getAs<RecordType>()) {
1987  ParentDecl = RT->getAsCXXRecordDecl();
1988  }
1989 
1990  if (!ParentDecl) {
1991  // Handle a dependent base such as "Base<T>" by using the primary
1992  // template.
1993  if (const TemplateSpecializationType *TS =
1994  Type->getAs<TemplateSpecializationType>()) {
1995  TemplateName TN = TS->getTemplateName();
1996  if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
1997  ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
1998  }
1999  }
2000  }
2001 
2002  if (ParentDecl)
2003  Result.push_back(ParentDecl);
2004  }
2005 
2006  return Result;
2007 }
2008 
2009 llvm::Optional<TypeHierarchyItem>
2010 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
2011  TypeHierarchyDirection Direction, const SymbolIndex *Index,
2012  PathRef TUPath) {
2013  const CXXRecordDecl *CXXRD = findRecordTypeAt(AST, Pos);
2014  if (!CXXRD)
2015  return llvm::None;
2016 
2017  bool WantParents = Direction == TypeHierarchyDirection::Parents ||
2018  Direction == TypeHierarchyDirection::Both;
2019  bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2020  Direction == TypeHierarchyDirection::Both;
2021 
2022  // If we're looking for children, we're doing the lookup in the index.
2023  // The index does not store relationships between implicit
2024  // specializations, so if we have one, use the template pattern instead.
2025  // Note that this needs to be done before the declToTypeHierarchyItem(),
2026  // otherwise the type hierarchy item would misleadingly contain the
2027  // specialization parameters, while the children would involve classes
2028  // that derive from other specializations of the template.
2029  if (WantChildren) {
2030  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2031  CXXRD = CTSD->getTemplateInstantiationPattern();
2032  }
2033 
2034  Optional<TypeHierarchyItem> Result = declToTypeHierarchyItem(*CXXRD);
2035  if (!Result)
2036  return Result;
2037 
2038  if (WantParents) {
2039  Result->parents.emplace();
2040 
2041  RecursionProtectionSet RPSet;
2042  fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet);
2043  }
2044 
2045  if (WantChildren && ResolveLevels > 0) {
2046  Result->children.emplace();
2047 
2048  if (Index) {
2049  if (auto ID = getSymbolID(CXXRD))
2050  fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2051  }
2052  }
2053 
2054  return Result;
2055 }
2056 
2057 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
2058  TypeHierarchyDirection Direction,
2059  const SymbolIndex *Index) {
2060  // We only support typeHierarchy/resolve for children, because for parents
2061  // we ignore ResolveLevels and return all levels of parents eagerly.
2062  if (Direction == TypeHierarchyDirection::Parents || ResolveLevels == 0)
2063  return;
2064 
2065  Item.children.emplace();
2066 
2067  if (Index && Item.data) {
2068  // We store the item's SymbolID in the 'data' field, and the client
2069  // passes it back to us in typeHierarchy/resolve.
2070  if (Expected<SymbolID> ID = SymbolID::fromStr(*Item.data)) {
2071  fillSubTypes(*ID, *Item.children, Index, ResolveLevels, Item.uri.file());
2072  }
2073  }
2074 }
2075 
2076 std::vector<CallHierarchyItem>
2078  std::vector<CallHierarchyItem> Result;
2079  const auto &SM = AST.getSourceManager();
2080  auto Loc = sourceLocationInMainFile(SM, Pos);
2081  if (!Loc) {
2082  elog("prepareCallHierarchy failed to convert position to source location: "
2083  "{0}",
2084  Loc.takeError());
2085  return Result;
2086  }
2087  for (const NamedDecl *Decl : getDeclAtPosition(AST, *Loc, {})) {
2088  if (!(isa<DeclContext>(Decl) &&
2089  cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2090  Decl->getKind() != Decl::Kind::FunctionTemplate)
2091  continue;
2092  if (auto CHI = declToCallHierarchyItem(*Decl))
2093  Result.emplace_back(std::move(*CHI));
2094  }
2095  return Result;
2096 }
2097 
2098 std::vector<CallHierarchyIncomingCall>
2100  std::vector<CallHierarchyIncomingCall> Results;
2101  if (!Index || Item.data.empty())
2102  return Results;
2103  auto ID = SymbolID::fromStr(Item.data);
2104  if (!ID) {
2105  elog("incomingCalls failed to find symbol: {0}", ID.takeError());
2106  return Results;
2107  }
2108  // In this function, we find incoming calls based on the index only.
2109  // In principle, the AST could have more up-to-date information about
2110  // occurrences within the current file. However, going from a SymbolID
2111  // to an AST node isn't cheap, particularly when the declaration isn't
2112  // in the main file.
2113  // FIXME: Consider also using AST information when feasible.
2114  RefsRequest Request;
2115  Request.IDs.insert(*ID);
2116  // We could restrict more specifically to calls by introducing a new RefKind,
2117  // but non-call references (such as address-of-function) can still be
2118  // interesting as they can indicate indirect calls.
2119  Request.Filter = RefKind::Reference;
2120  // Initially store the ranges in a map keyed by SymbolID of the caller.
2121  // This allows us to group different calls with the same caller
2122  // into the same CallHierarchyIncomingCall.
2123  llvm::DenseMap<SymbolID, std::vector<Range>> CallsIn;
2124  // We can populate the ranges based on a refs request only. As we do so, we
2125  // also accumulate the container IDs into a lookup request.
2126  LookupRequest ContainerLookup;
2127  Index->refs(Request, [&](const Ref &R) {
2128  auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
2129  if (!Loc) {
2130  elog("incomingCalls failed to convert location: {0}", Loc.takeError());
2131  return;
2132  }
2133  auto It = CallsIn.try_emplace(R.Container, std::vector<Range>{}).first;
2134  It->second.push_back(Loc->range);
2135 
2136  ContainerLookup.IDs.insert(R.Container);
2137  });
2138  // Perform the lookup request and combine its results with CallsIn to
2139  // get complete CallHierarchyIncomingCall objects.
2140  Index->lookup(ContainerLookup, [&](const Symbol &Caller) {
2141  auto It = CallsIn.find(Caller.ID);
2142  assert(It != CallsIn.end());
2143  if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file()))
2144  Results.push_back(
2145  CallHierarchyIncomingCall{std::move(*CHI), std::move(It->second)});
2146  });
2147  // Sort results by name of container.
2148  llvm::sort(Results, [](const CallHierarchyIncomingCall &A,
2149  const CallHierarchyIncomingCall &B) {
2150  return A.from.name < B.from.name;
2151  });
2152  return Results;
2153 }
2154 
2155 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
2156  const FunctionDecl *FD) {
2157  if (!FD->hasBody())
2158  return {};
2159  llvm::DenseSet<const Decl *> DeclRefs;
2161  FD,
2162  [&](ReferenceLoc Ref) {
2163  for (const Decl *D : Ref.Targets) {
2164  if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2165  !Ref.IsDecl)
2166  DeclRefs.insert(D);
2167  }
2168  },
2169  AST.getHeuristicResolver());
2170  return DeclRefs;
2171 }
2172 
2173 } // namespace clangd
2174 } // namespace clang
dlog
#define dlog(...)
Definition: Logger.h:102
clang::clangd::SymbolRelevanceSignals::merge
void merge(const CodeCompletionResult &SemaResult)
Definition: Quality.cpp:326
clang::clangd::Ref::Kind
RefKind Kind
Definition: Ref.h:90
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
XRefs.h
clang::clangd::findRecordTypeAt
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
Definition: XRefs.cpp:1743
Loc
SourceLocation Loc
Definition: KernelNameRestrictionCheck.cpp:45
clang::clangd::incomingCalls
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
Definition: XRefs.cpp:2099
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:89
RecursiveASTVisitor
References
unsigned References
Definition: CodeComplete.cpp:179
clang::clangd::locateMacroAt
llvm::Optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
Definition: SourceCode.cpp:976
Selection.h
clang::clangd::RelationKind::BaseOf
@ BaseOf
clang::clangd::findReferences
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns references of the symbol at a specified Pos.
Definition: XRefs.cpp:1335
clang::clangd::SpelledWord
Definition: SourceCode.h:233
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::clangd::toHalfOpenFileRange
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
Definition: SourceCode.cpp:424
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::SymbolRelevanceSignals::Query
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
clang::clangd::Symbol::ID
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:310
clang::clangd::declToTypeHierarchyItem
static llvm::Optional< TypeHierarchyItem > declToTypeHierarchyItem(const NamedDecl &ND)
Definition: XRefs.cpp:1639
clang::clangd::CallHierarchyItem::uri
URIForFile uri
The resource identifier of this item.
Definition: Protocol.h:1460
clang::clangd::RefKind::Declaration
@ Declaration
clang::clangd::typeForNode
static QualType typeForNode(const SelectionTree::Node *N)
Definition: XRefs.cpp:1794
SymbolLocation.h
clang::clangd::ReferencesResult::Reference::Loc
Location Loc
Definition: XRefs.h:93
Location
Definition: Modularize.cpp:382
clang::clangd::resolveTypeHierarchy
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Definition: XRefs.cpp:2057
clang::clangd::HighlightingModifier::Deduced
@ Deduced
clang::clangd::ReferencesResult::Declaration
@ Declaration
Definition: XRefs.h:87
clang::clangd::findImplementations
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
Definition: XRefs.cpp:1282
clang::clangd::ParsedAST::getIncludeStructure
const IncludeStructure & getIncludeStructure() const
Definition: ParsedAST.cpp:687
clang::clangd::evaluateSymbolAndRelevance
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
Definition: Quality.cpp:531
clang::clangd::ParsedAST::getASTContext
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:632
clang::clangd::SymbolKind::Object
@ Object
clang::clangd::splitQualifiedName
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
Definition: SourceCode.cpp:491
clang::clangd::visibleNamespaces
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
Definition: SourceCode.cpp:800
clang::clangd::TypeHierarchyDirection::Parents
@ Parents
clang::clangd::fillSubTypes
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
Definition: XRefs.cpp:1694
Index.h
clang::clangd::RefSlab::end
const_iterator end() const
Definition: Ref.h:122
clang::clangd::SelectionTree::createEach
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
Definition: Selection.cpp:1005
Root
ASTNode Root
Definition: DumpAST.cpp:332
clang::clangd::locateSymbolTextually
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, const std::string &MainFilePath, ASTNodeKind NodeKind)
Definition: XRefs.cpp:564
clang::clangd::Symbol::Deprecated
@ Deprecated
Indicates if the symbol is deprecated.
Definition: Symbol.h:121
clang::clangd::FuzzyFindRequest::Scopes
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:37
Ctx
Context Ctx
Definition: TUScheduler.cpp:460
clang::clangd::indexToLSPLocation
llvm::Expected< Location > indexToLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath)
Helper function for deriving an LSP Location from an index SymbolLocation.
Definition: FindSymbols.cpp:63
clang::clangd::typeParents
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
Definition: XRefs.cpp:1968
clang::clangd::unwrapFindType
static QualType unwrapFindType(QualType T)
Definition: XRefs.cpp:1913
clang::clangd::MainFileMacros::MacroRefs
llvm::DenseMap< SymbolID, std::vector< MacroOccurrence > > MacroRefs
Definition: CollectMacros.h:33
FindSymbols.h
clang::clangd::RelationsRequest::Predicate
RelationKind Predicate
Definition: Index.h:80
clang::clangd::URIForFile::fromURI
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
Definition: Protocol.cpp:61
clang::clangd::nameLocation
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
Definition: AST.cpp:167
clang::clangd::SymbolRelevanceSignals::evaluateHeuristics
float evaluateHeuristics() const
Definition: Quality.cpp:396
clang::clangd::FuzzyFindRequest
Definition: Index.h:27
clang::clangd::DeclRelationSet
Definition: FindTarget.h:176
FindTarget.h
clang::clangd::sourceLocToPosition
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:216
clang::clangd::SymbolQualitySignals
Attributes of a symbol that affect how much we like it.
Definition: Quality.h:58
clang::clangd::CallHierarchyIncomingCall
Represents an incoming call, e.g. a caller of a method or constructor.
Definition: Protocol.h:1486
clang::clangd::IncludeStructure::MainFileIncludes
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:236
clang::clangd::URI::parse
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:179
clang::clangd::SymbolDetails::containerName
std::string containerName
Definition: Protocol.h:1076
clang::clangd::getDeducedType
llvm::Optional< QualType > getDeducedType(ASTContext &ASTCtx, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
Definition: AST.cpp:493
clang::clangd::SymbolKind
SymbolKind
A symbol kind.
Definition: Protocol.h:333
clang::clangd::ParsedAST::getLangOpts
const LangOptions & getLangOpts() const
Definition: ParsedAST.h:82
clang::clangd::ReferencesResult::Override
@ Override
Definition: XRefs.h:90
clang::clangd::FuzzyFindRequest::Query
std::string Query
A query string for the fuzzy find.
Definition: Index.h:30
clang::clangd::SelectionTree::Node::ASTNode
DynTypedNode ASTNode
Definition: Selection.h:128
clang::clangd::HighlightingKind::Macro
@ Macro
clang::clangd::Position::line
int line
Line position in a document (zero-based).
Definition: Protocol.h:155
clang::clangd::SymbolDetails::name
std::string name
Definition: Protocol.h:1074
Protocol.h
M
const google::protobuf::Message & M
Definition: Server.cpp:309
clang::clangd::findType
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos)
Returns symbols for types referenced at Pos.
Definition: XRefs.cpp:1943
clang::clangd::findNearbyIdentifier
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
Definition: XRefs.cpp:672
clang::clangd::TypeHierarchyDirection::Both
@ Both
Relation.h
Offset
size_t Offset
Definition: CodeComplete.cpp:1192
ns1::ns2::A
@ A
Definition: CategoricalFeature.h:3
clang::clangd::halfOpenToRange
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
Definition: SourceCode.cpp:466
clang::clangd::Position
Definition: Protocol.h:153
clang::clangd::SymbolDetails::ID
SymbolID ID
Definition: Protocol.h:1085
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::tidy::bugprone::model::MixFlags::Invalid
@ Invalid
Sentinel bit pattern. DO NOT USE!
clang::clangd::locateSymbolAt
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:763
clang::clangd::SymbolIndex::lookup
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.
clang::clangd::RelationsRequest::Subjects
llvm::DenseSet< SymbolID > Subjects
Definition: Index.h:79
clang::clangd::printName
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:213
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::clangd::SymbolIndex::relations
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....
CodeCompletionStrings.h
Line
int Line
Definition: PreprocessorTracker.cpp:514
clang::clangd::TypeHierarchyDirection::Children
@ Children
clang::clangd::getCanonicalPath
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:514
clang::clangd::Ref::Container
SymbolID Container
The ID of the symbol whose definition contains this reference.
Definition: Ref.h:94
clang::clangd::Ref::Location
SymbolLocation Location
The source location where the symbol is named.
Definition: Ref.h:89
Quality
SignatureQualitySignals Quality
Definition: CodeComplete.cpp:888
Role
index::SymbolRoleSet Role
Definition: XRefs.cpp:887
clang::clangd::getNonLocalDeclRefs
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:2155
clang::clangd::printQualifiedName
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:174
Logger.h
clang::clangd::getSymbolInfo
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:1515
clang::tidy::bugprone::model::ImplicitConversionModellingMode::All
@ All
Only model a unidirectional implicit conversion and within it only one standard conversion sequence.
clang::clangd::declToHierarchyItem
static llvm::Optional< HierarchyItem > declToHierarchyItem(const NamedDecl &ND)
Definition: XRefs.cpp:1589
clang::clangd::Symbol
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
clang::clangd::positionToOffset
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:175
if
if(CLANGD_ENABLE_REMOTE) generate_protos(RemoteIndexProto "Index.proto") generate_protos(MonitoringServiceProto "MonitoringService.proto" GRPC) generate_protos(RemoteIndexServiceProto "Service.proto" DEPENDS "Index.proto" GRPC) target_link_libraries(RemoteIndexServiceProto PRIVATE RemoteIndexProto MonitoringServiceProto) include_directories($
Definition: clangd/index/remote/CMakeLists.txt:1
clang::clangd::Symbol::Flags
SymbolFlag Flags
Definition: Symbol.h:128
clang::clangd::Symbol::SymInfo
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
Definition: Symbol.h:40
clang::clangd::SpelledWord::touching
static llvm::Optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
Definition: SourceCode.cpp:926
clang::clangd::CallHierarchyItem::data
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
Definition: Protocol.h:1473
Bounds
PreambleBounds Bounds
Definition: Preamble.cpp:240
clang::clangd::ReferencesResult
Definition: XRefs.h:84
clang::clangd::indexSymbolKindToSymbolKind
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
Definition: Protocol.cpp:253
clang::clangd::SymbolTag::Deprecated
@ Deprecated
clang::clangd::mergeSymbol
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition: Merge.cpp:213
clang::clangd::RefKind::Reference
@ Reference
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:73
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:781
clang::clangd::Symbol::Name
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition: Symbol.h:42
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::clangd::SymbolID::str
std::string str() const
Definition: SymbolID.cpp:34
clang::clangd::RefsRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:70
clang::clangd::ParsedAST::getHeuristicResolver
const HeuristicResolver * getHeuristicResolver() const
Definition: ParsedAST.h:117
clang::clangd::CompletionItemKind::Method
@ Method
clang::clangd::SelectionTree
Definition: Selection.h:76
clang::clangd::explicitReferenceTargets
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
Find declarations explicitly referenced in the source code defined by N.
Definition: FindTarget.cpp:565
clang::clangd::TypeHierarchyItem::children
llvm::Optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
Definition: Protocol.h:1414
clang::clangd::DeclRelation::Underlying
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
clang::clangd::symbolToLocation
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath)
Helper function for deriving an LSP Location for a Symbol.
Definition: FindSymbols.cpp:80
clang::clangd::operator<<
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Definition: CodeComplete.cpp:2160
clang::clangd::TypeHierarchyItem::uri
URIForFile uri
The URI of the text document where this type hierarchy item belongs to.
Definition: Protocol.h:1393
clang::clangd::DocumentHighlightKind::Write
@ Write
clang::clangd::SymbolDetails
Represents information about identifier.
Definition: Protocol.h:1073
clang::clangd::ParsedAST::getPreprocessor
Preprocessor & getPreprocessor()
Definition: ParsedAST.cpp:638
clang::clangd::FuzzyFindRequest::Limit
llvm::Optional< uint32_t > Limit
The number of top candidates to return.
Definition: Index.h:43
clang::clangd::SymbolDetails::USR
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Definition: Protocol.h:1083
clang::clangd::SelectionTree::Node
Definition: Selection.h:122
clang::clangd::symbolToTypeHierarchyItem
static llvm::Optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath)
Definition: XRefs.cpp:1679
clang::clangd::SelectionTree::Node::Parent
Node * Parent
Definition: Selection.h:124
clang::clangd::Symbol::CanonicalDeclaration
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Definition: Symbol.h:56
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:68
clang::query::QueryKind
QueryKind
Definition: Query.h:23
Word
std::string Word
Definition: FuzzyMatchTests.cpp:40
clang::clangd::symbolToCallHierarchyItem
static llvm::Optional< CallHierarchyItem > symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath)
Definition: XRefs.cpp:1687
Entry
Definition: Modularize.cpp:428
clang::clangd::LookupRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:66
clang::clangd::getSymbolID
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition: AST.cpp:337
SourceCode.h
Index
const SymbolIndex * Index
Definition: Dexp.cpp:99
clang::clangd::SymbolIndex::refs
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
clang::clangd::SymbolRelevanceSignals::Name
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
Definition: Quality.h:90
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:111
clang::clangd::trace::Metric::Counter
@ Counter
An aggregate number whose rate of change over time is meaningful.
Definition: Trace.h:46
clang::clangd::RefsRequest::Filter
RefKind Filter
Definition: Index.h:71
clang::clangd::LookupRequest
Definition: Index.h:65
clang::clangd::ReferenceLoc
Information about a reference written in the source code, independent of the actual AST node that thi...
Definition: FindTarget.h:129
clang::clangd::TypeHierarchyDirection
TypeHierarchyDirection
Definition: Protocol.h:1361
clang::clangd::ReferencesResult::Reference::Attributes
unsigned Attributes
Definition: XRefs.h:94
clang::clangd::TypeHierarchyItem
Definition: Protocol.h:1378
ID
static char ID
Definition: Logger.cpp:74
Score
llvm::Optional< float > Score
Definition: FuzzyMatchTests.cpp:48
clang::clangd::Ref
Represents a symbol occurrence in the source file.
Definition: Ref.h:87
SpelledTok
syntax::Token SpelledTok
Definition: XRefs.cpp:886
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:29
clang::clangd::LocatedSymbol::Name
std::string Name
Definition: XRefs.h:46
clang::clangd::RecursionProtectionSet
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
Definition: XRefs.cpp:1712
Target
SymbolID Target
Definition: XRefs.cpp:888
clang::clangd::Symbol::TemplateSpecializationArgs
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
Definition: Symbol.h:69
clang::tidy::bugprone::model::MixFlags::None
@ None
Mix between the two parameters is not possible.
clang::clangd::Range
Definition: Protocol.h:182
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::SymbolID::fromStr
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:36
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:48
clang::clangd::ReferencesResult::Reference
Definition: XRefs.h:92
clang::clangd::LocatedSymbol
Definition: XRefs.h:44
clang::clangd::Symbol::Scope
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Definition: Symbol.h:44
clang::clangd::fillSuperTypes
static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx, std::vector< TypeHierarchyItem > &SuperTypes, RecursionProtectionSet &RPSet)
Definition: XRefs.cpp:1714
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:163
clang::clangd::ParsedAST::getTokens
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Definition: ParsedAST.h:108
clang::clangd::ReferencesResult::Definition
@ Definition
Definition: XRefs.h:88
clang::clangd::isInsideMainFile
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Definition: SourceCode.cpp:417
clang::clangd::allTargetDecls
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 ...
Definition: FindTarget.cpp:528
clang::clangd::ParsedAST::getLocalTopLevelDecls
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
Definition: ParsedAST.cpp:648
clang::clangd::LocatedSymbol::ID
SymbolID ID
Definition: XRefs.h:52
clang::clangd::LocatedSymbol::PreferredDeclaration
Location PreferredDeclaration
Definition: XRefs.h:48
clang::clangd::CallHierarchyItem
Represents programming constructs like functions or constructors in the context of call hierarchy.
Definition: Protocol.h:1446
SymbolInfo
clang::find_all_symbols::SymbolInfo SymbolInfo
Definition: FindAllSymbolsMain.cpp:38
clang::clangd::targetDecl
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const DynTypedNode &N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
targetDecl() finds the declaration referred to by an AST node.
Definition: FindTarget.cpp:554
clang::clangd::URIForFile::file
llvm::StringRef file() const
Retrieves absolute path to the file.
Definition: Protocol.h:101
clang::clangd::getTypeHierarchy
llvm::Optional< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
Definition: XRefs.cpp:2010
clang::clangd::RefsRequest::Limit
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:75
clang::clangd::FuzzyFindRequest::AnyScope
bool AnyScope
If set to true, allow symbols from any scope.
Definition: Index.h:40
clang::clangd::Symbol::Definition
SymbolLocation Definition
The location of the symbol's definition, if one was found.
Definition: Symbol.h:47
clang::clangd::DocumentHighlightKind::Read
@ Read
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:49
Pos
Position Pos
Definition: SourceCode.cpp:657
clang::clangd::RelationsRequest
Definition: Index.h:78
Merge.h
URI.h
Quality.h
ns1::ns2::B
@ B
Definition: CategoricalFeature.h:3
clang::clangd::SymbolRelevanceSignals::Generic
@ Generic
Definition: Quality.h:125
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
clang::clangd::SymbolID
Definition: SymbolID.h:32
clang::clangd::SelectionTree::Node::getDeclContext
const DeclContext & getDeclContext() const
Definition: Selection.cpp:1057
clang::clangd::DocumentHighlightKind::Text
@ Text
clang::clangd::RefKind::Definition
@ Definition
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:75
clang::clangd::getDocumentLinks
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Definition: XRefs.cpp:847
clang::clangd::findExplicitReferences
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.
Definition: FindTarget.cpp:1129
clang::clangd::RefsRequest
Definition: Index.h:69
clang::clangd::DeclRelation::TemplatePattern
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
clang::clangd::RelationKind::OverriddenBy
@ OverriddenBy
clang::clangd::FuzzyFindRequest::ProximityPaths
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
Definition: Index.h:48
clang::clangd::SymbolRelevanceSignals
Attributes of a symbol-query pair that affect how much we like it.
Definition: Quality.h:88
clang::clangd::declToCallHierarchyItem
static llvm::Optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND)
Definition: XRefs.cpp:1647
clang::clangd::sourceLocationInMainFile
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
Definition: SourceCode.cpp:456
clang::clangd::prepareCallHierarchy
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
Definition: XRefs.cpp:2077
clang::clangd::LocatedSymbol::Definition
llvm::Optional< Location > Definition
Definition: XRefs.h:50
clang::clangd::SymbolIndex::fuzzyFind
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.
clang::clangd::TypeHierarchyItem::data
llvm::Optional< std::string > data
An optional 'data' field, which can be used to identify a type hierarchy item in a resolve request.
Definition: Protocol.h:1418
clang::clangd::DeclRelation::Alias
@ Alias
This declaration is an alias that was referred to.
AST.h
ParsedAST.h
clang::clangd::symbolToHierarchyItem
static llvm::Optional< HierarchyItem > symbolToHierarchyItem(const Symbol &S, PathRef TUPath)
Definition: XRefs.cpp:1655
clang::clangd::RelationKind
RelationKind
Definition: Relation.h:22
clang::clangd::findDocumentHighlights
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:1237
clang::clangd::ParsedAST::getMacros
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
Definition: ParsedAST.cpp:652