clang-tools  10.0.0git
Hover.cpp
Go to the documentation of this file.
1 //===--- Hover.cpp - Information about code at the cursor location --------===//
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 
9 #include "Hover.h"
10 
11 #include "AST.h"
12 #include "CodeCompletionStrings.h"
13 #include "FindTarget.h"
14 #include "FormattedString.h"
15 #include "Logger.h"
16 #include "ParsedAST.h"
17 #include "Selection.h"
18 #include "SourceCode.h"
19 #include "index/SymbolCollector.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/ASTTypeTraits.h"
22 #include "clang/AST/Decl.h"
23 #include "clang/AST/DeclBase.h"
24 #include "clang/AST/DeclTemplate.h"
25 #include "clang/AST/Expr.h"
26 #include "clang/AST/ExprCXX.h"
27 #include "clang/AST/PrettyPrinter.h"
28 #include "clang/AST/Type.h"
29 #include "clang/Basic/Specifiers.h"
30 #include "clang/Index/IndexSymbol.h"
31 #include "llvm/ADT/None.h"
32 #include "llvm/ADT/Optional.h"
33 #include "llvm/ADT/STLExtras.h"
34 #include "llvm/ADT/SmallVector.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/StringRef.h"
37 #include "llvm/Support/Casting.h"
38 #include "llvm/Support/ErrorHandling.h"
39 #include "llvm/Support/raw_ostream.h"
40 #include <string>
41 
42 namespace clang {
43 namespace clangd {
44 namespace {
45 
46 PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
47  PrintingPolicy Policy(Base);
48 
49  Policy.AnonymousTagLocations = false;
50  Policy.TerseOutput = true;
51  Policy.PolishForDeclaration = true;
52  Policy.ConstantsAsWritten = true;
53  Policy.SuppressTagKeyword = false;
54 
55  return Policy;
56 }
57 
58 /// Given a declaration \p D, return a human-readable string representing the
59 /// local scope in which it is declared, i.e. class(es) and method name. Returns
60 /// an empty string if it is not local.
61 std::string getLocalScope(const Decl *D) {
62  std::vector<std::string> Scopes;
63  const DeclContext *DC = D->getDeclContext();
64  auto GetName = [](const TypeDecl *D) {
65  if (!D->getDeclName().isEmpty()) {
66  PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
67  Policy.SuppressScope = true;
68  return declaredType(D).getAsString(Policy);
69  }
70  if (auto RD = dyn_cast<RecordDecl>(D))
71  return ("(anonymous " + RD->getKindName() + ")").str();
72  return std::string("");
73  };
74  while (DC) {
75  if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
76  Scopes.push_back(GetName(TD));
77  else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
78  Scopes.push_back(FD->getNameAsString());
79  DC = DC->getParent();
80  }
81 
82  return llvm::join(llvm::reverse(Scopes), "::");
83 }
84 
85 /// Returns the human-readable representation for namespace containing the
86 /// declaration \p D. Returns empty if it is contained global namespace.
87 std::string getNamespaceScope(const Decl *D) {
88  const DeclContext *DC = D->getDeclContext();
89 
90  if (const TagDecl *TD = dyn_cast<TagDecl>(DC))
91  return getNamespaceScope(TD);
92  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
93  return getNamespaceScope(FD);
94  if (const NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(DC)) {
95  // Skip inline/anon namespaces.
96  if (NSD->isInline() || NSD->isAnonymousNamespace())
97  return getNamespaceScope(NSD);
98  }
99  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
100  return printQualifiedName(*ND);
101 
102  return "";
103 }
104 
105 std::string printDefinition(const Decl *D) {
106  std::string Definition;
107  llvm::raw_string_ostream OS(Definition);
108  PrintingPolicy Policy =
109  printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
110  Policy.IncludeTagDefinition = false;
111  Policy.SuppressTemplateArgsInCXXConstructors = true;
112  Policy.SuppressTagKeyword = true;
113  D->print(OS, Policy);
114  OS.flush();
115  return Definition;
116 }
117 
118 void printParams(llvm::raw_ostream &OS,
119  const std::vector<HoverInfo::Param> &Params) {
120  for (size_t I = 0, E = Params.size(); I != E; ++I) {
121  if (I)
122  OS << ", ";
123  OS << Params.at(I);
124  }
125 }
126 
127 std::string printType(QualType QT, const PrintingPolicy &Policy) {
128  // TypePrinter doesn't resolve decltypes, so resolve them here.
129  // FIXME: This doesn't handle composite types that contain a decltype in them.
130  // We should rather have a printing policy for that.
131  while (const auto *DT = QT->getAs<DecltypeType>())
132  QT = DT->getUnderlyingType();
133  return QT.getAsString(Policy);
134 }
135 
136 std::vector<HoverInfo::Param>
137 fetchTemplateParameters(const TemplateParameterList *Params,
138  const PrintingPolicy &PP) {
139  assert(Params);
140  std::vector<HoverInfo::Param> TempParameters;
141 
142  for (const Decl *Param : *Params) {
143  HoverInfo::Param P;
144  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
145  P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
146  if (TTP->isParameterPack())
147  *P.Type += "...";
148 
149  if (!TTP->getName().empty())
150  P.Name = TTP->getNameAsString();
151  if (TTP->hasDefaultArgument())
152  P.Default = TTP->getDefaultArgument().getAsString(PP);
153  } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
154  if (IdentifierInfo *II = NTTP->getIdentifier())
155  P.Name = II->getName().str();
156 
157  P.Type = printType(NTTP->getType(), PP);
158  if (NTTP->isParameterPack())
159  *P.Type += "...";
160 
161  if (NTTP->hasDefaultArgument()) {
162  P.Default.emplace();
163  llvm::raw_string_ostream Out(*P.Default);
164  NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
165  }
166  } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
167  P.Type.emplace();
168  llvm::raw_string_ostream OS(*P.Type);
169  OS << "template <";
170  printParams(OS,
171  fetchTemplateParameters(TTPD->getTemplateParameters(), PP));
172  OS << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
173  // info on whether this param was a "typename" or
174  // "class".
175  if (!TTPD->getName().empty())
176  P.Name = TTPD->getNameAsString();
177  if (TTPD->hasDefaultArgument()) {
178  P.Default.emplace();
179  llvm::raw_string_ostream Out(*P.Default);
180  TTPD->getDefaultArgument().getArgument().print(PP, Out);
181  }
182  }
183  TempParameters.push_back(std::move(P));
184  }
185 
186  return TempParameters;
187 }
188 
189 const FunctionDecl *getUnderlyingFunction(const Decl *D) {
190  // Extract lambda from variables.
191  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
192  auto QT = VD->getType();
193  if (!QT.isNull()) {
194  while (!QT->getPointeeType().isNull())
195  QT = QT->getPointeeType();
196 
197  if (const auto *CD = QT->getAsCXXRecordDecl())
198  return CD->getLambdaCallOperator();
199  }
200  }
201 
202  // Non-lambda functions.
203  return D->getAsFunction();
204 }
205 
206 // Returns the decl that should be used for querying comments, either from index
207 // or AST.
208 const NamedDecl *getDeclForComment(const NamedDecl *D) {
209  if (const auto *TSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
210  // Template may not be instantiated e.g. if the type didn't need to be
211  // complete; fallback to primary template.
212  if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
213  return TSD->getSpecializedTemplate();
214  if (const auto *TIP = TSD->getTemplateInstantiationPattern())
215  return TIP;
216  }
217  if (const auto *TSD = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
218  if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
219  return TSD->getSpecializedTemplate();
220  if (const auto *TIP = TSD->getTemplateInstantiationPattern())
221  return TIP;
222  }
223  if (const auto *FD = D->getAsFunction())
224  if (const auto *TIP = FD->getTemplateInstantiationPattern())
225  return TIP;
226  return D;
227 }
228 
229 // Look up information about D from the index, and add it to Hover.
230 void enhanceFromIndex(HoverInfo &Hover, const NamedDecl &ND,
231  const SymbolIndex *Index) {
232  assert(&ND == getDeclForComment(&ND));
233  // We only add documentation, so don't bother if we already have some.
234  if (!Hover.Documentation.empty() || !Index)
235  return;
236 
237  // Skip querying for non-indexable symbols, there's no point.
238  // We're searching for symbols that might be indexed outside this main file.
239  if (!SymbolCollector::shouldCollectSymbol(ND, ND.getASTContext(),
240  SymbolCollector::Options(),
241  /*IsMainFileOnly=*/false))
242  return;
243  auto ID = getSymbolID(&ND);
244  if (!ID)
245  return;
246  LookupRequest Req;
247  Req.IDs.insert(*ID);
248  Index->lookup(
249  Req, [&](const Symbol &S) { Hover.Documentation = S.Documentation; });
250 }
251 
252 // Populates Type, ReturnType, and Parameters for function-like decls.
253 void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
254  const FunctionDecl *FD,
255  const PrintingPolicy &Policy) {
256  HI.Parameters.emplace();
257  for (const ParmVarDecl *PVD : FD->parameters()) {
258  HI.Parameters->emplace_back();
259  auto &P = HI.Parameters->back();
260  if (!PVD->getType().isNull()) {
261  P.Type = printType(PVD->getType(), Policy);
262  } else {
263  std::string Param;
264  llvm::raw_string_ostream OS(Param);
265  PVD->dump(OS);
266  OS.flush();
267  elog("Got param with null type: {0}", Param);
268  }
269  if (!PVD->getName().empty())
270  P.Name = PVD->getNameAsString();
271  if (PVD->hasDefaultArg()) {
272  P.Default.emplace();
273  llvm::raw_string_ostream Out(*P.Default);
274  PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
275  }
276  }
277 
278  // We don't want any type info, if name already contains it. This is true for
279  // constructors/destructors and conversion operators.
280  const auto NK = FD->getDeclName().getNameKind();
281  if (NK == DeclarationName::CXXConstructorName ||
282  NK == DeclarationName::CXXDestructorName ||
283  NK == DeclarationName::CXXConversionFunctionName)
284  return;
285 
286  HI.ReturnType = printType(FD->getReturnType(), Policy);
287  QualType QT = FD->getType();
288  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
289  QT = VD->getType().getDesugaredType(D->getASTContext());
290  HI.Type = printType(QT, Policy);
291  // FIXME: handle variadics.
292 }
293 
294 llvm::Optional<std::string> printExprValue(const Expr *E,
295  const ASTContext &Ctx) {
296  Expr::EvalResult Constant;
297  // Evaluating [[foo]]() as "&foo" isn't useful, and prevents us walking up
298  // to the enclosing call.
299  QualType T = E->getType();
300  if (T.isNull() || T->isFunctionType() || T->isFunctionPointerType() ||
301  T->isFunctionReferenceType())
302  return llvm::None;
303  // Attempt to evaluate. If expr is dependent, evaluation crashes!
304  if (E->isValueDependent() || !E->EvaluateAsRValue(Constant, Ctx))
305  return llvm::None;
306 
307  // Show enums symbolically, not numerically like APValue::printPretty().
308  if (T->isEnumeralType() && Constant.Val.getInt().getMinSignedBits() <= 64) {
309  // Compare to int64_t to avoid bit-width match requirements.
310  int64_t Val = Constant.Val.getInt().getExtValue();
311  for (const EnumConstantDecl *ECD :
312  T->castAs<EnumType>()->getDecl()->enumerators())
313  if (ECD->getInitVal() == Val)
314  return llvm::formatv("{0} ({1})", ECD->getNameAsString(), Val).str();
315  }
316  return Constant.Val.getAsString(Ctx, E->getType());
317 }
318 
319 llvm::Optional<std::string> printExprValue(const SelectionTree::Node *N,
320  const ASTContext &Ctx) {
321  for (; N; N = N->Parent) {
322  // Try to evaluate the first evaluatable enclosing expression.
323  if (const Expr *E = N->ASTNode.get<Expr>()) {
324  if (auto Val = printExprValue(E, Ctx))
325  return Val;
326  } else if (N->ASTNode.get<Decl>() || N->ASTNode.get<Stmt>()) {
327  // Refuse to cross certain non-exprs. (TypeLoc are OK as part of Exprs).
328  // This tries to ensure we're showing a value related to the cursor.
329  break;
330  }
331  }
332  return llvm::None;
333 }
334 
335 /// Generate a \p Hover object given the declaration \p D.
336 HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) {
337  HoverInfo HI;
338  const ASTContext &Ctx = D->getASTContext();
339 
340  HI.NamespaceScope = getNamespaceScope(D);
341  if (!HI.NamespaceScope->empty())
342  HI.NamespaceScope->append("::");
343  HI.LocalScope = getLocalScope(D);
344  if (!HI.LocalScope.empty())
345  HI.LocalScope.append("::");
346 
347  PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy());
348  HI.Name = printName(Ctx, *D);
349  const auto *CommentD = getDeclForComment(D);
350  HI.Documentation = getDeclComment(Ctx, *CommentD);
351  enhanceFromIndex(HI, *CommentD, Index);
352 
353  HI.Kind = index::getSymbolInfo(D).Kind;
354 
355  // Fill in template params.
356  if (const TemplateDecl *TD = D->getDescribedTemplate()) {
357  HI.TemplateParameters =
358  fetchTemplateParameters(TD->getTemplateParameters(), Policy);
359  D = TD;
360  } else if (const FunctionDecl *FD = D->getAsFunction()) {
361  if (const auto *FTD = FD->getDescribedTemplate()) {
362  HI.TemplateParameters =
363  fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
364  D = FTD;
365  }
366  }
367 
368  // Fill in types and params.
369  if (const FunctionDecl *FD = getUnderlyingFunction(D))
370  fillFunctionTypeAndParams(HI, D, FD, Policy);
371  else if (const auto *VD = dyn_cast<ValueDecl>(D))
372  HI.Type = printType(VD->getType(), Policy);
373 
374  // Fill in value with evaluated initializer if possible.
375  if (const auto *Var = dyn_cast<VarDecl>(D)) {
376  if (const Expr *Init = Var->getInit())
377  HI.Value = printExprValue(Init, Ctx);
378  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
379  // Dependent enums (e.g. nested in template classes) don't have values yet.
380  if (!ECD->getType()->isDependentType())
381  HI.Value = ECD->getInitVal().toString(10);
382  }
383 
384  HI.Definition = printDefinition(D);
385  return HI;
386 }
387 
388 /// Generate a \p Hover object given the type \p T.
389 HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx,
390  const SymbolIndex *Index) {
391  HoverInfo HI;
392 
393  if (const auto *D = T->getAsTagDecl()) {
394  HI.Name = printName(ASTCtx, *D);
395  HI.Kind = index::getSymbolInfo(D).Kind;
396 
397  const auto *CommentD = getDeclForComment(D);
398  HI.Documentation = getDeclComment(ASTCtx, *CommentD);
399  enhanceFromIndex(HI, *CommentD, Index);
400  } else {
401  // Builtin types
402  auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
403  Policy.SuppressTagKeyword = true;
404  HI.Name = T.getAsString(Policy);
405  }
406  return HI;
407 }
408 
409 /// Generate a \p Hover object given the macro \p MacroDecl.
410 HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
411  HoverInfo HI;
412  SourceManager &SM = AST.getSourceManager();
413  HI.Name = Macro.Name;
414  HI.Kind = index::SymbolKind::Macro;
415  // FIXME: Populate documentation
416  // FIXME: Pupulate parameters
417 
418  // Try to get the full definition, not just the name
419  SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
420  SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
421  if (EndLoc.isValid()) {
422  EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM, AST.getLangOpts());
423  bool Invalid;
424  StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
425  if (!Invalid) {
426  unsigned StartOffset = SM.getFileOffset(StartLoc);
427  unsigned EndOffset = SM.getFileOffset(EndLoc);
428  if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
429  HI.Definition =
430  ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
431  .str();
432  }
433  }
434  return HI;
435 }
436 
437 bool isLiteral(const Expr *E) {
438  // Unfortunately there's no common base Literal classes inherits from
439  // (apart from Expr), therefore this is a nasty blacklist.
440  return llvm::isa<CharacterLiteral>(E) || llvm::isa<CompoundLiteralExpr>(E) ||
441  llvm::isa<CXXBoolLiteralExpr>(E) ||
442  llvm::isa<CXXNullPtrLiteralExpr>(E) ||
443  llvm::isa<FixedPointLiteral>(E) || llvm::isa<FloatingLiteral>(E) ||
444  llvm::isa<ImaginaryLiteral>(E) || llvm::isa<IntegerLiteral>(E) ||
445  llvm::isa<StringLiteral>(E) || llvm::isa<UserDefinedLiteral>(E);
446 }
447 
448 llvm::StringLiteral getNameForExpr(const Expr *E) {
449  // FIXME: Come up with names for `special` expressions.
450  return "expression";
451 }
452 
453 // Generates hover info for evaluatable expressions.
454 // FIXME: Support hover for literals (esp user-defined)
455 llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST) {
456  // There's not much value in hovering over "42" and getting a hover card
457  // saying "42 is an int", similar for other literals.
458  if (isLiteral(E))
459  return llvm::None;
460 
461  HoverInfo HI;
462  // For expressions we currently print the type and the value, iff it is
463  // evaluatable.
464  if (auto Val = printExprValue(E, AST.getASTContext())) {
465  auto Policy =
466  printingPolicyForDecls(AST.getASTContext().getPrintingPolicy());
467  Policy.SuppressTagKeyword = true;
468  HI.Type = printType(E->getType(), Policy);
469  HI.Value = *Val;
470  HI.Name = getNameForExpr(E);
471  return HI;
472  }
473  return llvm::None;
474 }
475 } // namespace
476 
477 llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
478  format::FormatStyle Style,
479  const SymbolIndex *Index) {
480  const SourceManager &SM = AST.getSourceManager();
481  llvm::Optional<HoverInfo> HI;
482  SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
483  getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
484 
485  if (auto Deduced = getDeducedType(AST.getASTContext(), SourceLocationBeg)) {
486  HI = getHoverContents(*Deduced, AST.getASTContext(), Index);
487  } else if (auto M = locateMacroAt(SourceLocationBeg, AST.getPreprocessor())) {
488  HI = getHoverContents(*M, AST);
489  } else {
490  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
491  if (!Offset) {
492  llvm::consumeError(Offset.takeError());
493  return llvm::None;
494  }
495  SelectionTree Selection(AST.getASTContext(), AST.getTokens(), *Offset);
496  std::vector<const Decl *> Result;
497  if (const SelectionTree::Node *N = Selection.commonAncestor()) {
499  if (!Decls.empty()) {
500  HI = getHoverContents(Decls.front(), Index);
501  // Look for a close enclosing expression to show the value of.
502  if (!HI->Value)
503  HI->Value = printExprValue(N, AST.getASTContext());
504  } else if (const Expr *E = N->ASTNode.get<Expr>()) {
505  HI = getHoverContents(E, AST);
506  }
507  // FIXME: support hovers for other nodes?
508  // - built-in types
509  }
510  }
511 
512  if (!HI)
513  return llvm::None;
514 
515  auto Replacements = format::reformat(
516  Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
517  if (auto Formatted =
518  tooling::applyAllReplacements(HI->Definition, Replacements))
519  HI->Definition = *Formatted;
520 
521  HI->SymRange = getTokenRange(AST.getSourceManager(), AST.getLangOpts(),
522  SourceLocationBeg);
523  return HI;
524 }
525 
527  markup::Document Output;
528  // Header contains a text of the form:
529  // variable `var`
530  //
531  // class `X`
532  //
533  // function `foo`
534  //
535  // expression
536  //
537  // Note that we are making use of a level-3 heading because VSCode renders
538  // level 1 and 2 headers in a huge font, see
539  // https://github.com/microsoft/vscode/issues/88417 for details.
540  markup::Paragraph &Header = Output.addHeading(3);
542  Header.appendText(index::getSymbolKindString(Kind));
543  assert(!Name.empty() && "hover triggered on a nameless symbol");
544  Header.appendCode(Name);
545 
546  // Put a linebreak after header to increase readability.
547  Output.addRuler();
548  // Print Types on their own lines to reduce chances of getting line-wrapped by
549  // editor, as they might be long.
550  if (ReturnType) {
551  // For functions we display signature in a list form, e.g.:
552  // → `x`
553  // Parameters:
554  // - `bool param1`
555  // - `int param2 = 5`
556  Output.addParagraph().appendText("→").appendCode(*ReturnType);
557  if (Parameters && !Parameters->empty()) {
558  Output.addParagraph().appendText("Parameters:");
559  markup::BulletList &L = Output.addBulletList();
560  for (const auto &Param : *Parameters) {
561  std::string Buffer;
562  llvm::raw_string_ostream OS(Buffer);
563  OS << Param;
564  L.addItem().addParagraph().appendCode(std::move(OS.str()));
565  }
566  }
567  } else if (Type) {
568  Output.addParagraph().appendText("Type: ").appendCode(*Type);
569  }
570 
571  if (Value) {
572  markup::Paragraph &P = Output.addParagraph();
573  P.appendText("Value =");
574  P.appendCode(*Value);
575  }
576 
577  if (!Documentation.empty())
579 
580  if (!Definition.empty()) {
581  Output.addRuler();
582  std::string ScopeComment;
583  // Drop trailing "::".
584  if (!LocalScope.empty()) {
585  // Container name, e.g. class, method, function.
586  // We might want to propogate some info about container type to print
587  // function foo, class X, method X::bar, etc.
588  ScopeComment =
589  "// In " + llvm::StringRef(LocalScope).rtrim(':').str() + '\n';
590  } else if (NamespaceScope && !NamespaceScope->empty()) {
591  ScopeComment = "// In namespace " +
592  llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n';
593  }
594  // Note that we don't print anything for global namespace, to not annoy
595  // non-c++ projects or projects that are not making use of namespaces.
596  Output.addCodeBlock(ScopeComment + Definition);
597  }
598  return Output;
599 }
600 
601 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
602  const HoverInfo::Param &P) {
603  std::vector<llvm::StringRef> Output;
604  if (P.Type)
605  Output.push_back(*P.Type);
606  if (P.Name)
607  Output.push_back(*P.Name);
608  OS << llvm::join(Output, " ");
609  if (P.Default)
610  OS << " = " << *P.Default;
611  return OS;
612 }
613 
614 } // namespace clangd
615 } // namespace clang
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
const FunctionDecl * Decl
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:169
Paragraph & appendCode(std::string Code)
Append inline code, this translates to the ` block in markdown.
llvm::Optional< QualType > getDeducedType(ASTContext &ASTCtx, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
Definition: AST.cpp:418
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
index::SymbolKind Kind
Definition: Hover.h:57
Preprocessor & getPreprocessor()
Definition: ParsedAST.cpp:430
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:85
llvm::Optional< std::string > Name
None for unnamed parameters.
Definition: Hover.h:35
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 > Type
Pretty-printed variable type.
Definition: Hover.h:64
Documents should not be synced at all.
llvm::Optional< std::vector< Param > > Parameters
Set for functions, lambdas and macros with parameters.
Definition: Hover.h:68
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
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
std::string printType(const QualType QT, const DeclContext &CurContext)
Returns a QualType as string.
Definition: AST.cpp:305
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:424
Represents parameters of a function, a template or a macro.
Definition: Hover.h:30
llvm::Optional< std::string > Type
The pretty-printed parameter type, e.g.
Definition: Hover.h:33
Context Ctx
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:519
std::string Name
Name of the symbol, does not contain any "::".
Definition: Hover.h:55
llvm::Optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, format::FormatStyle Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
Definition: Hover.cpp:477
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:155
void addCodeBlock(std::string Code, std::string Language="cpp")
Adds a block of code.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
Definition: FindTarget.cpp:502
llvm::Optional< std::string > Default
None if no default is provided.
Definition: Hover.h:37
QualType declaredType(const TypeDecl *D)
Definition: AST.cpp:321
Paragraph & appendText(std::string Text)
Append plain text to the end of the string.
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
A format-agnostic representation for structured text.
std::string LocalScope
Remaining named contexts in symbol&#39;s qualified name, empty string means symbol is not local...
Definition: Hover.h:53
llvm::Optional< std::string > NamespaceScope
For a variable named Bar, declared in clang::clangd::Foo::getFoo the following fields will hold: ...
Definition: Hover.h:50
Stores and provides access to parsed AST.
Definition: ParsedAST.h:46
SourceManager & getSourceManager()
Definition: ParsedAST.h:73
size_t Offset
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
llvm::Optional< std::string > ReturnType
Set for functions and lambadas.
Definition: Hover.h:66
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void addRuler()
Inserts a horizontal separator to the document.
CharSourceRange Range
SourceRange for the file name.
llvm::Optional< std::string > Value
Contains the evaluated value of the symbol if available.
Definition: Hover.h:72
Represents parts of the markup that can contain strings, like inline code, code block or plain text...
markup::Document present() const
Produce a user-readable information.
Definition: Hover.cpp:526
Paragraph & addHeading(size_t Level)
Heading is a special type of paragraph that will be prepended with Level many &#39;#&#39;s in markdown...
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls
Definition: FindTarget.cpp:170
const Expr * E
Paragraph & addParagraph()
Adds a semantical block that will be separate from others.
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
std::unique_ptr< GlobalCompilationDatabase > Base
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
std::string Documentation
Definition: Hover.h:58
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
Definition: SourceCode.cpp:987
const SymbolIndex * Index
Definition: Dexp.cpp:84
static cl::opt< std::string > FormatStyle("format-style", cl::desc(R"( Style for formatting code around applied fixes: - 'none' (default) turns off formatting - 'file' (literally 'file', not a placeholder) uses .clang-format file in the closest parent directory - '{ <json> }' specifies options inline, e.g. -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' - 'llvm', 'google', 'webkit', 'mozilla' See clang-format documentation for the up-to-date information about formatting styles and options. This option overrides the 'FormatStyle` option in .clang-tidy file, if any. )"), cl::init("none"), cl::cat(ClangTidyCategory))
Represents a sequence of one or more documents.