xref: /llvm-project/clang-tools-extra/clangd/InlayHints.cpp (revision ae932becb2c952876edbb3591bfa997bf4629a4d)
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 "../clang-tidy/utils/DesignatedInitializers.h"
10 #include "AST.h"
11 #include "Config.h"
12 #include "ParsedAST.h"
13 #include "Protocol.h"
14 #include "SourceCode.h"
15 #include "clang/AST/ASTDiagnostic.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclBase.h"
18 #include "clang/AST/DeclarationName.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprCXX.h"
21 #include "clang/AST/RecursiveASTVisitor.h"
22 #include "clang/AST/Stmt.h"
23 #include "clang/AST/StmtVisitor.h"
24 #include "clang/AST/Type.h"
25 #include "clang/Basic/Builtins.h"
26 #include "clang/Basic/OperatorKinds.h"
27 #include "clang/Basic/SourceLocation.h"
28 #include "clang/Basic/SourceManager.h"
29 #include "clang/Sema/HeuristicResolver.h"
30 #include "llvm/ADT/DenseSet.h"
31 #include "llvm/ADT/STLExtras.h"
32 #include "llvm/ADT/SmallVector.h"
33 #include "llvm/ADT/StringExtras.h"
34 #include "llvm/ADT/StringRef.h"
35 #include "llvm/ADT/Twine.h"
36 #include "llvm/Support/Casting.h"
37 #include "llvm/Support/ErrorHandling.h"
38 #include "llvm/Support/FormatVariadic.h"
39 #include "llvm/Support/SaveAndRestore.h"
40 #include "llvm/Support/ScopedPrinter.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include <algorithm>
43 #include <iterator>
44 #include <optional>
45 #include <string>
46 
47 namespace clang {
48 namespace clangd {
49 namespace {
50 
51 // For now, inlay hints are always anchored at the left or right of their range.
52 enum class HintSide { Left, Right };
53 
54 void stripLeadingUnderscores(StringRef &Name) { Name = Name.ltrim('_'); }
55 
56 // getDeclForType() returns the decl responsible for Type's spelling.
57 // This is the inverse of ASTContext::getTypeDeclType().
58 template <typename Ty, typename = decltype(((Ty *)nullptr)->getDecl())>
59 const NamedDecl *getDeclForTypeImpl(const Ty *T) {
60   return T->getDecl();
61 }
62 const NamedDecl *getDeclForTypeImpl(const void *T) { return nullptr; }
63 const NamedDecl *getDeclForType(const Type *T) {
64   switch (T->getTypeClass()) {
65 #define ABSTRACT_TYPE(TY, BASE)
66 #define TYPE(TY, BASE)                                                         \
67   case Type::TY:                                                               \
68     return getDeclForTypeImpl(llvm::cast<TY##Type>(T));
69 #include "clang/AST/TypeNodes.inc"
70   }
71   llvm_unreachable("Unknown TypeClass enum");
72 }
73 
74 // getSimpleName() returns the plain identifier for an entity, if any.
75 llvm::StringRef getSimpleName(const DeclarationName &DN) {
76   if (IdentifierInfo *Ident = DN.getAsIdentifierInfo())
77     return Ident->getName();
78   return "";
79 }
80 llvm::StringRef getSimpleName(const NamedDecl &D) {
81   return getSimpleName(D.getDeclName());
82 }
83 llvm::StringRef getSimpleName(QualType T) {
84   if (const auto *ET = llvm::dyn_cast<ElaboratedType>(T))
85     return getSimpleName(ET->getNamedType());
86   if (const auto *BT = llvm::dyn_cast<BuiltinType>(T)) {
87     PrintingPolicy PP(LangOptions{});
88     PP.adjustForCPlusPlus();
89     return BT->getName(PP);
90   }
91   if (const auto *D = getDeclForType(T.getTypePtr()))
92     return getSimpleName(D->getDeclName());
93   return "";
94 }
95 
96 // Returns a very abbreviated form of an expression, or "" if it's too complex.
97 // For example: `foo->bar()` would produce "bar".
98 // This is used to summarize e.g. the condition of a while loop.
99 std::string summarizeExpr(const Expr *E) {
100   struct Namer : ConstStmtVisitor<Namer, std::string> {
101     std::string Visit(const Expr *E) {
102       if (E == nullptr)
103         return "";
104       return ConstStmtVisitor::Visit(E->IgnoreImplicit());
105     }
106 
107     // Any sort of decl reference, we just use the unqualified name.
108     std::string VisitMemberExpr(const MemberExpr *E) {
109       return getSimpleName(*E->getMemberDecl()).str();
110     }
111     std::string VisitDeclRefExpr(const DeclRefExpr *E) {
112       return getSimpleName(*E->getFoundDecl()).str();
113     }
114     std::string VisitCallExpr(const CallExpr *E) {
115       return Visit(E->getCallee());
116     }
117     std::string
118     VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) {
119       return getSimpleName(E->getMember()).str();
120     }
121     std::string
122     VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E) {
123       return getSimpleName(E->getDeclName()).str();
124     }
125     std::string VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *E) {
126       return getSimpleName(E->getType()).str();
127     }
128     std::string VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *E) {
129       return getSimpleName(E->getType()).str();
130     }
131 
132     // Step through implicit nodes that clang doesn't classify as such.
133     std::string VisitCXXMemberCallExpr(const CXXMemberCallExpr *E) {
134       // Call to operator bool() inside if (X): dispatch to X.
135       if (E->getNumArgs() == 0 && E->getMethodDecl() &&
136           E->getMethodDecl()->getDeclName().getNameKind() ==
137               DeclarationName::CXXConversionFunctionName &&
138           E->getSourceRange() ==
139               E->getImplicitObjectArgument()->getSourceRange())
140         return Visit(E->getImplicitObjectArgument());
141       return ConstStmtVisitor::VisitCXXMemberCallExpr(E);
142     }
143     std::string VisitCXXConstructExpr(const CXXConstructExpr *E) {
144       if (E->getNumArgs() == 1)
145         return Visit(E->getArg(0));
146       return "";
147     }
148 
149     // Literals are just printed
150     std::string VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
151       return E->getValue() ? "true" : "false";
152     }
153     std::string VisitIntegerLiteral(const IntegerLiteral *E) {
154       return llvm::to_string(E->getValue());
155     }
156     std::string VisitFloatingLiteral(const FloatingLiteral *E) {
157       std::string Result;
158       llvm::raw_string_ostream OS(Result);
159       E->getValue().print(OS);
160       // Printer adds newlines?!
161       Result.resize(llvm::StringRef(Result).rtrim().size());
162       return Result;
163     }
164     std::string VisitStringLiteral(const StringLiteral *E) {
165       std::string Result = "\"";
166       if (E->containsNonAscii()) {
167         Result += "...";
168       } else if (E->getLength() > 10) {
169         Result += E->getString().take_front(7);
170         Result += "...";
171       } else {
172         llvm::raw_string_ostream OS(Result);
173         llvm::printEscapedString(E->getString(), OS);
174       }
175       Result.push_back('"');
176       return Result;
177     }
178 
179     // Simple operators. Motivating cases are `!x` and `I < Length`.
180     std::string printUnary(llvm::StringRef Spelling, const Expr *Operand,
181                            bool Prefix) {
182       std::string Sub = Visit(Operand);
183       if (Sub.empty())
184         return "";
185       if (Prefix)
186         return (Spelling + Sub).str();
187       Sub += Spelling;
188       return Sub;
189     }
190     bool InsideBinary = false; // No recursing into binary expressions.
191     std::string printBinary(llvm::StringRef Spelling, const Expr *LHSOp,
192                             const Expr *RHSOp) {
193       if (InsideBinary)
194         return "";
195       llvm::SaveAndRestore InBinary(InsideBinary, true);
196 
197       std::string LHS = Visit(LHSOp);
198       std::string RHS = Visit(RHSOp);
199       if (LHS.empty() && RHS.empty())
200         return "";
201 
202       if (LHS.empty())
203         LHS = "...";
204       LHS.push_back(' ');
205       LHS += Spelling;
206       LHS.push_back(' ');
207       if (RHS.empty())
208         LHS += "...";
209       else
210         LHS += RHS;
211       return LHS;
212     }
213     std::string VisitUnaryOperator(const UnaryOperator *E) {
214       return printUnary(E->getOpcodeStr(E->getOpcode()), E->getSubExpr(),
215                         !E->isPostfix());
216     }
217     std::string VisitBinaryOperator(const BinaryOperator *E) {
218       return printBinary(E->getOpcodeStr(E->getOpcode()), E->getLHS(),
219                          E->getRHS());
220     }
221     std::string VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *E) {
222       const char *Spelling = getOperatorSpelling(E->getOperator());
223       // Handle weird unary-that-look-like-binary postfix operators.
224       if ((E->getOperator() == OO_PlusPlus ||
225            E->getOperator() == OO_MinusMinus) &&
226           E->getNumArgs() == 2)
227         return printUnary(Spelling, E->getArg(0), false);
228       if (E->isInfixBinaryOp())
229         return printBinary(Spelling, E->getArg(0), E->getArg(1));
230       if (E->getNumArgs() == 1) {
231         switch (E->getOperator()) {
232         case OO_Plus:
233         case OO_Minus:
234         case OO_Star:
235         case OO_Amp:
236         case OO_Tilde:
237         case OO_Exclaim:
238         case OO_PlusPlus:
239         case OO_MinusMinus:
240           return printUnary(Spelling, E->getArg(0), true);
241         default:
242           break;
243         }
244       }
245       return "";
246     }
247   };
248   return Namer{}.Visit(E);
249 }
250 
251 // Determines if any intermediate type in desugaring QualType QT is of
252 // substituted template parameter type. Ignore pointer or reference wrappers.
253 bool isSugaredTemplateParameter(QualType QT) {
254   static auto PeelWrapper = [](QualType QT) {
255     // Neither `PointerType` nor `ReferenceType` is considered as sugared
256     // type. Peel it.
257     QualType Peeled = QT->getPointeeType();
258     return Peeled.isNull() ? QT : Peeled;
259   };
260 
261   // This is a bit tricky: we traverse the type structure and find whether or
262   // not a type in the desugaring process is of SubstTemplateTypeParmType.
263   // During the process, we may encounter pointer or reference types that are
264   // not marked as sugared; therefore, the desugar function won't apply. To
265   // move forward the traversal, we retrieve the pointees using
266   // QualType::getPointeeType().
267   //
268   // However, getPointeeType could leap over our interests: The QT::getAs<T>()
269   // invoked would implicitly desugar the type. Consequently, if the
270   // SubstTemplateTypeParmType is encompassed within a TypedefType, we may lose
271   // the chance to visit it.
272   // For example, given a QT that represents `std::vector<int *>::value_type`:
273   //  `-ElaboratedType 'value_type' sugar
274   //    `-TypedefType 'vector<int *>::value_type' sugar
275   //      |-Typedef 'value_type'
276   //      `-SubstTemplateTypeParmType 'int *' sugar class depth 0 index 0 T
277   //        |-ClassTemplateSpecialization 'vector'
278   //        `-PointerType 'int *'
279   //          `-BuiltinType 'int'
280   // Applying `getPointeeType` to QT results in 'int', a child of our target
281   // node SubstTemplateTypeParmType.
282   //
283   // As such, we always prefer the desugared over the pointee for next type
284   // in the iteration. It could avoid the getPointeeType's implicit desugaring.
285   while (true) {
286     if (QT->getAs<SubstTemplateTypeParmType>())
287       return true;
288     QualType Desugared = QT->getLocallyUnqualifiedSingleStepDesugaredType();
289     if (Desugared != QT)
290       QT = Desugared;
291     else if (auto Peeled = PeelWrapper(Desugared); Peeled != QT)
292       QT = Peeled;
293     else
294       break;
295   }
296   return false;
297 }
298 
299 // A simple wrapper for `clang::desugarForDiagnostic` that provides optional
300 // semantic.
301 std::optional<QualType> desugar(ASTContext &AST, QualType QT) {
302   bool ShouldAKA = false;
303   auto Desugared = clang::desugarForDiagnostic(AST, QT, ShouldAKA);
304   if (!ShouldAKA)
305     return std::nullopt;
306   return Desugared;
307 }
308 
309 // Apply a series of heuristic methods to determine whether or not a QualType QT
310 // is suitable for desugaring (e.g. getting the real name behind the using-alias
311 // name). If so, return the desugared type. Otherwise, return the unchanged
312 // parameter QT.
313 //
314 // This could be refined further. See
315 // https://github.com/clangd/clangd/issues/1298.
316 QualType maybeDesugar(ASTContext &AST, QualType QT) {
317   // Prefer desugared type for name that aliases the template parameters.
318   // This can prevent things like printing opaque `: type` when accessing std
319   // containers.
320   if (isSugaredTemplateParameter(QT))
321     return desugar(AST, QT).value_or(QT);
322 
323   // Prefer desugared type for `decltype(expr)` specifiers.
324   if (QT->isDecltypeType())
325     return QT.getCanonicalType();
326   if (const AutoType *AT = QT->getContainedAutoType())
327     if (!AT->getDeducedType().isNull() &&
328         AT->getDeducedType()->isDecltypeType())
329       return QT.getCanonicalType();
330 
331   return QT;
332 }
333 
334 // Given a callee expression `Fn`, if the call is through a function pointer,
335 // try to find the declaration of the corresponding function pointer type,
336 // so that we can recover argument names from it.
337 // FIXME: This function is mostly duplicated in SemaCodeComplete.cpp; unify.
338 static FunctionProtoTypeLoc getPrototypeLoc(Expr *Fn) {
339   TypeLoc Target;
340   Expr *NakedFn = Fn->IgnoreParenCasts();
341   if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
342     Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
343   } else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
344     const auto *D = DR->getDecl();
345     if (const auto *const VD = dyn_cast<VarDecl>(D)) {
346       Target = VD->getTypeSourceInfo()->getTypeLoc();
347     }
348   }
349 
350   if (!Target)
351     return {};
352 
353   // Unwrap types that may be wrapping the function type
354   while (true) {
355     if (auto P = Target.getAs<PointerTypeLoc>()) {
356       Target = P.getPointeeLoc();
357       continue;
358     }
359     if (auto A = Target.getAs<AttributedTypeLoc>()) {
360       Target = A.getModifiedLoc();
361       continue;
362     }
363     if (auto P = Target.getAs<ParenTypeLoc>()) {
364       Target = P.getInnerLoc();
365       continue;
366     }
367     break;
368   }
369 
370   if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
371     return F;
372   }
373 
374   return {};
375 }
376 
377 ArrayRef<const ParmVarDecl *>
378 maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
379   if (!Params.empty() && Params.front()->isExplicitObjectParameter())
380     Params = Params.drop_front(1);
381   return Params;
382 }
383 
384 template <typename R>
385 std::string joinAndTruncate(const R &Range, size_t MaxLength) {
386   std::string Out;
387   llvm::raw_string_ostream OS(Out);
388   llvm::ListSeparator Sep(", ");
389   for (auto &&Element : Range) {
390     OS << Sep;
391     if (Out.size() + Element.size() >= MaxLength) {
392       OS << "...";
393       break;
394     }
395     OS << Element;
396   }
397   OS.flush();
398   return Out;
399 }
400 
401 struct Callee {
402   // Only one of Decl or Loc is set.
403   // Loc is for calls through function pointers.
404   const FunctionDecl *Decl = nullptr;
405   FunctionProtoTypeLoc Loc;
406 };
407 
408 class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
409 public:
410   InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST,
411                    const Config &Cfg, std::optional<Range> RestrictRange)
412       : Results(Results), AST(AST.getASTContext()), Tokens(AST.getTokens()),
413         Cfg(Cfg), RestrictRange(std::move(RestrictRange)),
414         MainFileID(AST.getSourceManager().getMainFileID()),
415         Resolver(AST.getHeuristicResolver()),
416         TypeHintPolicy(this->AST.getPrintingPolicy()) {
417     bool Invalid = false;
418     llvm::StringRef Buf =
419         AST.getSourceManager().getBufferData(MainFileID, &Invalid);
420     MainFileBuf = Invalid ? StringRef{} : Buf;
421 
422     TypeHintPolicy.SuppressScope = true; // keep type names short
423     TypeHintPolicy.AnonymousTagLocations =
424         false; // do not print lambda locations
425 
426     // Not setting PrintCanonicalTypes for "auto" allows
427     // SuppressDefaultTemplateArgs (set by default) to have an effect.
428   }
429 
430   bool VisitTypeLoc(TypeLoc TL) {
431     if (const auto *DT = llvm::dyn_cast<DecltypeType>(TL.getType()))
432       if (QualType UT = DT->getUnderlyingType(); !UT->isDependentType())
433         addTypeHint(TL.getSourceRange(), UT, ": ");
434     return true;
435   }
436 
437   bool VisitCXXConstructExpr(CXXConstructExpr *E) {
438     // Weed out constructor calls that don't look like a function call with
439     // an argument list, by checking the validity of getParenOrBraceRange().
440     // Also weed out std::initializer_list constructors as there are no names
441     // for the individual arguments.
442     if (!E->getParenOrBraceRange().isValid() ||
443         E->isStdInitListInitialization()) {
444       return true;
445     }
446 
447     Callee Callee;
448     Callee.Decl = E->getConstructor();
449     if (!Callee.Decl)
450       return true;
451     processCall(Callee, E->getParenOrBraceRange().getEnd(),
452                 {E->getArgs(), E->getNumArgs()});
453     return true;
454   }
455 
456   // Carefully recurse into PseudoObjectExprs, which typically incorporate
457   // a syntactic expression and several semantic expressions.
458   bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
459     Expr *SyntacticExpr = E->getSyntacticForm();
460     if (isa<CallExpr>(SyntacticExpr))
461       // Since the counterpart semantics usually get the identical source
462       // locations as the syntactic one, visiting those would end up presenting
463       // confusing hints e.g., __builtin_dump_struct.
464       // Thus, only traverse the syntactic forms if this is written as a
465       // CallExpr. This leaves the door open in case the arguments in the
466       // syntactic form could possibly get parameter names.
467       return RecursiveASTVisitor<InlayHintVisitor>::TraverseStmt(SyntacticExpr);
468     // We don't want the hints for some of the MS property extensions.
469     // e.g.
470     // struct S {
471     //   __declspec(property(get=GetX, put=PutX)) int x[];
472     //   void PutX(int y);
473     //   void Work(int y) { x = y; } // Bad: `x = y: y`.
474     // };
475     if (isa<BinaryOperator>(SyntacticExpr))
476       return true;
477     // FIXME: Handle other forms of a pseudo object expression.
478     return RecursiveASTVisitor<InlayHintVisitor>::TraversePseudoObjectExpr(E);
479   }
480 
481   bool VisitCallExpr(CallExpr *E) {
482     if (!Cfg.InlayHints.Parameters)
483       return true;
484 
485     bool IsFunctor = isFunctionObjectCallExpr(E);
486     // Do not show parameter hints for user-defined literals or
487     // operator calls except for operator(). (Among other reasons, the resulting
488     // hints can look awkward, e.g. the expression can itself be a function
489     // argument and then we'd get two hints side by side).
490     if ((isa<CXXOperatorCallExpr>(E) && !IsFunctor) ||
491         isa<UserDefinedLiteral>(E))
492       return true;
493 
494     auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
495     if (CalleeDecls.size() != 1)
496       return true;
497 
498     Callee Callee;
499     if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0]))
500       Callee.Decl = FD;
501     else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
502       Callee.Decl = FTD->getTemplatedDecl();
503     else if (FunctionProtoTypeLoc Loc = getPrototypeLoc(E->getCallee()))
504       Callee.Loc = Loc;
505     else
506       return true;
507 
508     // N4868 [over.call.object]p3 says,
509     // The argument list submitted to overload resolution consists of the
510     // argument expressions present in the function call syntax preceded by the
511     // implied object argument (E).
512     //
513     // As well as the provision from P0847R7 Deducing This [expr.call]p7:
514     // ...If the function is an explicit object member function and there is an
515     // implied object argument ([over.call.func]), the list of provided
516     // arguments is preceded by the implied object argument for the purposes of
517     // this correspondence...
518     llvm::ArrayRef<const Expr *> Args = {E->getArgs(), E->getNumArgs()};
519     // We don't have the implied object argument through a function pointer
520     // either.
521     if (const CXXMethodDecl *Method =
522             dyn_cast_or_null<CXXMethodDecl>(Callee.Decl))
523       if (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter())
524         Args = Args.drop_front(1);
525     processCall(Callee, E->getRParenLoc(), Args);
526     return true;
527   }
528 
529   bool VisitFunctionDecl(FunctionDecl *D) {
530     if (auto *FPT =
531             llvm::dyn_cast<FunctionProtoType>(D->getType().getTypePtr())) {
532       if (!FPT->hasTrailingReturn()) {
533         if (auto FTL = D->getFunctionTypeLoc())
534           addReturnTypeHint(D, FTL.getRParenLoc());
535       }
536     }
537     if (Cfg.InlayHints.BlockEnd && D->isThisDeclarationADefinition()) {
538       // We use `printName` here to properly print name of ctor/dtor/operator
539       // overload.
540       if (const Stmt *Body = D->getBody())
541         addBlockEndHint(Body->getSourceRange(), "", printName(AST, *D), "");
542     }
543     return true;
544   }
545 
546   bool VisitForStmt(ForStmt *S) {
547     if (Cfg.InlayHints.BlockEnd) {
548       std::string Name;
549       // Common case: for (int I = 0; I < N; I++). Use "I" as the name.
550       if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S->getInit());
551           DS && DS->isSingleDecl())
552         Name = getSimpleName(llvm::cast<NamedDecl>(*DS->getSingleDecl()));
553       else
554         Name = summarizeExpr(S->getCond());
555       markBlockEnd(S->getBody(), "for", Name);
556     }
557     return true;
558   }
559 
560   bool VisitCXXForRangeStmt(CXXForRangeStmt *S) {
561     if (Cfg.InlayHints.BlockEnd)
562       markBlockEnd(S->getBody(), "for", getSimpleName(*S->getLoopVariable()));
563     return true;
564   }
565 
566   bool VisitWhileStmt(WhileStmt *S) {
567     if (Cfg.InlayHints.BlockEnd)
568       markBlockEnd(S->getBody(), "while", summarizeExpr(S->getCond()));
569     return true;
570   }
571 
572   bool VisitSwitchStmt(SwitchStmt *S) {
573     if (Cfg.InlayHints.BlockEnd)
574       markBlockEnd(S->getBody(), "switch", summarizeExpr(S->getCond()));
575     return true;
576   }
577 
578   // If/else chains are tricky.
579   //   if (cond1) {
580   //   } else if (cond2) {
581   //   } // mark as "cond1" or "cond2"?
582   // For now, the answer is neither, just mark as "if".
583   // The ElseIf is a different IfStmt that doesn't know about the outer one.
584   llvm::DenseSet<const IfStmt *> ElseIfs; // not eligible for names
585   bool VisitIfStmt(IfStmt *S) {
586     if (Cfg.InlayHints.BlockEnd) {
587       if (const auto *ElseIf = llvm::dyn_cast_or_null<IfStmt>(S->getElse()))
588         ElseIfs.insert(ElseIf);
589       // Don't use markBlockEnd: the relevant range is [then.begin, else.end].
590       if (const auto *EndCS = llvm::dyn_cast<CompoundStmt>(
591               S->getElse() ? S->getElse() : S->getThen())) {
592         addBlockEndHint(
593             {S->getThen()->getBeginLoc(), EndCS->getRBracLoc()}, "if",
594             ElseIfs.contains(S) ? "" : summarizeExpr(S->getCond()), "");
595       }
596     }
597     return true;
598   }
599 
600   void markBlockEnd(const Stmt *Body, llvm::StringRef Label,
601                     llvm::StringRef Name = "") {
602     if (const auto *CS = llvm::dyn_cast_or_null<CompoundStmt>(Body))
603       addBlockEndHint(CS->getSourceRange(), Label, Name, "");
604   }
605 
606   bool VisitTagDecl(TagDecl *D) {
607     if (Cfg.InlayHints.BlockEnd && D->isThisDeclarationADefinition()) {
608       std::string DeclPrefix = D->getKindName().str();
609       if (const auto *ED = dyn_cast<EnumDecl>(D)) {
610         if (ED->isScoped())
611           DeclPrefix += ED->isScopedUsingClassTag() ? " class" : " struct";
612       };
613       addBlockEndHint(D->getBraceRange(), DeclPrefix, getSimpleName(*D), ";");
614     }
615     return true;
616   }
617 
618   bool VisitNamespaceDecl(NamespaceDecl *D) {
619     if (Cfg.InlayHints.BlockEnd) {
620       // For namespace, the range actually starts at the namespace keyword. But
621       // it should be fine since it's usually very short.
622       addBlockEndHint(D->getSourceRange(), "namespace", getSimpleName(*D), "");
623     }
624     return true;
625   }
626 
627   bool VisitLambdaExpr(LambdaExpr *E) {
628     FunctionDecl *D = E->getCallOperator();
629     if (!E->hasExplicitResultType()) {
630       SourceLocation TypeHintLoc;
631       if (!E->hasExplicitParameters())
632         TypeHintLoc = E->getIntroducerRange().getEnd();
633       else if (auto FTL = D->getFunctionTypeLoc())
634         TypeHintLoc = FTL.getRParenLoc();
635       if (TypeHintLoc.isValid())
636         addReturnTypeHint(D, TypeHintLoc);
637     }
638     return true;
639   }
640 
641   void addReturnTypeHint(FunctionDecl *D, SourceRange Range) {
642     auto *AT = D->getReturnType()->getContainedAutoType();
643     if (!AT || AT->getDeducedType().isNull())
644       return;
645     addTypeHint(Range, D->getReturnType(), /*Prefix=*/"-> ");
646   }
647 
648   bool VisitVarDecl(VarDecl *D) {
649     // Do not show hints for the aggregate in a structured binding,
650     // but show hints for the individual bindings.
651     if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
652       for (auto *Binding : DD->bindings()) {
653         // For structured bindings, print canonical types. This is important
654         // because for bindings that use the tuple_element protocol, the
655         // non-canonical types would be "tuple_element<I, A>::type".
656         if (auto Type = Binding->getType();
657             !Type.isNull() && !Type->isDependentType())
658           addTypeHint(Binding->getLocation(), Type.getCanonicalType(),
659                       /*Prefix=*/": ");
660       }
661       return true;
662     }
663 
664     if (auto *AT = D->getType()->getContainedAutoType()) {
665       if (AT->isDeduced() && !D->getType()->isDependentType()) {
666         // Our current approach is to place the hint on the variable
667         // and accordingly print the full type
668         // (e.g. for `const auto& x = 42`, print `const int&`).
669         // Alternatively, we could place the hint on the `auto`
670         // (and then just print the type deduced for the `auto`).
671         addTypeHint(D->getLocation(), D->getType(), /*Prefix=*/": ");
672       }
673     }
674 
675     // Handle templates like `int foo(auto x)` with exactly one instantiation.
676     if (auto *PVD = llvm::dyn_cast<ParmVarDecl>(D)) {
677       if (D->getIdentifier() && PVD->getType()->isDependentType() &&
678           !getContainedAutoParamType(D->getTypeSourceInfo()->getTypeLoc())
679                .isNull()) {
680         if (auto *IPVD = getOnlyParamInstantiation(PVD))
681           addTypeHint(D->getLocation(), IPVD->getType(), /*Prefix=*/": ");
682       }
683     }
684 
685     return true;
686   }
687 
688   ParmVarDecl *getOnlyParamInstantiation(ParmVarDecl *D) {
689     auto *TemplateFunction = llvm::dyn_cast<FunctionDecl>(D->getDeclContext());
690     if (!TemplateFunction)
691       return nullptr;
692     auto *InstantiatedFunction = llvm::dyn_cast_or_null<FunctionDecl>(
693         getOnlyInstantiation(TemplateFunction));
694     if (!InstantiatedFunction)
695       return nullptr;
696 
697     unsigned ParamIdx = 0;
698     for (auto *Param : TemplateFunction->parameters()) {
699       // Can't reason about param indexes in the presence of preceding packs.
700       // And if this param is a pack, it may expand to multiple params.
701       if (Param->isParameterPack())
702         return nullptr;
703       if (Param == D)
704         break;
705       ++ParamIdx;
706     }
707     assert(ParamIdx < TemplateFunction->getNumParams() &&
708            "Couldn't find param in list?");
709     assert(ParamIdx < InstantiatedFunction->getNumParams() &&
710            "Instantiated function has fewer (non-pack) parameters?");
711     return InstantiatedFunction->getParamDecl(ParamIdx);
712   }
713 
714   bool VisitInitListExpr(InitListExpr *Syn) {
715     // We receive the syntactic form here (shouldVisitImplicitCode() is false).
716     // This is the one we will ultimately attach designators to.
717     // It may have subobject initializers inlined without braces. The *semantic*
718     // form of the init-list has nested init-lists for these.
719     // getUnwrittenDesignators will look at the semantic form to determine the
720     // labels.
721     assert(Syn->isSyntacticForm() && "RAV should not visit implicit code!");
722     if (!Cfg.InlayHints.Designators)
723       return true;
724     if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts()))
725       return true;
726     llvm::DenseMap<SourceLocation, std::string> Designators =
727         tidy::utils::getUnwrittenDesignators(Syn);
728     for (const Expr *Init : Syn->inits()) {
729       if (llvm::isa<DesignatedInitExpr>(Init))
730         continue;
731       auto It = Designators.find(Init->getBeginLoc());
732       if (It != Designators.end() &&
733           !isPrecededByParamNameComment(Init, It->second))
734         addDesignatorHint(Init->getSourceRange(), It->second);
735     }
736     return true;
737   }
738 
739   // FIXME: Handle RecoveryExpr to try to hint some invalid calls.
740 
741 private:
742   using NameVec = SmallVector<StringRef, 8>;
743 
744   void processCall(Callee Callee, SourceLocation RParenOrBraceLoc,
745                    llvm::ArrayRef<const Expr *> Args) {
746     assert(Callee.Decl || Callee.Loc);
747 
748     if ((!Cfg.InlayHints.Parameters && !Cfg.InlayHints.DefaultArguments) ||
749         Args.size() == 0)
750       return;
751 
752     // The parameter name of a move or copy constructor is not very interesting.
753     if (Callee.Decl)
754       if (auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee.Decl))
755         if (Ctor->isCopyOrMoveConstructor())
756           return;
757 
758     SmallVector<std::string> FormattedDefaultArgs;
759     bool HasNonDefaultArgs = false;
760 
761     ArrayRef<const ParmVarDecl *> Params, ForwardedParams;
762     // Resolve parameter packs to their forwarded parameter
763     SmallVector<const ParmVarDecl *> ForwardedParamsStorage;
764     if (Callee.Decl) {
765       Params = maybeDropCxxExplicitObjectParameters(Callee.Decl->parameters());
766       ForwardedParamsStorage = resolveForwardingParameters(Callee.Decl);
767       ForwardedParams =
768           maybeDropCxxExplicitObjectParameters(ForwardedParamsStorage);
769     } else {
770       Params = maybeDropCxxExplicitObjectParameters(Callee.Loc.getParams());
771       ForwardedParams = {Params.begin(), Params.end()};
772     }
773 
774     NameVec ParameterNames = chooseParameterNames(ForwardedParams);
775 
776     // Exclude setters (i.e. functions with one argument whose name begins with
777     // "set"), and builtins like std::move/forward/... as their parameter name
778     // is also not likely to be interesting.
779     if (Callee.Decl &&
780         (isSetter(Callee.Decl, ParameterNames) || isSimpleBuiltin(Callee.Decl)))
781       return;
782 
783     for (size_t I = 0; I < ParameterNames.size() && I < Args.size(); ++I) {
784       // Pack expansion expressions cause the 1:1 mapping between arguments and
785       // parameters to break down, so we don't add further inlay hints if we
786       // encounter one.
787       if (isa<PackExpansionExpr>(Args[I])) {
788         break;
789       }
790 
791       StringRef Name = ParameterNames[I];
792       const bool NameHint =
793           shouldHintName(Args[I], Name) && Cfg.InlayHints.Parameters;
794       const bool ReferenceHint =
795           shouldHintReference(Params[I], ForwardedParams[I]) &&
796           Cfg.InlayHints.Parameters;
797 
798       const bool IsDefault = isa<CXXDefaultArgExpr>(Args[I]);
799       HasNonDefaultArgs |= !IsDefault;
800       if (IsDefault) {
801         if (Cfg.InlayHints.DefaultArguments) {
802           const auto SourceText = Lexer::getSourceText(
803               CharSourceRange::getTokenRange(Params[I]->getDefaultArgRange()),
804               AST.getSourceManager(), AST.getLangOpts());
805           const auto Abbrev =
806               (SourceText.size() > Cfg.InlayHints.TypeNameLimit ||
807                SourceText.contains("\n"))
808                   ? "..."
809                   : SourceText;
810           if (NameHint)
811             FormattedDefaultArgs.emplace_back(
812                 llvm::formatv("{0}: {1}", Name, Abbrev));
813           else
814             FormattedDefaultArgs.emplace_back(llvm::formatv("{0}", Abbrev));
815         }
816       } else if (NameHint || ReferenceHint) {
817         addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
818                      InlayHintKind::Parameter, ReferenceHint ? "&" : "",
819                      NameHint ? Name : "", ": ");
820       }
821     }
822 
823     if (!FormattedDefaultArgs.empty()) {
824       std::string Hint =
825           joinAndTruncate(FormattedDefaultArgs, Cfg.InlayHints.TypeNameLimit);
826       addInlayHint(SourceRange{RParenOrBraceLoc}, HintSide::Left,
827                    InlayHintKind::DefaultArgument,
828                    HasNonDefaultArgs ? ", " : "", Hint, "");
829     }
830   }
831 
832   static bool isSetter(const FunctionDecl *Callee, const NameVec &ParamNames) {
833     if (ParamNames.size() != 1)
834       return false;
835 
836     StringRef Name = getSimpleName(*Callee);
837     if (!Name.starts_with_insensitive("set"))
838       return false;
839 
840     // In addition to checking that the function has one parameter and its
841     // name starts with "set", also check that the part after "set" matches
842     // the name of the parameter (ignoring case). The idea here is that if
843     // the parameter name differs, it may contain extra information that
844     // may be useful to show in a hint, as in:
845     //   void setTimeout(int timeoutMillis);
846     // This currently doesn't handle cases where params use snake_case
847     // and functions don't, e.g.
848     //   void setExceptionHandler(EHFunc exception_handler);
849     // We could improve this by replacing `equals_insensitive` with some
850     // `sloppy_equals` which ignores case and also skips underscores.
851     StringRef WhatItIsSetting = Name.substr(3).ltrim("_");
852     return WhatItIsSetting.equals_insensitive(ParamNames[0]);
853   }
854 
855   // Checks if the callee is one of the builtins
856   // addressof, as_const, forward, move(_if_noexcept)
857   static bool isSimpleBuiltin(const FunctionDecl *Callee) {
858     switch (Callee->getBuiltinID()) {
859     case Builtin::BIaddressof:
860     case Builtin::BIas_const:
861     case Builtin::BIforward:
862     case Builtin::BImove:
863     case Builtin::BImove_if_noexcept:
864       return true;
865     default:
866       return false;
867     }
868   }
869 
870   bool shouldHintName(const Expr *Arg, StringRef ParamName) {
871     if (ParamName.empty())
872       return false;
873 
874     // If the argument expression is a single name and it matches the
875     // parameter name exactly, omit the name hint.
876     if (ParamName == getSpelledIdentifier(Arg))
877       return false;
878 
879     // Exclude argument expressions preceded by a /*paramName*/.
880     if (isPrecededByParamNameComment(Arg, ParamName))
881       return false;
882 
883     return true;
884   }
885 
886   bool shouldHintReference(const ParmVarDecl *Param,
887                            const ParmVarDecl *ForwardedParam) {
888     // We add a & hint only when the argument is passed as mutable reference.
889     // For parameters that are not part of an expanded pack, this is
890     // straightforward. For expanded pack parameters, it's likely that they will
891     // be forwarded to another function. In this situation, we only want to add
892     // the reference hint if the argument is actually being used via mutable
893     // reference. This means we need to check
894     // 1. whether the value category of the argument is preserved, i.e. each
895     //    pack expansion uses std::forward correctly.
896     // 2. whether the argument is ever copied/cast instead of passed
897     //    by-reference
898     // Instead of checking this explicitly, we use the following proxy:
899     // 1. the value category can only change from rvalue to lvalue during
900     //    forwarding, so checking whether both the parameter of the forwarding
901     //    function and the forwarded function are lvalue references detects such
902     //    a conversion.
903     // 2. if the argument is copied/cast somewhere in the chain of forwarding
904     //    calls, it can only be passed on to an rvalue reference or const lvalue
905     //    reference parameter. Thus if the forwarded parameter is a mutable
906     //    lvalue reference, it cannot have been copied/cast to on the way.
907     // Additionally, we should not add a reference hint if the forwarded
908     // parameter was only partially resolved, i.e. points to an expanded pack
909     // parameter, since we do not know how it will be used eventually.
910     auto Type = Param->getType();
911     auto ForwardedType = ForwardedParam->getType();
912     return Type->isLValueReferenceType() &&
913            ForwardedType->isLValueReferenceType() &&
914            !ForwardedType.getNonReferenceType().isConstQualified() &&
915            !isExpandedFromParameterPack(ForwardedParam);
916   }
917 
918   // Checks if "E" is spelled in the main file and preceded by a C-style comment
919   // whose contents match ParamName (allowing for whitespace and an optional "="
920   // at the end.
921   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
922     auto &SM = AST.getSourceManager();
923     auto FileLoc = SM.getFileLoc(E->getBeginLoc());
924     auto Decomposed = SM.getDecomposedLoc(FileLoc);
925     if (Decomposed.first != MainFileID)
926       return false;
927 
928     StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
929     // Allow whitespace between comment and expression.
930     SourcePrefix = SourcePrefix.rtrim();
931     // Check for comment ending.
932     if (!SourcePrefix.consume_back("*/"))
933       return false;
934     // Ignore some punctuation and whitespace around comment.
935     // In particular this allows designators to match nicely.
936     llvm::StringLiteral IgnoreChars = " =.";
937     SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
938     ParamName = ParamName.trim(IgnoreChars);
939     // Other than that, the comment must contain exactly ParamName.
940     if (!SourcePrefix.consume_back(ParamName))
941       return false;
942     SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
943     return SourcePrefix.ends_with("/*");
944   }
945 
946   // If "E" spells a single unqualified identifier, return that name.
947   // Otherwise, return an empty string.
948   static StringRef getSpelledIdentifier(const Expr *E) {
949     E = E->IgnoreUnlessSpelledInSource();
950 
951     if (auto *DRE = dyn_cast<DeclRefExpr>(E))
952       if (!DRE->getQualifier())
953         return getSimpleName(*DRE->getDecl());
954 
955     if (auto *ME = dyn_cast<MemberExpr>(E))
956       if (!ME->getQualifier() && ME->isImplicitAccess())
957         return getSimpleName(*ME->getMemberDecl());
958 
959     return {};
960   }
961 
962   NameVec chooseParameterNames(ArrayRef<const ParmVarDecl *> Parameters) {
963     NameVec ParameterNames;
964     for (const auto *P : Parameters) {
965       if (isExpandedFromParameterPack(P)) {
966         // If we haven't resolved a pack paramater (e.g. foo(Args... args)) to a
967         // non-pack parameter, then hinting as foo(args: 1, args: 2, args: 3) is
968         // unlikely to be useful.
969         ParameterNames.emplace_back();
970       } else {
971         auto SimpleName = getSimpleName(*P);
972         // If the parameter is unnamed in the declaration:
973         // attempt to get its name from the definition
974         if (SimpleName.empty()) {
975           if (const auto *PD = getParamDefinition(P)) {
976             SimpleName = getSimpleName(*PD);
977           }
978         }
979         ParameterNames.emplace_back(SimpleName);
980       }
981     }
982 
983     // Standard library functions often have parameter names that start
984     // with underscores, which makes the hints noisy, so strip them out.
985     for (auto &Name : ParameterNames)
986       stripLeadingUnderscores(Name);
987 
988     return ParameterNames;
989   }
990 
991   // for a ParmVarDecl from a function declaration, returns the corresponding
992   // ParmVarDecl from the definition if possible, nullptr otherwise.
993   static const ParmVarDecl *getParamDefinition(const ParmVarDecl *P) {
994     if (auto *Callee = dyn_cast<FunctionDecl>(P->getDeclContext())) {
995       if (auto *Def = Callee->getDefinition()) {
996         auto I = std::distance(Callee->param_begin(),
997                                llvm::find(Callee->parameters(), P));
998         if (I < (int)Callee->getNumParams()) {
999           return Def->getParamDecl(I);
1000         }
1001       }
1002     }
1003     return nullptr;
1004   }
1005 
1006   // We pass HintSide rather than SourceLocation because we want to ensure
1007   // it is in the same file as the common file range.
1008   void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind,
1009                     llvm::StringRef Prefix, llvm::StringRef Label,
1010                     llvm::StringRef Suffix) {
1011     auto LSPRange = getHintRange(R);
1012     if (!LSPRange)
1013       return;
1014 
1015     addInlayHint(*LSPRange, Side, Kind, Prefix, Label, Suffix);
1016   }
1017 
1018   void addInlayHint(Range LSPRange, HintSide Side, InlayHintKind Kind,
1019                     llvm::StringRef Prefix, llvm::StringRef Label,
1020                     llvm::StringRef Suffix) {
1021     // We shouldn't get as far as adding a hint if the category is disabled.
1022     // We'd like to disable as much of the analysis as possible above instead.
1023     // Assert in debug mode but add a dynamic check in production.
1024     assert(Cfg.InlayHints.Enabled && "Shouldn't get here if disabled!");
1025     switch (Kind) {
1026 #define CHECK_KIND(Enumerator, ConfigProperty)                                 \
1027   case InlayHintKind::Enumerator:                                              \
1028     assert(Cfg.InlayHints.ConfigProperty &&                                    \
1029            "Shouldn't get here if kind is disabled!");                         \
1030     if (!Cfg.InlayHints.ConfigProperty)                                        \
1031       return;                                                                  \
1032     break
1033       CHECK_KIND(Parameter, Parameters);
1034       CHECK_KIND(Type, DeducedTypes);
1035       CHECK_KIND(Designator, Designators);
1036       CHECK_KIND(BlockEnd, BlockEnd);
1037       CHECK_KIND(DefaultArgument, DefaultArguments);
1038 #undef CHECK_KIND
1039     }
1040 
1041     Position LSPPos = Side == HintSide::Left ? LSPRange.start : LSPRange.end;
1042     if (RestrictRange &&
1043         (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end)))
1044       return;
1045     bool PadLeft = Prefix.consume_front(" ");
1046     bool PadRight = Suffix.consume_back(" ");
1047     Results.push_back(InlayHint{LSPPos,
1048                                 /*label=*/{(Prefix + Label + Suffix).str()},
1049                                 Kind, PadLeft, PadRight, LSPRange});
1050   }
1051 
1052   // Get the range of the main file that *exactly* corresponds to R.
1053   std::optional<Range> getHintRange(SourceRange R) {
1054     const auto &SM = AST.getSourceManager();
1055     auto Spelled = Tokens.spelledForExpanded(Tokens.expandedTokens(R));
1056     // TokenBuffer will return null if e.g. R corresponds to only part of a
1057     // macro expansion.
1058     if (!Spelled || Spelled->empty())
1059       return std::nullopt;
1060     // Hint must be within the main file, not e.g. a non-preamble include.
1061     if (SM.getFileID(Spelled->front().location()) != SM.getMainFileID() ||
1062         SM.getFileID(Spelled->back().location()) != SM.getMainFileID())
1063       return std::nullopt;
1064     return Range{sourceLocToPosition(SM, Spelled->front().location()),
1065                  sourceLocToPosition(SM, Spelled->back().endLocation())};
1066   }
1067 
1068   void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
1069     if (!Cfg.InlayHints.DeducedTypes || T.isNull())
1070       return;
1071 
1072     // The sugared type is more useful in some cases, and the canonical
1073     // type in other cases.
1074     auto Desugared = maybeDesugar(AST, T);
1075     std::string TypeName = Desugared.getAsString(TypeHintPolicy);
1076     if (T != Desugared && !shouldPrintTypeHint(TypeName)) {
1077       // If the desugared type is too long to display, fallback to the sugared
1078       // type.
1079       TypeName = T.getAsString(TypeHintPolicy);
1080     }
1081     if (shouldPrintTypeHint(TypeName))
1082       addInlayHint(R, HintSide::Right, InlayHintKind::Type, Prefix, TypeName,
1083                    /*Suffix=*/"");
1084   }
1085 
1086   void addDesignatorHint(SourceRange R, llvm::StringRef Text) {
1087     addInlayHint(R, HintSide::Left, InlayHintKind::Designator,
1088                  /*Prefix=*/"", Text, /*Suffix=*/"=");
1089   }
1090 
1091   bool shouldPrintTypeHint(llvm::StringRef TypeName) const noexcept {
1092     return Cfg.InlayHints.TypeNameLimit == 0 ||
1093            TypeName.size() < Cfg.InlayHints.TypeNameLimit;
1094   }
1095 
1096   void addBlockEndHint(SourceRange BraceRange, StringRef DeclPrefix,
1097                        StringRef Name, StringRef OptionalPunctuation) {
1098     auto HintRange = computeBlockEndHintRange(BraceRange, OptionalPunctuation);
1099     if (!HintRange)
1100       return;
1101 
1102     std::string Label = DeclPrefix.str();
1103     if (!Label.empty() && !Name.empty())
1104       Label += ' ';
1105     Label += Name;
1106 
1107     constexpr unsigned HintMaxLengthLimit = 60;
1108     if (Label.length() > HintMaxLengthLimit)
1109       return;
1110 
1111     addInlayHint(*HintRange, HintSide::Right, InlayHintKind::BlockEnd, " // ",
1112                  Label, "");
1113   }
1114 
1115   // Compute the LSP range to attach the block end hint to, if any allowed.
1116   // 1. "}" is the last non-whitespace character on the line. The range of "}"
1117   // is returned.
1118   // 2. After "}", if the trimmed trailing text is exactly
1119   // `OptionalPunctuation`, say ";". The range of "} ... ;" is returned.
1120   // Otherwise, the hint shouldn't be shown.
1121   std::optional<Range> computeBlockEndHintRange(SourceRange BraceRange,
1122                                                 StringRef OptionalPunctuation) {
1123     constexpr unsigned HintMinLineLimit = 2;
1124 
1125     auto &SM = AST.getSourceManager();
1126     auto [BlockBeginFileId, BlockBeginOffset] =
1127         SM.getDecomposedLoc(SM.getFileLoc(BraceRange.getBegin()));
1128     auto RBraceLoc = SM.getFileLoc(BraceRange.getEnd());
1129     auto [RBraceFileId, RBraceOffset] = SM.getDecomposedLoc(RBraceLoc);
1130 
1131     // Because we need to check the block satisfies the minimum line limit, we
1132     // require both source location to be in the main file. This prevents hint
1133     // to be shown in weird cases like '{' is actually in a "#include", but it's
1134     // rare anyway.
1135     if (BlockBeginFileId != MainFileID || RBraceFileId != MainFileID)
1136       return std::nullopt;
1137 
1138     StringRef RestOfLine = MainFileBuf.substr(RBraceOffset).split('\n').first;
1139     if (!RestOfLine.starts_with("}"))
1140       return std::nullopt;
1141 
1142     StringRef TrimmedTrailingText = RestOfLine.drop_front().trim();
1143     if (!TrimmedTrailingText.empty() &&
1144         TrimmedTrailingText != OptionalPunctuation)
1145       return std::nullopt;
1146 
1147     auto BlockBeginLine = SM.getLineNumber(BlockBeginFileId, BlockBeginOffset);
1148     auto RBraceLine = SM.getLineNumber(RBraceFileId, RBraceOffset);
1149 
1150     // Don't show hint on trivial blocks like `class X {};`
1151     if (BlockBeginLine + HintMinLineLimit - 1 > RBraceLine)
1152       return std::nullopt;
1153 
1154     // This is what we attach the hint to, usually "}" or "};".
1155     StringRef HintRangeText = RestOfLine.take_front(
1156         TrimmedTrailingText.empty()
1157             ? 1
1158             : TrimmedTrailingText.bytes_end() - RestOfLine.bytes_begin());
1159 
1160     Position HintStart = sourceLocToPosition(SM, RBraceLoc);
1161     Position HintEnd = sourceLocToPosition(
1162         SM, RBraceLoc.getLocWithOffset(HintRangeText.size()));
1163     return Range{HintStart, HintEnd};
1164   }
1165 
1166   static bool isFunctionObjectCallExpr(CallExpr *E) noexcept {
1167     if (auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(E))
1168       return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
1169     return false;
1170   }
1171 
1172   std::vector<InlayHint> &Results;
1173   ASTContext &AST;
1174   const syntax::TokenBuffer &Tokens;
1175   const Config &Cfg;
1176   std::optional<Range> RestrictRange;
1177   FileID MainFileID;
1178   StringRef MainFileBuf;
1179   const HeuristicResolver *Resolver;
1180   PrintingPolicy TypeHintPolicy;
1181 };
1182 
1183 } // namespace
1184 
1185 std::vector<InlayHint> inlayHints(ParsedAST &AST,
1186                                   std::optional<Range> RestrictRange) {
1187   std::vector<InlayHint> Results;
1188   const auto &Cfg = Config::current();
1189   if (!Cfg.InlayHints.Enabled)
1190     return Results;
1191   InlayHintVisitor Visitor(Results, AST, Cfg, std::move(RestrictRange));
1192   Visitor.TraverseAST(AST.getASTContext());
1193 
1194   // De-duplicate hints. Duplicates can sometimes occur due to e.g. explicit
1195   // template instantiations.
1196   llvm::sort(Results);
1197   Results.erase(std::unique(Results.begin(), Results.end()), Results.end());
1198 
1199   return Results;
1200 }
1201 
1202 } // namespace clangd
1203 } // namespace clang
1204