clang-tools  8.0.0
XRefs.cpp
Go to the documentation of this file.
1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "XRefs.h"
10 #include "AST.h"
11 #include "Logger.h"
12 #include "SourceCode.h"
13 #include "URI.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/RecursiveASTVisitor.h"
16 #include "clang/Index/IndexDataConsumer.h"
17 #include "clang/Index/IndexingAction.h"
18 #include "clang/Index/USRGeneration.h"
19 #include "llvm/Support/Path.h"
20 
21 namespace clang {
22 namespace clangd {
23 namespace {
24 
25 // Get the definition from a given declaration `D`.
26 // Return nullptr if no definition is found, or the declaration type of `D` is
27 // not supported.
28 const Decl *getDefinition(const Decl *D) {
29  assert(D);
30  if (const auto *TD = dyn_cast<TagDecl>(D))
31  return TD->getDefinition();
32  else if (const auto *VD = dyn_cast<VarDecl>(D))
33  return VD->getDefinition();
34  else if (const auto *FD = dyn_cast<FunctionDecl>(D))
35  return FD->getDefinition();
36  return nullptr;
37 }
38 
39 void logIfOverflow(const SymbolLocation &Loc) {
40  if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
41  log("Possible overflow in symbol location: {0}", Loc);
42 }
43 
44 // Convert a SymbolLocation to LSP's Location.
45 // TUPath is used to resolve the path of URI.
46 // FIXME: figure out a good home for it, and share the implementation with
47 // FindSymbols.
48 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
49  llvm::StringRef TUPath) {
50  if (!Loc)
51  return None;
52  auto Uri = URI::parse(Loc.FileURI);
53  if (!Uri) {
54  elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
55  return None;
56  }
57  auto U = URIForFile::fromURI(*Uri, TUPath);
58  if (!U) {
59  elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
60  return None;
61  }
62 
63  Location LSPLoc;
64  LSPLoc.uri = std::move(*U);
65  LSPLoc.range.start.line = Loc.Start.line();
66  LSPLoc.range.start.character = Loc.Start.column();
67  LSPLoc.range.end.line = Loc.End.line();
68  LSPLoc.range.end.character = Loc.End.column();
69  logIfOverflow(Loc);
70  return LSPLoc;
71 }
72 
73 struct MacroDecl {
74  llvm::StringRef Name;
75  const MacroInfo *Info;
76 };
77 
78 struct DeclInfo {
79  const Decl *D;
80  // Indicates the declaration is referenced by an explicit AST node.
81  bool IsReferencedExplicitly = false;
82 };
83 
84 /// Finds declarations locations that a given source location refers to.
85 class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
86  std::vector<MacroDecl> MacroInfos;
87  // The value of the map indicates whether the declaration has been referenced
88  // explicitly in the code.
89  // True means the declaration is explicitly referenced at least once; false
90  // otherwise.
91  llvm::DenseMap<const Decl *, bool> Decls;
92  const SourceLocation &SearchedLocation;
93  const ASTContext &AST;
94  Preprocessor &PP;
95 
96 public:
97  DeclarationAndMacrosFinder(const SourceLocation &SearchedLocation,
98  ASTContext &AST, Preprocessor &PP)
99  : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
100 
101  // Get all DeclInfo of the found declarations.
102  // The results are sorted by "IsReferencedExplicitly" and declaration
103  // location.
104  std::vector<DeclInfo> getFoundDecls() const {
105  std::vector<DeclInfo> Result;
106  for (auto It : Decls) {
107  Result.emplace_back();
108  Result.back().D = It.first;
109  Result.back().IsReferencedExplicitly = It.second;
110  }
111 
112  // Sort results. Declarations being referenced explicitly come first.
113  llvm::sort(Result, [](const DeclInfo &L, const DeclInfo &R) {
114  if (L.IsReferencedExplicitly != R.IsReferencedExplicitly)
115  return L.IsReferencedExplicitly > R.IsReferencedExplicitly;
116  return L.D->getBeginLoc() < R.D->getBeginLoc();
117  });
118  return Result;
119  }
120 
121  std::vector<MacroDecl> takeMacroInfos() {
122  // Don't keep the same Macro info multiple times.
123  llvm::sort(MacroInfos, [](const MacroDecl &Left, const MacroDecl &Right) {
124  return Left.Info < Right.Info;
125  });
126 
127  auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
128  [](const MacroDecl &Left, const MacroDecl &Right) {
129  return Left.Info == Right.Info;
130  });
131  MacroInfos.erase(Last, MacroInfos.end());
132  return std::move(MacroInfos);
133  }
134 
135  bool
136  handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
137  llvm::ArrayRef<index::SymbolRelation> Relations,
138  SourceLocation Loc,
139  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
140  if (Loc == SearchedLocation) {
141  auto isImplicitExpr = [](const Expr *E) {
142  if (!E)
143  return false;
144  // We assume that a constructor expression is implict (was inserted by
145  // clang) if it has an invalid paren/brace location, since such
146  // experssion is impossible to write down.
147  if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
148  return CtorExpr->getNumArgs() > 0 &&
149  CtorExpr->getParenOrBraceRange().isInvalid();
150  return isa<ImplicitCastExpr>(E);
151  };
152 
153  bool IsExplicit = !isImplicitExpr(ASTNode.OrigE);
154  // Find and add definition declarations (for GoToDefinition).
155  // We don't use parameter `D`, as Parameter `D` is the canonical
156  // declaration, which is the first declaration of a redeclarable
157  // declaration, and it could be a forward declaration.
158  if (const auto *Def = getDefinition(D)) {
159  Decls[Def] |= IsExplicit;
160  } else {
161  // Couldn't find a definition, fall back to use `D`.
162  Decls[D] |= IsExplicit;
163  }
164  }
165  return true;
166  }
167 
168 private:
169  void finish() override {
170  // Also handle possible macro at the searched location.
171  Token Result;
172  auto &Mgr = AST.getSourceManager();
173  if (!Lexer::getRawToken(Mgr.getSpellingLoc(SearchedLocation), Result, Mgr,
174  AST.getLangOpts(), false)) {
175  if (Result.is(tok::raw_identifier)) {
176  PP.LookUpIdentifierInfo(Result);
177  }
178  IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
179  if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
180  std::pair<FileID, unsigned int> DecLoc =
181  Mgr.getDecomposedExpansionLoc(SearchedLocation);
182  // Get the definition just before the searched location so that a macro
183  // referenced in a '#undef MACRO' can still be found.
184  SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
185  Mgr.getLocForStartOfFile(DecLoc.first)
186  .getLocWithOffset(DecLoc.second - 1));
187  MacroDefinition MacroDef =
188  PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
189  MacroInfo *MacroInf = MacroDef.getMacroInfo();
190  if (MacroInf) {
191  MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
192  assert(Decls.empty());
193  }
194  }
195  }
196  }
197 };
198 
199 struct IdentifiedSymbol {
200  std::vector<DeclInfo> Decls;
201  std::vector<MacroDecl> Macros;
202 };
203 
204 IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
205  auto DeclMacrosFinder = DeclarationAndMacrosFinder(Pos, AST.getASTContext(),
206  AST.getPreprocessor());
207  index::IndexingOptions IndexOpts;
208  IndexOpts.SystemSymbolFilter =
209  index::IndexingOptions::SystemSymbolFilterKind::All;
210  IndexOpts.IndexFunctionLocals = true;
211  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
212  AST.getLocalTopLevelDecls(), DeclMacrosFinder, IndexOpts);
213 
214  return {DeclMacrosFinder.getFoundDecls(), DeclMacrosFinder.takeMacroInfos()};
215 }
216 
217 Range getTokenRange(ParsedAST &AST, SourceLocation TokLoc) {
218  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
219  SourceLocation LocEnd = Lexer::getLocForEndOfToken(
220  TokLoc, 0, SourceMgr, AST.getASTContext().getLangOpts());
221  return {sourceLocToPosition(SourceMgr, TokLoc),
222  sourceLocToPosition(SourceMgr, LocEnd)};
223 }
224 
225 llvm::Optional<Location> makeLocation(ParsedAST &AST, SourceLocation TokLoc,
226  llvm::StringRef TUPath) {
227  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
228  const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
229  if (!F)
230  return None;
231  auto FilePath = getCanonicalPath(F, SourceMgr);
232  if (!FilePath) {
233  log("failed to get path!");
234  return None;
235  }
236  Location L;
237  L.uri = URIForFile::canonicalize(*FilePath, TUPath);
238  L.range = getTokenRange(AST, TokLoc);
239  return L;
240 }
241 
242 } // namespace
243 
244 std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
245  const SymbolIndex *Index) {
246  const auto &SM = AST.getASTContext().getSourceManager();
247  auto MainFilePath =
248  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
249  if (!MainFilePath) {
250  elog("Failed to get a path for the main file, so no references");
251  return {};
252  }
253 
254  std::vector<Location> Result;
255  // Handle goto definition for #include.
256  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
257  if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line)
258  Result.push_back(
259  Location{URIForFile::canonicalize(Inc.Resolved, *MainFilePath), {}});
260  }
261  if (!Result.empty())
262  return Result;
263 
264  // Identified symbols at a specific position.
265  SourceLocation SourceLocationBeg =
266  getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
267  auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
268 
269  for (auto Item : Symbols.Macros) {
270  auto Loc = Item.Info->getDefinitionLoc();
271  auto L = makeLocation(AST, Loc, *MainFilePath);
272  if (L)
273  Result.push_back(*L);
274  }
275 
276  // Declaration and definition are different terms in C-family languages, and
277  // LSP only defines the "GoToDefinition" specification, so we try to perform
278  // the "most sensible" GoTo operation:
279  //
280  // - We use the location from AST and index (if available) to provide the
281  // final results. When there are duplicate results, we prefer AST over
282  // index because AST is more up-to-date.
283  //
284  // - For each symbol, we will return a location of the canonical declaration
285  // (e.g. function declaration in header), and a location of definition if
286  // they are available.
287  //
288  // So the work flow:
289  //
290  // 1. Identify the symbols being search for by traversing the AST.
291  // 2. Populate one of the locations with the AST location.
292  // 3. Use the AST information to query the index, and populate the index
293  // location (if available).
294  // 4. Return all populated locations for all symbols, definition first (
295  // which we think is the users wants most often).
296  struct CandidateLocation {
297  llvm::Optional<Location> Def;
298  llvm::Optional<Location> Decl;
299  };
300  // We respect the order in Symbols.Decls.
301  llvm::SmallVector<CandidateLocation, 8> ResultCandidates;
302  llvm::DenseMap<SymbolID, size_t> CandidatesIndex;
303 
304  // Emit all symbol locations (declaration or definition) from AST.
305  for (const DeclInfo &DI : Symbols.Decls) {
306  const Decl *D = DI.D;
307  // Fake key for symbols don't have USR (no SymbolID).
308  // Ideally, there should be a USR for each identified symbols. Symbols
309  // without USR are rare and unimportant cases, we use the a fake holder to
310  // minimize the invasiveness of these cases.
311  SymbolID Key("");
312  if (auto ID = getSymbolID(D))
313  Key = *ID;
314 
315  auto R = CandidatesIndex.try_emplace(Key, ResultCandidates.size());
316  if (R.second) // new entry
317  ResultCandidates.emplace_back();
318  auto &Candidate = ResultCandidates[R.first->second];
319 
320  auto Loc = findNameLoc(D);
321  auto L = makeLocation(AST, Loc, *MainFilePath);
322  // The declaration in the identified symbols is a definition if possible
323  // otherwise it is declaration.
324  bool IsDef = getDefinition(D) == D;
325  // Populate one of the slots with location for the AST.
326  if (!IsDef)
327  Candidate.Decl = L;
328  else
329  Candidate.Def = L;
330  }
331 
332  if (Index) {
333  LookupRequest QueryRequest;
334  // Build request for index query, using SymbolID.
335  for (auto It : CandidatesIndex)
336  QueryRequest.IDs.insert(It.first);
337  std::string TUPath;
338  const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
339  if (auto Path = getCanonicalPath(FE, SM))
340  TUPath = *Path;
341  // Query the index and populate the empty slot.
342  Index->lookup(QueryRequest, [&TUPath, &ResultCandidates,
343  &CandidatesIndex](const Symbol &Sym) {
344  auto It = CandidatesIndex.find(Sym.ID);
345  assert(It != CandidatesIndex.end());
346  auto &Value = ResultCandidates[It->second];
347 
348  if (!Value.Def)
349  Value.Def = toLSPLocation(Sym.Definition, TUPath);
350  if (!Value.Decl)
351  Value.Decl = toLSPLocation(Sym.CanonicalDeclaration, TUPath);
352  });
353  }
354 
355  // Populate the results, definition first.
356  for (const auto &Candidate : ResultCandidates) {
357  if (Candidate.Def)
358  Result.push_back(*Candidate.Def);
359  if (Candidate.Decl &&
360  Candidate.Decl != Candidate.Def) // Decl and Def might be the same
361  Result.push_back(*Candidate.Decl);
362  }
363 
364  return Result;
365 }
366 
367 namespace {
368 
369 /// Collects references to symbols within the main file.
370 class ReferenceFinder : public index::IndexDataConsumer {
371 public:
372  struct Reference {
373  const Decl *CanonicalTarget;
374  SourceLocation Loc;
375  index::SymbolRoleSet Role;
376  };
377 
378  ReferenceFinder(ASTContext &AST, Preprocessor &PP,
379  const std::vector<const Decl *> &TargetDecls)
380  : AST(AST) {
381  for (const Decl *D : TargetDecls)
382  CanonicalTargets.insert(D->getCanonicalDecl());
383  }
384 
385  std::vector<Reference> take() && {
386  llvm::sort(References, [](const Reference &L, const Reference &R) {
387  return std::tie(L.Loc, L.CanonicalTarget, L.Role) <
388  std::tie(R.Loc, R.CanonicalTarget, R.Role);
389  });
390  // We sometimes see duplicates when parts of the AST get traversed twice.
391  References.erase(
392  std::unique(References.begin(), References.end(),
393  [](const Reference &L, const Reference &R) {
394  return std::tie(L.CanonicalTarget, L.Loc, L.Role) ==
395  std::tie(R.CanonicalTarget, R.Loc, R.Role);
396  }),
397  References.end());
398  return std::move(References);
399  }
400 
401  bool
402  handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
403  llvm::ArrayRef<index::SymbolRelation> Relations,
404  SourceLocation Loc,
405  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
406  assert(D->isCanonicalDecl() && "expect D to be a canonical declaration");
407  const SourceManager &SM = AST.getSourceManager();
408  Loc = SM.getFileLoc(Loc);
409  if (SM.isWrittenInMainFile(Loc) && CanonicalTargets.count(D))
410  References.push_back({D, Loc, Roles});
411  return true;
412  }
413 
414 private:
415  llvm::SmallSet<const Decl *, 4> CanonicalTargets;
416  std::vector<Reference> References;
417  const ASTContext &AST;
418 };
419 
420 std::vector<ReferenceFinder::Reference>
421 findRefs(const std::vector<const Decl *> &Decls, ParsedAST &AST) {
422  ReferenceFinder RefFinder(AST.getASTContext(), AST.getPreprocessor(), Decls);
423  index::IndexingOptions IndexOpts;
424  IndexOpts.SystemSymbolFilter =
425  index::IndexingOptions::SystemSymbolFilterKind::All;
426  IndexOpts.IndexFunctionLocals = true;
427  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
428  AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
429  return std::move(RefFinder).take();
430 }
431 
432 } // namespace
433 
434 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
435  Position Pos) {
436  const SourceManager &SM = AST.getASTContext().getSourceManager();
437  auto Symbols = getSymbolAtPosition(
438  AST, getBeginningOfIdentifier(AST, Pos, SM.getMainFileID()));
439  std::vector<const Decl *> TargetDecls;
440  for (const DeclInfo &DI : Symbols.Decls) {
441  TargetDecls.push_back(DI.D);
442  }
443  auto References = findRefs(TargetDecls, AST);
444 
445  std::vector<DocumentHighlight> Result;
446  for (const auto &Ref : References) {
448  DH.range = getTokenRange(AST, Ref.Loc);
449  if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
451  else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
453  else
455  Result.push_back(std::move(DH));
456  }
457  return Result;
458 }
459 
460 static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
461  PrintingPolicy Policy(Base);
462 
463  Policy.AnonymousTagLocations = false;
464  Policy.TerseOutput = true;
465  Policy.PolishForDeclaration = true;
466  Policy.ConstantsAsWritten = true;
467  Policy.SuppressTagKeyword = false;
468 
469  return Policy;
470 }
471 
472 /// Return a string representation (e.g. "class MyNamespace::MyClass") of
473 /// the type declaration \p TD.
474 static std::string typeDeclToString(const TypeDecl *TD) {
475  QualType Type = TD->getASTContext().getTypeDeclType(TD);
476 
477  PrintingPolicy Policy =
478  printingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
479 
480  std::string Name;
481  llvm::raw_string_ostream Stream(Name);
482  Type.print(Stream, Policy);
483 
484  return Stream.str();
485 }
486 
487 /// Return a string representation (e.g. "namespace ns1::ns2") of
488 /// the named declaration \p ND.
489 static std::string namedDeclQualifiedName(const NamedDecl *ND,
490  llvm::StringRef Prefix) {
491  PrintingPolicy Policy =
492  printingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
493 
494  std::string Name;
495  llvm::raw_string_ostream Stream(Name);
496  Stream << Prefix << ' ';
497  ND->printQualifiedName(Stream, Policy);
498 
499  return Stream.str();
500 }
501 
502 /// Given a declaration \p D, return a human-readable string representing the
503 /// scope in which it is declared. If the declaration is in the global scope,
504 /// return the string "global namespace".
505 static llvm::Optional<std::string> getScopeName(const Decl *D) {
506  const DeclContext *DC = D->getDeclContext();
507 
508  if (isa<TranslationUnitDecl>(DC))
509  return std::string("global namespace");
510  if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
511  return typeDeclToString(TD);
512  else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
513  return namedDeclQualifiedName(ND, "namespace");
514  else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
515  return namedDeclQualifiedName(FD, "function");
516 
517  return None;
518 }
519 
520 /// Generate a \p Hover object given the declaration \p D.
521 static Hover getHoverContents(const Decl *D) {
522  Hover H;
523  llvm::Optional<std::string> NamedScope = getScopeName(D);
524 
525  // Generate the "Declared in" section.
526  if (NamedScope) {
527  assert(!NamedScope->empty());
528 
529  H.contents.value += "Declared in ";
530  H.contents.value += *NamedScope;
531  H.contents.value += "\n\n";
532  }
533 
534  // We want to include the template in the Hover.
535  if (TemplateDecl *TD = D->getDescribedTemplate())
536  D = TD;
537 
538  std::string DeclText;
539  llvm::raw_string_ostream OS(DeclText);
540 
541  PrintingPolicy Policy =
542  printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
543 
544  D->print(OS, Policy);
545 
546  OS.flush();
547 
548  H.contents.value += DeclText;
549  return H;
550 }
551 
552 /// Generate a \p Hover object given the type \p T.
553 static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
554  Hover H;
555  std::string TypeText;
556  llvm::raw_string_ostream OS(TypeText);
557  PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
558  T.print(OS, Policy);
559  OS.flush();
560  H.contents.value += TypeText;
561  return H;
562 }
563 
564 /// Generate a \p Hover object given the macro \p MacroInf.
565 static Hover getHoverContents(llvm::StringRef MacroName) {
566  Hover H;
567 
568  H.contents.value = "#define ";
569  H.contents.value += MacroName;
570 
571  return H;
572 }
573 
574 namespace {
575 /// Computes the deduced type at a given location by visiting the relevant
576 /// nodes. We use this to display the actual type when hovering over an "auto"
577 /// keyword or "decltype()" expression.
578 /// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
579 /// seems that the AutoTypeLocs that can be visited along with their AutoType do
580 /// not have the deduced type set. Instead, we have to go to the appropriate
581 /// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
582 /// a deduced type set. The AST should be improved to simplify this scenario.
583 class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
584  SourceLocation SearchedLocation;
585  llvm::Optional<QualType> DeducedType;
586 
587 public:
588  DeducedTypeVisitor(SourceLocation SearchedLocation)
589  : SearchedLocation(SearchedLocation) {}
590 
591  llvm::Optional<QualType> getDeducedType() { return DeducedType; }
592 
593  // Handle auto initializers:
594  //- auto i = 1;
595  //- decltype(auto) i = 1;
596  //- auto& i = 1;
597  //- auto* i = &a;
598  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
599  if (!D->getTypeSourceInfo() ||
600  D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
601  return true;
602 
603  if (auto *AT = D->getType()->getContainedAutoType()) {
604  if (!AT->getDeducedType().isNull())
605  DeducedType = AT->getDeducedType();
606  }
607  return true;
608  }
609 
610  // Handle auto return types:
611  //- auto foo() {}
612  //- auto& foo() {}
613  //- auto foo() -> int {}
614  //- auto foo() -> decltype(1+1) {}
615  //- operator auto() const { return 10; }
616  bool VisitFunctionDecl(FunctionDecl *D) {
617  if (!D->getTypeSourceInfo())
618  return true;
619  // Loc of auto in return type (c++14).
620  auto CurLoc = D->getReturnTypeSourceRange().getBegin();
621  // Loc of "auto" in operator auto()
622  if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
623  CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
624  // Loc of "auto" in function with traling return type (c++11).
625  if (CurLoc.isInvalid())
626  CurLoc = D->getSourceRange().getBegin();
627  if (CurLoc != SearchedLocation)
628  return true;
629 
630  const AutoType *AT = D->getReturnType()->getContainedAutoType();
631  if (AT && !AT->getDeducedType().isNull()) {
632  DeducedType = AT->getDeducedType();
633  } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
634  // auto in a trailing return type just points to a DecltypeType and
635  // getContainedAutoType does not unwrap it.
636  if (!DT->getUnderlyingType().isNull())
637  DeducedType = DT->getUnderlyingType();
638  } else if (!D->getReturnType().isNull()) {
639  DeducedType = D->getReturnType();
640  }
641  return true;
642  }
643 
644  // Handle non-auto decltype, e.g.:
645  // - auto foo() -> decltype(expr) {}
646  // - decltype(expr);
647  bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
648  if (TL.getBeginLoc() != SearchedLocation)
649  return true;
650 
651  // A DecltypeType's underlying type can be another DecltypeType! E.g.
652  // int I = 0;
653  // decltype(I) J = I;
654  // decltype(J) K = J;
655  const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
656  while (DT && !DT->getUnderlyingType().isNull()) {
657  DeducedType = DT->getUnderlyingType();
658  DT = dyn_cast<DecltypeType>(DeducedType->getTypePtr());
659  }
660  return true;
661  }
662 };
663 } // namespace
664 
665 /// Retrieves the deduced type at a given location (auto, decltype).
666 llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
667  SourceLocation SourceLocationBeg) {
668  Token Tok;
669  auto &ASTCtx = AST.getASTContext();
670  // Only try to find a deduced type if the token is auto or decltype.
671  if (!SourceLocationBeg.isValid() ||
672  Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
673  ASTCtx.getLangOpts(), false) ||
674  !Tok.is(tok::raw_identifier)) {
675  return {};
676  }
677  AST.getPreprocessor().LookUpIdentifierInfo(Tok);
678  if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
679  return {};
680 
681  DeducedTypeVisitor V(SourceLocationBeg);
682  V.TraverseAST(AST.getASTContext());
683  return V.getDeducedType();
684 }
685 
686 llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
687  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
688  SourceLocation SourceLocationBeg =
689  getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
690  // Identified symbols at a specific position.
691  auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
692 
693  if (!Symbols.Macros.empty())
694  return getHoverContents(Symbols.Macros[0].Name);
695 
696  if (!Symbols.Decls.empty())
697  return getHoverContents(Symbols.Decls[0].D);
698 
699  auto DeducedType = getDeducedType(AST, SourceLocationBeg);
700  if (DeducedType && !DeducedType->isNull())
701  return getHoverContents(*DeducedType, AST.getASTContext());
702 
703  return None;
704 }
705 
706 std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
707  uint32_t Limit, const SymbolIndex *Index) {
708  if (!Limit)
709  Limit = std::numeric_limits<uint32_t>::max();
710  std::vector<Location> Results;
711  const SourceManager &SM = AST.getASTContext().getSourceManager();
712  auto MainFilePath =
713  getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
714  if (!MainFilePath) {
715  elog("Failed to get a path for the main file, so no references");
716  return Results;
717  }
718  auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
719  auto Symbols = getSymbolAtPosition(AST, Loc);
720 
721  std::vector<const Decl *> TargetDecls;
722  for (const DeclInfo &DI : Symbols.Decls) {
723  if (DI.IsReferencedExplicitly)
724  TargetDecls.push_back(DI.D);
725  }
726 
727  // We traverse the AST to find references in the main file.
728  // TODO: should we handle macros, too?
729  auto MainFileRefs = findRefs(TargetDecls, AST);
730  for (const auto &Ref : MainFileRefs) {
732  Result.range = getTokenRange(AST, Ref.Loc);
733  Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
734  Results.push_back(std::move(Result));
735  }
736 
737  // Now query the index for references from other files.
738  if (Index && Results.size() < Limit) {
739  RefsRequest Req;
740  Req.Limit = Limit;
741 
742  for (const Decl *D : TargetDecls) {
743  // Not all symbols can be referenced from outside (e.g. function-locals).
744  // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
745  // we know this file isn't a header. The details might be tricky.
746  if (D->getParentFunctionOrMethod())
747  continue;
748  if (auto ID = getSymbolID(D))
749  Req.IDs.insert(*ID);
750  }
751  if (Req.IDs.empty())
752  return Results;
753  Index->refs(Req, [&](const Ref &R) {
754  auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
755  // Avoid indexed results for the main file - the AST is authoritative.
756  if (LSPLoc && LSPLoc->uri.file() != *MainFilePath)
757  Results.push_back(std::move(*LSPLoc));
758  });
759  }
760  if (Results.size() > Limit)
761  Results.resize(Limit);
762  return Results;
763 }
764 
765 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
766  const SourceManager &SM = AST.getASTContext().getSourceManager();
767 
768  auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
769  auto Symbols = getSymbolAtPosition(AST, Loc);
770 
771  std::vector<SymbolDetails> Results;
772 
773  for (const auto &Sym : Symbols.Decls) {
774  SymbolDetails NewSymbol;
775  if (const NamedDecl *ND = dyn_cast<NamedDecl>(Sym.D)) {
776  std::string QName = printQualifiedName(*ND);
777  std::tie(NewSymbol.containerName, NewSymbol.name) =
778  splitQualifiedName(QName);
779 
780  if (NewSymbol.containerName.empty()) {
781  if (const auto *ParentND =
782  dyn_cast_or_null<NamedDecl>(ND->getDeclContext()))
783  NewSymbol.containerName = printQualifiedName(*ParentND);
784  }
785  }
786  llvm::SmallString<32> USR;
787  if (!index::generateUSRForDecl(Sym.D, USR)) {
788  NewSymbol.USR = USR.str();
789  NewSymbol.ID = SymbolID(NewSymbol.USR);
790  }
791  Results.push_back(std::move(NewSymbol));
792  }
793 
794  for (const auto &Macro : Symbols.Macros) {
795  SymbolDetails NewMacro;
796  NewMacro.name = Macro.Name;
797  llvm::SmallString<32> USR;
798  if (!index::generateUSRForMacro(NewMacro.name, Loc, SM, USR)) {
799  NewMacro.USR = USR.str();
800  NewMacro.ID = SymbolID(NewMacro.USR);
801  }
802  Results.push_back(std::move(NewMacro));
803  }
804 
805  return Results;
806 }
807 
808 } // namespace clangd
809 } // namespace clang
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol...
Definition: Protocol.h:749
llvm::Optional< Hover > getHover(ParsedAST &AST, Position Pos)
Get the hover information when hovering at Pos.
Definition: XRefs.cpp:686
static llvm::Optional< std::string > getScopeName(const Decl *D)
Given a declaration D, return a human-readable string representing the scope in which it is declared...
Definition: XRefs.cpp:505
std::vector< Location > findDefinitions(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:244
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:477
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:54
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:117
Range range
The range this highlight applies to.
Definition: Protocol.h:979
Preprocessor & getPreprocessor()
Definition: ClangdUnit.cpp:354
bool IsReferencedExplicitly
Definition: XRefs.cpp:81
const Decl * CanonicalTarget
Definition: XRefs.cpp:373
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:487
static Hover getHoverContents(const Decl *D)
Generate a Hover object given the declaration D.
Definition: XRefs.cpp:521
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:473
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:46
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:182
std::vector< CodeCompletionResult > Results
Documents should not be synced at all.
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:57
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ClangdUnit.cpp:348
MarkupContent contents
The hover&#39;s content.
Definition: Protocol.h:816
A document highlight is a range inside a text document which deserves special attention.
Definition: Protocol.h:977
static std::string typeDeclToString(const TypeDecl *TD)
Return a string representation (e.g.
Definition: XRefs.cpp:474
SymbolLocation Definition
Definition: Index.h:171
llvm::Optional< SymbolID > ID
Definition: Protocol.h:751
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:765
const IncludeStructure & getIncludeStructure() const
Definition: ClangdUnit.cpp:402
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
Definition: Protocol.cpp:45
SymbolLocation Location
Definition: Index.h:375
static std::string namedDeclQualifiedName(const NamedDecl *ND, llvm::StringRef Prefix)
Return a string representation (e.g.
Definition: XRefs.cpp:489
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:63
index::SymbolRoleSet Role
Definition: XRefs.cpp:375
std::string Path
A typedef to represent a file path.
Definition: Path.h:21
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
virtual void refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
const Decl * D
Definition: XRefs.cpp:79
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:434
SourceLocation Loc
Definition: XRefs.cpp:374
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:128
Position Pos
std::vector< MacroDecl > Macros
Definition: XRefs.cpp:201
Stores and provides access to parsed AST.
Definition: ClangdUnit.h:71
int line
Line position in a document (zero-based).
Definition: Protocol.h:127
std::vector< Location > findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns reference locations of the symbol at a specified Pos.
Definition: XRefs.cpp:706
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:78
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
Definition: ClangdUnit.cpp:545
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const MacroInfo * Info
Definition: XRefs.cpp:75
static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base)
Definition: XRefs.cpp:460
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:482
CharSourceRange Range
SourceRange for the file name.
std::pair< llvm::StringRef, llvm::StringRef > splitQualifiedName(llvm::StringRef QName)
From "a::b::c", return {"a::b::", "c"}.
Definition: SourceCode.cpp:164
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
Definition: Protocol.h:982
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:187
llvm::Optional< QualType > getDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg)
Retrieves the deduced type at a given location (auto, decltype).
Definition: XRefs.cpp:666
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:166
llvm::StringRef Name
Definition: XRefs.cpp:74
std::array< uint8_t, 20 > SymbolID
Represents information about identifier.
Definition: Protocol.h:739
const SymbolIndex * Index
Definition: Dexp.cpp:85