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 "SourceCode.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclarationName.h"
16 #include "clang/AST/ExprCXX.h"
17 #include "clang/AST/RecursiveASTVisitor.h"
18 #include "clang/Basic/Builtins.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "llvm/ADT/ScopeExit.h"
21 
22 namespace clang {
23 namespace clangd {
24 namespace {
25 
26 // For now, inlay hints are always anchored at the left or right of their range.
27 enum class HintSide { Left, Right };
28 
29 // Helper class to iterate over the designator names of an aggregate type.
30 //
31 // For an array type, yields [0], [1], [2]...
32 // For aggregate classes, yields null for each base, then .field1, .field2, ...
33 class AggregateDesignatorNames {
34 public:
35  AggregateDesignatorNames(QualType T) {
36  if (!T.isNull()) {
37  T = T.getCanonicalType();
38  if (T->isArrayType()) {
39  IsArray = true;
40  Valid = true;
41  return;
42  }
43  if (const RecordDecl *RD = T->getAsRecordDecl()) {
44  Valid = true;
45  FieldsIt = RD->field_begin();
46  FieldsEnd = RD->field_end();
47  if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
48  BasesIt = CRD->bases_begin();
49  BasesEnd = CRD->bases_end();
50  Valid = CRD->isAggregate();
51  }
52  OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&
53  std::next(FieldsIt) == FieldsEnd;
54  }
55  }
56  }
57  // Returns false if the type was not an aggregate.
58  operator bool() { return Valid; }
59  // Advance to the next element in the aggregate.
60  void next() {
61  if (IsArray)
62  ++Index;
63  else if (BasesIt != BasesEnd)
64  ++BasesIt;
65  else if (FieldsIt != FieldsEnd)
66  ++FieldsIt;
67  }
68  // Print the designator to Out.
69  // Returns false if we could not produce a designator for this element.
70  bool append(std::string &Out, bool ForSubobject) {
71  if (IsArray) {
72  Out.push_back('[');
73  Out.append(std::to_string(Index));
74  Out.push_back(']');
75  return true;
76  }
77  if (BasesIt != BasesEnd)
78  return false; // Bases can't be designated. Should we make one up?
79  if (FieldsIt != FieldsEnd) {
80  llvm::StringRef FieldName;
81  if (const IdentifierInfo *II = FieldsIt->getIdentifier())
82  FieldName = II->getName();
83 
84  // For certain objects, their subobjects may be named directly.
85  if (ForSubobject &&
86  (FieldsIt->isAnonymousStructOrUnion() ||
87  // std::array<int,3> x = {1,2,3}. Designators not strictly valid!
88  (OneField && isReservedName(FieldName))))
89  return true;
90 
91  if (!FieldName.empty() && !isReservedName(FieldName)) {
92  Out.push_back('.');
93  Out.append(FieldName.begin(), FieldName.end());
94  return true;
95  }
96  return false;
97  }
98  return false;
99  }
100 
101 private:
102  bool Valid = false;
103  bool IsArray = false;
104  bool OneField = false; // e.g. std::array { T __elements[N]; }
105  unsigned Index = 0;
106  CXXRecordDecl::base_class_const_iterator BasesIt;
107  CXXRecordDecl::base_class_const_iterator BasesEnd;
108  RecordDecl::field_iterator FieldsIt;
109  RecordDecl::field_iterator FieldsEnd;
110 };
111 
112 // Collect designator labels describing the elements of an init list.
113 //
114 // This function contributes the designators of some (sub)object, which is
115 // represented by the semantic InitListExpr Sem.
116 // This includes any nested subobjects, but *only* if they are part of the same
117 // original syntactic init list (due to brace elision).
118 // In other words, it may descend into subobjects but not written init-lists.
119 //
120 // For example: struct Outer { Inner a,b; }; struct Inner { int x, y; }
121 // Outer o{{1, 2}, 3};
122 // This function will be called with Sem = { {1, 2}, {3, ImplicitValue} }
123 // It should generate designators '.a:' and '.b.x:'.
124 // '.a:' is produced directly without recursing into the written sublist.
125 // (The written sublist will have a separate collectDesignators() call later).
126 // Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'.
127 void collectDesignators(const InitListExpr *Sem,
128  llvm::DenseMap<SourceLocation, std::string> &Out,
129  const llvm::DenseSet<SourceLocation> &NestedBraces,
130  std::string &Prefix) {
131  if (!Sem || Sem->isTransparent())
132  return;
133  assert(Sem->isSemanticForm());
134 
135  // The elements of the semantic form all correspond to direct subobjects of
136  // the aggregate type. `Fields` iterates over these subobject names.
137  AggregateDesignatorNames Fields(Sem->getType());
138  if (!Fields)
139  return;
140  for (const Expr *Init : Sem->inits()) {
141  auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {
142  Fields.next(); // Always advance to the next subobject name.
143  Prefix.resize(Size); // Erase any designator we appended.
144  });
145  // Skip for a broken initializer or if it is a "hole" in a subobject that
146  // was not explicitly initialized.
147  if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))
148  continue;
149 
150  const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);
151  if (BraceElidedSubobject &&
152  NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))
153  BraceElidedSubobject = nullptr; // there were braces!
154 
155  if (!Fields.append(Prefix, BraceElidedSubobject != nullptr))
156  continue; // no designator available for this subobject
157  if (BraceElidedSubobject) {
158  // If the braces were elided, this aggregate subobject is initialized
159  // inline in the same syntactic list.
160  // Descend into the semantic list describing the subobject.
161  // (NestedBraces are still correct, they're from the same syntactic list).
162  collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix);
163  continue;
164  }
165  Out.try_emplace(Init->getBeginLoc(), Prefix);
166  }
167 }
168 
169 // Get designators describing the elements of a (syntactic) init list.
170 // This does not produce designators for any explicitly-written nested lists.
171 llvm::DenseMap<SourceLocation, std::string>
172 getDesignators(const InitListExpr *Syn) {
173  assert(Syn->isSyntacticForm());
174 
175  // collectDesignators needs to know which InitListExprs in the semantic tree
176  // were actually written, but InitListExpr::isExplicit() lies.
177  // Instead, record where braces of sub-init-lists occur in the syntactic form.
178  llvm::DenseSet<SourceLocation> NestedBraces;
179  for (const Expr *Init : Syn->inits())
180  if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init))
181  NestedBraces.insert(Nested->getLBraceLoc());
182 
183  // Traverse the semantic form to find the designators.
184  // We use their SourceLocation to correlate with the syntactic form later.
185  llvm::DenseMap<SourceLocation, std::string> Designators;
186  std::string EmptyPrefix;
187  collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),
188  Designators, NestedBraces, EmptyPrefix);
189  return Designators;
190 }
191 
192 class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
193 public:
194  InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST,
195  const Config &Cfg, llvm::Optional<Range> RestrictRange)
196  : Results(Results), AST(AST.getASTContext()), Tokens(AST.getTokens()),
197  Cfg(Cfg), RestrictRange(std::move(RestrictRange)),
198  MainFileID(AST.getSourceManager().getMainFileID()),
199  Resolver(AST.getHeuristicResolver()),
200  TypeHintPolicy(this->AST.getPrintingPolicy()),
201  StructuredBindingPolicy(this->AST.getPrintingPolicy()) {
202  bool Invalid = false;
203  llvm::StringRef Buf =
204  AST.getSourceManager().getBufferData(MainFileID, &Invalid);
205  MainFileBuf = Invalid ? StringRef{} : Buf;
206 
207  TypeHintPolicy.SuppressScope = true; // keep type names short
208  TypeHintPolicy.AnonymousTagLocations =
209  false; // do not print lambda locations
210 
211  // For structured bindings, print canonical types. This is important because
212  // for bindings that use the tuple_element protocol, the non-canonical types
213  // would be "tuple_element<I, A>::type".
214  // For "auto", we often prefer sugared types.
215  // Not setting PrintCanonicalTypes for "auto" allows
216  // SuppressDefaultTemplateArgs (set by default) to have an effect.
217  StructuredBindingPolicy = TypeHintPolicy;
218  StructuredBindingPolicy.PrintCanonicalTypes = true;
219  }
220 
221  bool VisitCXXConstructExpr(CXXConstructExpr *E) {
222  // Weed out constructor calls that don't look like a function call with
223  // an argument list, by checking the validity of getParenOrBraceRange().
224  // Also weed out std::initializer_list constructors as there are no names
225  // for the individual arguments.
226  if (!E->getParenOrBraceRange().isValid() ||
227  E->isStdInitListInitialization()) {
228  return true;
229  }
230 
231  processCall(E->getConstructor(), {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(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, SourceRange Range) {
282  auto *AT = D->getReturnType()->getContainedAutoType();
283  if (!AT || AT->getDeducedType().isNull())
284  return;
285  addTypeHint(Range, 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  void processCall(const FunctionDecl *Callee,
379  llvm::ArrayRef<const Expr *> Args) {
380  if (!Cfg.InlayHints.Parameters || Args.size() == 0 || !Callee)
381  return;
382 
383  // The parameter name of a move or copy constructor is not very interesting.
384  if (auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee))
385  if (Ctor->isCopyOrMoveConstructor())
386  return;
387 
388  // Resolve parameter packs to their forwarded parameter
389  auto ForwardedParams = resolveForwardingParameters(Callee);
390 
391  NameVec ParameterNames = chooseParameterNames(ForwardedParams);
392 
393  // Exclude setters (i.e. functions with one argument whose name begins with
394  // "set"), and builtins like std::move/forward/... as their parameter name
395  // is also not likely to be interesting.
396  if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
397  return;
398 
399  for (size_t I = 0; I < ParameterNames.size() && I < Args.size(); ++I) {
400  // Pack expansion expressions cause the 1:1 mapping between arguments and
401  // parameters to break down, so we don't add further inlay hints if we
402  // encounter one.
403  if (isa<PackExpansionExpr>(Args[I])) {
404  break;
405  }
406 
407  StringRef Name = ParameterNames[I];
408  bool NameHint = shouldHintName(Args[I], Name);
409  bool ReferenceHint =
410  shouldHintReference(Callee->getParamDecl(I), ForwardedParams[I]);
411 
412  if (NameHint || ReferenceHint) {
413  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
414  InlayHintKind::Parameter, ReferenceHint ? "&" : "",
415  NameHint ? Name : "", ": ");
416  }
417  }
418  }
419 
420  static bool isSetter(const FunctionDecl *Callee, const NameVec &ParamNames) {
421  if (ParamNames.size() != 1)
422  return false;
423 
424  StringRef Name = getSimpleName(*Callee);
425  if (!Name.startswith_insensitive("set"))
426  return false;
427 
428  // In addition to checking that the function has one parameter and its
429  // name starts with "set", also check that the part after "set" matches
430  // the name of the parameter (ignoring case). The idea here is that if
431  // the parameter name differs, it may contain extra information that
432  // may be useful to show in a hint, as in:
433  // void setTimeout(int timeoutMillis);
434  // This currently doesn't handle cases where params use snake_case
435  // and functions don't, e.g.
436  // void setExceptionHandler(EHFunc exception_handler);
437  // We could improve this by replacing `equals_insensitive` with some
438  // `sloppy_equals` which ignores case and also skips underscores.
439  StringRef WhatItIsSetting = Name.substr(3).ltrim("_");
440  return WhatItIsSetting.equals_insensitive(ParamNames[0]);
441  }
442 
443  // Checks if the callee is one of the builtins
444  // addressof, as_const, forward, move(_if_noexcept)
445  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
446  switch (Callee->getBuiltinID()) {
447  case Builtin::BIaddressof:
448  case Builtin::BIas_const:
449  case Builtin::BIforward:
450  case Builtin::BImove:
451  case Builtin::BImove_if_noexcept:
452  return true;
453  default:
454  return false;
455  }
456  }
457 
458  bool shouldHintName(const Expr *Arg, StringRef ParamName) {
459  if (ParamName.empty())
460  return false;
461 
462  // If the argument expression is a single name and it matches the
463  // parameter name exactly, omit the name hint.
464  if (ParamName == getSpelledIdentifier(Arg))
465  return false;
466 
467  // Exclude argument expressions preceded by a /*paramName*/.
468  if (isPrecededByParamNameComment(Arg, ParamName))
469  return false;
470 
471  return true;
472  }
473 
474  bool shouldHintReference(const ParmVarDecl *Param,
475  const ParmVarDecl *ForwardedParam) {
476  // We add a & hint only when the argument is passed as mutable reference.
477  // For parameters that are not part of an expanded pack, this is
478  // straightforward. For expanded pack parameters, it's likely that they will
479  // be forwarded to another function. In this situation, we only want to add
480  // the reference hint if the argument is actually being used via mutable
481  // reference. This means we need to check
482  // 1. whether the value category of the argument is preserved, i.e. each
483  // pack expansion uses std::forward correctly.
484  // 2. whether the argument is ever copied/cast instead of passed
485  // by-reference
486  // Instead of checking this explicitly, we use the following proxy:
487  // 1. the value category can only change from rvalue to lvalue during
488  // forwarding, so checking whether both the parameter of the forwarding
489  // function and the forwarded function are lvalue references detects such
490  // a conversion.
491  // 2. if the argument is copied/cast somewhere in the chain of forwarding
492  // calls, it can only be passed on to an rvalue reference or const lvalue
493  // reference parameter. Thus if the forwarded parameter is a mutable
494  // lvalue reference, it cannot have been copied/cast to on the way.
495  // Additionally, we should not add a reference hint if the forwarded
496  // parameter was only partially resolved, i.e. points to an expanded pack
497  // parameter, since we do not know how it will be used eventually.
498  auto Type = Param->getType();
499  auto ForwardedType = ForwardedParam->getType();
500  return Type->isLValueReferenceType() &&
501  ForwardedType->isLValueReferenceType() &&
502  !ForwardedType.getNonReferenceType().isConstQualified() &&
503  !isExpandedFromParameterPack(ForwardedParam);
504  }
505 
506  // Checks if "E" is spelled in the main file and preceded by a C-style comment
507  // whose contents match ParamName (allowing for whitespace and an optional "="
508  // at the end.
509  bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
510  auto &SM = AST.getSourceManager();
511  auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
512  auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
513  if (Decomposed.first != MainFileID)
514  return false;
515 
516  StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
517  // Allow whitespace between comment and expression.
518  SourcePrefix = SourcePrefix.rtrim();
519  // Check for comment ending.
520  if (!SourcePrefix.consume_back("*/"))
521  return false;
522  // Ignore some punctuation and whitespace around comment.
523  // In particular this allows designators to match nicely.
524  llvm::StringLiteral IgnoreChars = " =.";
525  SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
526  ParamName = ParamName.trim(IgnoreChars);
527  // Other than that, the comment must contain exactly ParamName.
528  if (!SourcePrefix.consume_back(ParamName))
529  return false;
530  SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
531  return SourcePrefix.endswith("/*");
532  }
533 
534  // If "E" spells a single unqualified identifier, return that name.
535  // Otherwise, return an empty string.
536  static StringRef getSpelledIdentifier(const Expr *E) {
537  E = E->IgnoreUnlessSpelledInSource();
538 
539  if (auto *DRE = dyn_cast<DeclRefExpr>(E))
540  if (!DRE->getQualifier())
541  return getSimpleName(*DRE->getDecl());
542 
543  if (auto *ME = dyn_cast<MemberExpr>(E))
544  if (!ME->getQualifier() && ME->isImplicitAccess())
545  return getSimpleName(*ME->getMemberDecl());
546 
547  return {};
548  }
549 
550  NameVec chooseParameterNames(SmallVector<const ParmVarDecl *> Parameters) {
551  NameVec ParameterNames;
552  for (const auto *P : Parameters) {
554  // If we haven't resolved a pack paramater (e.g. foo(Args... args)) to a
555  // non-pack parameter, then hinting as foo(args: 1, args: 2, args: 3) is
556  // unlikely to be useful.
557  ParameterNames.emplace_back();
558  } else {
559  auto SimpleName = getSimpleName(*P);
560  // If the parameter is unnamed in the declaration:
561  // attempt to get its name from the definition
562  if (SimpleName.empty()) {
563  if (const auto *PD = getParamDefinition(P)) {
564  SimpleName = getSimpleName(*PD);
565  }
566  }
567  ParameterNames.emplace_back(SimpleName);
568  }
569  }
570 
571  // Standard library functions often have parameter names that start
572  // with underscores, which makes the hints noisy, so strip them out.
573  for (auto &Name : ParameterNames)
574  stripLeadingUnderscores(Name);
575 
576  return ParameterNames;
577  }
578 
579  // for a ParmVarDecl from a function declaration, returns the corresponding
580  // ParmVarDecl from the definition if possible, nullptr otherwise.
581  static const ParmVarDecl *getParamDefinition(const ParmVarDecl *P) {
582  if (auto *Callee = dyn_cast<FunctionDecl>(P->getDeclContext())) {
583  if (auto *Def = Callee->getDefinition()) {
584  auto I = std::distance(Callee->param_begin(),
585  llvm::find(Callee->parameters(), P));
586  if (I < Callee->getNumParams()) {
587  return Def->getParamDecl(I);
588  }
589  }
590  }
591  return nullptr;
592  }
593 
594  static void stripLeadingUnderscores(StringRef &Name) {
595  Name = Name.ltrim('_');
596  }
597 
598  static StringRef getSimpleName(const NamedDecl &D) {
599  if (IdentifierInfo *Ident = D.getDeclName().getAsIdentifierInfo()) {
600  return Ident->getName();
601  }
602 
603  return StringRef();
604  }
605 
606  // We pass HintSide rather than SourceLocation because we want to ensure
607  // it is in the same file as the common file range.
608  void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind,
609  llvm::StringRef Prefix, llvm::StringRef Label,
610  llvm::StringRef Suffix) {
611  // We shouldn't get as far as adding a hint if the category is disabled.
612  // We'd like to disable as much of the analysis as possible above instead.
613  // Assert in debug mode but add a dynamic check in production.
614  assert(Cfg.InlayHints.Enabled && "Shouldn't get here if disabled!");
615  switch (Kind) {
616 #define CHECK_KIND(Enumerator, ConfigProperty) \
617  case InlayHintKind::Enumerator: \
618  assert(Cfg.InlayHints.ConfigProperty && \
619  "Shouldn't get here if kind is disabled!"); \
620  if (!Cfg.InlayHints.ConfigProperty) \
621  return; \
622  break
623  CHECK_KIND(Parameter, Parameters);
624  CHECK_KIND(Type, DeducedTypes);
625  CHECK_KIND(Designator, Designators);
626 #undef CHECK_KIND
627  }
628 
629  auto LSPRange = getHintRange(R);
630  if (!LSPRange)
631  return;
632  Position LSPPos = Side == HintSide::Left ? LSPRange->start : LSPRange->end;
633  if (RestrictRange &&
634  (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end)))
635  return;
636  bool PadLeft = Prefix.consume_front(" ");
637  bool PadRight = Suffix.consume_back(" ");
638  Results.push_back(InlayHint{LSPPos, (Prefix + Label + Suffix).str(), Kind,
639  PadLeft, PadRight, *LSPRange});
640  }
641 
642  // Get the range of the main file that *exactly* corresponds to R.
643  llvm::Optional<Range> getHintRange(SourceRange R) {
644  const auto &SM = AST.getSourceManager();
645  auto Spelled = Tokens.spelledForExpanded(Tokens.expandedTokens(R));
646  // TokenBuffer will return null if e.g. R corresponds to only part of a
647  // macro expansion.
648  if (!Spelled || Spelled->empty())
649  return llvm::None;
650  // Hint must be within the main file, not e.g. a non-preamble include.
651  if (SM.getFileID(Spelled->front().location()) != SM.getMainFileID() ||
652  SM.getFileID(Spelled->back().location()) != SM.getMainFileID())
653  return llvm::None;
654  return Range{sourceLocToPosition(SM, Spelled->front().location()),
655  sourceLocToPosition(SM, Spelled->back().endLocation())};
656  }
657 
658  void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
659  addTypeHint(R, T, Prefix, TypeHintPolicy);
660  }
661 
662  void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix,
663  const PrintingPolicy &Policy) {
664  if (!Cfg.InlayHints.DeducedTypes || T.isNull())
665  return;
666 
667  std::string TypeName = T.getAsString(Policy);
668  if (TypeName.length() < TypeNameLimit)
669  addInlayHint(R, HintSide::Right, InlayHintKind::Type, Prefix, TypeName,
670  /*Suffix=*/"");
671  }
672 
673  void addDesignatorHint(SourceRange R, llvm::StringRef Text) {
674  addInlayHint(R, HintSide::Left, InlayHintKind::Designator,
675  /*Prefix=*/"", Text, /*Suffix=*/"=");
676  }
677 
678  std::vector<InlayHint> &Results;
679  ASTContext &AST;
680  const syntax::TokenBuffer &Tokens;
681  const Config &Cfg;
682  llvm::Optional<Range> RestrictRange;
683  FileID MainFileID;
684  StringRef MainFileBuf;
685  const HeuristicResolver *Resolver;
686  // We want to suppress default template arguments, but otherwise print
687  // canonical types. Unfortunately, they're conflicting policies so we can't
688  // have both. For regular types, suppressing template arguments is more
689  // important, whereas printing canonical types is crucial for structured
690  // bindings, so we use two separate policies. (See the constructor where
691  // the policies are initialized for more details.)
692  PrintingPolicy TypeHintPolicy;
693  PrintingPolicy StructuredBindingPolicy;
694 
695  static const size_t TypeNameLimit = 32;
696 };
697 
698 } // namespace
699 
700 std::vector<InlayHint> inlayHints(ParsedAST &AST,
701  llvm::Optional<Range> RestrictRange) {
702  std::vector<InlayHint> Results;
703  const auto &Cfg = Config::current();
704  if (!Cfg.InlayHints.Enabled)
705  return Results;
706  InlayHintVisitor Visitor(Results, AST, Cfg, std::move(RestrictRange));
707  Visitor.TraverseAST(AST.getASTContext());
708 
709  // De-duplicate hints. Duplicates can sometimes occur due to e.g. explicit
710  // template instantiations.
711  llvm::sort(Results);
712  Results.erase(std::unique(Results.begin(), Results.end()), Results.end());
713 
714  return Results;
715 }
716 
717 } // namespace clangd
718 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:39
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
Type
NodeType Type
Definition: HTMLGenerator.cpp:74
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:984
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:700
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:927
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:329
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:605
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:792
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::clangd::getContainedAutoParamType
TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL)
Definition: AST.cpp:578
SourceCode.h
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::RefKind::Spelled
@ Spelled
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:782
clang::clangd::inlayHints
std::vector< InlayHint > inlayHints(ParsedAST &AST, llvm::Optional< Range > RestrictRange)
Compute and return inlay hints for a file.
Definition: InlayHints.cpp:700
Side
HintSide Side
Definition: InlayHintTests.cpp:48
clang::clangd::InlayHintKind
InlayHintKind
Inlay hint kinds.
Definition: Protocol.h:1560
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:99
AST.h
ParsedAST.h
clang::clangd::InlayHintKind::Parameter
@ Parameter
An inlay hint that is for a parameter.