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