kadircet created this revision.
kadircet added a reviewer: ilya-biryukov.
Herald added subscribers: usaxena95, arphaman.
Herald added a project: All.
kadircet requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang-tools-extra.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130261

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1429,6 +1429,31 @@
               ElementsAre(labelIs(": int"), labelIs(": char")));
 }
 
+TEST(ParameterHints, ArgPacksAndConstructors) {
+  assertParameterHints(
+      R"cpp(
+    struct Foo{ Foo(int x); };
+    void foo(Foo a, int b);
+
+    template <typename... Args>
+    void bar(Args... args) { foo(args...); }
+
+    template <typename... Args>
+    void baz(Args... args) { foo(Foo(args...), args...); }
+
+    template <typename... Args>
+    void bax(Args... args) { foo({args...}, args...); }
+
+    void foo() {
+      bar($param1[[Foo{2}]], $param2[[42]]);
+      baz($param3[[42]]);
+      bax($param4[[42]]);
+    }
+  )cpp",
+      ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
+      ExpectedHint{"x: ", "param3"}, ExpectedHint{"x: ", "param4"});
+}
+
 // FIXME: Low-hanging fruit where we could omit a type hint:
 //  - auto x = TypeName(...);
 //  - auto x = (TypeName) (...);
Index: clang-tools-extra/clangd/AST.cpp
===================================================================
--- clang-tools-extra/clangd/AST.cpp
+++ clang-tools-extra/clangd/AST.cpp
@@ -792,50 +792,45 @@
       return;
     }
     auto OptPackLocation = findPack(Args);
-    if (OptPackLocation) {
-      size_t PackLocation = OptPackLocation.value();
-      ArrayRef<ParmVarDecl *> MatchingParams =
-          Callee->parameters().slice(PackLocation, Parameters.size());
-      // Check whether the function has a parameter pack as the last template
-      // parameter
-      if (const auto *TTPT = getFunctionPackType(Callee)) {
-        // In this case: Separate the parameters into head, pack and tail
-        auto IsExpandedPack = [&](const ParmVarDecl *P) {
-          return getUnderylingPackType(P) == TTPT;
-        };
-        ForwardingInfo FI;
-        FI.Head = MatchingParams.take_until(IsExpandedPack);
-        FI.Pack = MatchingParams.drop_front(FI.Head.size())
-                      .take_while(IsExpandedPack);
-        FI.Tail = MatchingParams.drop_front(FI.Head.size() + FI.Pack.size());
-        FI.PackTarget = Callee;
-        Info = FI;
-        return;
-      }
-      // Default case: assume all parameters were fully resolved
+    if (!OptPackLocation)
+      return;
+    ArrayRef<ParmVarDecl *> MatchingParams =
+        Callee->parameters().slice(*OptPackLocation, Parameters.size());
+    // Check whether the function has a parameter pack as the last template
+    // parameter
+    if (const auto *TTPT = getFunctionPackType(Callee)) {
+      // In this case: Separate the parameters into head, pack and tail
+      auto IsExpandedPack = [&](const ParmVarDecl *P) {
+        return getUnderylingPackType(P) == TTPT;
+      };
       ForwardingInfo FI;
-      FI.Head = MatchingParams;
+      FI.Head = MatchingParams.take_until(IsExpandedPack);
+      FI.Pack =
+          MatchingParams.drop_front(FI.Head.size()).take_while(IsExpandedPack);
+      FI.Tail = MatchingParams.drop_front(FI.Head.size() + FI.Pack.size());
+      FI.PackTarget = Callee;
       Info = FI;
+      return;
     }
+    // Default case: assume all parameters were fully resolved
+    ForwardingInfo FI;
+    FI.Head = MatchingParams;
+    Info = FI;
   }
 
   // Returns the beginning of the expanded pack represented by Parameters
   // in the given arguments, if it is there.
   llvm::Optional<size_t> findPack(typename CallExpr::arg_range Args) {
     // find the argument directly referring to the first parameter
-    auto FirstMatch = std::find_if(Args.begin(), Args.end(), [&](Expr *Arg) {
-      const auto *RefArg = unwrapArgument(Arg);
-      if (RefArg) {
-        if (Parameters.front() == dyn_cast<ParmVarDecl>(RefArg->getDecl())) {
-          return true;
-        }
+    for (auto It = Args.begin(); It != Args.end(); ++It) {
+      const Expr *Arg = *It;
+      if (const auto *RefArg = unwrapForward(Arg)) {
+        if (Parameters.front() != dyn_cast<ParmVarDecl>(RefArg->getDecl()))
+          continue;
+        return std::distance(Args.begin(), It);
       }
-      return false;
-    });
-    if (FirstMatch == Args.end()) {
-      return llvm::None;
     }
-    return std::distance(Args.begin(), FirstMatch);
+    return llvm::None;
   }
 
   static FunctionDecl *getCalleeDeclOrUniqueOverload(CallExpr *E) {
@@ -847,7 +842,7 @@
       }
     }
     // Ignore the callee if the number of arguments is wrong (deal with va_args)
-    if (Callee->getNumParams() == E->getNumArgs())
+    if (Callee && Callee->getNumParams() == E->getNumArgs())
       return Callee;
     return nullptr;
   }
@@ -873,31 +868,16 @@
     return MatchingDecl;
   }
 
-  // Removes any implicit cast expressions around the given expression.
-  static const Expr *unwrapImplicitCast(const Expr *E) {
-    while (const auto *Cast = dyn_cast<ImplicitCastExpr>(E)) {
-      E = Cast->getSubExpr();
-    }
-    return E;
-  }
-
-  // Maps std::forward(E) to E, nullptr otherwise
-  static const Expr *unwrapForward(const Expr *E) {
+  // Maps std::forward(E) to E, identity otherwise.
+  static const DeclRefExpr *unwrapForward(const Expr *E) {
+    E = E->IgnoreImplicitAsWritten();
     if (const auto *Call = dyn_cast<CallExpr>(E)) {
       const auto Callee = Call->getBuiltinCallee();
       if (Callee == Builtin::BIforward) {
-        return Call->getArg(0);
+        return dyn_cast<DeclRefExpr>(
+            Call->getArg(0)->IgnoreImplicitAsWritten());
       }
     }
-    return E;
-  }
-
-  // Maps std::forward(DeclRefExpr) to DeclRefExpr, removing any intermediate
-  // implicit casts, nullptr otherwise
-  static const DeclRefExpr *unwrapArgument(const Expr *E) {
-    E = unwrapImplicitCast(E);
-    E = unwrapForward(E);
-    E = unwrapImplicitCast(E);
     return dyn_cast<DeclRefExpr>(E);
   }
 };
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to