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/ErrorHandling.h"
40+ #include " llvm/Support/FormatVariadic.h"
3241#include " llvm/Support/SaveAndRestore.h"
3342#include " llvm/Support/ScopedPrinter.h"
3443#include " llvm/Support/raw_ostream.h"
44+ #include < algorithm>
45+ #include < iterator>
3546#include < optional>
3647#include < string>
3748
@@ -372,6 +383,38 @@ maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
372383 return Params;
373384}
374385
386+ llvm::StringRef getLambdaCaptureName (const LambdaCapture &Capture) {
387+ switch (Capture.getCaptureKind ()) {
388+ case LCK_This:
389+ case LCK_StarThis:
390+ return llvm::StringRef{" this" };
391+ case LCK_ByCopy:
392+ case LCK_ByRef:
393+ case LCK_VLAType:
394+ return Capture.getCapturedVar ()->getName ();
395+ }
396+ llvm_unreachable (" unhandled capture kind" );
397+ }
398+
399+ template <typename R, typename P>
400+ std::string joinAndTruncate (R &&Range, size_t MaxLength,
401+ P &&GetAsStringFunction) {
402+ std::string Out;
403+ llvm::raw_string_ostream OS (Out);
404+ llvm::ListSeparator Sep (" , " );
405+ for (auto &&Element : Range) {
406+ OS << Sep;
407+ auto AsString = GetAsStringFunction (Element);
408+ if (Out.size () + AsString.size () >= MaxLength) {
409+ OS << " ..." ;
410+ break ;
411+ }
412+ OS << AsString;
413+ }
414+ OS.flush ();
415+ return Out;
416+ }
417+
375418struct Callee {
376419 // Only one of Decl or Loc is set.
377420 // Loc is for calls through function pointers.
@@ -422,7 +465,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
422465 Callee.Decl = E->getConstructor ();
423466 if (!Callee.Decl )
424467 return true ;
425- processCall (Callee, {E->getArgs (), E->getNumArgs ()});
468+ processCall (Callee, E->getParenOrBraceRange ().getEnd (),
469+ {E->getArgs (), E->getNumArgs ()});
426470 return true ;
427471 }
428472
@@ -495,7 +539,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
495539 dyn_cast_or_null<CXXMethodDecl>(Callee.Decl ))
496540 if (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter ())
497541 Args = Args.drop_front (1 );
498- processCall (Callee, Args);
542+ processCall (Callee, E-> getRParenLoc (), Args);
499543 return true ;
500544 }
501545
@@ -598,6 +642,15 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
598642 }
599643
600644 bool VisitLambdaExpr (LambdaExpr *E) {
645+ if (Cfg.InlayHints .LambdaCaptures && E->getCaptureDefault () != LCD_None &&
646+ !E->implicit_captures ().empty ()) {
647+ std::string FormattedCaptureList =
648+ joinAndTruncate (E->implicit_captures (), Cfg.InlayHints .TypeNameLimit ,
649+ [](const LambdaCapture &ImplicitCapture) {
650+ return getLambdaCaptureName (ImplicitCapture);
651+ });
652+ addImplicitCaptureHint (E->getCaptureDefaultLoc (), FormattedCaptureList);
653+ }
601654 FunctionDecl *D = E->getCallOperator ();
602655 if (!E->hasExplicitResultType ())
603656 addReturnTypeHint (D, E->hasExplicitParameters ()
@@ -709,7 +762,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
709762private:
710763 using NameVec = SmallVector<StringRef, 8 >;
711764
712- void processCall (Callee Callee, llvm::ArrayRef<const Expr *> Args) {
765+ void processCall (Callee Callee, SourceRange LParenOrBraceRange,
766+ llvm::ArrayRef<const Expr *> Args) {
713767 assert (Callee.Decl || Callee.Loc );
714768
715769 if (!Cfg.InlayHints .Parameters || Args.size () == 0 )
@@ -721,6 +775,9 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
721775 if (Ctor->isCopyOrMoveConstructor ())
722776 return ;
723777
778+ SmallVector<std::string> FormattedDefaultArgs;
779+ bool HasNonDefaultArgs = false ;
780+
724781 ArrayRef<const ParmVarDecl *> Params, ForwardedParams;
725782 // Resolve parameter packs to their forwarded parameter
726783 SmallVector<const ParmVarDecl *> ForwardedParamsStorage;
@@ -755,12 +812,33 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
755812 bool NameHint = shouldHintName (Args[I], Name);
756813 bool ReferenceHint = shouldHintReference (Params[I], ForwardedParams[I]);
757814
815+ bool IsDefault = isa<CXXDefaultArgExpr>(Args[I]);
816+ HasNonDefaultArgs |= !IsDefault;
817+ if (Cfg.InlayHints .DefaultArguments && IsDefault) {
818+ auto SourceText = Lexer::getSourceText (
819+ CharSourceRange::getTokenRange (Params[I]->getDefaultArgRange ()),
820+ AST.getSourceManager (), AST.getLangOpts ());
821+ FormattedDefaultArgs.emplace_back (llvm::formatv (
822+ " {0} = {1}" , Name,
823+ SourceText.size () > Cfg.InlayHints .TypeNameLimit ? " ..."
824+ : SourceText));
825+ }
826+
758827 if (NameHint || ReferenceHint) {
759828 addInlayHint (Args[I]->getSourceRange (), HintSide::Left,
760829 InlayHintKind::Parameter, ReferenceHint ? " &" : " " ,
761830 NameHint ? Name : " " , " : " );
762831 }
763832 }
833+
834+ if (!FormattedDefaultArgs.empty ()) {
835+ std::string Hint =
836+ joinAndTruncate (FormattedDefaultArgs, Cfg.InlayHints .TypeNameLimit ,
837+ [](const auto &E) { return E; });
838+ addInlayHint (LParenOrBraceRange, HintSide::Left,
839+ InlayHintKind::DefaultArgument,
840+ HasNonDefaultArgs ? " , " : " " , Hint, " " );
841+ }
764842 }
765843
766844 static bool isSetter (const FunctionDecl *Callee, const NameVec &ParamNames) {
@@ -968,6 +1046,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
9681046 CHECK_KIND (Type, DeducedTypes);
9691047 CHECK_KIND (Designator, Designators);
9701048 CHECK_KIND (BlockEnd, BlockEnd);
1049+ CHECK_KIND (LambdaCapture, LambdaCaptures);
1050+ CHECK_KIND (DefaultArgument, DefaultArguments);
9711051#undef CHECK_KIND
9721052 }
9731053
@@ -1021,6 +1101,11 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
10211101 /* Prefix=*/ " " , Text, /* Suffix=*/ " =" );
10221102 }
10231103
1104+ void addImplicitCaptureHint (SourceRange R, llvm::StringRef Text) {
1105+ addInlayHint (R, HintSide::Right, InlayHintKind::LambdaCapture,
1106+ /* Prefix=*/ " : " , Text, /* Suffix=*/ " " );
1107+ }
1108+
10241109 bool shouldPrintTypeHint (llvm::StringRef TypeName) const noexcept {
10251110 return Cfg.InlayHints .TypeNameLimit == 0 ||
10261111 TypeName.size () < Cfg.InlayHints .TypeNameLimit ;
0 commit comments