clang-tools  7.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 namespace clang {
21 namespace clangd {
22 using namespace llvm;
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 // Convert a SymbolLocation to LSP's Location.
40 // HintPath is used to resolve the path of URI.
41 // FIXME: figure out a good home for it, and share the implementation with
42 // FindSymbols.
43 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
44  llvm::StringRef HintPath) {
45  if (!Loc)
46  return llvm::None;
47  auto Uri = URI::parse(Loc.FileURI);
48  if (!Uri) {
49  log("Could not parse URI: {0}", Loc.FileURI);
50  return llvm::None;
51  }
52  auto Path = URI::resolve(*Uri, HintPath);
53  if (!Path) {
54  log("Could not resolve URI: {0}", Loc.FileURI);
55  return llvm::None;
56  }
57  Location LSPLoc;
58  LSPLoc.uri = URIForFile(*Path);
59  LSPLoc.range.start.line = Loc.Start.Line;
60  LSPLoc.range.start.character = Loc.Start.Column;
61  LSPLoc.range.end.line = Loc.End.Line;
62  LSPLoc.range.end.character = Loc.End.Column;
63  return LSPLoc;
64 }
65 
66 struct MacroDecl {
67  StringRef Name;
68  const MacroInfo *Info;
69 };
70 
71 /// Finds declarations locations that a given source location refers to.
72 class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
73  std::vector<const Decl *> Decls;
74  std::vector<MacroDecl> MacroInfos;
75  const SourceLocation &SearchedLocation;
76  const ASTContext &AST;
77  Preprocessor &PP;
78 
79 public:
80  DeclarationAndMacrosFinder(raw_ostream &OS,
81  const SourceLocation &SearchedLocation,
82  ASTContext &AST, Preprocessor &PP)
83  : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
84 
85  std::vector<const Decl *> takeDecls() {
86  // Don't keep the same declaration multiple times.
87  // This can happen when nodes in the AST are visited twice.
88  std::sort(Decls.begin(), Decls.end());
89  auto Last = std::unique(Decls.begin(), Decls.end());
90  Decls.erase(Last, Decls.end());
91  return std::move(Decls);
92  }
93 
94  std::vector<MacroDecl> takeMacroInfos() {
95  // Don't keep the same Macro info multiple times.
96  std::sort(MacroInfos.begin(), MacroInfos.end(),
97  [](const MacroDecl &Left, const MacroDecl &Right) {
98  return Left.Info < Right.Info;
99  });
100 
101  auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
102  [](const MacroDecl &Left, const MacroDecl &Right) {
103  return Left.Info == Right.Info;
104  });
105  MacroInfos.erase(Last, MacroInfos.end());
106  return std::move(MacroInfos);
107  }
108 
109  bool
110  handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
111  ArrayRef<index::SymbolRelation> Relations,
112  SourceLocation Loc,
113  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
114  if (Loc == SearchedLocation) {
115  // Find and add definition declarations (for GoToDefinition).
116  // We don't use parameter `D`, as Parameter `D` is the canonical
117  // declaration, which is the first declaration of a redeclarable
118  // declaration, and it could be a forward declaration.
119  if (const auto *Def = getDefinition(D)) {
120  Decls.push_back(Def);
121  } else {
122  // Couldn't find a definition, fall back to use `D`.
123  Decls.push_back(D);
124  }
125  }
126  return true;
127  }
128 
129 private:
130  void finish() override {
131  // Also handle possible macro at the searched location.
132  Token Result;
133  auto &Mgr = AST.getSourceManager();
134  if (!Lexer::getRawToken(Mgr.getSpellingLoc(SearchedLocation), Result, Mgr,
135  AST.getLangOpts(), false)) {
136  if (Result.is(tok::raw_identifier)) {
137  PP.LookUpIdentifierInfo(Result);
138  }
139  IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
140  if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
141  std::pair<FileID, unsigned int> DecLoc =
142  Mgr.getDecomposedExpansionLoc(SearchedLocation);
143  // Get the definition just before the searched location so that a macro
144  // referenced in a '#undef MACRO' can still be found.
145  SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
146  Mgr.getLocForStartOfFile(DecLoc.first)
147  .getLocWithOffset(DecLoc.second - 1));
148  MacroDefinition MacroDef =
149  PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
150  MacroInfo *MacroInf = MacroDef.getMacroInfo();
151  if (MacroInf) {
152  MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
153  assert(Decls.empty());
154  }
155  }
156  }
157  }
158 };
159 
160 struct IdentifiedSymbol {
161  std::vector<const Decl *> Decls;
162  std::vector<MacroDecl> Macros;
163 };
164 
165 IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
166  auto DeclMacrosFinder = DeclarationAndMacrosFinder(
167  llvm::errs(), Pos, AST.getASTContext(), AST.getPreprocessor());
168  index::IndexingOptions IndexOpts;
169  IndexOpts.SystemSymbolFilter =
170  index::IndexingOptions::SystemSymbolFilterKind::All;
171  IndexOpts.IndexFunctionLocals = true;
172  indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
173  DeclMacrosFinder, IndexOpts);
174 
175  return {DeclMacrosFinder.takeDecls(), DeclMacrosFinder.takeMacroInfos()};
176 }
177 
178 llvm::Optional<Location>
179 makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
180  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
181  const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
182  SourceLocation LocStart = ValSourceRange.getBegin();
183 
184  const FileEntry *F =
185  SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
186  if (!F)
187  return llvm::None;
188  SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
189  SourceMgr, LangOpts);
190  Position Begin = sourceLocToPosition(SourceMgr, LocStart);
191  Position End = sourceLocToPosition(SourceMgr, LocEnd);
192  Range R = {Begin, End};
193  Location L;
194 
195  auto FilePath = getAbsoluteFilePath(F, SourceMgr);
196  if (!FilePath) {
197  log("failed to get path!");
198  return llvm::None;
199  }
200  L.uri = URIForFile(*FilePath);
201  L.range = R;
202  return L;
203 }
204 
205 // Get the symbol ID for a declaration, if possible.
206 llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
207  llvm::SmallString<128> USR;
208  if (index::generateUSRForDecl(D, USR)) {
209  return None;
210  }
211  return SymbolID(USR);
212 }
213 
214 } // namespace
215 
216 std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
217  const SymbolIndex *Index) {
218  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
219 
220  std::vector<Location> Result;
221  // Handle goto definition for #include.
222  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
223  if (!Inc.Resolved.empty() && Inc.R.contains(Pos))
224  Result.push_back(Location{URIForFile{Inc.Resolved}, {}});
225  }
226  if (!Result.empty())
227  return Result;
228 
229  // Identified symbols at a specific position.
230  SourceLocation SourceLocationBeg =
231  getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
232  auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
233 
234  for (auto Item : Symbols.Macros) {
235  auto Loc = Item.Info->getDefinitionLoc();
236  auto L = makeLocation(AST, SourceRange(Loc, Loc));
237  if (L)
238  Result.push_back(*L);
239  }
240 
241  // Declaration and definition are different terms in C-family languages, and
242  // LSP only defines the "GoToDefinition" specification, so we try to perform
243  // the "most sensible" GoTo operation:
244  //
245  // - We use the location from AST and index (if available) to provide the
246  // final results. When there are duplicate results, we prefer AST over
247  // index because AST is more up-to-date.
248  //
249  // - For each symbol, we will return a location of the canonical declaration
250  // (e.g. function declaration in header), and a location of definition if
251  // they are available.
252  //
253  // So the work flow:
254  //
255  // 1. Identify the symbols being search for by traversing the AST.
256  // 2. Populate one of the locations with the AST location.
257  // 3. Use the AST information to query the index, and populate the index
258  // location (if available).
259  // 4. Return all populated locations for all symbols, definition first (
260  // which we think is the users wants most often).
261  struct CandidateLocation {
262  llvm::Optional<Location> Def;
263  llvm::Optional<Location> Decl;
264  };
265  llvm::DenseMap<SymbolID, CandidateLocation> ResultCandidates;
266 
267  // Emit all symbol locations (declaration or definition) from AST.
268  for (const auto *D : Symbols.Decls) {
269  // Fake key for symbols don't have USR (no SymbolID).
270  // Ideally, there should be a USR for each identified symbols. Symbols
271  // without USR are rare and unimportant cases, we use the a fake holder to
272  // minimize the invasiveness of these cases.
273  SymbolID Key("");
274  if (auto ID = getSymbolID(D))
275  Key = *ID;
276 
277  auto &Candidate = ResultCandidates[Key];
278  auto Loc = findNameLoc(D);
279  auto L = makeLocation(AST, SourceRange(Loc, Loc));
280  // The declaration in the identified symbols is a definition if possible
281  // otherwise it is declaration.
282  bool IsDef = getDefinition(D) == D;
283  // Populate one of the slots with location for the AST.
284  if (!IsDef)
285  Candidate.Decl = L;
286  else
287  Candidate.Def = L;
288  }
289 
290  if (Index) {
291  LookupRequest QueryRequest;
292  // Build request for index query, using SymbolID.
293  for (auto It : ResultCandidates)
294  QueryRequest.IDs.insert(It.first);
295  std::string HintPath;
296  const FileEntry *FE =
297  SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
298  if (auto Path = getAbsoluteFilePath(FE, SourceMgr))
299  HintPath = *Path;
300  // Query the index and populate the empty slot.
301  Index->lookup(
302  QueryRequest, [&HintPath, &ResultCandidates](const Symbol &Sym) {
303  auto It = ResultCandidates.find(Sym.ID);
304  assert(It != ResultCandidates.end());
305  auto &Value = It->second;
306 
307  if (!Value.Def)
308  Value.Def = toLSPLocation(Sym.Definition, HintPath);
309  if (!Value.Decl)
310  Value.Decl = toLSPLocation(Sym.CanonicalDeclaration, HintPath);
311  });
312  }
313 
314  // Populate the results, definition first.
315  for (auto It : ResultCandidates) {
316  const auto &Candidate = It.second;
317  if (Candidate.Def)
318  Result.push_back(*Candidate.Def);
319  if (Candidate.Decl &&
320  Candidate.Decl != Candidate.Def) // Decl and Def might be the same
321  Result.push_back(*Candidate.Decl);
322  }
323 
324  return Result;
325 }
326 
327 namespace {
328 
329 /// Finds document highlights that a given list of declarations refers to.
330 class DocumentHighlightsFinder : public index::IndexDataConsumer {
331  std::vector<const Decl *> &Decls;
332  std::vector<DocumentHighlight> DocumentHighlights;
333  const ASTContext &AST;
334 
335 public:
336  DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
337  std::vector<const Decl *> &Decls)
338  : Decls(Decls), AST(AST) {}
339  std::vector<DocumentHighlight> takeHighlights() {
340  // Don't keep the same highlight multiple times.
341  // This can happen when nodes in the AST are visited twice.
342  std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
343  auto Last =
344  std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
345  DocumentHighlights.erase(Last, DocumentHighlights.end());
346  return std::move(DocumentHighlights);
347  }
348 
349  bool
350  handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
351  ArrayRef<index::SymbolRelation> Relations,
352  SourceLocation Loc,
353  index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
354  const SourceManager &SourceMgr = AST.getSourceManager();
355  SourceLocation HighlightStartLoc = SourceMgr.getFileLoc(Loc);
356  if (SourceMgr.getMainFileID() != SourceMgr.getFileID(HighlightStartLoc) ||
357  std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
358  return true;
359  }
360  SourceLocation End;
361  const LangOptions &LangOpts = AST.getLangOpts();
362  End = Lexer::getLocForEndOfToken(HighlightStartLoc, 0, SourceMgr, LangOpts);
363  SourceRange SR(HighlightStartLoc, End);
364 
366  if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
368  else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
370 
371  DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
372  return true;
373  }
374 
375 private:
376  DocumentHighlight getDocumentHighlight(SourceRange SR,
378  const SourceManager &SourceMgr = AST.getSourceManager();
379  Position Begin = sourceLocToPosition(SourceMgr, SR.getBegin());
380  Position End = sourceLocToPosition(SourceMgr, SR.getEnd());
381  Range R = {Begin, End};
383  DH.range = R;
384  DH.kind = Kind;
385  return DH;
386  }
387 };
388 
389 } // namespace
390 
391 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
392  Position Pos) {
393  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
394  SourceLocation SourceLocationBeg =
395  getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
396 
397  auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
398  std::vector<const Decl *> SelectedDecls = Symbols.Decls;
399 
400  DocumentHighlightsFinder DocHighlightsFinder(
401  llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
402 
403  index::IndexingOptions IndexOpts;
404  IndexOpts.SystemSymbolFilter =
405  index::IndexingOptions::SystemSymbolFilterKind::All;
406  IndexOpts.IndexFunctionLocals = true;
407  indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
408  DocHighlightsFinder, IndexOpts);
409 
410  return DocHighlightsFinder.takeHighlights();
411 }
412 
413 static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
414  PrintingPolicy Policy(Base);
415 
416  Policy.AnonymousTagLocations = false;
417  Policy.TerseOutput = true;
418  Policy.PolishForDeclaration = true;
419  Policy.ConstantsAsWritten = true;
420  Policy.SuppressTagKeyword = false;
421 
422  return Policy;
423 }
424 
425 /// Return a string representation (e.g. "class MyNamespace::MyClass") of
426 /// the type declaration \p TD.
427 static std::string typeDeclToString(const TypeDecl *TD) {
428  QualType Type = TD->getASTContext().getTypeDeclType(TD);
429 
430  PrintingPolicy Policy =
431  printingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
432 
433  std::string Name;
434  llvm::raw_string_ostream Stream(Name);
435  Type.print(Stream, Policy);
436 
437  return Stream.str();
438 }
439 
440 /// Return a string representation (e.g. "namespace ns1::ns2") of
441 /// the named declaration \p ND.
442 static std::string namedDeclQualifiedName(const NamedDecl *ND,
443  StringRef Prefix) {
444  PrintingPolicy Policy =
445  printingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
446 
447  std::string Name;
448  llvm::raw_string_ostream Stream(Name);
449  Stream << Prefix << ' ';
450  ND->printQualifiedName(Stream, Policy);
451 
452  return Stream.str();
453 }
454 
455 /// Given a declaration \p D, return a human-readable string representing the
456 /// scope in which it is declared. If the declaration is in the global scope,
457 /// return the string "global namespace".
458 static llvm::Optional<std::string> getScopeName(const Decl *D) {
459  const DeclContext *DC = D->getDeclContext();
460 
461  if (isa<TranslationUnitDecl>(DC))
462  return std::string("global namespace");
463  if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
464  return typeDeclToString(TD);
465  else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
466  return namedDeclQualifiedName(ND, "namespace");
467  else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
468  return namedDeclQualifiedName(FD, "function");
469 
470  return llvm::None;
471 }
472 
473 /// Generate a \p Hover object given the declaration \p D.
474 static Hover getHoverContents(const Decl *D) {
475  Hover H;
476  llvm::Optional<std::string> NamedScope = getScopeName(D);
477 
478  // Generate the "Declared in" section.
479  if (NamedScope) {
480  assert(!NamedScope->empty());
481 
482  H.contents.value += "Declared in ";
483  H.contents.value += *NamedScope;
484  H.contents.value += "\n\n";
485  }
486 
487  // We want to include the template in the Hover.
488  if (TemplateDecl *TD = D->getDescribedTemplate())
489  D = TD;
490 
491  std::string DeclText;
492  llvm::raw_string_ostream OS(DeclText);
493 
494  PrintingPolicy Policy =
495  printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
496 
497  D->print(OS, Policy);
498 
499  OS.flush();
500 
501  H.contents.value += DeclText;
502  return H;
503 }
504 
505 /// Generate a \p Hover object given the type \p T.
506 static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
507  Hover H;
508  std::string TypeText;
509  llvm::raw_string_ostream OS(TypeText);
510  PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
511  T.print(OS, Policy);
512  OS.flush();
513  H.contents.value += TypeText;
514  return H;
515 }
516 
517 /// Generate a \p Hover object given the macro \p MacroInf.
518 static Hover getHoverContents(StringRef MacroName) {
519  Hover H;
520 
521  H.contents.value = "#define ";
522  H.contents.value += MacroName;
523 
524  return H;
525 }
526 
527 namespace {
528 /// Computes the deduced type at a given location by visiting the relevant
529 /// nodes. We use this to display the actual type when hovering over an "auto"
530 /// keyword or "decltype()" expression.
531 /// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
532 /// seems that the AutoTypeLocs that can be visited along with their AutoType do
533 /// not have the deduced type set. Instead, we have to go to the appropriate
534 /// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
535 /// a deduced type set. The AST should be improved to simplify this scenario.
536 class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
537  SourceLocation SearchedLocation;
538  llvm::Optional<QualType> DeducedType;
539 
540 public:
541  DeducedTypeVisitor(SourceLocation SearchedLocation)
542  : SearchedLocation(SearchedLocation) {}
543 
544  llvm::Optional<QualType> getDeducedType() { return DeducedType; }
545 
546  // Handle auto initializers:
547  //- auto i = 1;
548  //- decltype(auto) i = 1;
549  //- auto& i = 1;
550  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
551  if (!D->getTypeSourceInfo() ||
552  D->getTypeSourceInfo()->getTypeLoc().getLocStart() != SearchedLocation)
553  return true;
554 
555  auto DeclT = D->getType();
556  // "auto &" is represented as a ReferenceType containing an AutoType
557  if (const ReferenceType *RT = dyn_cast<ReferenceType>(DeclT.getTypePtr()))
558  DeclT = RT->getPointeeType();
559 
560  const AutoType *AT = dyn_cast<AutoType>(DeclT.getTypePtr());
561  if (AT && !AT->getDeducedType().isNull()) {
562  // For auto, use the underlying type because the const& would be
563  // represented twice: written in the code and in the hover.
564  // Example: "const auto I = 1", we only want "int" when hovering on auto,
565  // not "const int".
566  //
567  // For decltype(auto), take the type as is because it cannot be written
568  // with qualifiers or references but its decuded type can be const-ref.
569  DeducedType = AT->isDecltypeAuto() ? DeclT : DeclT.getUnqualifiedType();
570  }
571  return true;
572  }
573 
574  // Handle auto return types:
575  //- auto foo() {}
576  //- auto& foo() {}
577  //- auto foo() -> decltype(1+1) {}
578  //- operator auto() const { return 10; }
579  bool VisitFunctionDecl(FunctionDecl *D) {
580  if (!D->getTypeSourceInfo())
581  return true;
582  // Loc of auto in return type (c++14).
583  auto CurLoc = D->getReturnTypeSourceRange().getBegin();
584  // Loc of "auto" in operator auto()
585  if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
586  CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
587  // Loc of "auto" in function with traling return type (c++11).
588  if (CurLoc.isInvalid())
589  CurLoc = D->getSourceRange().getBegin();
590  if (CurLoc != SearchedLocation)
591  return true;
592 
593  auto T = D->getReturnType();
594  // "auto &" is represented as a ReferenceType containing an AutoType.
595  if (const ReferenceType *RT = dyn_cast<ReferenceType>(T.getTypePtr()))
596  T = RT->getPointeeType();
597 
598  const AutoType *AT = dyn_cast<AutoType>(T.getTypePtr());
599  if (AT && !AT->getDeducedType().isNull()) {
600  DeducedType = T.getUnqualifiedType();
601  } else { // auto in a trailing return type just points to a DecltypeType.
602  const DecltypeType *DT = dyn_cast<DecltypeType>(T.getTypePtr());
603  if (!DT->getUnderlyingType().isNull())
604  DeducedType = DT->getUnderlyingType();
605  }
606  return true;
607  }
608 
609  // Handle non-auto decltype, e.g.:
610  // - auto foo() -> decltype(expr) {}
611  // - decltype(expr);
612  bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
613  if (TL.getBeginLoc() != SearchedLocation)
614  return true;
615 
616  // A DecltypeType's underlying type can be another DecltypeType! E.g.
617  // int I = 0;
618  // decltype(I) J = I;
619  // decltype(J) K = J;
620  const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
621  while (DT && !DT->getUnderlyingType().isNull()) {
622  DeducedType = DT->getUnderlyingType();
623  DT = dyn_cast<DecltypeType>(DeducedType->getTypePtr());
624  }
625  return true;
626  }
627 };
628 } // namespace
629 
630 /// Retrieves the deduced type at a given location (auto, decltype).
631 llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
632  SourceLocation SourceLocationBeg) {
633  Token Tok;
634  auto &ASTCtx = AST.getASTContext();
635  // Only try to find a deduced type if the token is auto or decltype.
636  if (!SourceLocationBeg.isValid() ||
637  Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
638  ASTCtx.getLangOpts(), false) ||
639  !Tok.is(tok::raw_identifier)) {
640  return {};
641  }
642  AST.getPreprocessor().LookUpIdentifierInfo(Tok);
643  if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
644  return {};
645 
646  DeducedTypeVisitor V(SourceLocationBeg);
647  for (Decl *D : AST.getLocalTopLevelDecls())
648  V.TraverseDecl(D);
649  return V.getDeducedType();
650 }
651 
652 Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
653  const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
654  SourceLocation SourceLocationBeg =
655  getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
656  // Identified symbols at a specific position.
657  auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
658 
659  if (!Symbols.Macros.empty())
660  return getHoverContents(Symbols.Macros[0].Name);
661 
662  if (!Symbols.Decls.empty())
663  return getHoverContents(Symbols.Decls[0]);
664 
665  auto DeducedType = getDeducedType(AST, SourceLocationBeg);
666  if (DeducedType && !DeducedType->isNull())
667  return getHoverContents(*DeducedType, AST.getASTContext());
668 
669  return None;
670 }
671 
672 } // namespace clangd
673 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
Optional< Hover > getHover(ParsedAST &AST, Position Pos)
Get the hover information when hovering at Pos.
Definition: XRefs.cpp:652
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:458
std::vector< Location > findDefinitions(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:216
unsigned Column
Definition: Modularize.cpp:386
Some operations such as code completion produce a set of candidates.
Preprocessor & getPreprocessor()
Definition: ClangdUnit.cpp:196
Range range
The range this highlight applies to.
Definition: Protocol.h:811
static std::string namedDeclQualifiedName(const NamedDecl *ND, StringRef Prefix)
Return a string representation (e.g.
Definition: XRefs.cpp:442
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:317
static Hover getHoverContents(const Decl *D)
Generate a Hover object given the declaration D.
Definition: XRefs.cpp:474
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:312
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:20
Documents should not be synced at all.
const IncludeStructure & getIncludeStructure() const
Definition: ClangdUnit.cpp:244
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ClangdUnit.cpp:190
BindArgumentKind Kind
MarkupContent contents
The hover&#39;s content.
Definition: Protocol.h:635
A document highlight is a range inside a text document which deserves special attention.
Definition: Protocol.h:809
static std::string typeDeclToString(const TypeDecl *TD)
Return a string representation (e.g.
Definition: XRefs.cpp:427
SymbolLocation Definition
Definition: Index.h:175
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
Definition: ClangdUnit.cpp:206
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
std::string Path
A typedef to represent a file path.
Definition: Path.h:21
SymbolLocation CanonicalDeclaration
Definition: Index.h:184
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:391
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:130
Position Pos
std::vector< MacroDecl > Macros
Definition: XRefs.cpp:162
Stores and provides access to parsed AST.
Definition: ClangdUnit.h:66
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:59
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
Definition: ClangdUnit.cpp:375
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
StringRef Name
Definition: XRefs.cpp:67
const MacroInfo * Info
Definition: XRefs.cpp:68
static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base)
Definition: XRefs.cpp:413
CharSourceRange Range
SourceRange for the file name.
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
Definition: Protocol.h:814
llvm::Optional< QualType > getDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg)
Retrieves the deduced type at a given location (auto, decltype).
Definition: XRefs.cpp:631
llvm::Optional< std::string > getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr)
Get the absolute file path of a given file entry.
Definition: SourceCode.cpp:189
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
Definition: URI.cpp:191
unsigned Line
Definition: Modularize.cpp:386
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:156
std::array< uint8_t, 20 > SymbolID