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  //
451  // It's an known issue for GCC5, https://godbolt.org/z/Z_tbgi. Work around
452  // that by using explicit conversion constructor.
453  //
454  // TODO: Once GCC5 is fully retired and not the minimal requirement as stated
455  // in `GettingStarted`, please remove the explicit conversion constructor.
456  return llvm::StringLiteral("expression");
457 }
458 
459 // Generates hover info for evaluatable expressions.
460 // FIXME: Support hover for literals (esp user-defined)
461 llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST) {
462  // There's not much value in hovering over "42" and getting a hover card
463  // saying "42 is an int", similar for other literals.
464  if (isLiteral(E))
465  return llvm::None;
466 
467  HoverInfo HI;
468  // For expressions we currently print the type and the value, iff it is
469  // evaluatable.
470  if (auto Val = printExprValue(E, AST.getASTContext())) {
471  auto Policy =
472  printingPolicyForDecls(AST.getASTContext().getPrintingPolicy());
473  Policy.SuppressTagKeyword = true;
474  HI.Type = printType(E->getType(), Policy);
475  HI.Value = *Val;
476  HI.Name = getNameForExpr(E);
477  return HI;
478  }
479  return llvm::None;
480 }
481 } // namespace
482 
483 llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
484  format::FormatStyle Style,
485  const SymbolIndex *Index) {
486  const SourceManager &SM = AST.getSourceManager();
487  llvm::Optional<HoverInfo> HI;
488  SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
489  getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
490 
491  if (auto Deduced = getDeducedType(AST.getASTContext(), SourceLocationBeg)) {
492  HI = getHoverContents(*Deduced, AST.getASTContext(), Index);
493  } else if (auto M = locateMacroAt(SourceLocationBeg, AST.getPreprocessor())) {
494  HI = getHoverContents(*M, AST);
495  } else {
496  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
497  if (!Offset) {
498  llvm::consumeError(Offset.takeError());
499  return llvm::None;
500  }
501  SelectionTree Selection(AST.getASTContext(), AST.getTokens(), *Offset);
502  std::vector<const Decl *> Result;
503  if (const SelectionTree::Node *N = Selection.commonAncestor()) {
505  if (!Decls.empty()) {
506  HI = getHoverContents(Decls.front(), Index);
507  // Look for a close enclosing expression to show the value of.
508  if (!HI->Value)
509  HI->Value = printExprValue(N, AST.getASTContext());
510  } else if (const Expr *E = N->ASTNode.get<Expr>()) {
511  HI = getHoverContents(E, AST);
512  }
513  // FIXME: support hovers for other nodes?
514  // - built-in types
515  }
516  }
517 
518  if (!HI)
519  return llvm::None;
520 
521  auto Replacements = format::reformat(
522  Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
523  if (auto Formatted =
524  tooling::applyAllReplacements(HI->Definition, Replacements))
525  HI->Definition = *Formatted;
526 
527  HI->SymRange = getTokenRange(AST.getSourceManager(), AST.getLangOpts(),
528  SourceLocationBeg);
529  return HI;
530 }
531 
533  markup::Document Output;
534  // Header contains a text of the form:
535  // variable `var`
536  //
537  // class `X`
538  //
539  // function `foo`
540  //
541  // expression
542  //
543  // Note that we are making use of a level-3 heading because VSCode renders
544  // level 1 and 2 headers in a huge font, see
545  // https://github.com/microsoft/vscode/issues/88417 for details.
546  markup::Paragraph &Header = Output.addHeading(3);
548  Header.appendText(index::getSymbolKindString(Kind));
549  assert(!Name.empty() && "hover triggered on a nameless symbol");
550  Header.appendCode(Name);
551 
552  // Put a linebreak after header to increase readability.
553  Output.addRuler();
554  // Print Types on their own lines to reduce chances of getting line-wrapped by
555  // editor, as they might be long.
556  if (ReturnType) {
557  // For functions we display signature in a list form, e.g.:
558  // → `x`
559  // Parameters:
560  // - `bool param1`
561  // - `int param2 = 5`
562  Output.addParagraph().appendText("→").appendCode(*ReturnType);
563  if (Parameters && !Parameters->empty()) {
564  Output.addParagraph().appendText("Parameters:");
565  markup::BulletList &L = Output.addBulletList();
566  for (const auto &Param : *Parameters) {
567  std::string Buffer;
568  llvm::raw_string_ostream OS(Buffer);
569  OS << Param;
570  L.addItem().addParagraph().appendCode(std::move(OS.str()));
571  }
572  }
573  } else if (Type) {
574  Output.addParagraph().appendText("Type: ").appendCode(*Type);
575  }
576 
577  if (Value) {
578  markup::Paragraph &P = Output.addParagraph();
579  P.appendText("Value =");
580  P.appendCode(*Value);
581  }
582 
583  if (!Documentation.empty())
585 
586  if (!Definition.empty()) {
587  Output.addRuler();
588  std::string ScopeComment;
589  // Drop trailing "::".
590  if (!LocalScope.empty()) {
591  // Container name, e.g. class, method, function.
592  // We might want to propogate some info about container type to print
593  // function foo, class X, method X::bar, etc.
594  ScopeComment =
595  "// In " + llvm::StringRef(LocalScope).rtrim(':').str() + '\n';
596  } else if (NamespaceScope && !NamespaceScope->empty()) {
597  ScopeComment = "// In namespace " +
598  llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n';
599  }
600  // Note that we don't print anything for global namespace, to not annoy
601  // non-c++ projects or projects that are not making use of namespaces.
602  Output.addCodeBlock(ScopeComment + Definition);
603  }
604  return Output;
605 }
606 
607 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
608  const HoverInfo::Param &P) {
609  std::vector<llvm::StringRef> Output;
610  if (P.Type)
611  Output.push_back(*P.Type);
612  if (P.Name)
613  Output.push_back(*P.Name);
614  OS << llvm::join(Output, " ");
615  if (P.Default)
616  OS << " = " << *P.Default;
617  return OS;
618 }
619 
620 } // namespace clangd
621 } // 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:483
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:532
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.