clang-tools  10.0.0git
XRefs.cpp
Go to the documentation of this file.
1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "XRefs.h"
9 #include "AST.h"
10 #include "CodeCompletionStrings.h"
11 #include "FindSymbols.h"
12 #include "FindTarget.h"
13 #include "Logger.h"
14 #include "ParsedAST.h"
15 #include "Protocol.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 "clang/AST/ASTContext.h"
24 #include "clang/AST/Decl.h"
25 #include "clang/AST/DeclCXX.h"
26 #include "clang/AST/DeclTemplate.h"
27 #include "clang/AST/ExprCXX.h"
28 #include "clang/AST/Type.h"
29 #include "clang/Basic/LLVM.h"
30 #include "clang/Basic/SourceLocation.h"
31 #include "clang/Basic/SourceManager.h"
32 #include "clang/Index/IndexDataConsumer.h"
33 #include "clang/Index/IndexSymbol.h"
34 #include "clang/Index/IndexingAction.h"
35 #include "clang/Index/IndexingOptions.h"
36 #include "clang/Index/USRGeneration.h"
37 #include "llvm/ADT/ArrayRef.h"
38 #include "llvm/ADT/None.h"
39 #include "llvm/ADT/STLExtras.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringRef.h"
42 #include "llvm/Support/Casting.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/raw_ostream.h"
45 
46 namespace clang {
47 namespace clangd {
48 namespace {
49 
50 // Returns the single definition of the entity declared by D, if visible.
51 // In particular:
52 // - for non-redeclarable kinds (e.g. local vars), return D
53 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
54 // Kinds of nodes that always return nullptr here will not have definitions
55 // reported by locateSymbolAt().
56 const NamedDecl *getDefinition(const NamedDecl *D) {
57  assert(D);
58  // Decl has one definition that we can find.
59  if (const auto *TD = dyn_cast<TagDecl>(D))
60  return TD->getDefinition();
61  if (const auto *VD = dyn_cast<VarDecl>(D))
62  return VD->getDefinition();
63  if (const auto *FD = dyn_cast<FunctionDecl>(D))
64  return FD->getDefinition();
65  // Only a single declaration is allowed.
66  if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
67  isa<TemplateTemplateParmDecl>(D)) // except cases above
68  return D;
69  // Multiple definitions are allowed.
70  return nullptr; // except cases above
71 }
72 
73 void logIfOverflow(const SymbolLocation &Loc) {
74  if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
75  log("Possible overflow in symbol location: {0}", Loc);
76 }
77 
78 // Convert a SymbolLocation to LSP's Location.
79 // TUPath is used to resolve the path of URI.
80 // FIXME: figure out a good home for it, and share the implementation with
81 // FindSymbols.
82 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
83  llvm::StringRef TUPath) {
84  if (!Loc)
85  return None;
86  auto Uri = URI::parse(Loc.FileURI);
87  if (!Uri) {
88  elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
89  return None;
90  }
91  auto U = URIForFile::fromURI(*Uri, TUPath);
92  if (!U) {
93  elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
94  return None;
95  }
96 
97  Location LSPLoc;
98  LSPLoc.uri = std::move(*U);
99  LSPLoc.range.start.line = Loc.Start.line();
100  LSPLoc.range.start.character = Loc.Start.column();
101  LSPLoc.range.end.line = Loc.End.line();
102  LSPLoc.range.end.character = Loc.End.column();
103  logIfOverflow(Loc);
104  return LSPLoc;
105 }
106 
107 SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
108  SymbolLocation SymLoc;
109  URIStorage = Loc.uri.uri();
110  SymLoc.FileURI = URIStorage.c_str();
111  SymLoc.Start.setLine(Loc.range.start.line);
112  SymLoc.Start.setColumn(Loc.range.start.character);
113  SymLoc.End.setLine(Loc.range.end.line);
114  SymLoc.End.setColumn(Loc.range.end.character);
115  return SymLoc;
116 }
117 
118 // Returns the preferred location between an AST location and an index location.
119 SymbolLocation getPreferredLocation(const Location &ASTLoc,
120  const SymbolLocation &IdxLoc,
121  std::string &Scratch) {
122  // Also use a dummy symbol for the index location so that other fields (e.g.
123  // definition) are not factored into the preference.
124  Symbol ASTSym, IdxSym;
125  ASTSym.ID = IdxSym.ID = SymbolID("dummy_id");
126  ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
127  IdxSym.CanonicalDeclaration = IdxLoc;
128  auto Merged = mergeSymbol(ASTSym, IdxSym);
129  return Merged.CanonicalDeclaration;
130 }
131 
132 std::vector<const NamedDecl *> getDeclAtPosition(ParsedAST &AST,
133  SourceLocation Pos,
134  DeclRelationSet Relations) {
135  FileID FID;
136  unsigned Offset;
137  std::tie(FID, Offset) = AST.getSourceManager().getDecomposedSpellingLoc(Pos);
138  SelectionTree Selection(AST.getASTContext(), AST.getTokens(), Offset);
139  std::vector<const NamedDecl *> Result;
140  if (const SelectionTree::Node *N = Selection.commonAncestor()) {
141  auto Decls = targetDecl(N->ASTNode, Relations);
142  Result.assign(Decls.begin(), Decls.end());
143  }
144  return Result;
145 }
146 
147 llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,
148  llvm::StringRef TUPath) {
149  const SourceManager &SourceMgr = AST.getSourceManager();
150  const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
151  if (!F)
152  return None;
153  auto FilePath = getCanonicalPath(F, SourceMgr);
154  if (!FilePath) {
155  log("failed to get path!");
156  return None;
157  }
158  if (auto Range =
159  getTokenRange(AST.getSourceManager(), AST.getLangOpts(), TokLoc)) {
160  Location L;
161  L.uri = URIForFile::canonicalize(*FilePath, TUPath);
162  L.range = *Range;
163  return L;
164  }
165  return None;
166 }
167 
168 } // namespace
169 
170 std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
171  const auto &SM = AST.getSourceManager();
172  auto MainFilePath =
173  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
174  if (!MainFilePath) {
175  elog("Failed to get a path for the main file, so no links");
176  return {};
177  }
178 
179  std::vector<DocumentLink> Result;
180  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
181  if (!Inc.Resolved.empty()) {
182  Result.push_back(DocumentLink(
183  {Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
184  }
185  }
186 
187  return Result;
188 }
189 
190 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
191  const SymbolIndex *Index) {
192  const auto &SM = AST.getSourceManager();
193  auto MainFilePath =
194  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
195  if (!MainFilePath) {
196  elog("Failed to get a path for the main file, so no references");
197  return {};
198  }
199 
200  // Treat #included files as symbols, to enable go-to-definition on them.
201  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
202  if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) {
203  LocatedSymbol File;
204  File.Name = llvm::sys::path::filename(Inc.Resolved);
205  File.PreferredDeclaration = {
206  URIForFile::canonicalize(Inc.Resolved, *MainFilePath), Range{}};
207  File.Definition = File.PreferredDeclaration;
208  // We're not going to find any further symbols on #include lines.
209  return {std::move(File)};
210  }
211  }
212 
213  // Macros are simple: there's no declaration/definition distinction.
214  // As a consequence, there's no need to look them up in the index either.
215  SourceLocation IdentStartLoc = SM.getMacroArgExpandedLocation(
217  std::vector<LocatedSymbol> Result;
218  if (auto M = locateMacroAt(IdentStartLoc, AST.getPreprocessor())) {
219  if (auto Loc = makeLocation(AST.getASTContext(),
220  M->Info->getDefinitionLoc(), *MainFilePath)) {
222  Macro.Name = M->Name;
223  Macro.PreferredDeclaration = *Loc;
224  Macro.Definition = Loc;
225  Result.push_back(std::move(Macro));
226 
227  // Don't look at the AST or index if we have a macro result.
228  // (We'd just return declarations referenced from the macro's
229  // expansion.)
230  return Result;
231  }
232  }
233 
234  // Decls are more complicated.
235  // The AST contains at least a declaration, maybe a definition.
236  // These are up-to-date, and so generally preferred over index results.
237  // We perform a single batch index lookup to find additional definitions.
238 
239  // Results follow the order of Symbols.Decls.
240  // Keep track of SymbolID -> index mapping, to fill in index data later.
241  llvm::DenseMap<SymbolID, size_t> ResultIndex;
242 
243  SourceLocation SourceLoc;
244  if (auto L = sourceLocationInMainFile(SM, Pos)) {
245  SourceLoc = *L;
246  } else {
247  elog("locateSymbolAt failed to convert position to source location: {0}",
248  L.takeError());
249  return Result;
250  }
251 
252  // Emit all symbol locations (declaration or definition) from AST.
253  DeclRelationSet Relations =
255  for (const NamedDecl *D : getDeclAtPosition(AST, SourceLoc, Relations)) {
256  const NamedDecl *Def = getDefinition(D);
257  const NamedDecl *Preferred = Def ? Def : D;
258 
259  // If we're at the point of declaration of a template specialization,
260  // it's more useful to navigate to the template declaration.
261  if (SM.getMacroArgExpandedLocation(Preferred->getLocation()) ==
262  IdentStartLoc) {
263  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Preferred)) {
264  D = CTSD->getSpecializedTemplate();
265  Def = getDefinition(D);
266  Preferred = Def ? Def : D;
267  }
268  }
269 
270  auto Loc = makeLocation(AST.getASTContext(), nameLocation(*Preferred, SM),
271  *MainFilePath);
272  if (!Loc)
273  continue;
274 
275  Result.emplace_back();
276  Result.back().Name = printName(AST.getASTContext(), *D);
277  Result.back().PreferredDeclaration = *Loc;
278  // Preferred is always a definition if possible, so this check works.
279  if (Def == Preferred)
280  Result.back().Definition = *Loc;
281 
282  // Record SymbolID for index lookup later.
283  if (auto ID = getSymbolID(Preferred))
284  ResultIndex[*ID] = Result.size() - 1;
285  }
286 
287  // Now query the index for all Symbol IDs we found in the AST.
288  if (Index && !ResultIndex.empty()) {
289  LookupRequest QueryRequest;
290  for (auto It : ResultIndex)
291  QueryRequest.IDs.insert(It.first);
292  std::string Scratch;
293  Index->lookup(QueryRequest, [&](const Symbol &Sym) {
294  auto &R = Result[ResultIndex.lookup(Sym.ID)];
295 
296  if (R.Definition) { // from AST
297  // Special case: if the AST yielded a definition, then it may not be
298  // the right *declaration*. Prefer the one from the index.
299  if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, *MainFilePath))
300  R.PreferredDeclaration = *Loc;
301 
302  // We might still prefer the definition from the index, e.g. for
303  // generated symbols.
304  if (auto Loc = toLSPLocation(
305  getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
306  *MainFilePath))
307  R.Definition = *Loc;
308  } else {
309  R.Definition = toLSPLocation(Sym.Definition, *MainFilePath);
310 
311  // Use merge logic to choose AST or index declaration.
312  if (auto Loc = toLSPLocation(
313  getPreferredLocation(R.PreferredDeclaration,
314  Sym.CanonicalDeclaration, Scratch),
315  *MainFilePath))
316  R.PreferredDeclaration = *Loc;
317  }
318  });
319  }
320 
321  return Result;
322 }
323 
324 namespace {
325 
326 /// Collects references to symbols within the main file.
327 class ReferenceFinder : public index::IndexDataConsumer {
328 public:
329  struct Reference {
330  SourceLocation Loc;
331  index::SymbolRoleSet Role;
332  };
333 
334  ReferenceFinder(ASTContext &AST, Preprocessor &PP,
335  const std::vector<const NamedDecl *> &TargetDecls)
336  : AST(AST) {
337  for (const NamedDecl *D : TargetDecls)
338  CanonicalTargets.insert(D->getCanonicalDecl());
339  }
340 
341  std::vector<Reference> take() && {
342  llvm::sort(References, [](const Reference &L, const Reference &R) {
343  return std::tie(L.Loc, L.Role) < std::tie(R.Loc, R.Role);
344  });
345  // We sometimes see duplicates when parts of the AST get traversed twice.
346  References.erase(std::unique(References.begin(), References.end(),
347  [](const Reference &L, const Reference &R) {
348  return std::tie(L.Loc, L.Role) ==
349  std::tie(R.Loc, R.Role);
350  }),
351  References.end());
352  return std::move(References);
353  }
354 
355  bool
356  handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
357  llvm::ArrayRef<index::SymbolRelation> Relations,
358  SourceLocation Loc,
359  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
360  assert(D->isCanonicalDecl() && "expect D to be a canonical declaration");
361  const SourceManager &SM = AST.getSourceManager();
362  Loc = SM.getFileLoc(Loc);
363  if (isInsideMainFile(Loc, SM) && CanonicalTargets.count(D))
364  References.push_back({Loc, Roles});
365  return true;
366  }
367 
368 private:
369  llvm::SmallSet<const Decl *, 4> CanonicalTargets;
370  std::vector<Reference> References;
371  const ASTContext &AST;
372 };
373 
374 std::vector<ReferenceFinder::Reference>
375 findRefs(const std::vector<const NamedDecl *> &Decls, ParsedAST &AST) {
376  ReferenceFinder RefFinder(AST.getASTContext(), AST.getPreprocessor(), Decls);
377  index::IndexingOptions IndexOpts;
378  IndexOpts.SystemSymbolFilter =
379  index::IndexingOptions::SystemSymbolFilterKind::All;
380  IndexOpts.IndexFunctionLocals = true;
381  IndexOpts.IndexParametersInDeclarations = true;
382  IndexOpts.IndexTemplateParameters = true;
383  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
384  AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
385  return std::move(RefFinder).take();
386 }
387 
388 } // namespace
389 
390 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
391  Position Pos) {
392  const SourceManager &SM = AST.getSourceManager();
393  // FIXME: show references to macro within file?
394  DeclRelationSet Relations =
396  auto References = findRefs(
397  getDeclAtPosition(AST,
398  SM.getMacroArgExpandedLocation(getBeginningOfIdentifier(
399  Pos, SM, AST.getLangOpts())),
400  Relations),
401  AST);
402 
403  // FIXME: we may get multiple DocumentHighlights with the same location and
404  // different kinds, deduplicate them.
405  std::vector<DocumentHighlight> Result;
406  for (const auto &Ref : References) {
407  if (auto Range =
408  getTokenRange(AST.getSourceManager(), AST.getLangOpts(), Ref.Loc)) {
410  DH.range = *Range;
411  if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
413  else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
415  else
417  Result.push_back(std::move(DH));
418  }
419  }
420  return Result;
421 }
422 
424  const SymbolIndex *Index) {
425  if (!Limit)
426  Limit = std::numeric_limits<uint32_t>::max();
428  const SourceManager &SM = AST.getSourceManager();
429  auto MainFilePath =
430  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
431  if (!MainFilePath) {
432  elog("Failed to get a path for the main file, so no references");
433  return Results;
434  }
435  auto URIMainFile = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
436  auto Loc = SM.getMacroArgExpandedLocation(
437  getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
438  RefsRequest Req;
439 
440  if (auto Macro = locateMacroAt(Loc, AST.getPreprocessor())) {
441  // Handle references to macro.
442  if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
443  // Collect macro references from main file.
444  const auto &IDToRefs = AST.getMacros().MacroRefs;
445  auto Refs = IDToRefs.find(*MacroSID);
446  if (Refs != IDToRefs.end()) {
447  for (const auto Ref : Refs->second) {
448  Location Result;
449  Result.range = Ref;
450  Result.uri = URIMainFile;
451  Results.References.push_back(std::move(Result));
452  }
453  }
454  Req.IDs.insert(*MacroSID);
455  }
456  } else {
457  // Handle references to Decls.
458 
459  // We also show references to the targets of using-decls, so we include
460  // DeclRelation::Underlying.
463  auto Decls = getDeclAtPosition(AST, Loc, Relations);
464 
465  // We traverse the AST to find references in the main file.
466  auto MainFileRefs = findRefs(Decls, AST);
467  // We may get multiple refs with the same location and different Roles, as
468  // cross-reference is only interested in locations, we deduplicate them
469  // by the location to avoid emitting duplicated locations.
470  MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
471  [](const ReferenceFinder::Reference &L,
472  const ReferenceFinder::Reference &R) {
473  return L.Loc == R.Loc;
474  }),
475  MainFileRefs.end());
476  for (const auto &Ref : MainFileRefs) {
477  if (auto Range = getTokenRange(SM, AST.getLangOpts(), Ref.Loc)) {
478  Location Result;
479  Result.range = *Range;
480  Result.uri = URIMainFile;
481  Results.References.push_back(std::move(Result));
482  }
483  }
484  if (Index && Results.References.size() <= Limit) {
485  for (const Decl *D : Decls) {
486  // Not all symbols can be referenced from outside (e.g.
487  // function-locals).
488  // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
489  // we know this file isn't a header. The details might be tricky.
490  if (D->getParentFunctionOrMethod())
491  continue;
492  if (auto ID = getSymbolID(D))
493  Req.IDs.insert(*ID);
494  }
495  }
496  }
497  // Now query the index for references from other files.
498  if (!Req.IDs.empty() && Index && Results.References.size() <= Limit) {
499  Req.Limit = Limit;
500  Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
501  // No need to continue process if we reach the limit.
502  if (Results.References.size() > Limit)
503  return;
504  auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
505  // Avoid indexed results for the main file - the AST is authoritative.
506  if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath)
507  return;
508 
509  Results.References.push_back(std::move(*LSPLoc));
510  });
511  }
512  if (Results.References.size() > Limit) {
513  Results.HasMore = true;
514  Results.References.resize(Limit);
515  }
516  return Results;
517 }
518 
519 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
520  const SourceManager &SM = AST.getSourceManager();
521  auto Loc = SM.getMacroArgExpandedLocation(
522  getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
523 
524  std::vector<SymbolDetails> Results;
525 
526  // We also want the targets of using-decls, so we include
527  // DeclRelation::Underlying.
530  for (const NamedDecl *D : getDeclAtPosition(AST, Loc, Relations)) {
531  SymbolDetails NewSymbol;
532  std::string QName = printQualifiedName(*D);
533  std::tie(NewSymbol.containerName, NewSymbol.name) =
534  splitQualifiedName(QName);
535 
536  if (NewSymbol.containerName.empty()) {
537  if (const auto *ParentND =
538  dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
539  NewSymbol.containerName = printQualifiedName(*ParentND);
540  }
541  llvm::SmallString<32> USR;
542  if (!index::generateUSRForDecl(D, USR)) {
543  NewSymbol.USR = USR.str();
544  NewSymbol.ID = SymbolID(NewSymbol.USR);
545  }
546  Results.push_back(std::move(NewSymbol));
547  }
548 
549  if (auto M = locateMacroAt(Loc, AST.getPreprocessor())) {
550  SymbolDetails NewMacro;
551  NewMacro.name = M->Name;
552  llvm::SmallString<32> USR;
553  if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
554  SM, USR)) {
555  NewMacro.USR = USR.str();
556  NewMacro.ID = SymbolID(NewMacro.USR);
557  }
558  Results.push_back(std::move(NewMacro));
559  }
560 
561  return Results;
562 }
563 
564 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
565  OS << S.Name << ": " << S.PreferredDeclaration;
566  if (S.Definition)
567  OS << " def=" << *S.Definition;
568  return OS;
569 }
570 
571 // FIXME(nridge): Reduce duplication between this function and declToSym().
572 static llvm::Optional<TypeHierarchyItem>
573 declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND) {
574  auto &SM = Ctx.getSourceManager();
575 
576  SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
577  // getFileLoc is a good choice for us, but we also need to make sure
578  // sourceLocToPosition won't switch files, so we call getSpellingLoc on top of
579  // that to make sure it does not switch files.
580  // FIXME: sourceLocToPosition should not switch files!
581  SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
582  SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
583  if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid())
584  return llvm::None;
585 
586  Position NameBegin = sourceLocToPosition(SM, NameLoc);
587  Position NameEnd = sourceLocToPosition(
588  SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
589 
591  // FIXME: this is not classifying constructors, destructors and operators
592  // correctly (they're all "methods").
593  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
594 
595  TypeHierarchyItem THI;
596  THI.name = printName(Ctx, ND);
597  THI.kind = SK;
598  THI.deprecated = ND.isDeprecated();
599  THI.range =
600  Range{sourceLocToPosition(SM, BeginLoc), sourceLocToPosition(SM, EndLoc)};
601  THI.selectionRange = Range{NameBegin, NameEnd};
602  if (!THI.range.contains(THI.selectionRange)) {
603  // 'selectionRange' must be contained in 'range', so in cases where clang
604  // reports unrelated ranges we need to reconcile somehow.
605  THI.range = THI.selectionRange;
606  }
607 
608  auto FilePath =
609  getCanonicalPath(SM.getFileEntryForID(SM.getFileID(BeginLoc)), SM);
610  auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
611  if (!FilePath || !TUPath)
612  return llvm::None; // Not useful without a uri.
613  THI.uri = URIForFile::canonicalize(*FilePath, *TUPath);
614 
615  return THI;
616 }
617 
618 static Optional<TypeHierarchyItem>
620  PathRef TUPath) {
621  auto Loc = symbolToLocation(S, TUPath);
622  if (!Loc) {
623  log("Type hierarchy: {0}", Loc.takeError());
624  return llvm::None;
625  }
626  TypeHierarchyItem THI;
627  THI.name = S.Name;
629  THI.deprecated = (S.Flags & Symbol::Deprecated);
630  THI.selectionRange = Loc->range;
631  // FIXME: Populate 'range' correctly
632  // (https://github.com/clangd/clangd/issues/59).
633  THI.range = THI.selectionRange;
634  THI.uri = Loc->uri;
635  // Store the SymbolID in the 'data' field. The client will
636  // send this back in typeHierarchy/resolve, allowing us to
637  // continue resolving additional levels of the type hierarchy.
638  THI.data = S.ID.str();
639 
640  return std::move(THI);
641 }
642 
643 static void fillSubTypes(const SymbolID &ID,
644  std::vector<TypeHierarchyItem> &SubTypes,
645  const SymbolIndex *Index, int Levels, PathRef TUPath) {
646  RelationsRequest Req;
647  Req.Subjects.insert(ID);
649  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
650  if (Optional<TypeHierarchyItem> ChildSym =
651  symbolToTypeHierarchyItem(Object, Index, TUPath)) {
652  if (Levels > 1) {
653  ChildSym->children.emplace();
654  fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
655  }
656  SubTypes.emplace_back(std::move(*ChildSym));
657  }
658  });
659 }
660 
661 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
662 
663 static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx,
664  std::vector<TypeHierarchyItem> &SuperTypes,
665  RecursionProtectionSet &RPSet) {
666  // typeParents() will replace dependent template specializations
667  // with their class template, so to avoid infinite recursion for
668  // certain types of hierarchies, keep the templates encountered
669  // along the parent chain in a set, and stop the recursion if one
670  // starts to repeat.
671  auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
672  if (Pattern) {
673  if (!RPSet.insert(Pattern).second) {
674  return;
675  }
676  }
677 
678  for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
679  if (Optional<TypeHierarchyItem> ParentSym =
680  declToTypeHierarchyItem(ASTCtx, *ParentDecl)) {
681  ParentSym->parents.emplace();
682  fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet);
683  SuperTypes.emplace_back(std::move(*ParentSym));
684  }
685  }
686 
687  if (Pattern) {
688  RPSet.erase(Pattern);
689  }
690 }
691 
692 const CXXRecordDecl *findRecordTypeAt(ParsedAST &AST, Position Pos) {
693  const SourceManager &SM = AST.getSourceManager();
694  SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
695  getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
696  unsigned Offset =
697  AST.getSourceManager().getDecomposedSpellingLoc(SourceLocationBeg).second;
698  SelectionTree Selection(AST.getASTContext(), AST.getTokens(), Offset);
699  const SelectionTree::Node *N = Selection.commonAncestor();
700  if (!N)
701  return nullptr;
702 
703  // Note: explicitReferenceTargets() will search for both template
704  // instantiations and template patterns, and prefer the former if available
705  // (generally, one will be available for non-dependent specializations of a
706  // class template).
708  if (Decls.empty())
709  return nullptr;
710 
711  const NamedDecl *D = Decls[0];
712 
713  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
714  // If this is a variable, use the type of the variable.
715  return VD->getType().getTypePtr()->getAsCXXRecordDecl();
716  }
717 
718  if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
719  // If this is a method, use the type of the class.
720  return Method->getParent();
721  }
722 
723  // We don't handle FieldDecl because it's not clear what behaviour
724  // the user would expect: the enclosing class type (as with a
725  // method), or the field's type (as with a variable).
726 
727  return dyn_cast<CXXRecordDecl>(D);
728 }
729 
730 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
731  std::vector<const CXXRecordDecl *> Result;
732 
733  // If this is an invalid instantiation, instantiation of the bases
734  // may not have succeeded, so fall back to the template pattern.
735  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
736  if (CTSD->isInvalidDecl())
737  CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
738  }
739 
740  for (auto Base : CXXRD->bases()) {
741  const CXXRecordDecl *ParentDecl = nullptr;
742 
743  const Type *Type = Base.getType().getTypePtr();
744  if (const RecordType *RT = Type->getAs<RecordType>()) {
745  ParentDecl = RT->getAsCXXRecordDecl();
746  }
747 
748  if (!ParentDecl) {
749  // Handle a dependent base such as "Base<T>" by using the primary
750  // template.
751  if (const TemplateSpecializationType *TS =
752  Type->getAs<TemplateSpecializationType>()) {
753  TemplateName TN = TS->getTemplateName();
754  if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
755  ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
756  }
757  }
758  }
759 
760  if (ParentDecl)
761  Result.push_back(ParentDecl);
762  }
763 
764  return Result;
765 }
766 
767 llvm::Optional<TypeHierarchyItem>
768 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
769  TypeHierarchyDirection Direction, const SymbolIndex *Index,
770  PathRef TUPath) {
771  const CXXRecordDecl *CXXRD = findRecordTypeAt(AST, Pos);
772  if (!CXXRD)
773  return llvm::None;
774 
775  Optional<TypeHierarchyItem> Result =
776  declToTypeHierarchyItem(AST.getASTContext(), *CXXRD);
777  if (!Result)
778  return Result;
779 
780  if (Direction == TypeHierarchyDirection::Parents ||
781  Direction == TypeHierarchyDirection::Both) {
782  Result->parents.emplace();
783 
785  fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet);
786  }
787 
788  if ((Direction == TypeHierarchyDirection::Children ||
789  Direction == TypeHierarchyDirection::Both) &&
790  ResolveLevels > 0) {
791  Result->children.emplace();
792 
793  if (Index) {
794  // The index does not store relationships between implicit
795  // specializations, so if we have one, use the template pattern instead.
796  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
797  CXXRD = CTSD->getTemplateInstantiationPattern();
798 
799  if (Optional<SymbolID> ID = getSymbolID(CXXRD))
800  fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
801  }
802  }
803 
804  return Result;
805 }
806 
807 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
808  TypeHierarchyDirection Direction,
809  const SymbolIndex *Index) {
810  // We only support typeHierarchy/resolve for children, because for parents
811  // we ignore ResolveLevels and return all levels of parents eagerly.
812  if (Direction == TypeHierarchyDirection::Parents || ResolveLevels == 0)
813  return;
814 
815  Item.children.emplace();
816 
817  if (Index && Item.data) {
818  // We store the item's SymbolID in the 'data' field, and the client
819  // passes it back to us in typeHierarchy/resolve.
820  if (Expected<SymbolID> ID = SymbolID::fromStr(*Item.data)) {
821  fillSubTypes(*ID, *Item.children, Index, ResolveLevels, Item.uri.file());
822  }
823  }
824 }
825 
826 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
827  const FunctionDecl *FD) {
828  if (!FD->hasBody())
829  return {};
830  llvm::DenseSet<const Decl *> DeclRefs;
832  for (const Decl *D : Ref.Targets) {
833  if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
834  !Ref.IsDecl)
835  DeclRefs.insert(D);
836  }
837  });
838  return DeclRefs;
839 }
840 } // namespace clangd
841 } // namespace clang
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...
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol...
Definition: Protocol.h:857
int Limit
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:208
static llvm::Optional< TypeHierarchyItem > declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND)
Definition: XRefs.cpp:573
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:1165
static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx, std::vector< TypeHierarchyItem > &SuperTypes, RecursionProtectionSet &RPSet)
Definition: XRefs.cpp:663
const FunctionDecl * Decl
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:68
static Optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, const SymbolIndex *Index, PathRef TUPath)
Definition: XRefs.cpp:619
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:169
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
Definition: AST.cpp:162
const LangOptions & getLangOpts() const
Definition: ParsedAST.h:80
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:286
Range range
The range this highlight applies to.
Definition: Protocol.h:1094
Preprocessor & getPreprocessor()
Definition: ParsedAST.cpp:430
Information about a reference written in the source code, independent of the actual AST node that thi...
Definition: FindTarget.h:119
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Definition: XRefs.cpp:170
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:35
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
Definition: XRefs.cpp:661
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
Definition: XRefs.cpp:807
This is the pattern the template specialization was instantiated from.
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:85
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:64
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
Definition: SourceCode.cpp:599
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
Definition: Protocol.cpp:216
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Definition: SourceCode.cpp:534
Represents a symbol occurrence in the source file.
Definition: Ref.h:52
llvm::Optional< Location > Definition
Definition: XRefs.h:44
SourceLocation getBeginningOfIdentifier(const Position &Pos, const SourceManager &SM, const LangOptions &LangOpts)
Get the beginning SourceLocation at a specified Pos in the main file.
Definition: SourceCode.cpp:277
llvm::Optional< std::string > data
An optional &#39;data&#39; filed, which can be used to identify a type hierarchy item in a resolve request...
Definition: Protocol.h:1169
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:184
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
std::vector< CodeCompletionResult > Results
std::string name
The human readable name of the hierarchy item.
Definition: Protocol.h:1131
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns references of the symbol at a specified Pos.
Definition: XRefs.cpp:423
Documents should not be synced at all.
Range selectionRange
The range that should be selected and revealed when this type hierarchy item is being picked...
Definition: Protocol.h:1155
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
Definition: SourceCode.cpp:571
This declaration is an alias that was referred to.
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Definition: ParsedAST.h:102
Range range
The range enclosing this type hierarchy item not including leading/trailing whitespace but everything...
Definition: Protocol.h:1150
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:424
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
Definition: Symbol.h:40
A document highlight is a range inside a text document which deserves special attention.
Definition: Protocol.h:1092
llvm::DenseMap< SymbolID, std::vector< Range > > MacroRefs
Definition: CollectMacros.h:28
SymbolLocation Definition
The location of the symbol&#39;s definition, if one was found.
Definition: Symbol.h:47
llvm::Optional< SymbolID > ID
Definition: Protocol.h:859
Context Ctx
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:519
std::string QName
const IncludeStructure & getIncludeStructure() const
Definition: ParsedAST.cpp:480
clang::find_all_symbols::SymbolInfo SymbolInfo
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
Definition: Protocol.cpp:45
SymbolFlag Flags
Definition: Symbol.h:128
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
Definition: FindTarget.cpp:502
SymbolLocation Location
The source location where the symbol is named.
Definition: Ref.h:54
std::string str() const
Definition: SymbolID.cpp:33
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
index::SymbolRoleSet Role
Definition: XRefs.cpp:331
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Definition: Symbol.h:56
Location PreferredDeclaration
Definition: XRefs.h:42
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition: Merge.cpp:172
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
Definition: XRefs.cpp:643
llvm::SmallVector< const NamedDecl *, 1 > Targets
A list of targets referenced by this name.
Definition: FindTarget.h:131
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
Position Pos
Definition: SourceCode.cpp:772
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:390
SourceLocation Loc
Definition: XRefs.cpp:330
llvm::DenseSet< SymbolID > Subjects
Definition: Index.h:77
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef HintPath)
Helper function for deriving an LSP Location for a Symbol.
Definition: FindSymbols.cpp:42
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:492
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:200
Stores and provides access to parsed AST.
Definition: ParsedAST.h:46
SourceManager & getSourceManager()
Definition: ParsedAST.h:73
int line
Line position in a document (zero-based).
Definition: Protocol.h:129
size_t Offset
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
Definition: ParsedAST.cpp:444
bool contains(Position Pos) const
Definition: Protocol.h:173
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:111
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
Definition: XRefs.cpp:692
unsigned References
SymbolKind
A symbol kind.
Definition: Protocol.h:300
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:850
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition: Symbol.h:42
This is the underlying declaration for an alias, decltype etc.
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:73
CharSourceRange Range
SourceRange for the file name.
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
Definition: Protocol.h:1097
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:768
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:622
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls
Definition: FindTarget.cpp:170
SymbolKind kind
The kind of the hierarchy item. For instance, class or interface.
Definition: Protocol.h:1138
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:190
Indicates if the symbol is deprecated.
Definition: Symbol.h:121
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:164
RefSlab Refs
std::unique_ptr< GlobalCompilationDatabase > Base
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
URIForFile uri
The URI of the text document where this type hierarchy item belongs to.
Definition: Protocol.h:1144
std::array< uint8_t, 20 > SymbolID
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
Definition: SourceCode.cpp:987
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...
NodeType Type
bool deprecated
true if the hierarchy item is deprecated. Otherwise, false.
Definition: Protocol.h:1141
Represents information about identifier.
Definition: Protocol.h:847
std::vector< Location > References
Definition: XRefs.h:60
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
Definition: XRefs.cpp:730
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:826
llvm::StringRef file() const
Retrieves absolute path to the file.
Definition: Protocol.h:93
const SymbolIndex * Index
Definition: Dexp.cpp:84