diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index e6e5e11b889bf..3da047f954213 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -528,6 +528,13 @@ static FunctionProtoTypeLoc getPrototypeLoc(Expr *Fn) { return {}; } +ArrayRef +maybeDropCxxExplicitObjectParameters(ArrayRef Params) { + if (!Params.empty() && Params.front()->isExplicitObjectParameter()) + Params = Params.drop_front(1); + return Params; +} + struct Callee { // Only one of Decl or Loc is set. // Loc is for calls through function pointers. @@ -614,15 +621,21 @@ class InlayHintVisitor : public RecursiveASTVisitor { // argument expressions present in the function call syntax preceded by the // implied object argument (E). // - // However, we don't have the implied object argument for static - // operator() per clang::Sema::BuildCallToObjectOfClassType. + // As well as the provision from P0847R7 Deducing This [expr.call]p7: + // ...If the function is an explicit object member function and there is an + // implied object argument ([over.call.func]), the list of provided + // arguments is preceded by the implied object argument for the purposes of + // this correspondence... + // + // However, we don't have the implied object argument + // for static operator() per clang::Sema::BuildCallToObjectOfClassType. llvm::ArrayRef Args = {E->getArgs(), E->getNumArgs()}; - if (IsFunctor) - // We don't have the implied object argument through - // a function pointer either. - if (const CXXMethodDecl *Method = - dyn_cast_or_null(Callee.Decl); - Method && Method->isInstance()) + // We don't have the implied object argument through a function pointer + // either. + if (const CXXMethodDecl *Method = + dyn_cast_or_null(Callee.Decl)) + if (Method->isInstance() && + (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter())) Args = Args.drop_front(1); processCall(Callee, Args); return true; @@ -849,15 +862,18 @@ class InlayHintVisitor : public RecursiveASTVisitor { if (Ctor->isCopyOrMoveConstructor()) return; - auto Params = - Callee.Decl ? Callee.Decl->parameters() : Callee.Loc.getParams(); - + ArrayRef Params, ForwardedParams; // Resolve parameter packs to their forwarded parameter - SmallVector ForwardedParams; - if (Callee.Decl) - ForwardedParams = resolveForwardingParameters(Callee.Decl); - else + SmallVector ForwardedParamsStorage; + if (Callee.Decl) { + Params = maybeDropCxxExplicitObjectParameters(Callee.Decl->parameters()); + ForwardedParamsStorage = resolveForwardingParameters(Callee.Decl); + ForwardedParams = + maybeDropCxxExplicitObjectParameters(ForwardedParamsStorage); + } else { + Params = maybeDropCxxExplicitObjectParameters(Callee.Loc.getParams()); ForwardedParams = {Params.begin(), Params.end()}; + } NameVec ParameterNames = chooseParameterNames(ForwardedParams); @@ -1018,7 +1034,7 @@ class InlayHintVisitor : public RecursiveASTVisitor { return {}; } - NameVec chooseParameterNames(SmallVector Parameters) { + NameVec chooseParameterNames(ArrayRef Parameters) { NameVec ParameterNames; for (const auto *P : Parameters) { if (isExpandedFromParameterPack(P)) { diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index a8c3546eb80cc..20c1cdd985dbc 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -843,6 +843,34 @@ TEST(ParameterHints, FunctionCallOperator) { ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"}); } +TEST(ParameterHints, DeducingThis) { + assertParameterHints(R"cpp( + struct S { + template + auto operator()(this This &&Self, int Param) { + return 42; + } + + auto function(this auto &Self, int Param) { + return Param; + } + }; + void work() { + S s; + s($1[[42]]); + s.function($2[[42]]); + S()($3[[42]]); + auto lambda = [](this auto &Self, char C) -> void { + return Self(C); + }; + lambda($4[['A']]); + } + )cpp", + ExpectedHint{"Param: ", "1"}, + ExpectedHint{"Param: ", "2"}, + ExpectedHint{"Param: ", "3"}, ExpectedHint{"C: ", "4"}); +} + TEST(ParameterHints, Macros) { // Handling of macros depends on where the call's argument list comes from.