1111#include " Config.h"
1212#include " HeuristicResolver.h"
1313#include " ParsedAST.h"
14+ #include " Protocol.h"
1415#include " SourceCode.h"
1516#include " clang/AST/ASTDiagnostic.h"
1617#include " clang/AST/Decl.h"
18+ #include " clang/AST/DeclBase.h"
1719#include " clang/AST/DeclarationName.h"
1820#include " clang/AST/Expr.h"
1921#include " clang/AST/ExprCXX.h"
22+ #include " clang/AST/LambdaCapture.h"
2023#include " clang/AST/RecursiveASTVisitor.h"
2124#include " clang/AST/Stmt.h"
2225#include " clang/AST/StmtVisitor.h"
2326#include " clang/AST/Type.h"
2427#include " clang/Basic/Builtins.h"
28+ #include " clang/Basic/Lambda.h"
2529#include " clang/Basic/OperatorKinds.h"
30+ #include " clang/Basic/SourceLocation.h"
2631#include " clang/Basic/SourceManager.h"
2732#include " llvm/ADT/DenseSet.h"
33+ #include " llvm/ADT/STLExtras.h"
34+ #include " llvm/ADT/SmallVector.h"
2835#include " llvm/ADT/StringExtras.h"
2936#include " llvm/ADT/StringRef.h"
3037#include " llvm/ADT/Twine.h"
3138#include " llvm/Support/Casting.h"
39+ #include " llvm/Support/FormatVariadic.h"
3240#include " llvm/Support/SaveAndRestore.h"
3341#include " llvm/Support/ScopedPrinter.h"
3442#include " llvm/Support/raw_ostream.h"
43+ #include < algorithm>
44+ #include < iterator>
3545#include < optional>
3646#include < string>
3747
@@ -372,6 +382,34 @@ maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
372382 return Params;
373383}
374384
385+ llvm::StringRef getLambdaCaptureName (const LambdaCapture &Capture) {
386+ if (Capture.capturesVariable ())
387+ return Capture.getCapturedVar ()->getName ();
388+ if (Capture.capturesThis ())
389+ return llvm::StringRef{" this" };
390+ return llvm::StringRef{" unknown" };
391+ }
392+
393+ template <typename R, typename P>
394+ std::string joinAndTruncate (R &&Range, size_t MaxLength,
395+ P &&GetAsStringFunction) {
396+ std::string Out;
397+ bool IsFirst = true ;
398+ for (auto &&Element : Range) {
399+ if (!IsFirst)
400+ Out.append (" , " );
401+ else
402+ IsFirst = false ;
403+ auto AsString = GetAsStringFunction (Element);
404+ if (Out.size () + AsString.size () >= MaxLength) {
405+ Out.append (" ..." );
406+ break ;
407+ }
408+ Out.append (AsString);
409+ }
410+ return Out;
411+ }
412+
375413struct Callee {
376414 // Only one of Decl or Loc is set.
377415 // Loc is for calls through function pointers.
@@ -422,7 +460,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
422460 Callee.Decl = E->getConstructor ();
423461 if (!Callee.Decl )
424462 return true ;
425- processCall (Callee, {E->getArgs (), E->getNumArgs ()});
463+ processCall (Callee, E->getParenOrBraceRange ().getEnd (),
464+ {E->getArgs (), E->getNumArgs ()});
426465 return true ;
427466 }
428467
@@ -495,7 +534,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
495534 dyn_cast_or_null<CXXMethodDecl>(Callee.Decl ))
496535 if (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter ())
497536 Args = Args.drop_front (1 );
498- processCall (Callee, Args);
537+ processCall (Callee, E-> getRParenLoc (), Args);
499538 return true ;
500539 }
501540
@@ -598,6 +637,15 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
598637 }
599638
600639 bool VisitLambdaExpr (LambdaExpr *E) {
640+ if (Cfg.InlayHints .LambdaCaptures && E->getCaptureDefault () != LCD_None &&
641+ !E->implicit_captures ().empty ()) {
642+ std::string FormattedCaptureList =
643+ joinAndTruncate (E->implicit_captures (), Cfg.InlayHints .TypeNameLimit ,
644+ [](const LambdaCapture &ImplicitCapture) {
645+ return getLambdaCaptureName (ImplicitCapture);
646+ });
647+ addImplicitCaptureHint (E->getCaptureDefaultLoc (), FormattedCaptureList);
648+ }
601649 FunctionDecl *D = E->getCallOperator ();
602650 if (!E->hasExplicitResultType ())
603651 addReturnTypeHint (D, E->hasExplicitParameters ()
@@ -709,7 +757,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
709757private:
710758 using NameVec = SmallVector<StringRef, 8 >;
711759
712- void processCall (Callee Callee, llvm::ArrayRef<const Expr *> Args) {
760+ void processCall (Callee Callee, SourceRange LParenOrBraceRange,
761+ llvm::ArrayRef<const Expr *> Args) {
713762 assert (Callee.Decl || Callee.Loc );
714763
715764 if (!Cfg.InlayHints .Parameters || Args.size () == 0 )
@@ -721,6 +770,9 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
721770 if (Ctor->isCopyOrMoveConstructor ())
722771 return ;
723772
773+ SmallVector<std::string> FormattedDefaultArgs;
774+ bool HasNonDefaultArgs = false ;
775+
724776 ArrayRef<const ParmVarDecl *> Params, ForwardedParams;
725777 // Resolve parameter packs to their forwarded parameter
726778 SmallVector<const ParmVarDecl *> ForwardedParamsStorage;
@@ -755,12 +807,34 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
755807 bool NameHint = shouldHintName (Args[I], Name);
756808 bool ReferenceHint = shouldHintReference (Params[I], ForwardedParams[I]);
757809
810+ bool IsDefault = isa<CXXDefaultArgExpr>(Args[I]);
811+ HasNonDefaultArgs |= !IsDefault;
812+ if (Cfg.InlayHints .DefaultArguments && IsDefault) {
813+ auto SourceText = Lexer::getSourceText (
814+ CharSourceRange::getTokenRange (Params[I]->getDefaultArgRange ()),
815+ Callee.Decl ->getASTContext ().getSourceManager (),
816+ Callee.Decl ->getASTContext ().getLangOpts ());
817+ FormattedDefaultArgs.emplace_back (llvm::formatv (
818+ " {0} = {1}" , Name,
819+ SourceText.size () > Cfg.InlayHints .TypeNameLimit ? " ..."
820+ : SourceText));
821+ }
822+
758823 if (NameHint || ReferenceHint) {
759824 addInlayHint (Args[I]->getSourceRange (), HintSide::Left,
760825 InlayHintKind::Parameter, ReferenceHint ? " &" : " " ,
761826 NameHint ? Name : " " , " : " );
762827 }
763828 }
829+
830+ if (!FormattedDefaultArgs.empty ()) {
831+ std::string Hint =
832+ joinAndTruncate (FormattedDefaultArgs, Cfg.InlayHints .TypeNameLimit ,
833+ [](const auto &E) { return E; });
834+ addInlayHint (LParenOrBraceRange, HintSide::Left,
835+ InlayHintKind::DefaultArgument,
836+ HasNonDefaultArgs ? " , " : " " , Hint, " " );
837+ }
764838 }
765839
766840 static bool isSetter (const FunctionDecl *Callee, const NameVec &ParamNames) {
@@ -968,6 +1042,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
9681042 CHECK_KIND (Type, DeducedTypes);
9691043 CHECK_KIND (Designator, Designators);
9701044 CHECK_KIND (BlockEnd, BlockEnd);
1045+ CHECK_KIND (LambdaCapture, LambdaCaptures);
1046+ CHECK_KIND (DefaultArgument, DefaultArguments);
9711047#undef CHECK_KIND
9721048 }
9731049
@@ -1021,6 +1097,11 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
10211097 /* Prefix=*/ " " , Text, /* Suffix=*/ " =" );
10221098 }
10231099
1100+ void addImplicitCaptureHint (SourceRange R, llvm::StringRef Text) {
1101+ addInlayHint (R, HintSide::Right, InlayHintKind::LambdaCapture,
1102+ /* Prefix=*/ " : " , Text, /* Suffix=*/ " " );
1103+ }
1104+
10241105 bool shouldPrintTypeHint (llvm::StringRef TypeName) const noexcept {
10251106 return Cfg.InlayHints .TypeNameLimit == 0 ||
10261107 TypeName.size () < Cfg.InlayHints .TypeNameLimit ;
0 commit comments