clang-tools  11.0.0
XRefs.cpp
Go to the documentation of this file.
1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "XRefs.h"
9 #include "AST.h"
10 #include "CodeCompletionStrings.h"
11 #include "FindSymbols.h"
12 #include "FindTarget.h"
13 #include "ParsedAST.h"
14 #include "Protocol.h"
15 #include "Quality.h"
16 #include "Selection.h"
17 #include "SourceCode.h"
18 #include "URI.h"
19 #include "index/Index.h"
20 #include "index/Merge.h"
21 #include "index/Relation.h"
22 #include "index/SymbolLocation.h"
23 #include "support/Logger.h"
24 #include "clang/AST/ASTContext.h"
25 #include "clang/AST/ASTTypeTraits.h"
26 #include "clang/AST/Attr.h"
27 #include "clang/AST/Attrs.inc"
28 #include "clang/AST/Decl.h"
29 #include "clang/AST/DeclCXX.h"
30 #include "clang/AST/DeclObjC.h"
31 #include "clang/AST/DeclTemplate.h"
32 #include "clang/AST/ExprCXX.h"
33 #include "clang/AST/RecursiveASTVisitor.h"
34 #include "clang/AST/Stmt.h"
35 #include "clang/AST/StmtCXX.h"
36 #include "clang/AST/Type.h"
37 #include "clang/Basic/CharInfo.h"
38 #include "clang/Basic/LLVM.h"
39 #include "clang/Basic/LangOptions.h"
40 #include "clang/Basic/SourceLocation.h"
41 #include "clang/Basic/SourceManager.h"
42 #include "clang/Basic/TokenKinds.h"
43 #include "clang/Index/IndexDataConsumer.h"
44 #include "clang/Index/IndexSymbol.h"
45 #include "clang/Index/IndexingAction.h"
46 #include "clang/Index/IndexingOptions.h"
47 #include "clang/Index/USRGeneration.h"
48 #include "clang/Tooling/Syntax/Tokens.h"
49 #include "llvm/ADT/ArrayRef.h"
50 #include "llvm/ADT/None.h"
51 #include "llvm/ADT/STLExtras.h"
52 #include "llvm/ADT/ScopeExit.h"
53 #include "llvm/ADT/SmallSet.h"
54 #include "llvm/ADT/StringExtras.h"
55 #include "llvm/ADT/StringRef.h"
56 #include "llvm/Support/Casting.h"
57 #include "llvm/Support/Error.h"
58 #include "llvm/Support/MathExtras.h"
59 #include "llvm/Support/Path.h"
60 #include "llvm/Support/raw_ostream.h"
61 
62 namespace clang {
63 namespace clangd {
64 namespace {
65 
66 // Returns the single definition of the entity declared by D, if visible.
67 // In particular:
68 // - for non-redeclarable kinds (e.g. local vars), return D
69 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
70 // Kinds of nodes that always return nullptr here will not have definitions
71 // reported by locateSymbolAt().
72 const NamedDecl *getDefinition(const NamedDecl *D) {
73  assert(D);
74  // Decl has one definition that we can find.
75  if (const auto *TD = dyn_cast<TagDecl>(D))
76  return TD->getDefinition();
77  if (const auto *VD = dyn_cast<VarDecl>(D))
78  return VD->getDefinition();
79  if (const auto *FD = dyn_cast<FunctionDecl>(D))
80  return FD->getDefinition();
81  // Only a single declaration is allowed.
82  if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
83  isa<TemplateTemplateParmDecl>(D)) // except cases above
84  return D;
85  // Multiple definitions are allowed.
86  return nullptr; // except cases above
87 }
88 
89 void logIfOverflow(const SymbolLocation &Loc) {
90  if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
91  log("Possible overflow in symbol location: {0}", Loc);
92 }
93 
94 // Convert a SymbolLocation to LSP's Location.
95 // TUPath is used to resolve the path of URI.
96 // FIXME: figure out a good home for it, and share the implementation with
97 // FindSymbols.
98 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
99  llvm::StringRef TUPath) {
100  if (!Loc)
101  return None;
102  auto Uri = URI::parse(Loc.FileURI);
103  if (!Uri) {
104  elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
105  return None;
106  }
107  auto U = URIForFile::fromURI(*Uri, TUPath);
108  if (!U) {
109  elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
110  return None;
111  }
112 
113  Location LSPLoc;
114  LSPLoc.uri = std::move(*U);
115  LSPLoc.range.start.line = Loc.Start.line();
116  LSPLoc.range.start.character = Loc.Start.column();
117  LSPLoc.range.end.line = Loc.End.line();
118  LSPLoc.range.end.character = Loc.End.column();
119  logIfOverflow(Loc);
120  return LSPLoc;
121 }
122 
123 SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
124  SymbolLocation SymLoc;
125  URIStorage = Loc.uri.uri();
126  SymLoc.FileURI = URIStorage.c_str();
127  SymLoc.Start.setLine(Loc.range.start.line);
128  SymLoc.Start.setColumn(Loc.range.start.character);
129  SymLoc.End.setLine(Loc.range.end.line);
130  SymLoc.End.setColumn(Loc.range.end.character);
131  return SymLoc;
132 }
133 
134 // Returns the preferred location between an AST location and an index location.
135 SymbolLocation getPreferredLocation(const Location &ASTLoc,
136  const SymbolLocation &IdxLoc,
137  std::string &Scratch) {
138  // Also use a dummy symbol for the index location so that other fields (e.g.
139  // definition) are not factored into the preference.
140  Symbol ASTSym, IdxSym;
141  ASTSym.ID = IdxSym.ID = SymbolID("dummy_id");
142  ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
143  IdxSym.CanonicalDeclaration = IdxLoc;
144  auto Merged = mergeSymbol(ASTSym, IdxSym);
145  return Merged.CanonicalDeclaration;
146 }
147 
148 std::vector<const NamedDecl *>
149 getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,
150  ASTNodeKind *NodeKind = nullptr) {
151  unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
152  std::vector<const NamedDecl *> Result;
154  Offset, [&](SelectionTree ST) {
155  if (const SelectionTree::Node *N =
156  ST.commonAncestor()) {
157  if (NodeKind)
158  *NodeKind = N->ASTNode.getNodeKind();
159  llvm::copy(targetDecl(N->ASTNode, Relations),
160  std::back_inserter(Result));
161  }
162  return !Result.empty();
163  });
164  return Result;
165 }
166 
167 // Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
168 // figure out a filename.
169 llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,
170  llvm::StringRef TUPath) {
171  const auto &SM = AST.getSourceManager();
172  const FileEntry *F = SM.getFileEntryForID(SM.getFileID(Loc));
173  if (!F)
174  return None;
175  auto FilePath = getCanonicalPath(F, SM);
176  if (!FilePath) {
177  log("failed to get path!");
178  return None;
179  }
180  Location L;
181  L.uri = URIForFile::canonicalize(*FilePath, TUPath);
182  // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
183  // outside the main file.
184  auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());
185  L.range = halfOpenToRange(
186  SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
187  return L;
188 }
189 
190 // Treat #included files as symbols, to enable go-to-definition on them.
191 llvm::Optional<LocatedSymbol> locateFileReferent(const Position &Pos,
192  ParsedAST &AST,
193  llvm::StringRef MainFilePath) {
194  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
195  if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
196  LocatedSymbol File;
197  File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
198  File.PreferredDeclaration = {
199  URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
200  File.Definition = File.PreferredDeclaration;
201  // We're not going to find any further symbols on #include lines.
202  return File;
203  }
204  }
205  return llvm::None;
206 }
207 
208 // Macros are simple: there's no declaration/definition distinction.
209 // As a consequence, there's no need to look them up in the index either.
210 llvm::Optional<LocatedSymbol>
211 locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
212  llvm::StringRef MainFilePath) {
213  if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
214  if (auto Loc =
215  makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {
216  LocatedSymbol Macro;
217  Macro.Name = std::string(M->Name);
218  Macro.PreferredDeclaration = *Loc;
219  Macro.Definition = Loc;
220  return Macro;
221  }
222  }
223  return llvm::None;
224 }
225 
226 // Decls are more complicated.
227 // The AST contains at least a declaration, maybe a definition.
228 // These are up-to-date, and so generally preferred over index results.
229 // We perform a single batch index lookup to find additional definitions.
230 std::vector<LocatedSymbol>
231 locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
232  ParsedAST &AST, llvm::StringRef MainFilePath,
233  const SymbolIndex *Index, ASTNodeKind *NodeKind) {
234  const SourceManager &SM = AST.getSourceManager();
235  // Results follow the order of Symbols.Decls.
236  std::vector<LocatedSymbol> Result;
237  // Keep track of SymbolID -> index mapping, to fill in index data later.
238  llvm::DenseMap<SymbolID, size_t> ResultIndex;
239 
240  auto AddResultDecl = [&](const NamedDecl *D) {
241  D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
242  auto Loc =
243  makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
244  if (!Loc)
245  return;
246 
247  Result.emplace_back();
248  Result.back().Name = printName(AST.getASTContext(), *D);
249  Result.back().PreferredDeclaration = *Loc;
250  if (const NamedDecl *Def = getDefinition(D))
251  Result.back().Definition = makeLocation(
252  AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
253 
254  // Record SymbolID for index lookup later.
255  if (auto ID = getSymbolID(D))
256  ResultIndex[*ID] = Result.size() - 1;
257  };
258 
259  // Emit all symbol locations (declaration or definition) from AST.
260  DeclRelationSet Relations =
262  for (const NamedDecl *D :
263  getDeclAtPosition(AST, CurLoc, Relations, NodeKind)) {
264  // Special case: void foo() ^override: jump to the overridden method.
265  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
266  const InheritableAttr *Attr = D->getAttr<OverrideAttr>();
267  if (!Attr)
268  Attr = D->getAttr<FinalAttr>();
269  if (Attr && TouchedIdentifier &&
270  SM.getSpellingLoc(Attr->getLocation()) ==
271  TouchedIdentifier->location()) {
272  // We may be overridding multiple methods - offer them all.
273  for (const NamedDecl *ND : CMD->overridden_methods())
274  AddResultDecl(ND);
275  continue;
276  }
277  }
278 
279  // Special case: the point of declaration of a template specialization,
280  // it's more useful to navigate to the template declaration.
281  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
282  if (TouchedIdentifier &&
283  D->getLocation() == TouchedIdentifier->location()) {
284  AddResultDecl(CTSD->getSpecializedTemplate());
285  continue;
286  }
287  }
288 
289  // Otherwise the target declaration is the right one.
290  AddResultDecl(D);
291  }
292 
293  // Now query the index for all Symbol IDs we found in the AST.
294  if (Index && !ResultIndex.empty()) {
295  LookupRequest QueryRequest;
296  for (auto It : ResultIndex)
297  QueryRequest.IDs.insert(It.first);
298  std::string Scratch;
299  Index->lookup(QueryRequest, [&](const Symbol &Sym) {
300  auto &R = Result[ResultIndex.lookup(Sym.ID)];
301 
302  if (R.Definition) { // from AST
303  // Special case: if the AST yielded a definition, then it may not be
304  // the right *declaration*. Prefer the one from the index.
305  if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
306  R.PreferredDeclaration = *Loc;
307 
308  // We might still prefer the definition from the index, e.g. for
309  // generated symbols.
310  if (auto Loc = toLSPLocation(
311  getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
312  MainFilePath))
313  R.Definition = *Loc;
314  } else {
315  R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
316 
317  // Use merge logic to choose AST or index declaration.
318  if (auto Loc = toLSPLocation(
319  getPreferredLocation(R.PreferredDeclaration,
320  Sym.CanonicalDeclaration, Scratch),
321  MainFilePath))
322  R.PreferredDeclaration = *Loc;
323  }
324  });
325  }
326 
327  return Result;
328 }
329 
330 bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {
331  auto ExpandedTokens = TB.expandedTokens(
332  TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
333  return !ExpandedTokens.empty();
334 }
335 
336 llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {
337  auto D = SM.getDecomposedLoc(Loc);
338  bool Invalid = false;
339  llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
340  if (Invalid || D.second > Buf.size())
341  return "";
342  return Buf.substr(0, D.second);
343 }
344 
345 bool isDependentName(ASTNodeKind NodeKind) {
346  return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
347  NodeKind.isSame(
348  ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
349  NodeKind.isSame(
350  ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
351 }
352 
353 } // namespace
354 
355 std::vector<LocatedSymbol>
357  const SymbolIndex *Index, const std::string &MainFilePath,
358  ASTNodeKind NodeKind) {
359  // Don't use heuristics if this is a real identifier, or not an
360  // identifier.
361  // Exception: dependent names, because those may have useful textual
362  // matches that AST-based heuristics cannot find.
363  if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||
364  !Word.LikelyIdentifier || !Index)
365  return {};
366  // We don't want to handle words in string literals. It'd be nice to include
367  // comments, but they're not retained in TokenBuffer.
368  if (Word.PartOfSpelledToken &&
369  isStringLiteral(Word.PartOfSpelledToken->kind()))
370  return {};
371 
372  const auto &SM = AST.getSourceManager();
373  // Look up the selected word in the index.
374  FuzzyFindRequest Req;
375  Req.Query = Word.Text.str();
376  Req.ProximityPaths = {MainFilePath};
377  // Find the namespaces to query by lexing the file.
378  Req.Scopes =
379  visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());
380  // FIXME: For extra strictness, consider AnyScope=false.
381  Req.AnyScope = true;
382  // We limit the results to 3 further below. This limit is to avoid fetching
383  // too much data, while still likely having enough for 3 results to remain
384  // after additional filtering.
385  Req.Limit = 10;
386  bool TooMany = false;
387  using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
388  std::vector<ScoredLocatedSymbol> ScoredResults;
389  Index->fuzzyFind(Req, [&](const Symbol &Sym) {
390  // Only consider exact name matches, including case.
391  // This is to avoid too many false positives.
392  // We could relax this in the future (e.g. to allow for typos) if we make
393  // the query more accurate by other means.
394  if (Sym.Name != Word.Text)
395  return;
396 
397  // Exclude constructor results. They have the same name as the class,
398  // but we don't have enough context to prefer them over the class.
399  if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)
400  return;
401 
402  auto MaybeDeclLoc =
403  indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
404  if (!MaybeDeclLoc) {
405  log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
406  return;
407  }
408  Location DeclLoc = *MaybeDeclLoc;
409  Location DefLoc;
410  if (Sym.Definition) {
411  auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
412  if (!MaybeDefLoc) {
413  log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
414  return;
415  }
416  DefLoc = *MaybeDefLoc;
417  }
418 
419  if (ScoredResults.size() >= 3) {
420  // If we have more than 3 results, don't return anything,
421  // as confidence is too low.
422  // FIXME: Alternatively, try a stricter query?
423  TooMany = true;
424  return;
425  }
426 
427  LocatedSymbol Located;
428  Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
429  Located.PreferredDeclaration = bool(Sym.Definition) ? DefLoc : DeclLoc;
430  Located.Definition = DefLoc;
431 
433  Quality.merge(Sym);
434  SymbolRelevanceSignals Relevance;
435  Relevance.Name = Sym.Name;
437  Relevance.merge(Sym);
438  auto Score =
439  evaluateSymbolAndRelevance(Quality.evaluate(), Relevance.evaluate());
440  dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,
441  Sym.Name, Score, Quality, Relevance);
442 
443  ScoredResults.push_back({Score, std::move(Located)});
444  });
445 
446  if (TooMany) {
447  vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
448  Word.Text);
449  return {};
450  }
451 
452  llvm::sort(ScoredResults,
453  [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {
454  return A.first > B.first;
455  });
456  std::vector<LocatedSymbol> Results;
457  for (auto &Res : std::move(ScoredResults))
458  Results.push_back(std::move(Res.second));
459  if (Results.empty())
460  vlog("No heuristic index definition for {0}", Word.Text);
461  else
462  log("Found definition heuristically in index for {0}", Word.Text);
463  return Results;
464 }
465 
466 const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
467  const syntax::TokenBuffer &TB) {
468  // Don't use heuristics if this is a real identifier.
469  // Unlikely identifiers are OK if they were used as identifiers nearby.
470  if (Word.ExpandedToken)
471  return nullptr;
472  // We don't want to handle words in string literals. It'd be nice to include
473  // comments, but they're not retained in TokenBuffer.
474  if (Word.PartOfSpelledToken &&
475  isStringLiteral(Word.PartOfSpelledToken->kind()))
476  return {};
477 
478  const SourceManager &SM = TB.sourceManager();
479  // We prefer the closest possible token, line-wise. Backwards is penalized.
480  // Ties are implicitly broken by traversal order (first-one-wins).
481  auto File = SM.getFileID(Word.Location);
482  unsigned WordLine = SM.getSpellingLineNumber(Word.Location);
483  auto Cost = [&](SourceLocation Loc) -> unsigned {
484  assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
485  unsigned Line = SM.getSpellingLineNumber(Loc);
486  if (Line > WordLine)
487  return 1 + llvm::Log2_64(Line - WordLine);
488  if (Line < WordLine)
489  return 2 + llvm::Log2_64(WordLine - Line);
490  return 0;
491  };
492  const syntax::Token *BestTok = nullptr;
493  // Search bounds are based on word length: 2^N lines forward.
494  unsigned BestCost = Word.Text.size() + 1;
495 
496  // Updates BestTok and BestCost if Tok is a good candidate.
497  // May return true if the cost is too high for this token.
498  auto Consider = [&](const syntax::Token &Tok) {
499  if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
500  return false;
501  // No point guessing the same location we started with.
502  if (Tok.location() == Word.Location)
503  return false;
504  // We've done cheap checks, compute cost so we can break the caller's loop.
505  unsigned TokCost = Cost(Tok.location());
506  if (TokCost >= BestCost)
507  return true; // causes the outer loop to break.
508  // Allow locations that might be part of the AST, and macros (even if empty)
509  // but not things like disabled preprocessor sections.
510  if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
511  return false;
512  // We already verified this token is an improvement.
513  BestCost = TokCost;
514  BestTok = &Tok;
515  return false;
516  };
517  auto SpelledTokens = TB.spelledTokens(File);
518  // Find where the word occurred in the token stream, to search forward & back.
519  auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {
520  assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));
521  return T.location() >= Word.Location; // Comparison OK: same file.
522  });
523  // Search for matches after the cursor.
524  for (const syntax::Token &Tok : llvm::makeArrayRef(I, SpelledTokens.end()))
525  if (Consider(Tok))
526  break; // costs of later tokens are greater...
527  // Search for matches before the cursor.
528  for (const syntax::Token &Tok :
529  llvm::reverse(llvm::makeArrayRef(SpelledTokens.begin(), I)))
530  if (Consider(Tok))
531  break;
532 
533  if (BestTok)
534  vlog(
535  "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
536  Word.Text, Word.Location.printToString(SM),
537  BestTok->location().printToString(SM));
538 
539  return BestTok;
540 }
541 
542 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
543  const SymbolIndex *Index) {
544  const auto &SM = AST.getSourceManager();
545  auto MainFilePath =
546  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
547  if (!MainFilePath) {
548  elog("Failed to get a path for the main file, so no references");
549  return {};
550  }
551 
552  if (auto File = locateFileReferent(Pos, AST, *MainFilePath))
553  return {std::move(*File)};
554 
555  auto CurLoc = sourceLocationInMainFile(SM, Pos);
556  if (!CurLoc) {
557  elog("locateSymbolAt failed to convert position to source location: {0}",
558  CurLoc.takeError());
559  return {};
560  }
561 
562  const syntax::Token *TouchedIdentifier =
563  syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
564  if (TouchedIdentifier)
565  if (auto Macro =
566  locateMacroReferent(*TouchedIdentifier, AST, *MainFilePath))
567  // Don't look at the AST or index if we have a macro result.
568  // (We'd just return declarations referenced from the macro's
569  // expansion.)
570  return {*std::move(Macro)};
571 
572  ASTNodeKind NodeKind;
573  auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,
574  *MainFilePath, Index, &NodeKind);
575  if (!ASTResults.empty())
576  return ASTResults;
577 
578  // If the cursor can't be resolved directly, try fallback strategies.
579  auto Word =
580  SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());
581  if (Word) {
582  // Is the same word nearby a real identifier that might refer to something?
583  if (const syntax::Token *NearbyIdent =
585  if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) {
586  log("Found macro definition heuristically using nearby identifier {0}",
587  Word->Text);
588  return {*std::move(Macro)};
589  }
590  ASTResults =
591  locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,
592  *MainFilePath, Index, /*NodeKind=*/nullptr);
593  if (!ASTResults.empty()) {
594  log("Found definition heuristically using nearby identifier {0}",
595  NearbyIdent->text(SM));
596  return ASTResults;
597  } else {
598  vlog("No definition found using nearby identifier {0} at {1}",
599  Word->Text, Word->Location.printToString(SM));
600  }
601  }
602  // No nearby word, or it didn't refer to anything either. Try the index.
603  auto TextualResults =
604  locateSymbolTextually(*Word, AST, Index, *MainFilePath, NodeKind);
605  if (!TextualResults.empty())
606  return TextualResults;
607  }
608 
609  return {};
610 }
611 
612 std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
613  const auto &SM = AST.getSourceManager();
614  auto MainFilePath =
615  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
616  if (!MainFilePath) {
617  elog("Failed to get a path for the main file, so no links");
618  return {};
619  }
620 
621  std::vector<DocumentLink> Result;
622  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
623  if (Inc.Resolved.empty())
624  continue;
625  auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
626  const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
627  assert(HashTok && "got inclusion at wrong offset");
628  const auto *IncludeTok = std::next(HashTok);
629  const auto *FileTok = std::next(IncludeTok);
630  // FileTok->range is not sufficient here, as raw lexing wouldn't yield
631  // correct tokens for angled filenames. Hence we explicitly use
632  // Inc.Written's length.
633  auto FileRange =
634  syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
635  .toCharRange(SM);
636 
637  Result.push_back(
638  DocumentLink({halfOpenToRange(SM, FileRange),
639  URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
640  }
641 
642  return Result;
643 }
644 
645 namespace {
646 
647 /// Collects references to symbols within the main file.
648 class ReferenceFinder : public index::IndexDataConsumer {
649 public:
650  struct Reference {
651  syntax::Token SpelledTok;
652  index::SymbolRoleSet Role;
653 
654  Range range(const SourceManager &SM) const {
655  return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));
656  }
657  };
658 
659  ReferenceFinder(const ParsedAST &AST,
660  const std::vector<const NamedDecl *> &TargetDecls)
661  : AST(AST) {
662  for (const NamedDecl *D : TargetDecls)
663  CanonicalTargets.insert(D->getCanonicalDecl());
664  }
665 
666  std::vector<Reference> take() && {
667  llvm::sort(References, [](const Reference &L, const Reference &R) {
668  auto LTok = L.SpelledTok.location();
669  auto RTok = R.SpelledTok.location();
670  return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
671  });
672  // We sometimes see duplicates when parts of the AST get traversed twice.
673  References.erase(std::unique(References.begin(), References.end(),
674  [](const Reference &L, const Reference &R) {
675  auto LTok = L.SpelledTok.location();
676  auto RTok = R.SpelledTok.location();
677  return std::tie(LTok, L.Role) ==
678  std::tie(RTok, R.Role);
679  }),
680  References.end());
681  return std::move(References);
682  }
683 
684  bool
685  handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
686  llvm::ArrayRef<index::SymbolRelation> Relations,
687  SourceLocation Loc,
688  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
689  assert(D->isCanonicalDecl() && "expect D to be a canonical declaration");
690  const SourceManager &SM = AST.getSourceManager();
691  if (!CanonicalTargets.count(D) || !isInsideMainFile(Loc, SM))
692  return true;
693  const auto &TB = AST.getTokens();
694  Loc = SM.getFileLoc(Loc);
695  if (const auto *Tok = TB.spelledTokenAt(Loc))
696  References.push_back({*Tok, Roles});
697  return true;
698  }
699 
700 private:
701  llvm::SmallSet<const Decl *, 4> CanonicalTargets;
702  std::vector<Reference> References;
703  const ParsedAST &AST;
704 };
705 
706 std::vector<ReferenceFinder::Reference>
707 findRefs(const std::vector<const NamedDecl *> &Decls, ParsedAST &AST) {
708  ReferenceFinder RefFinder(AST, Decls);
709  index::IndexingOptions IndexOpts;
710  IndexOpts.SystemSymbolFilter =
711  index::IndexingOptions::SystemSymbolFilterKind::All;
712  IndexOpts.IndexFunctionLocals = true;
713  IndexOpts.IndexParametersInDeclarations = true;
714  IndexOpts.IndexTemplateParameters = true;
715  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
716  AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
717  return std::move(RefFinder).take();
718 }
719 
720 const Stmt *getFunctionBody(DynTypedNode N) {
721  if (const auto *FD = N.get<FunctionDecl>())
722  return FD->getBody();
723  if (const auto *FD = N.get<BlockDecl>())
724  return FD->getBody();
725  if (const auto *FD = N.get<LambdaExpr>())
726  return FD->getBody();
727  if (const auto *FD = N.get<ObjCMethodDecl>())
728  return FD->getBody();
729  return nullptr;
730 }
731 
732 const Stmt *getLoopBody(DynTypedNode N) {
733  if (const auto *LS = N.get<ForStmt>())
734  return LS->getBody();
735  if (const auto *LS = N.get<CXXForRangeStmt>())
736  return LS->getBody();
737  if (const auto *LS = N.get<WhileStmt>())
738  return LS->getBody();
739  if (const auto *LS = N.get<DoStmt>())
740  return LS->getBody();
741  return nullptr;
742 }
743 
744 // AST traversal to highlight control flow statements under some root.
745 // Once we hit further control flow we prune the tree (or at least restrict
746 // what we highlight) so we capture e.g. breaks from the outer loop only.
747 class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {
748  // Types of control-flow statements we might highlight.
749  enum Target {
750  Break = 1,
751  Continue = 2,
752  Return = 4,
753  Case = 8,
754  Throw = 16,
755  Goto = 32,
756  All = Break | Continue | Return | Case | Throw | Goto,
757  };
758  int Ignore = 0; // bitmask of Target - what are we *not* highlighting?
759  SourceRange Bounds; // Half-open, restricts reported targets.
760  std::vector<SourceLocation> &Result;
761  const SourceManager &SM;
762 
763  // Masks out targets for a traversal into D.
764  // Traverses the subtree using Delegate() if any targets remain.
765  template <typename Func>
766  bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {
767  auto RestoreIgnore = llvm::make_scope_exit(
768  [OldIgnore(Ignore), this] { Ignore = OldIgnore; });
769  if (getFunctionBody(D))
770  Ignore = All;
771  else if (getLoopBody(D))
772  Ignore |= Continue | Break;
773  else if (D.get<SwitchStmt>())
774  Ignore |= Break | Case;
775  // Prune tree if we're not looking for anything.
776  return (Ignore == All) ? true : Delegate();
777  }
778 
779  void found(Target T, SourceLocation Loc) {
780  if (T & Ignore)
781  return;
782  if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
783  SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
784  return;
785  Result.push_back(Loc);
786  }
787 
788 public:
789  FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
790  const SourceManager &SM)
791  : Bounds(Bounds), Result(Result), SM(SM) {}
792 
793  // When traversing function or loops, limit targets to those that still
794  // refer to the original root.
795  bool TraverseDecl(Decl *D) {
796  return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
797  return RecursiveASTVisitor::TraverseDecl(D);
798  });
799  }
800  bool TraverseStmt(Stmt *S) {
801  return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
802  return RecursiveASTVisitor::TraverseStmt(S);
803  });
804  }
805 
806  // Add leaves that we found and want.
807  bool VisitReturnStmt(ReturnStmt *R) {
808  found(Return, R->getReturnLoc());
809  return true;
810  }
811  bool VisitBreakStmt(BreakStmt *B) {
812  found(Break, B->getBreakLoc());
813  return true;
814  }
815  bool VisitContinueStmt(ContinueStmt *C) {
816  found(Continue, C->getContinueLoc());
817  return true;
818  }
819  bool VisitSwitchCase(SwitchCase *C) {
820  found(Case, C->getKeywordLoc());
821  return true;
822  }
823  bool VisitCXXThrowExpr(CXXThrowExpr *T) {
824  found(Throw, T->getThrowLoc());
825  return true;
826  }
827  bool VisitGotoStmt(GotoStmt *G) {
828  // Goto is interesting if its target is outside the root.
829  if (const auto *LD = G->getLabel()) {
830  if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
831  SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
832  found(Goto, G->getGotoLoc());
833  }
834  return true;
835  }
836 };
837 
838 // Given a location within a switch statement, return the half-open range that
839 // covers the case it's contained in.
840 // We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
841 SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,
842  const SourceManager &SM) {
843  // Cases are not stored in order, sort them first.
844  // (In fact they seem to be stored in reverse order, don't rely on this)
845  std::vector<const SwitchCase *> Cases;
846  for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
847  Case = Case->getNextSwitchCase())
848  Cases.push_back(Case);
849  llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {
850  return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
851  });
852 
853  // Find the first case after the target location, the end of our range.
854  auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {
855  return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());
856  });
857  SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
858  : (*CaseAfter)->getKeywordLoc();
859 
860  // Our target can be before the first case - cases are optional!
861  if (CaseAfter == Cases.begin())
862  return SourceRange(Switch.getBeginLoc(), End);
863  // The start of our range is usually the previous case, but...
864  auto CaseBefore = std::prev(CaseAfter);
865  // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
866  while (CaseBefore != Cases.begin() &&
867  (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
868  --CaseBefore;
869  return SourceRange((*CaseBefore)->getKeywordLoc(), End);
870 }
871 
872 // Returns the locations of control flow statements related to N. e.g.:
873 // for => branches: break/continue/return/throw
874 // break => controlling loop (forwhile/do), and its related control flow
875 // return => all returns/throws from the same function
876 // When an inner block is selected, we include branches bound to outer blocks
877 // as these are exits from the inner block. e.g. return in a for loop.
878 // FIXME: We don't analyze catch blocks, throw is treated the same as return.
879 std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {
880  const SourceManager &SM =
881  N.getDeclContext().getParentASTContext().getSourceManager();
882  std::vector<SourceLocation> Result;
883 
884  // First, check if we're at a node that can resolve to a root.
885  enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;
886  if (N.ASTNode.get<BreakStmt>()) {
887  Cursor = Cur::Break;
888  } else if (N.ASTNode.get<ContinueStmt>()) {
889  Cursor = Cur::Continue;
890  } else if (N.ASTNode.get<ReturnStmt>()) {
891  Cursor = Cur::Return;
892  } else if (N.ASTNode.get<CXXThrowExpr>()) {
893  Cursor = Cur::Throw;
894  } else if (N.ASTNode.get<SwitchCase>()) {
895  Cursor = Cur::Case;
896  } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
897  // We don't know what root to associate with, but highlight the goto/label.
898  Result.push_back(GS->getGotoLoc());
899  if (const auto *LD = GS->getLabel())
900  Result.push_back(LD->getLocation());
901  Cursor = Cur::None;
902  } else {
903  Cursor = Cur::None;
904  }
905 
906  const Stmt *Root = nullptr; // Loop or function body to traverse.
907  SourceRange Bounds;
908  // Look up the tree for a root (or just at this node if we didn't find a leaf)
909  for (const auto *P = &N; P; P = P->Parent) {
910  // return associates with enclosing function
911  if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
912  if (Cursor == Cur::Return || Cursor == Cur::Throw) {
913  Root = FunctionBody;
914  }
915  break; // other leaves don't cross functions.
916  }
917  // break/continue associate with enclosing loop.
918  if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
919  if (Cursor == Cur::None || Cursor == Cur::Break ||
920  Cursor == Cur::Continue) {
921  Root = LoopBody;
922  // Highlight the loop keyword itself.
923  // FIXME: for do-while, this only covers the `do`..
924  Result.push_back(P->ASTNode.getSourceRange().getBegin());
925  break;
926  }
927  }
928  // For switches, users think of case statements as control flow blocks.
929  // We highlight only occurrences surrounded by the same case.
930  // We don't detect fallthrough (other than 'case X, case Y').
931  if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {
932  if (Cursor == Cur::Break || Cursor == Cur::Case) {
933  Result.push_back(SS->getSwitchLoc()); // Highlight the switch.
934  Root = SS->getBody();
935  // Limit to enclosing case, if there is one.
936  Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
937  break;
938  }
939  }
940  // If we didn't start at some interesting node, we're done.
941  if (Cursor == Cur::None)
942  break;
943  }
944  if (Root) {
945  if (!Bounds.isValid())
946  Bounds = Root->getSourceRange();
947  FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));
948  }
949  return Result;
950 }
951 
952 DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
953  const SourceManager &SM) {
954  DocumentHighlight DH;
955  DH.range = Ref.range(SM);
956  if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
958  else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
959  DH.kind = DocumentHighlightKind::Read;
960  else
961  DH.kind = DocumentHighlightKind::Text;
962  return DH;
963 }
964 
965 llvm::Optional<DocumentHighlight> toHighlight(SourceLocation Loc,
966  const syntax::TokenBuffer &TB) {
967  Loc = TB.sourceManager().getFileLoc(Loc);
968  if (const auto *Tok = TB.spelledTokenAt(Loc)) {
969  DocumentHighlight Result;
970  Result.range = halfOpenToRange(
971  TB.sourceManager(),
972  CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
973  return Result;
974  }
975  return llvm::None;
976 }
977 
978 } // namespace
979 
980 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
981  Position Pos) {
982  const SourceManager &SM = AST.getSourceManager();
983  // FIXME: show references to macro within file?
984  auto CurLoc = sourceLocationInMainFile(SM, Pos);
985  if (!CurLoc) {
986  llvm::consumeError(CurLoc.takeError());
987  return {};
988  }
989  std::vector<DocumentHighlight> Result;
990  auto TryTree = [&](SelectionTree ST) {
991  if (const SelectionTree::Node *N = ST.commonAncestor()) {
992  DeclRelationSet Relations =
994  auto Decls = targetDecl(N->ASTNode, Relations);
995  if (!Decls.empty()) {
996  // FIXME: we may get multiple DocumentHighlights with the same location
997  // and different kinds, deduplicate them.
998  for (const auto &Ref : findRefs({Decls.begin(), Decls.end()}, AST))
999  Result.push_back(toHighlight(Ref, SM));
1000  return true;
1001  }
1002  auto ControlFlow = relatedControlFlow(*N);
1003  if (!ControlFlow.empty()) {
1004  for (SourceLocation Loc : ControlFlow)
1005  if (auto Highlight = toHighlight(Loc, AST.getTokens()))
1006  Result.push_back(std::move(*Highlight));
1007  return true;
1008  }
1009  }
1010  return false;
1011  };
1012 
1013  unsigned Offset =
1014  AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1016  Offset, TryTree);
1017  return Result;
1018 }
1019 
1021  const SymbolIndex *Index) {
1022  if (!Limit)
1023  Limit = std::numeric_limits<uint32_t>::max();
1025  const SourceManager &SM = AST.getSourceManager();
1026  auto MainFilePath =
1027  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1028  if (!MainFilePath) {
1029  elog("Failed to get a path for the main file, so no references");
1030  return Results;
1031  }
1032  auto URIMainFile = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
1033  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1034  if (!CurLoc) {
1035  llvm::consumeError(CurLoc.takeError());
1036  return {};
1037  }
1038  llvm::Optional<DefinedMacro> Macro;
1039  if (const auto *IdentifierAtCursor =
1040  syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens())) {
1041  Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1042  }
1043 
1044  RefsRequest Req;
1045  if (Macro) {
1046  // Handle references to macro.
1047  if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
1048  // Collect macro references from main file.
1049  const auto &IDToRefs = AST.getMacros().MacroRefs;
1050  auto Refs = IDToRefs.find(*MacroSID);
1051  if (Refs != IDToRefs.end()) {
1052  for (const auto &Ref : Refs->second) {
1053  Location Result;
1054  Result.range = Ref;
1055  Result.uri = URIMainFile;
1056  Results.References.push_back(std::move(Result));
1057  }
1058  }
1059  Req.IDs.insert(*MacroSID);
1060  }
1061  } else {
1062  // Handle references to Decls.
1063 
1064  // We also show references to the targets of using-decls, so we include
1065  // DeclRelation::Underlying.
1068  auto Decls = getDeclAtPosition(AST, *CurLoc, Relations);
1069 
1070  // We traverse the AST to find references in the main file.
1071  auto MainFileRefs = findRefs(Decls, AST);
1072  // We may get multiple refs with the same location and different Roles, as
1073  // cross-reference is only interested in locations, we deduplicate them
1074  // by the location to avoid emitting duplicated locations.
1075  MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1076  [](const ReferenceFinder::Reference &L,
1077  const ReferenceFinder::Reference &R) {
1078  return L.SpelledTok.location() ==
1079  R.SpelledTok.location();
1080  }),
1081  MainFileRefs.end());
1082  for (const auto &Ref : MainFileRefs) {
1083  Location Result;
1084  Result.range = Ref.range(SM);
1085  Result.uri = URIMainFile;
1086  Results.References.push_back(std::move(Result));
1087  }
1088  if (Index && Results.References.size() <= Limit) {
1089  for (const Decl *D : Decls) {
1090  // Not all symbols can be referenced from outside (e.g.
1091  // function-locals).
1092  // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1093  // we know this file isn't a header. The details might be tricky.
1094  if (D->getParentFunctionOrMethod())
1095  continue;
1096  if (auto ID = getSymbolID(D))
1097  Req.IDs.insert(*ID);
1098  }
1099  }
1100  }
1101  // Now query the index for references from other files.
1102  if (!Req.IDs.empty() && Index && Results.References.size() <= Limit) {
1103  Req.Limit = Limit;
1104  Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
1105  // No need to continue process if we reach the limit.
1106  if (Results.References.size() > Limit)
1107  return;
1108  auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
1109  // Avoid indexed results for the main file - the AST is authoritative.
1110  if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath)
1111  return;
1112 
1113  Results.References.push_back(std::move(*LSPLoc));
1114  });
1115  }
1116  if (Results.References.size() > Limit) {
1117  Results.HasMore = true;
1118  Results.References.resize(Limit);
1119  }
1120  return Results;
1121 }
1122 
1123 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
1124  const SourceManager &SM = AST.getSourceManager();
1125  auto CurLoc = sourceLocationInMainFile(SM, Pos);
1126  if (!CurLoc) {
1127  llvm::consumeError(CurLoc.takeError());
1128  return {};
1129  }
1130 
1131  std::vector<SymbolDetails> Results;
1132 
1133  // We also want the targets of using-decls, so we include
1134  // DeclRelation::Underlying.
1137  for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1138  SymbolDetails NewSymbol;
1139  std::string QName = printQualifiedName(*D);
1140  auto SplitQName = splitQualifiedName(QName);
1141  NewSymbol.containerName = std::string(SplitQName.first);
1142  NewSymbol.name = std::string(SplitQName.second);
1143 
1144  if (NewSymbol.containerName.empty()) {
1145  if (const auto *ParentND =
1146  dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1147  NewSymbol.containerName = printQualifiedName(*ParentND);
1148  }
1149  llvm::SmallString<32> USR;
1150  if (!index::generateUSRForDecl(D, USR)) {
1151  NewSymbol.USR = std::string(USR.str());
1152  NewSymbol.ID = SymbolID(NewSymbol.USR);
1153  }
1154  Results.push_back(std::move(NewSymbol));
1155  }
1156 
1157  const auto *IdentifierAtCursor =
1158  syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1159  if (!IdentifierAtCursor)
1160  return Results;
1161 
1162  if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1163  SymbolDetails NewMacro;
1164  NewMacro.name = std::string(M->Name);
1165  llvm::SmallString<32> USR;
1166  if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
1167  SM, USR)) {
1168  NewMacro.USR = std::string(USR.str());
1169  NewMacro.ID = SymbolID(NewMacro.USR);
1170  }
1171  Results.push_back(std::move(NewMacro));
1172  }
1173 
1174  return Results;
1175 }
1176 
1177 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1178  OS << S.Name << ": " << S.PreferredDeclaration;
1179  if (S.Definition)
1180  OS << " def=" << *S.Definition;
1181  return OS;
1182 }
1183 
1184 // FIXME(nridge): Reduce duplication between this function and declToSym().
1185 static llvm::Optional<TypeHierarchyItem>
1186 declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND,
1187  const syntax::TokenBuffer &TB) {
1188  auto &SM = Ctx.getSourceManager();
1189  SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
1190  auto FilePath =
1191  getCanonicalPath(SM.getFileEntryForID(SM.getFileID(NameLoc)), SM);
1192  auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1193  if (!FilePath || !TUPath)
1194  return llvm::None; // Not useful without a uri.
1195 
1196  auto DeclToks = TB.spelledForExpanded(TB.expandedTokens(ND.getSourceRange()));
1197  if (!DeclToks || DeclToks->empty())
1198  return llvm::None;
1199 
1200  auto NameToks = TB.spelledForExpanded(TB.expandedTokens(NameLoc));
1201  if (!NameToks || NameToks->empty())
1202  return llvm::None;
1203 
1204  index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1205  // FIXME: this is not classifying constructors, destructors and operators
1206  // correctly (they're all "methods").
1207  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
1208 
1209  TypeHierarchyItem THI;
1210  THI.name = printName(Ctx, ND);
1211  THI.kind = SK;
1212  THI.deprecated = ND.isDeprecated();
1213  THI.range = halfOpenToRange(
1214  SM, syntax::Token::range(SM, DeclToks->front(), DeclToks->back())
1215  .toCharRange(SM));
1217  SM, syntax::Token::range(SM, NameToks->front(), NameToks->back())
1218  .toCharRange(SM));
1219  if (!THI.range.contains(THI.selectionRange)) {
1220  // 'selectionRange' must be contained in 'range', so in cases where clang
1221  // reports unrelated ranges we need to reconcile somehow.
1222  THI.range = THI.selectionRange;
1223  }
1224 
1225  THI.uri = URIForFile::canonicalize(*FilePath, *TUPath);
1226 
1227  // Compute the SymbolID and store it in the 'data' field.
1228  // This allows typeHierarchy/resolve to be used to
1229  // resolve children of items returned in a previous request
1230  // for parents.
1231  if (auto ID = getSymbolID(&ND)) {
1232  THI.data = ID->str();
1233  }
1234 
1235  return THI;
1236 }
1237 
1238 static Optional<TypeHierarchyItem>
1240  PathRef TUPath) {
1241  auto Loc = symbolToLocation(S, TUPath);
1242  if (!Loc) {
1243  log("Type hierarchy: {0}", Loc.takeError());
1244  return llvm::None;
1245  }
1246  TypeHierarchyItem THI;
1247  THI.name = std::string(S.Name);
1249  THI.deprecated = (S.Flags & Symbol::Deprecated);
1250  THI.selectionRange = Loc->range;
1251  // FIXME: Populate 'range' correctly
1252  // (https://github.com/clangd/clangd/issues/59).
1253  THI.range = THI.selectionRange;
1254  THI.uri = Loc->uri;
1255  // Store the SymbolID in the 'data' field. The client will
1256  // send this back in typeHierarchy/resolve, allowing us to
1257  // continue resolving additional levels of the type hierarchy.
1258  THI.data = S.ID.str();
1259 
1260  return std::move(THI);
1261 }
1262 
1263 static void fillSubTypes(const SymbolID &ID,
1264  std::vector<TypeHierarchyItem> &SubTypes,
1265  const SymbolIndex *Index, int Levels, PathRef TUPath) {
1266  RelationsRequest Req;
1267  Req.Subjects.insert(ID);
1269  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
1270  if (Optional<TypeHierarchyItem> ChildSym =
1272  if (Levels > 1) {
1273  ChildSym->children.emplace();
1274  fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
1275  }
1276  SubTypes.emplace_back(std::move(*ChildSym));
1277  }
1278  });
1279 }
1280 
1281 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
1282 
1283 static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx,
1284  std::vector<TypeHierarchyItem> &SuperTypes,
1285  RecursionProtectionSet &RPSet,
1286  const syntax::TokenBuffer &TB) {
1287  // typeParents() will replace dependent template specializations
1288  // with their class template, so to avoid infinite recursion for
1289  // certain types of hierarchies, keep the templates encountered
1290  // along the parent chain in a set, and stop the recursion if one
1291  // starts to repeat.
1292  auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
1293  if (Pattern) {
1294  if (!RPSet.insert(Pattern).second) {
1295  return;
1296  }
1297  }
1298 
1299  for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
1300  if (Optional<TypeHierarchyItem> ParentSym =
1301  declToTypeHierarchyItem(ASTCtx, *ParentDecl, TB)) {
1302  ParentSym->parents.emplace();
1303  fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet, TB);
1304  SuperTypes.emplace_back(std::move(*ParentSym));
1305  }
1306  }
1307 
1308  if (Pattern) {
1309  RPSet.erase(Pattern);
1310  }
1311 }
1312 
1313 const CXXRecordDecl *findRecordTypeAt(ParsedAST &AST, Position Pos) {
1314  auto RecordFromNode =
1315  [](const SelectionTree::Node *N) -> const CXXRecordDecl * {
1316  if (!N)
1317  return nullptr;
1318 
1319  // Note: explicitReferenceTargets() will search for both template
1320  // instantiations and template patterns, and prefer the former if available
1321  // (generally, one will be available for non-dependent specializations of a
1322  // class template).
1323  auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying);
1324  if (Decls.empty())
1325  return nullptr;
1326 
1327  const NamedDecl *D = Decls[0];
1328 
1329  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1330  // If this is a variable, use the type of the variable.
1331  return VD->getType().getTypePtr()->getAsCXXRecordDecl();
1332  }
1333 
1334  if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
1335  // If this is a method, use the type of the class.
1336  return Method->getParent();
1337  }
1338 
1339  // We don't handle FieldDecl because it's not clear what behaviour
1340  // the user would expect: the enclosing class type (as with a
1341  // method), or the field's type (as with a variable).
1342 
1343  return dyn_cast<CXXRecordDecl>(D);
1344  };
1345 
1346  const SourceManager &SM = AST.getSourceManager();
1347  const CXXRecordDecl *Result = nullptr;
1348  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1349  if (!Offset) {
1350  llvm::consumeError(Offset.takeError());
1351  return Result;
1352  }
1354  *Offset, [&](SelectionTree ST) {
1355  Result = RecordFromNode(ST.commonAncestor());
1356  return Result != nullptr;
1357  });
1358  return Result;
1359 }
1360 
1361 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
1362  std::vector<const CXXRecordDecl *> Result;
1363 
1364  // If this is an invalid instantiation, instantiation of the bases
1365  // may not have succeeded, so fall back to the template pattern.
1366  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
1367  if (CTSD->isInvalidDecl())
1368  CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
1369  }
1370 
1371  for (auto Base : CXXRD->bases()) {
1372  const CXXRecordDecl *ParentDecl = nullptr;
1373 
1374  const Type *Type = Base.getType().getTypePtr();
1375  if (const RecordType *RT = Type->getAs<RecordType>()) {
1376  ParentDecl = RT->getAsCXXRecordDecl();
1377  }
1378 
1379  if (!ParentDecl) {
1380  // Handle a dependent base such as "Base<T>" by using the primary
1381  // template.
1382  if (const TemplateSpecializationType *TS =
1383  Type->getAs<TemplateSpecializationType>()) {
1384  TemplateName TN = TS->getTemplateName();
1385  if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
1386  ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
1387  }
1388  }
1389  }
1390 
1391  if (ParentDecl)
1392  Result.push_back(ParentDecl);
1393  }
1394 
1395  return Result;
1396 }
1397 
1398 llvm::Optional<TypeHierarchyItem>
1399 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
1400  TypeHierarchyDirection Direction, const SymbolIndex *Index,
1401  PathRef TUPath) {
1402  const CXXRecordDecl *CXXRD = findRecordTypeAt(AST, Pos);
1403  if (!CXXRD)
1404  return llvm::None;
1405 
1406  Optional<TypeHierarchyItem> Result =
1407  declToTypeHierarchyItem(AST.getASTContext(), *CXXRD, AST.getTokens());
1408  if (!Result)
1409  return Result;
1410 
1411  if (Direction == TypeHierarchyDirection::Parents ||
1412  Direction == TypeHierarchyDirection::Both) {
1413  Result->parents.emplace();
1414 
1415  RecursionProtectionSet RPSet;
1416  fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet,
1417  AST.getTokens());
1418  }
1419 
1420  if ((Direction == TypeHierarchyDirection::Children ||
1421  Direction == TypeHierarchyDirection::Both) &&
1422  ResolveLevels > 0) {
1423  Result->children.emplace();
1424 
1425  if (Index) {
1426  // The index does not store relationships between implicit
1427  // specializations, so if we have one, use the template pattern instead.
1428  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
1429  CXXRD = CTSD->getTemplateInstantiationPattern();
1430 
1431  if (Optional<SymbolID> ID = getSymbolID(CXXRD))
1432  fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
1433  }
1434  }
1435 
1436  return Result;
1437 }
1438 
1439 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
1440  TypeHierarchyDirection Direction,
1441  const SymbolIndex *Index) {
1442  // We only support typeHierarchy/resolve for children, because for parents
1443  // we ignore ResolveLevels and return all levels of parents eagerly.
1444  if (Direction == TypeHierarchyDirection::Parents || ResolveLevels == 0)
1445  return;
1446 
1447  Item.children.emplace();
1448 
1449  if (Index && Item.data) {
1450  // We store the item's SymbolID in the 'data' field, and the client
1451  // passes it back to us in typeHierarchy/resolve.
1452  if (Expected<SymbolID> ID = SymbolID::fromStr(*Item.data)) {
1453  fillSubTypes(*ID, *Item.children, Index, ResolveLevels, Item.uri.file());
1454  }
1455  }
1456 }
1457 
1458 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
1459  const FunctionDecl *FD) {
1460  if (!FD->hasBody())
1461  return {};
1462  llvm::DenseSet<const Decl *> DeclRefs;
1464  for (const Decl *D : Ref.Targets) {
1465  if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
1466  !Ref.IsDecl)
1467  DeclRefs.insert(D);
1468  }
1469  });
1470  return DeclRefs;
1471 }
1472 } // namespace clangd
1473 } // namespace clang
dlog
#define dlog(...)
Definition: Logger.h:72
clang::clangd::SymbolRelevanceSignals::merge
void merge(const CodeCompletionResult &SemaResult)
Definition: Quality.cpp:297
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::TypeHierarchyItem::selectionRange
Range selectionRange
The range that should be selected and revealed when this type hierarchy item is being picked,...
Definition: Protocol.h:1311
XRefs.h
clang::clangd::findRecordTypeAt
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
Definition: XRefs.cpp:1313
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
clang::clangd::targetDecl
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const ast_type_traits::DynTypedNode &N, DeclRelationSet Mask)
targetDecl() finds the declaration referred to by an AST node.
Definition: FindTarget.cpp:568
References
unsigned References
Definition: CodeComplete.cpp:161
clang::clangd::locateMacroAt
llvm::Optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
Definition: SourceCode.cpp:968
Selection.h
clang::clangd::RelationKind::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:1020
clang::clangd::SpelledWord
Definition: SourceCode.h:223
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
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:471
clang::clangd::Symbol::ID
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
clang::clangd::RefKind::All
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:296
SymbolLocation.h
Location
Definition: Modularize.cpp:383
clang::clangd::symbolToTypeHierarchyItem
static Optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, const SymbolIndex *Index, PathRef TUPath)
Definition: XRefs.cpp:1239
clang::clangd::resolveTypeHierarchy
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Definition: XRefs.cpp:1439
clang::clangd::Location
Definition: Protocol.h:199
clang::clangd::ParsedAST::getIncludeStructure
const IncludeStructure & getIncludeStructure() const
Definition: ParsedAST.cpp:527
clang::clangd::evaluateSymbolAndRelevance
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
Definition: Quality.cpp:467
clang::clangd::SymbolKind::Object
clang::clangd::splitQualifiedName
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
Definition: SourceCode.cpp:489
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:792
clang::clangd::TypeHierarchyDirection::Parents
clang::clangd::fillSubTypes
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
Definition: XRefs.cpp:1263
Index.h
clang::clangd::RefSlab::end
const_iterator end() const
Definition: Ref.h:116
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:775
clang::clangd::locateSymbolTextually
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, const std::string &MainFilePath, ASTNodeKind NodeKind)
Definition: XRefs.cpp:356
clang::clangd::Symbol::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:324
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:43
clang::clangd::typeParents
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
Definition: XRefs.cpp:1361
clang::clangd::TypeHierarchyItem::kind
SymbolKind kind
The kind of the hierarchy item. For instance, class or interface.
Definition: Protocol.h:1294
FindSymbols.h
clang::clangd::TextDocumentSyncKind::None
Documents should not be synced at all.
clang::clangd::RelationsRequest::Predicate
RelationKind Predicate
Definition: Index.h:78
clang::clangd::URIForFile::fromURI
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
Definition: Protocol.cpp:46
clang::clangd::nameLocation
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
Definition: AST.cpp:161
clang::clangd::MainFileMacros::MacroRefs
llvm::DenseMap< SymbolID, std::vector< Range > > MacroRefs
Definition: CollectMacros.h:28
clang::clangd::FuzzyFindRequest
Definition: Index.h:26
clang::clangd::DeclRelationSet
Definition: FindTarget.h:163
FindTarget.h
clang::clangd::SymbolQualitySignals
Attributes of a symbol that affect how much we like it.
Definition: Quality.h:57
clang::clangd::IncludeStructure::MainFileIncludes
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:115
clang::clangd::URI::parse
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:163
clang::clangd::SymbolDetails::containerName
std::string containerName
Definition: Protocol.h:997
clang::clangd::TypeHierarchyItem::range
Range range
The range enclosing this type hierarchy item not including leading/trailing whitespace but everything...
Definition: Protocol.h:1306
clang::clangd::SymbolKind
SymbolKind
A symbol kind.
Definition: Protocol.h:321
clang::clangd::ParsedAST::getLangOpts
const LangOptions & getLangOpts() const
Definition: ParsedAST.h:81
clang::clangd::FuzzyFindRequest::Query
std::string Query
A query string for the fuzzy find.
Definition: Index.h:29
clang::clangd::HighlightingKind::Macro
clang::clangd::explicitReferenceTargets
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
Definition: FindTarget.cpp:578
clang::clangd::Position::line
int line
Line position in a document (zero-based).
Definition: Protocol.h:146
clang::clangd::SymbolDetails::name
std::string name
Definition: Protocol.h:995
Protocol.h
clang::clangd::declToTypeHierarchyItem
static llvm::Optional< TypeHierarchyItem > declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND, const syntax::TokenBuffer &TB)
Definition: XRefs.cpp:1186
clang::clangd::findNearbyIdentifier
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
Definition: XRefs.cpp:466
clang::clangd::TypeHierarchyDirection::Both
Relation.h
Offset
size_t Offset
Definition: CodeComplete.cpp:1044
clang::clangd::halfOpenToRange
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
Definition: SourceCode.cpp:471
clang::clangd::Position
Definition: Protocol.h:144
clang::clangd::SymbolRelevanceSignals::evaluate
float evaluate() const
Definition: Quality.cpp:351
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:542
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:77
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:207
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::clangd::SymbolIndex::relations
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
CodeCompletionStrings.h
Line
int Line
Definition: PreprocessorTracker.cpp:513
clang::clangd::TypeHierarchyDirection::Children
clang::clangd::getCanonicalPath
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:512
clang::clangd::Ref::Location
SymbolLocation Location
The source location where the symbol is named.
Definition: Ref.h:89
Quality
SignatureQualitySignals Quality
Definition: CodeComplete.cpp:819
Role
index::SymbolRoleSet Role
Definition: XRefs.cpp:652
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:1458
clang::clangd::printQualifiedName
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:168
Logger.h
clang::clangd::getSymbolInfo
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:1123
clang::clangd::TypeHierarchyItem::name
std::string name
The human readable name of the hierarchy item.
Definition: Protocol.h:1287
clang::clangd::Symbol
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
clang::clangd::positionToOffset
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:175
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:918
Bounds
PreambleBounds Bounds
Definition: Preamble.cpp:222
clang::clangd::ReferencesResult
Definition: XRefs.h:81
clang::clangd::indexSymbolKindToSymbolKind
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
Definition: Protocol.cpp:230
clang::clangd::SymbolRelevanceSignals::Query
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
clang::clangd::mergeSymbol
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition: Merge.cpp:172
clang::clangd::RefKind::Reference
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:712
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::fillSuperTypes
static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx, std::vector< TypeHierarchyItem > &SuperTypes, RecursionProtectionSet &RPSet, const syntax::TokenBuffer &TB)
Definition: XRefs.cpp:1283
clang::clangd::SymbolID::str
std::string str() const
Definition: SymbolID.cpp:33
clang::clangd::RefsRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:68
clang::clangd::CompletionItemKind::Method
clang::clangd::SelectionTree
Definition: Selection.h:76
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:1321
clang::clangd::DeclRelation::Underlying
This is the underlying declaration for an 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:63
clang::clangd::operator<<
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Definition: CodeComplete.cpp:1912
clang::clangd::TypeHierarchyItem::uri
URIForFile uri
The URI of the text document where this type hierarchy item belongs to.
Definition: Protocol.h:1300
clang::clangd::SymbolOrigin::AST
clang::clangd::DocumentHighlightKind::Write
clang::clangd::SymbolDetails
Represents information about identifier.
Definition: Protocol.h:994
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:1004
clang::clangd::SelectionTree::Node
Definition: Selection.h:122
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:62
Word
std::string Word
Definition: FuzzyMatchTests.cpp:40
SourceCode.h
Index
const SymbolIndex * Index
Definition: Dexp.cpp:95
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:89
clang::clangd::ParsedAST::getPreprocessor
Preprocessor & getPreprocessor()
Definition: ParsedAST.cpp:477
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:85
clang::clangd::ReferenceLoc
Information about a reference written in the source code, independent of the actual AST node that thi...
Definition: FindTarget.h:119
clang::clangd::TypeHierarchyDirection
TypeHierarchyDirection
Definition: Protocol.h:1270
clang::clangd::TypeHierarchyItem
Definition: Protocol.h:1285
clang::clangd::TypeHierarchyItem::deprecated
bool deprecated
true if the hierarchy item is deprecated. Otherwise, false.
Definition: Protocol.h:1297
Score
llvm::Optional< float > Score
Definition: FuzzyMatchTests.cpp:48
clang::clangd::Ref
Represents a symbol occurrence in the source file.
Definition: Ref.h:87
SpelledTok
syntax::Token SpelledTok
Definition: XRefs.cpp:651
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
clang::clangd::LocatedSymbol::Name
std::string Name
Definition: XRefs.h:45
clang::clangd::RecursionProtectionSet
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
Definition: XRefs.cpp:1281
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::clangd::SymbolID::fromStr
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:35
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:33
clang::clangd::LocatedSymbol
Definition: XRefs.h:43
clang::clangd::Symbol::Scope
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Definition: Symbol.h:44
clang::clangd::findExplicitReferences
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out)
Recursively traverse S and report all references explicitly written in the code.
Definition: FindTarget.cpp:1017
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:162
clang::clangd::ParsedAST::getTokens
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Definition: ParsedAST.h:103
clang::clangd::isInsideMainFile
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Definition: SourceCode.cpp:421
clang::clangd::ParsedAST::getLocalTopLevelDecls
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
Definition: ParsedAST.cpp:487
clang::clangd::LocatedSymbol::PreferredDeclaration
Location PreferredDeclaration
Definition: XRefs.h:47
SymbolInfo
clang::find_all_symbols::SymbolInfo SymbolInfo
Definition: FindAllSymbolsMain.cpp:38
clang::clangd::Range::contains
bool contains(Position Pos) const
Definition: Protocol.h:190
clang::clangd::URIForFile::file
llvm::StringRef file() const
Retrieves absolute path to the file.
Definition: Protocol.h:94
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:1399
clang::clangd::RefsRequest::Limit
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:73
clang::clangd::FuzzyFindRequest::AnyScope
bool AnyScope
If set to true, allow symbols from any scope.
Definition: Index.h:39
clang::clangd::getSymbolID
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:285
clang::clangd::Symbol::Definition
SymbolLocation Definition
The location of the symbol's definition, if one was found.
Definition: Symbol.h:47
Loc
SourceLocation Loc
'#' location in the include directive
Definition: IncludeOrderCheck.cpp:37
clang::clangd::DocumentHighlightKind::Read
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:48
Pos
Position Pos
Definition: SourceCode.cpp:649
clang::clangd::RelationsRequest
Definition: Index.h:76
Merge.h
clang::clangd::SymbolDetails::ID
llvm::Optional< SymbolID > ID
Definition: Protocol.h:1006
URI.h
Quality.h
clang::clangd::SymbolRelevanceSignals::Generic
Definition: Quality.h:124
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
clang::clangd::SymbolID
Definition: SymbolID.h:31
clang::clangd::DocumentHighlightKind::Text
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:74
clang::clangd::getDocumentLinks
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Definition: XRefs.cpp:612
clang::clangd::RefsRequest
Definition: Index.h:67
clang::clangd::DeclRelation::TemplatePattern
This is the pattern the template specialization was instantiated from.
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:87
clang::clangd::sourceLocationInMainFile
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
Definition: SourceCode.cpp:461
clang::clangd::LocatedSymbol::Definition
llvm::Optional< Location > Definition
Definition: XRefs.h:49
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' filed, which can be used to identify a type hierarchy item in a resolve request.
Definition: Protocol.h:1325
clang::clangd::DeclRelation::Alias
This declaration is an alias that was referred to.
AST.h
ParsedAST.h
clang::clangd::findDocumentHighlights
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:980
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:491