clang-tools  16.0.0git
InlayHints.cpp
Go to the documentation of this file.
1 //===--- InlayHints.cpp ------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "InlayHints.h"
9 #include "AST.h"
10 #include "Config.h"
11 #include "HeuristicResolver.h"
12 #include "ParsedAST.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/AST/DeclarationName.h"
15 #include "clang/AST/ExprCXX.h"
16 #include "clang/AST/RecursiveASTVisitor.h"
17 #include "clang/Basic/Builtins.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "llvm/ADT/ScopeExit.h"
20 
21 namespace clang {
22 namespace clangd {
23 namespace {
24 
25 // For now, inlay hints are always anchored at the left or right of their range.
26 enum class HintSide { Left, Right };
27 
28 // Helper class to iterate over the designator names of an aggregate type.
29 //
30 // For an array type, yields [0], [1], [2]...
31 // For aggregate classes, yields null for each base, then .field1, .field2, ...
32 class AggregateDesignatorNames {
33 public:
34  AggregateDesignatorNames(QualType T) {
35  if (!T.isNull()) {
36  T = T.getCanonicalType();
37  if (T->isArrayType()) {
38  IsArray = true;
39  Valid = true;
40  return;
41  }
42  if (const RecordDecl *RD = T->getAsRecordDecl()) {
43  Valid = true;
44  FieldsIt = RD->field_begin();
45  FieldsEnd = RD->field_end();
46  if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
47  BasesIt = CRD->bases_begin();
48  BasesEnd = CRD->bases_end();
49  Valid = CRD->isAggregate();
50  }
51  OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&
52  std::next(FieldsIt) == FieldsEnd;
53  }
54  }
55  }
56  // Returns false if the type was not an aggregate.
57  operator bool() { return Valid; }
58  // Advance to the next element in the aggregate.
59  void next() {
60  if (IsArray)
61  ++Index;
62  else if (BasesIt != BasesEnd)
63  ++BasesIt;
64  else if (FieldsIt != FieldsEnd)
65  ++FieldsIt;
66  }
67  // Print the designator to Out.
68  // Returns false if we could not produce a designator for this element.
69  bool append(std::string &Out, bool ForSubobject) {
70  if (IsArray) {
71  Out.push_back('[');
72  Out.append(std::to_string(Index));
73  Out.push_back(']');
74  return true;
75  }
76  if (BasesIt != BasesEnd)
77  return false; // Bases can't be designated. Should we make one up?
78  if (FieldsIt != FieldsEnd) {
79  llvm::StringRef FieldName;
80  if (const IdentifierInfo *II = FieldsIt->getIdentifier())
81  FieldName = II->getName();
82 
83  // For certain objects, their subobjects may be named directly.
84  if (ForSubobject &&
85  (FieldsIt->isAnonymousStructOrUnion() ||
86  // std::array<int,3> x = {1,2,3}. Designators not strictly valid!
87  (OneField && isReservedName(FieldName))))
88  return true;
89 
90  if (!FieldName.empty() && !isReservedName(FieldName)) {
91  Out.push_back('.');
92  Out.append(FieldName.begin(), FieldName.end());
93  return true;
94  }
95  return false;
96  }
97  return false;
98  }
99 
100 private:
101  bool Valid = false;
102  bool IsArray = false;
103  bool OneField = false; // e.g. std::array { T __elements[N]; }
104  unsigned Index = 0;
105  CXXRecordDecl::base_class_const_iterator BasesIt;
106  CXXRecordDecl::base_class_const_iterator BasesEnd;
107  RecordDecl::field_iterator FieldsIt;
108  RecordDecl::field_iterator FieldsEnd;
109 };
110 
111 // Collect designator labels describing the elements of an init list.
112 //
113 // This function contributes the designators of some (sub)object, which is
114 // represented by the semantic InitListExpr Sem.
115 // This includes any nested subobjects, but *only* if they are part of the same
116 // original syntactic init list (due to brace elision).
117 // In other words, it may descend into subobjects but not written init-lists.
118 //
119 // For example: struct Outer { Inner a,b; }; struct Inner { int x, y; }
120 // Outer o{{1, 2}, 3};
121 // This function will be called with Sem = { {1, 2}, {3, ImplicitValue} }
122 // It should generate designators '.a:' and '.b.x:'.
123 // '.a:' is produced directly without recursing into the written sublist.
124 // (The written sublist will have a separate collectDesignators() call later).
125 // Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'.
126 void collectDesignators(const InitListExpr *Sem,
127  llvm::DenseMap<SourceLocation, std::string> &Out,
128  const llvm::DenseSet<SourceLocation> &NestedBraces,
129  std::string &Prefix) {
130  if (!Sem || Sem->isTransparent())
131  return;
132  assert(Sem->isSemanticForm());
133 
134  // The elements of the semantic form all correspond to direct subobjects of
135  // the aggregate type. `Fields` iterates over these subobject names.
136  AggregateDesignatorNames Fields(Sem->getType());
137  if (!Fields)
138  return;
139  for (const Expr *Init : Sem->inits()) {
140  auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {
141  Fields.next(); // Always advance to the next subobject name.
142  Prefix.resize(Size); // Erase any designator we appended.
143  });
144  // Skip for a broken initializer or if it is a "hole" in a subobject that
145  // was not explicitly initialized.
146  if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))
147  continue;
148 
149  const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);
150  if (BraceElidedSubobject &&
151  NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))
152  BraceElidedSubobject = nullptr; // there were braces!
153 
154  if (!Fields.append(Prefix, BraceElidedSubobject != nullptr))
155  continue; // no designator available for this subobject
156  if (BraceElidedSubobject) {
157  // If the braces were elided, this aggregate subobject is initialized
158  // inline in the same syntactic list.
159  // Descend into the semantic list describing the subobject.
160  // (NestedBraces are still correct, they're from the same syntactic list).
161  collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix);
162  continue;
163  }
164  Out.try_emplace(Init->getBeginLoc(), Prefix);
165  }
166 }
167 
168 // Get designators describing the elements of a (syntactic) init list.
169 // This does not produce designators for any explicitly-written nested lists.
170 llvm::DenseMap<SourceLocation, std::string>
171 getDesignators(const InitListExpr *Syn) {
172  assert(Syn->isSyntacticForm());
173 
174  // collectDesignators needs to know which InitListExprs in the semantic tree
175  // were actually written, but InitListExpr::isExplicit() lies.
176  // Instead, record where braces of sub-init-lists occur in the syntactic form.
177  llvm::DenseSet<SourceLocation> NestedBraces;
178  for (const Expr *Init : Syn->inits())
179  if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init))
180  NestedBraces.insert(Nested->getLBraceLoc());
181 
182  // Traverse the semantic form to find the designators.
183  // We use their SourceLocation to correlate with the syntactic form later.
184  llvm::DenseMap<SourceLocation, std::string> Designators;
185  std::string EmptyPrefix;
186  collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),
187  Designators, NestedBraces, EmptyPrefix);
188  return Designators;
189 }
190 
191 class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
192 public:
193  InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST,
194  const Config &Cfg, llvm::Optional<Range> RestrictRange)
195  : Results(Results), AST(AST.getASTContext()), Cfg(Cfg),
196  RestrictRange(std::move(RestrictRange)),
197  MainFileID(AST.getSourceManager().getMainFileID()),
198  Resolver(AST.getHeuristicResolver()),
199  TypeHintPolicy(this->AST.getPrintingPolicy()),
200  StructuredBindingPolicy(this->AST.getPrintingPolicy()) {
201  bool Invalid = false;
202  llvm::StringRef Buf =
203  AST.getSourceManager().getBufferData(MainFileID, &Invalid);
204  MainFileBuf = Invalid ? StringRef{} : Buf;
205 
206  TypeHintPolicy.SuppressScope = true; // keep type names short
207  TypeHintPolicy.AnonymousTagLocations =
208  false; // do not print lambda locations
209 
210  // For structured bindings, print canonical types. This is important because
211  // for bindings that use the tuple_element protocol, the non-canonical types
212  // would be "tuple_element<I, A>::type".
213  // For "auto", we often prefer sugared types.
214  // Not setting PrintCanonicalTypes for "auto" allows
215  // SuppressDefaultTemplateArgs (set by default) to have an effect.
216  StructuredBindingPolicy = TypeHintPolicy;
217  StructuredBindingPolicy.PrintCanonicalTypes = true;
218  }
219 
220  bool VisitCXXConstructExpr(CXXConstructExpr *E) {
221  // Weed out constructor calls that don't look like a function call with
222  // an argument list, by checking the validity of getParenOrBraceRange().
223  // Also weed out std::initializer_list constructors as there are no names
224  // for the individual arguments.
225  if (!E->getParenOrBraceRange().isValid() ||
226  E->isStdInitListInitialization()) {
227  return true;
228  }
229 
230  processCall(E->getParenOrBraceRange().getBegin(), E->getConstructor(),
231  {E->getArgs(), E->getNumArgs()});
232  return true;
233  }
234 
235  bool VisitCallExpr(CallExpr *E) {
236  if (!Cfg.InlayHints.Parameters)
237  return true;
238 
239  // Do not show parameter hints for operator calls written using operator
240  // syntax or user-defined literals. (Among other reasons, the resulting
241  // hints can look awkard, e.g. the expression can itself be a function
242  // argument and then we'd get two hints side by side).
243  if (isa<CXXOperatorCallExpr>(E) || isa<UserDefinedLiteral>(E))
244  return true;
245 
246  auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
247  if (CalleeDecls.size() != 1)
248  return true;
249  const FunctionDecl *Callee = nullptr;
250  if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0]))
251  Callee = FD;
252  else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
253  Callee = FTD->getTemplatedDecl();
254  if (!Callee)
255  return true;
256 
257  processCall(E->getRParenLoc(), Callee, {E->getArgs(), E->getNumArgs()});
258  return true;
259  }
260 
261  bool VisitFunctionDecl(FunctionDecl *D) {
262  if (auto *FPT =
263  llvm::dyn_cast<FunctionProtoType>(D->getType().getTypePtr())) {
264  if (!FPT->hasTrailingReturn()) {
265  if (auto FTL = D->getFunctionTypeLoc())
266  addReturnTypeHint(D, FTL.getRParenLoc());
267  }
268  }
269  return true;
270  }
271 
272  bool VisitLambdaExpr(LambdaExpr *E) {
273  FunctionDecl *D = E->getCallOperator();
274  if (!E->hasExplicitResultType())
275  addReturnTypeHint(D, E->hasExplicitParameters()
276  ? D->getFunctionTypeLoc().getRParenLoc()
277  : E->getIntroducerRange().getEnd());
278  return true;
279  }
280 
281  void addReturnTypeHint(FunctionDecl *D, SourceLocation Loc) {
282  auto *AT = D->getReturnType()->getContainedAutoType();
283  if (!AT || AT->getDeducedType().isNull())
284  return;
285  addTypeHint(Loc, D->getReturnType(), /*Prefix=*/"-> ");
286  }
287 
288  bool VisitVarDecl(VarDecl *D) {
289  // Do not show hints for the aggregate in a structured binding,
290  // but show hints for the individual bindings.
291  if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
292  for (auto *Binding : DD->bindings()) {
293  addTypeHint(Binding->getLocation(), Binding->getType(), /*Prefix=*/": ",
294  StructuredBindingPolicy);
295  }
296  return true;
297  }
298 
299  if (D->getType()->getContainedAutoType()) {
300  if (!D->getType()->isDependentType()) {
301  // Our current approach is to place the hint on the variable
302  // and accordingly print the full type
303  // (e.g. for `const auto& x = 42`, print `const int&`).
304  // Alternatively, we could place the hint on the `auto`
305  // (and then just print the type deduced for the `auto`).
306  addTypeHint(D->getLocation(), D->getType(), /*Prefix=*/": ");
307  }
308  }
309 
310  // Handle templates like `int foo(auto x)` with exactly one instantiation.
311  if (auto *PVD = llvm::dyn_cast<ParmVarDecl>(D)) {
312  if (D->getIdentifier() && PVD->getType()->isDependentType() &&
313  !getContainedAutoParamType(D->getTypeSourceInfo()->getTypeLoc())
314  .isNull()) {
315  if (auto *IPVD = getOnlyParamInstantiation(PVD))
316  addTypeHint(D->getLocation(), IPVD->getType(), /*Prefix=*/": ");
317  }
318  }
319 
320  return true;
321  }
322 
323  ParmVarDecl *getOnlyParamInstantiation(ParmVarDecl *D) {
324  auto *TemplateFunction = llvm::dyn_cast<FunctionDecl>(D->getDeclContext());
325  if (!TemplateFunction)
326  return nullptr;
327  auto *InstantiatedFunction = llvm::dyn_cast_or_null<FunctionDecl>(
328  getOnlyInstantiation(TemplateFunction));
329  if (!InstantiatedFunction)
330  return nullptr;
331 
332  unsigned ParamIdx = 0;
333  for (auto *Param : TemplateFunction->parameters()) {
334  // Can't reason about param indexes in the presence of preceding packs.
335  // And if this param is a pack, it may expand to multiple params.
336  if (Param->isParameterPack())
337  return nullptr;
338  if (Param == D)
339  break;
340  ++ParamIdx;
341  }
342  assert(ParamIdx < TemplateFunction->getNumParams() &&
343  "Couldn't find param in list?");
344  assert(ParamIdx < InstantiatedFunction->getNumParams() &&
345  "Instantiated function has fewer (non-pack) parameters?");
346  return InstantiatedFunction->getParamDecl(ParamIdx);
347  }
348 
349  bool VisitInitListExpr(InitListExpr *Syn) {
350  // We receive the syntactic form here (shouldVisitImplicitCode() is false).
351  // This is the one we will ultimately attach designators to.
352  // It may have subobject initializers inlined without braces. The *semantic*
353  // form of the init-list has nested init-lists for these.
354  // getDesignators will look at the semantic form to determine the labels.
355  assert(Syn->isSyntacticForm() && "RAV should not visit implicit code!");
356  if (!Cfg.InlayHints.Designators)
357  return true;
358  if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts()))
359  return true;
360  llvm::DenseMap<SourceLocation, std::string> Designators =
361  getDesignators(Syn);
362  for (const Expr *Init : Syn->inits()) {
363  if (llvm::isa<DesignatedInitExpr>(Init))
364  continue;
365  auto It = Designators.find(Init->getBeginLoc());
366  if (It != Designators.end() &&
367  !isPrecededByParamNameComment(Init, It->second))
368  addDesignatorHint(Init->getSourceRange(), It->second);
369  }
370  return true;
371  }
372 
373  // FIXME: Handle RecoveryExpr to try to hint some invalid calls.
374 
375 private:
376  using NameVec = SmallVector<StringRef, 8>;
377 
378  // The purpose of Anchor is to deal with macros. It should be the call's
379  // opening or closing parenthesis or brace. (Always using the opening would
380  // make more sense but CallExpr only exposes the closing.) We heuristically
381  // assume that if this location does not come from a macro definition, then
382  // the entire argument list likely appears in the main file and can be hinted.
383  void processCall(SourceLocation Anchor, const FunctionDecl *Callee,
384  llvm::ArrayRef<const Expr *> Args) {
385  if (!Cfg.InlayHints.Parameters || Args.size() == 0 || !Callee)
386  return;
387 
388  // If the anchor location comes from a macro definition, there's nowhere to
389  // put hints.
390  if (!AST.getSourceManager().getTopMacroCallerLoc(Anchor).isFileID())
391  return;
392 
393  // The parameter name of a move or copy constructor is not very interesting.
394  if (auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee))
395  if (Ctor->isCopyOrMoveConstructor())
396  return;
397 
398  // Resolve parameter packs to their forwarded parameter
399  auto ForwardedParams = resolveForwardingParameters(Callee);
400 
401  NameVec ParameterNames = chooseParameterNames(ForwardedParams);
402 
403  // Exclude setters (i.e. functions with one argument whose name begins with
404  // "set"), and builtins like std::move/forward/... as their parameter name
405  // is also not likely to be interesting.
406  if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
407  return;
408 
409  for (size_t I = 0; I < ParameterNames.size() && I < Args.size(); ++I) {
410  // Pack expansion expressions cause the 1:1 mapping between arguments and
411  // parameters to break down, so we don't add further inlay hints if we
412  // encounter one.
413  if (isa<PackExpansionExpr>(Args[I])) {
414  break;
415  }
416 
417  StringRef Name = ParameterNames[I];
418  bool NameHint = shouldHintName(Args[I], Name);
419  bool ReferenceHint =
420  shouldHintReference(Callee->getParamDecl(I), ForwardedParams[I]);
421 
422  if (NameHint || ReferenceHint) {
423  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
424  InlayHintKind::Parameter, ReferenceHint ? "&" : "",
425  NameHint ? Name : "", ": ");
426  }
427  }
428  }
429 
430  static bool isSetter(const FunctionDecl *Callee, const NameVec &ParamNames) {
431  if (ParamNames.size() != 1)
432  return false;
433 
434  StringRef Name = getSimpleName(*Callee);
435  if (!Name.startswith_insensitive("set"))
436  return false;
437 
438  // In addition to checking that the function has one parameter and its
439  // name starts with "set", also check that the part after "set" matches
440  // the name of the parameter (ignoring case). The idea here is that if
441  // the parameter name differs, it may contain extra information that
442  // may be useful to show in a hint, as in:
443  // void setTimeout(int timeoutMillis);
444  // This currently doesn't handle cases where params use snake_case
445  // and functions don't, e.g.
446  // void setExceptionHandler(EHFunc exception_handler);
447  // We could improve this by replacing `equals_insensitive` with some
448  // `sloppy_equals` which ignores case and also skips underscores.
449  StringRef WhatItIsSetting = Name.substr(3).ltrim("_");
450  return WhatItIsSetting.equals_insensitive(ParamNames[0]);
451  }
452 
453  // Checks if the callee is one of the builtins
454  // addressof, as_const, forward, move(_if_noexcept)
455  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
456  switch (Callee->getBuiltinID()) {
457  case Builtin::BIaddressof:
458  case Builtin::BIas_const:
459  case Builtin::BIforward:
460  case Builtin::BImove:
461  case Builtin::BImove_if_noexcept:
462  return true;
463  default:
464  return false;
465  }
466  }
467 
468  bool shouldHintName(const Expr *Arg, StringRef ParamName) {
469  if (ParamName.empty())
470  return false;
471 
472  // If the argument expression is a single name and it matches the
473  // parameter name exactly, omit the name hint.
474  if (ParamName == getSpelledIdentifier(Arg))
475  return false;
476 
477  // Exclude argument expressions preceded by a /*paramName*/.
478  if (isPrecededByParamNameComment(Arg, ParamName))
479  return false;
480 
481  return true;
482  }
483 
484  bool shouldHintReference(const ParmVarDecl *Param,
485  const ParmVarDecl *ForwardedParam) {
486  // We add a & hint only when the argument is passed as mutable reference.
487  // For parameters that are not part of an expanded pack, this is
488  // straightforward. For expanded pack parameters, it's likely that they will
489  // be forwarded to another function. In this situation, we only want to add
490  // the reference hint if the argument is actually being used via mutable
491  // reference. This means we need to check
492  // 1. whether the value category of the argument is preserved, i.e. each
493  // pack expansion uses std::forward correctly.
494  // 2. whether the argument is ever copied/cast instead of passed
495  // by-reference
496  // Instead of checking this explicitly, we use the following proxy:
497  // 1. the value category can only change from rvalue to lvalue during
498  // forwarding, so checking whether both the parameter of the forwarding
499  // function and the forwarded function are lvalue references detects such
500  // a conversion.
501  // 2. if the argument is copied/cast somewhere in the chain of forwarding
502  // calls, it can only be passed on to an rvalue reference or const lvalue
503  // reference parameter. Thus if the forwarded parameter is a mutable
504  // lvalue reference, it cannot have been copied/cast to on the way.
505  // Additionally, we should not add a reference hint if the forwarded
506  // parameter was only partially resolved, i.e. points to an expanded pack
507  // parameter, since we do not know how it will be used eventually.
508  auto Type = Param->getType();
509  auto ForwardedType = ForwardedParam->getType();
510  return Type->isLValueReferenceType() &&
511  ForwardedType->isLValueReferenceType() &&
512  !ForwardedType.getNonReferenceType().isConstQualified() &&
513  !isExpandedFromParameterPack(ForwardedParam);
514  }
515 
516  // Checks if "E" is spelled in the main file and preceded by a C-style comment
517  // whose contents match ParamName (allowing for whitespace and an optional "="
518  // at the end.
519  bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
520  auto &SM = AST.getSourceManager();
521  auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
522  auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
523  if (Decomposed.first != MainFileID)
524  return false;
525 
526  StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
527  // Allow whitespace between comment and expression.
528  SourcePrefix = SourcePrefix.rtrim();
529  // Check for comment ending.
530  if (!SourcePrefix.consume_back("*/"))
531  return false;
532  // Ignore some punctuation and whitespace around comment.
533  // In particular this allows designators to match nicely.
534  llvm::StringLiteral IgnoreChars = " =.";
535  SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
536  ParamName = ParamName.trim(IgnoreChars);
537  // Other than that, the comment must contain exactly ParamName.
538  if (!SourcePrefix.consume_back(ParamName))
539  return false;
540  SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
541  return SourcePrefix.endswith("/*");
542  }
543 
544  // If "E" spells a single unqualified identifier, return that name.
545  // Otherwise, return an empty string.
546  static StringRef getSpelledIdentifier(const Expr *E) {
547  E = E->IgnoreUnlessSpelledInSource();
548 
549  if (auto *DRE = dyn_cast<DeclRefExpr>(E))
550  if (!DRE->getQualifier())
551  return getSimpleName(*DRE->getDecl());
552 
553  if (auto *ME = dyn_cast<MemberExpr>(E))
554  if (!ME->getQualifier() && ME->isImplicitAccess())
555  return getSimpleName(*ME->getMemberDecl());
556 
557  return {};
558  }
559 
560  NameVec chooseParameterNames(SmallVector<const ParmVarDecl *> Parameters) {
561  NameVec ParameterNames;
562  for (const auto *P : Parameters) {
564  // If we haven't resolved a pack paramater (e.g. foo(Args... args)) to a
565  // non-pack parameter, then hinting as foo(args: 1, args: 2, args: 3) is
566  // unlikely to be useful.
567  ParameterNames.emplace_back();
568  } else {
569  auto SimpleName = getSimpleName(*P);
570  // If the parameter is unnamed in the declaration:
571  // attempt to get its name from the definition
572  if (SimpleName.empty()) {
573  if (const auto *PD = getParamDefinition(P)) {
574  SimpleName = getSimpleName(*PD);
575  }
576  }
577  ParameterNames.emplace_back(SimpleName);
578  }
579  }
580 
581  // Standard library functions often have parameter names that start
582  // with underscores, which makes the hints noisy, so strip them out.
583  for (auto &Name : ParameterNames)
584  stripLeadingUnderscores(Name);
585 
586  return ParameterNames;
587  }
588 
589  // for a ParmVarDecl from a function declaration, returns the corresponding
590  // ParmVarDecl from the definition if possible, nullptr otherwise.
591  static const ParmVarDecl *getParamDefinition(const ParmVarDecl *P) {
592  if (auto *Callee = dyn_cast<FunctionDecl>(P->getDeclContext())) {
593  if (auto *Def = Callee->getDefinition()) {
594  auto I = std::distance(
595  Callee->param_begin(),
596  std::find(Callee->param_begin(), Callee->param_end(), P));
597  if (I < Callee->getNumParams()) {
598  return Def->getParamDecl(I);
599  }
600  }
601  }
602  return nullptr;
603  }
604 
605  static void stripLeadingUnderscores(StringRef &Name) {
606  Name = Name.ltrim('_');
607  }
608 
609  static StringRef getSimpleName(const NamedDecl &D) {
610  if (IdentifierInfo *Ident = D.getDeclName().getAsIdentifierInfo()) {
611  return Ident->getName();
612  }
613 
614  return StringRef();
615  }
616 
617  // We pass HintSide rather than SourceLocation because we want to ensure
618  // it is in the same file as the common file range.
619  void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind,
620  llvm::StringRef Prefix, llvm::StringRef Label,
621  llvm::StringRef Suffix) {
622  // We shouldn't get as far as adding a hint if the category is disabled.
623  // We'd like to disable as much of the analysis as possible above instead.
624  // Assert in debug mode but add a dynamic check in production.
625  assert(Cfg.InlayHints.Enabled && "Shouldn't get here if disabled!");
626  switch (Kind) {
627 #define CHECK_KIND(Enumerator, ConfigProperty) \
628  case InlayHintKind::Enumerator: \
629  assert(Cfg.InlayHints.ConfigProperty && \
630  "Shouldn't get here if kind is disabled!"); \
631  if (!Cfg.InlayHints.ConfigProperty) \
632  return; \
633  break
634  CHECK_KIND(Parameter, Parameters);
635  CHECK_KIND(Type, DeducedTypes);
636  CHECK_KIND(Designator, Designators);
637 #undef CHECK_KIND
638  }
639 
640  auto FileRange =
641  toHalfOpenFileRange(AST.getSourceManager(), AST.getLangOpts(), R);
642  if (!FileRange)
643  return;
644  Range LSPRange{
645  sourceLocToPosition(AST.getSourceManager(), FileRange->getBegin()),
646  sourceLocToPosition(AST.getSourceManager(), FileRange->getEnd())};
647  Position LSPPos = Side == HintSide::Left ? LSPRange.start : LSPRange.end;
648  if (RestrictRange &&
649  (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end)))
650  return;
651  // The hint may be in a file other than the main file (for example, a header
652  // file that was included after the preamble), do not show in that case.
653  if (!AST.getSourceManager().isWrittenInMainFile(FileRange->getBegin()))
654  return;
655  bool PadLeft = Prefix.consume_front(" ");
656  bool PadRight = Suffix.consume_back(" ");
657  Results.push_back(InlayHint{LSPPos, (Prefix + Label + Suffix).str(), Kind,
658  PadLeft, PadRight, LSPRange});
659  }
660 
661  void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
662  addTypeHint(R, T, Prefix, TypeHintPolicy);
663  }
664 
665  void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix,
666  const PrintingPolicy &Policy) {
667  if (!Cfg.InlayHints.DeducedTypes || T.isNull())
668  return;
669 
670  std::string TypeName = T.getAsString(Policy);
671  if (TypeName.length() < TypeNameLimit)
672  addInlayHint(R, HintSide::Right, InlayHintKind::Type, Prefix, TypeName,
673  /*Suffix=*/"");
674  }
675 
676  void addDesignatorHint(SourceRange R, llvm::StringRef Text) {
677  addInlayHint(R, HintSide::Left, InlayHintKind::Designator,
678  /*Prefix=*/"", Text, /*Suffix=*/"=");
679  }
680 
681  std::vector<InlayHint> &Results;
682  ASTContext &AST;
683  const Config &Cfg;
684  llvm::Optional<Range> RestrictRange;
685  FileID MainFileID;
686  StringRef MainFileBuf;
687  const HeuristicResolver *Resolver;
688  // We want to suppress default template arguments, but otherwise print
689  // canonical types. Unfortunately, they're conflicting policies so we can't
690  // have both. For regular types, suppressing template arguments is more
691  // important, whereas printing canonical types is crucial for structured
692  // bindings, so we use two separate policies. (See the constructor where
693  // the policies are initialized for more details.)
694  PrintingPolicy TypeHintPolicy;
695  PrintingPolicy StructuredBindingPolicy;
696 
697  static const size_t TypeNameLimit = 32;
698 };
699 
700 } // namespace
701 
702 std::vector<InlayHint> inlayHints(ParsedAST &AST,
703  llvm::Optional<Range> RestrictRange) {
704  std::vector<InlayHint> Results;
705  const auto &Cfg = Config::current();
706  if (!Cfg.InlayHints.Enabled)
707  return Results;
708  InlayHintVisitor Visitor(Results, AST, Cfg, std::move(RestrictRange));
709  Visitor.TraverseAST(AST.getASTContext());
710 
711  // De-duplicate hints. Duplicates can sometimes occur due to e.g. explicit
712  // template instantiations.
713  llvm::sort(Results);
714  Results.erase(std::unique(Results.begin(), Results.end()), Results.end());
715 
716  return Results;
717 }
718 
719 } // namespace clangd
720 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:39
Loc
SourceLocation Loc
Definition: KernelNameRestrictionCheck.cpp:45
clang::clangd::InlayHintKind::Designator
@ Designator
A hint before an element of an aggregate braced initializer list, indicating what it is initializing.
Suffix
std::string Suffix
Definition: AddUsing.cpp:113
RecursiveASTVisitor
clang::clangd::Config::Enabled
bool Enabled
If false, inlay hints are completely disabled.
Definition: Config.h:136
Label
std::string Label
Definition: InlayHintTests.cpp:46
clang::tidy::utils::fixit::QualifierPolicy::Right
@ Right
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::clangd::toHalfOpenFileRange
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
Definition: SourceCode.cpp:421
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::isExpandedFromParameterPack
bool isExpandedFromParameterPack(const ParmVarDecl *D)
Checks whether D is instantiated from a function parameter pack whose type is a bare type parameter p...
Definition: AST.cpp:981
clang::clangd::ParsedAST::getASTContext
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:698
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:59
clang::clangd::sourceLocToPosition
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:213
clang::clangd::resolveForwardingParameters
SmallVector< const ParmVarDecl * > resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth)
Recursively resolves the parameters of a FunctionDecl that forwards its parameters to another functio...
Definition: AST.cpp:924
InlayHints.h
clang::tidy::utils::fixit::QualifierPolicy::Left
@ Left
CHECK_KIND
#define CHECK_KIND(Enumerator, ConfigProperty)
clang::clangd::isReservedName
bool isReservedName(llvm::StringRef Name)
Returns true if Name is reserved, like _Foo or __Vector_base.
Definition: SourceCode.h:334
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::tidy::bugprone::model::MixFlags::Invalid
@ Invalid
Sentinel bit pattern. DO NOT USE!
Config
static cl::opt< std::string > Config("config", cl::desc(R"( Specifies a configuration in YAML/JSON format: -config="{Checks:' *', CheckOptions:{x:y}}" When the value is empty, clang-tidy will attempt to find a file named .clang-tidy for each source file in its parent directories. )"), cl::init(""), cl::cat(ClangTidyCategory))
Args
llvm::json::Object Args
Definition: Trace.cpp:138
clang::clangd::getOnlyInstantiation
NamedDecl * getOnlyInstantiation(NamedDecl *TemplatedDecl)
Definition: AST.cpp:602
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:784
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::clangd::getContainedAutoParamType
TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL)
Definition: AST.cpp:575
Index
const SymbolIndex * Index
Definition: Dexp.cpp:98
HeuristicResolver.h
Config.h
clang::clangd::InlayHintKind::Type
@ Type
An inlay hint that for a type annotation.
clang::clangd::Config::InlayHints
struct clang::clangd::Config::@8 InlayHints
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::Config::current
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
Definition: Config.cpp:17
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:46
Parameters
ArrayRef< const ParmVarDecl * > Parameters
Definition: AST.cpp:779
clang::clangd::inlayHints
std::vector< InlayHint > inlayHints(ParsedAST &AST, llvm::Optional< Range > RestrictRange)
Compute and return inlay hints for a file.
Definition: InlayHints.cpp:702
Side
HintSide Side
Definition: InlayHintTests.cpp:48
clang::clangd::InlayHintKind
InlayHintKind
Inlay hint kinds.
Definition: Protocol.h:1543
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:99
AST.h
ParsedAST.h
clang::clangd::InlayHintKind::Parameter
@ Parameter
An inlay hint that is for a parameter.