[clang-tools-extra] cbd6ac6 - [clangd] Show parameter hints for operator()

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 10 00:56:08 PDT 2023


Author: Younan Zhang
Date: 2023-09-10T15:56:00+08:00
New Revision: cbd6ac6165e683f2eed4a5066c1ccf53bed0696d

URL: https://github.com/llvm/llvm-project/commit/cbd6ac6165e683f2eed4a5066c1ccf53bed0696d
DIFF: https://github.com/llvm/llvm-project/commit/cbd6ac6165e683f2eed4a5066c1ccf53bed0696d.diff

LOG: [clangd] Show parameter hints for operator()

Closes https://github.com/clangd/clangd/issues/1742

Reviewed By: nridge

Differential Revision: https://reviews.llvm.org/D158926

Added: 
    

Modified: 
    clang-tools-extra/clangd/InlayHints.cpp
    clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 56f85ee155cb236..e6e5e11b889bff8 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -586,11 +586,13 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     if (!Cfg.InlayHints.Parameters)
       return true;
 
-    // Do not show parameter hints for operator calls written using operator
-    // syntax or user-defined literals. (Among other reasons, the resulting
+    bool IsFunctor = isFunctionObjectCallExpr(E);
+    // Do not show parameter hints for user-defined literals or
+    // operator calls except for operator(). (Among other reasons, the resulting
     // hints can look awkward, e.g. the expression can itself be a function
     // argument and then we'd get two hints side by side).
-    if (isa<CXXOperatorCallExpr>(E) || isa<UserDefinedLiteral>(E))
+    if ((isa<CXXOperatorCallExpr>(E) && !IsFunctor) ||
+        isa<UserDefinedLiteral>(E))
       return true;
 
     auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
@@ -607,7 +609,22 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     else
       return true;
 
-    processCall(Callee, {E->getArgs(), E->getNumArgs()});
+    // N4868 [over.call.object]p3 says,
+    // The argument list submitted to overload resolution consists of the
+    // 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.
+    llvm::ArrayRef<const Expr *> 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<CXXMethodDecl>(Callee.Decl);
+          Method && Method->isInstance())
+        Args = Args.drop_front(1);
+    processCall(Callee, Args);
     return true;
   }
 
@@ -1203,6 +1220,12 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     return Range{HintStart, HintEnd};
   }
 
+  static bool isFunctionObjectCallExpr(CallExpr *E) noexcept {
+    if (auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(E))
+      return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
+    return false;
+  }
+
   std::vector<InlayHint> &Results;
   ASTContext &AST;
   const syntax::TokenBuffer &Tokens;

diff  --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 1d12db3661c9ebb..a8c3546eb80cc85 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -89,7 +89,7 @@ void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
                            ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
-  TU.ExtraArgs.push_back("-std=c++20");
+  TU.ExtraArgs.push_back("-std=c++23");
   TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
@@ -807,6 +807,42 @@ TEST(ParameterHints, Operator) {
   )cpp");
 }
 
+TEST(ParameterHints, FunctionCallOperator) {
+  assertParameterHints(R"cpp(
+    struct W {
+      void operator()(int x);
+    };
+    struct S : W {
+      using W::operator();
+      static void operator()(int x, int y);
+    };
+    void bar() {
+      auto l1 = [](int x) {};
+      auto l2 = [](int x) static {};
+
+      S s;
+      s($1[[1]]);
+      s.operator()($2[[1]]);
+      s.operator()($3[[1]], $4[[2]]);
+      S::operator()($5[[1]], $6[[2]]);
+
+      l1($7[[1]]);
+      l1.operator()($8[[1]]);
+      l2($9[[1]]);
+      l2.operator()($10[[1]]);
+
+      void (*ptr)(int a, int b) = &S::operator();
+      ptr($11[[1]], $12[[2]]);
+    }
+  )cpp",
+                       ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},
+                       ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},
+                       ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},
+                       ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},
+                       ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},
+                       ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});
+}
+
 TEST(ParameterHints, Macros) {
   // Handling of macros depends on where the call's argument list comes from.
 


        


More information about the cfe-commits mailing list