[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-11 Thread Nathan Ridge via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG94b14355e2ef: [clangd] allow extracting to variable for 
lambda expressions (authored by 5chmidti, committed by nridge).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -66,6 +66,11 @@
 Code completion
 ^^^
 
+Code actions
+
+
+- The extract variable tweak gained support for extracting lambda expressions to a variable.
+
 Signature help
 ^^
 
Index: clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
===
--- clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -98,6 +98,7 @@
   return [[t]].bar([[t]].z);
 }
 void v() { return; }
+
 // function default argument
 void f(int b = [[1]]) {
   // empty selection
@@ -131,10 +132,80 @@
   goto label;
   label:
 a = [[1]];
+
+  // lambdas: captures
+  int x = 0;
+  [ [[=]] ](){};
+  [ [[&]] ](){};
+  [ [[x]] ](){};
+  [ [[]] ](){};
+  [y = [[x]] ](){};
+  [ [[y = x]] ](){};
+
+  // lambdas: default args, cannot extract into function-local scope
+  [](int x = [[10]]){};
+  [](auto h = [[ [i = [](){}](){} ]]) {};
+
+  // lambdas: default args
+  // Extracting from capture initializers is usually fine,
+  // but not if the capture itself is nested inside a default argument
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [i = [[ 42 ]]](){}) {};
+
+  // lambdas: scope
+  if (int a = 1)
+if ([[ [&](){ return a + 1; } ]]() == 4)
+  a = a + 1;
+
+  for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
+  }
+  for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
+  }
+
+  // lambdas: scope with structured binding
+  struct Coordinates {
+int x{};
+int y{};
+  };
+  Coordinates c{};
+  if (const auto [x, y] = c; x > y)
+auto f = [[ [&]() { return x + y; } ]];
+
+  // lambdas: referencing outside variables that block extraction
+  //  in trailing return type or in a decltype used
+  //  by a parameter
+  if (int a = 1)
+if ([[ []() -> decltype(a) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4)
+  a = a + 1;
 }
   )cpp";
   EXPECT_UNAVAILABLE(UnavailableCases);
 
+  ExtraArgs = {"-std=c++20"};
+  const char *UnavailableCasesCXX20 = R"cpp(
+template 
+concept Constraint = requires (T t) { true; };
+void foo() {
+  // lambdas: referencing outside variables that block extraction
+  //  in requires clause or defaulted explicit template parameters
+  if (int a = 1)
+if ([[ [](auto b) requires (Constraint && Constraint) { return true; } ]] (a))
+  a = a + 1;
+
+  if (int a = 1)
+if ([[ [](T b) { return true; } ]] (a))
+  a = a + 1;
+}
+  )cpp";
+  EXPECT_UNAVAILABLE(UnavailableCasesCXX20);
+  ExtraArgs.clear();
+
   // vector of pairs of input and output strings
   std::vector> InputOutputs = {
   // extraction from variable declaration/assignment
@@ -282,6 +353,219 @@
  void f() {
auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
  })cpp"},
+  // lambda expressions
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([[ [](){ return 42; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = [](){ return 42; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([x = [[40 + 2]] ](){ return 42; });
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; });
+}
+)cpp"},
+  {R"cpp(auto foo(int 

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-10 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti added a comment.

Thank you. Could you please commit this for me with `Julian Schmidt 
<44101708+5chmi...@users.noreply.github.com>`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-10 Thread Nathan Ridge via Phabricator via cfe-commits
nridge accepted this revision.
nridge added a comment.

I'm fine with allowing partial selection for consistency with other expressions.

I think this patch is in a good state. Thanks for your patience with the review 
:) Let me know if you need me to commit it for you.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-09 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti marked an inline comment as done.
5chmidti added inline comments.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:187
+// Allow expressions, but only allow completely selected lambda
+// expressions or unselected lambda expressions that are the parent of
+// the originally selected node, not partially selected lambda

nridge wrote:
> nridge wrote:
> > 5chmidti wrote:
> > > nridge wrote:
> > > > I think it's worth adding to the comment *why* we allow unselected 
> > > > lambda expressions (to allow extracting from capture initializers), as 
> > > > it's not obvious
> > > I changed the previous return of `!isa(Stmt) || 
> > > InsertionPoint->Selected != SelectionTree::Partial;` to a simple `return 
> > > true;`. None of my partial selection tests fail and I can't think of a 
> > > case where the lambda would be partially selected.
> > Hmm, so what actually happens in these testcases?
> > 
> > ```
> >   // lambdas: partially selected
> >   [][[(){}]];
> >   []()[[{}]];
> >   [ [[ ](){}]];
> > ```
> I checked, and in these cases we disallow the extraction 
> [here](https://searchfox.org/llvm/rev/c2bee1ed26a3355d164c92f1eb70ebf88804560d/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp#426-432)
>  before we get to creating an `ExtractionContext`.
> 
> If the testcases are modified as follows:
> 
> ```
> template  void sink(T) {}
> ...
> void f() {
>   // lambdas: partially selected
>   sink([][[(){}]]);
>   sink([]()[[{}]]);
>   sink([ [[ ](){}]]);
> }
> ```
> 
> now they fail, unless the check for partial selection here is restored.
As stated in the update comment, I see no reason why we actually block partial 
selection of lambdas. It's okay to extract from the initializer of a capture 
(one of your comments above):
```
int foo();

void bar() {
  [x = [[foo()]] ]() {};
}
```
The tests in ln 138-143 (titled `lambdas: captures`) check that we don't 
extract the wrong things from lambda captures.
Do you see a way that extracting from a lambda capture or any kind of partial 
selection could be problematic?

To answer the question anyway:
`Hmm, so what actually happens in these testcases?`
The original diff had a sink that I probably removed because the tests would 
succeed even without the sink. However, those tests then tested a different 
condition and never hit the check for partial selection.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-09 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti updated this revision to Diff 556349.
5chmidti added a comment.

Fixup to last revision change:

- do not block the partial selection of lambdas

There is no reason to block the partial selection of lambdas. Other expressions 
can be partially selected as well and still offer an extraction:

  4[[0 +]] 2


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -66,6 +66,11 @@
 Code completion
 ^^^
 
+Code actions
+
+
+- The extract variable tweak gained support for extracting lambda expressions to a variable.
+
 Signature help
 ^^
 
Index: clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
===
--- clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -98,6 +98,7 @@
   return [[t]].bar([[t]].z);
 }
 void v() { return; }
+
 // function default argument
 void f(int b = [[1]]) {
   // empty selection
@@ -131,10 +132,80 @@
   goto label;
   label:
 a = [[1]];
+
+  // lambdas: captures
+  int x = 0;
+  [ [[=]] ](){};
+  [ [[&]] ](){};
+  [ [[x]] ](){};
+  [ [[]] ](){};
+  [y = [[x]] ](){};
+  [ [[y = x]] ](){};
+
+  // lambdas: default args, cannot extract into function-local scope
+  [](int x = [[10]]){};
+  [](auto h = [[ [i = [](){}](){} ]]) {};
+
+  // lambdas: default args
+  // Extracting from capture initializers is usually fine,
+  // but not if the capture itself is nested inside a default argument
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [i = [[ 42 ]]](){}) {};
+
+  // lambdas: scope
+  if (int a = 1)
+if ([[ [&](){ return a + 1; } ]]() == 4)
+  a = a + 1;
+
+  for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
+  }
+  for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
+  }
+
+  // lambdas: scope with structured binding
+  struct Coordinates {
+int x{};
+int y{};
+  };
+  Coordinates c{};
+  if (const auto [x, y] = c; x > y)
+auto f = [[ [&]() { return x + y; } ]];
+
+  // lambdas: referencing outside variables that block extraction
+  //  in trailing return type or in a decltype used
+  //  by a parameter
+  if (int a = 1)
+if ([[ []() -> decltype(a) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4)
+  a = a + 1;
 }
   )cpp";
   EXPECT_UNAVAILABLE(UnavailableCases);
 
+  ExtraArgs = {"-std=c++20"};
+  const char *UnavailableCasesCXX20 = R"cpp(
+template 
+concept Constraint = requires (T t) { true; };
+void foo() {
+  // lambdas: referencing outside variables that block extraction
+  //  in requires clause or defaulted explicit template parameters
+  if (int a = 1)
+if ([[ [](auto b) requires (Constraint && Constraint) { return true; } ]] (a))
+  a = a + 1;
+
+  if (int a = 1)
+if ([[ [](T b) { return true; } ]] (a))
+  a = a + 1;
+}
+  )cpp";
+  EXPECT_UNAVAILABLE(UnavailableCasesCXX20);
+  ExtraArgs.clear();
+
   // vector of pairs of input and output strings
   std::vector> InputOutputs = {
   // extraction from variable declaration/assignment
@@ -282,6 +353,219 @@
  void f() {
auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
  })cpp"},
+  // lambda expressions
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([[ [](){ return 42; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = [](){ return 42; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([x = [[40 + 2]] ](){ return 42; });
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; });
+}
+)cpp"},
+  {R"cpp(auto foo(int VarA) {
+  return 

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-09 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti updated this revision to Diff 556348.
5chmidti added a comment.

addressed comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -66,6 +66,11 @@
 Code completion
 ^^^
 
+Code actions
+
+
+- The extract variable tweak gained support for extracting lambda expressions to a variable.
+
 Signature help
 ^^
 
Index: clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
===
--- clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -98,6 +98,10 @@
   return [[t]].bar([[t]].z);
 }
 void v() { return; }
+
+template 
+void sink(T) {}
+
 // function default argument
 void f(int b = [[1]]) {
   // empty selection
@@ -131,10 +135,85 @@
   goto label;
   label:
 a = [[1]];
+
+  // lambdas: partially selected
+  sink([] [[ (){} ]] );
+  sink([ [[ ]( ]] )[[{}]]);
+  sink([ [[ ](){} ]] );
+
+  // lambdas: captures
+  int x = 0;
+  [ [[=]] ](){};
+  [ [[&]] ](){};
+  [ [[x]] ](){};
+  [ [[]] ](){};
+  [y = [[x]] ](){};
+  [ [[y = x]] ](){};
+
+  // lambdas: default args, cannot extract into function-local scope
+  [](int x = [[10]]){};
+  [](auto h = [[ [i = [](){}](){} ]]) {};
+
+  // lambdas: default args
+  // Extracting from capture initializers is usually fine,
+  // but not if the capture itself is nested inside a default argument
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [i = [[ 42 ]]](){}) {};
+
+  // lambdas: scope
+  if (int a = 1)
+if ([[ [&](){ return a + 1; } ]]() == 4)
+  a = a + 1;
+
+  for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
+  }
+  for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
+  }
+
+  // lambdas: scope with structured binding
+  struct Coordinates {
+int x{};
+int y{};
+  };
+  Coordinates c{};
+  if (const auto [x, y] = c; x > y)
+auto f = [[ [&]() { return x + y; } ]];
+
+  // lambdas: referencing outside variables that block extraction
+  //  in trailing return type or in a decltype used
+  //  by a parameter
+  if (int a = 1)
+if ([[ []() -> decltype(a) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4)
+  a = a + 1;
 }
   )cpp";
   EXPECT_UNAVAILABLE(UnavailableCases);
 
+  ExtraArgs = {"-std=c++20"};
+  const char *UnavailableCasesCXX20 = R"cpp(
+template 
+concept Constraint = requires (T t) { true; };
+void foo() {
+  // lambdas: referencing outside variables that block extraction
+  //  in requires clause or defaulted explicit template parameters
+  if (int a = 1)
+if ([[ [](auto b) requires (Constraint && Constraint) { return true; } ]] (a))
+  a = a + 1;
+
+  if (int a = 1)
+if ([[ [](T b) { return true; } ]] (a))
+  a = a + 1;
+}
+  )cpp";
+  EXPECT_UNAVAILABLE(UnavailableCasesCXX20);
+  ExtraArgs.clear();
+
   // vector of pairs of input and output strings
   std::vector> InputOutputs = {
   // extraction from variable declaration/assignment
@@ -282,6 +361,219 @@
  void f() {
auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
  })cpp"},
+  // lambda expressions
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([[ [](){ return 42; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = [](){ return 42; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([x = [[40 + 2]] ](){ return 42; });
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; });
+}
+)cpp"},
+  {R"cpp(auto foo(int VarA) {
+  return [VarA]() {
+return [[ [VarA, VarC = 

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-04 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

(Otherwise the updates look good!)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-04 Thread Nathan Ridge via Phabricator via cfe-commits
nridge requested changes to this revision.
nridge added inline comments.
This revision now requires changes to proceed.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:187
+// Allow expressions, but only allow completely selected lambda
+// expressions or unselected lambda expressions that are the parent of
+// the originally selected node, not partially selected lambda

nridge wrote:
> 5chmidti wrote:
> > nridge wrote:
> > > I think it's worth adding to the comment *why* we allow unselected lambda 
> > > expressions (to allow extracting from capture initializers), as it's not 
> > > obvious
> > I changed the previous return of `!isa(Stmt) || 
> > InsertionPoint->Selected != SelectionTree::Partial;` to a simple `return 
> > true;`. None of my partial selection tests fail and I can't think of a case 
> > where the lambda would be partially selected.
> Hmm, so what actually happens in these testcases?
> 
> ```
>   // lambdas: partially selected
>   [][[(){}]];
>   []()[[{}]];
>   [ [[ ](){}]];
> ```
I checked, and in these cases we disallow the extraction 
[here](https://searchfox.org/llvm/rev/c2bee1ed26a3355d164c92f1eb70ebf88804560d/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp#426-432)
 before we get to creating an `ExtractionContext`.

If the testcases are modified as follows:

```
template  void sink(T) {}
...
void f() {
  // lambdas: partially selected
  sink([][[(){}]]);
  sink([]()[[{}]]);
  sink([ [[ ](){}]]);
}
```

now they fail, unless the check for partial selection here is restored.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-09-04 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added inline comments.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:102
+
+  if (clang::Expr *const RequiresClause =
+  LExpr->getTrailingRequiresClause();

nit: just `if (clang::Expr *const RequiresClause = 
LExpr->getTrailingRequiresClause())` is equivalent



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:187
+// Allow expressions, but only allow completely selected lambda
+// expressions or unselected lambda expressions that are the parent of
+// the originally selected node, not partially selected lambda

5chmidti wrote:
> nridge wrote:
> > I think it's worth adding to the comment *why* we allow unselected lambda 
> > expressions (to allow extracting from capture initializers), as it's not 
> > obvious
> I changed the previous return of `!isa(Stmt) || 
> InsertionPoint->Selected != SelectionTree::Partial;` to a simple `return 
> true;`. None of my partial selection tests fail and I can't think of a case 
> where the lambda would be partially selected.
Hmm, so what actually happens in these testcases?

```
  // lambdas: partially selected
  [][[(){}]];
  []()[[{}]];
  [ [[ ](){}]];
```


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-31 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti marked an inline comment as done.
5chmidti added a comment.

Ping


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-21 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti marked 4 inline comments as done.
5chmidti added inline comments.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:91
+
+// Local variables declared inside of the selected lambda cannot go out of
+// scope. The DeclRefExprs that are important are the variables captured 
and

nridge wrote:
> 5chmidti wrote:
> > nridge wrote:
> > > Looking at 
> > > [RecursiveASTVisitor::TraverseLambdaExpr](https://searchfox.org/llvm/rev/094539cfcb46f55824402565e5c18580df689a67/clang/include/clang/AST/RecursiveASTVisitor.h#2652-2691),
> > >  there are a few things it traverses in addition to the lambda's 
> > > parameters and body (which we are saying are ok to skip) and the lambda's 
> > > captures (which we are traversing).
> > > 
> > > For example, the lambda may have an explicit result type which references 
> > > a variable in scope:
> > > 
> > > ```
> > > int main() {
> > >   if (int a = 1)
> > > if ([[ []() -> decltype(a){ return 1; } ]] () == 4)
> > >   a = a + 1;
> > > }
> > > 
> > > ```
> > > 
> > > Here, extracting the lambda succeeds, and the reference to `a` in 
> > > `decltype(a)` becomes dangling.
> > I'll update the diff when I've implemented this. A requires clause may 
> > reference a variable like `a` as well.
> > A requires clause may reference a variable like `a` as well.
> 
> Technically, an explicit template parameter list can also reference a local 
> variable via e.g. a default argument for a non-type parameter.
> 
> I appreciate that we're getting into increasingly obscure edge cases here, so 
> please feel free to use your judgment and draw a line somewhere; the 
> refactoring introducing a compiler error when invoked on some 
> obscure/unlikely piece of code is not that big of a deal.
I have added support for attributes, trailing return-type decls and explicit 
template parameters to the visitor. I think that is every edge case covered.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:187
+// Allow expressions, but only allow completely selected lambda
+// expressions or unselected lambda expressions that are the parent of
+// the originally selected node, not partially selected lambda

nridge wrote:
> I think it's worth adding to the comment *why* we allow unselected lambda 
> expressions (to allow extracting from capture initializers), as it's not 
> obvious
I changed the previous return of `!isa(Stmt) || 
InsertionPoint->Selected != SelectionTree::Partial;` to a simple `return 
true;`. None of my partial selection tests fail and I can't think of a case 
where the lambda would be partially selected.



Comment at: 
clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp:149
+  [](int x = [[10]]){};
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [[ [i = [](){}](){} ]]) {};

nridge wrote:
> It's easy to overlook the purpose of this line amidst all the brackets, I 
> would suggest adding a comment like:
> 
> ```
> // Extracting from a capture initializer is usually fine, but not if
> // the capture itself is nested inside a default argument
> ```
I added some comments like the one for this example to indicate why an 
extraction is expected to be unavailable. The same goes for the tests just 
above (ln134-189).


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-21 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti updated this revision to Diff 552065.
5chmidti added a comment.

Addressed comments:

- added explicit template parameters, trailing return-type declarations and 
attributes to the visitor that finds DeclRefExprs
- added a few more comments about why an extraction is expected to be 
unavailable


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -66,6 +66,11 @@
 Code completion
 ^^^
 
+Code actions
+
+
+- The extract variable tweak gained support for extracting lambda expressions to a variable.
+
 Signature help
 ^^
 
Index: clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
===
--- clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -131,10 +131,85 @@
   goto label;
   label:
 a = [[1]];
+
+  // lambdas: partially selected
+  [][[(){}]];
+  []()[[{}]];
+  [ [[ ](){}]];
+
+  // lambdas: captures
+  int x = 0;
+  [ [[=]] ](){};
+  [ [[&]] ](){};
+  [ [[x]] ](){};
+  [ [[]] ](){};
+  [y = [[x]] ](){};
+  [ [[y = x]] ](){};
+
+  // lambdas: default args, cannot extract into function-local scope
+  [](int x = [[10]]){};
+  [](auto h = [[ [i = [](){}](){} ]]) {};
+
+  // lambdas: default args
+  // Extracting from capture initializers is usually fine,
+  // but not if the capture itself is nested inside a default argument
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [i = [[ 42 ]]](){}) {};
+
+  // lambdas: scope
+  if (int a = 1)
+if ([[ [&](){ return a + 1; } ]]() == 4)
+  a = a + 1;
+
+  for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
+  }
+  for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
+  }
+
+  // lambdas: scope with structured binding
+  struct Coordinates {
+int x{};
+int y{};
+  };
+  Coordinates c{};
+  if (const auto [x, y] = c; x > y)
+auto f = [[ [&]() { return x + y; } ]];
+
+  // lambdas: referencing outside variables that block extraction
+  //  in trailing return type or in a decltype used
+  //  by a parameter
+  if (int a = 1)
+if ([[ []() -> decltype(a) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4)
+  a = a + 1;
+  if (int a = 1)
+if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4)
+  a = a + 1;
 }
   )cpp";
   EXPECT_UNAVAILABLE(UnavailableCases);
 
+  ExtraArgs = {"-std=c++20"};
+  const char *UnavailableCasesCXX20 = R"cpp(
+template 
+concept Constraint = requires (T t) { true; };
+void foo() {
+  // lambdas: referencing outside variables that block extraction
+  //  in requires clause or defaulted explicit template parameters
+  if (int a = 1)
+if ([[ [](auto b) requires (Constraint && Constraint) { return true; } ]] (a))
+  a = a + 1;
+
+  if (int a = 1)
+if ([[ [](T b) { return true; } ]] (a))
+  a = a + 1;
+}
+  )cpp";
+  EXPECT_UNAVAILABLE(UnavailableCasesCXX20);
+  ExtraArgs.clear();
+
   // vector of pairs of input and output strings
   std::vector> InputOutputs = {
   // extraction from variable declaration/assignment
@@ -282,6 +357,219 @@
  void f() {
auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
  })cpp"},
+  // lambda expressions
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([[ [](){ return 42; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = [](){ return 42; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([x = [[40 + 2]] ](){ return 42; });
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; });
+}
+)cpp"},
+  {R"cpp(auto foo(int VarA) {
+  return [VarA]() {
+return [[ [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }]];
+  

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-18 Thread Nathan Ridge via Phabricator via cfe-commits
nridge requested changes to this revision.
nridge added a comment.
This revision now requires changes to proceed.

Ok, I've finished looking through the patch; sorry it took so long to get to.

It generally looks pretty good to me, I just have some fairly minor comments.

Thanks again for your work on this!




Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:182-184
+if (InsertionPoint->Parent->ASTNode.get() != nullptr) {
+  return false;
+}

5chmidti wrote:
> nridge wrote:
> > 5chmidti wrote:
> > > This is supposed to stop the following invalid code from happening:
> > > ```
> > > void foo() {
> > >   int placeholder = 42;
> > >   [](int x = placeholder {};
> > >   extern void bar(int x = placeholder);
> > > }
> > > ```
> > > 
> > > clangd does not seem to support extracting from the initializers of 
> > > defaulted parameters, should I keep the condition as is, or should I do 
> > > something different here? It is legal to have default arguments in global 
> > > scope (examples below).
> > > 
> > > The following insertions could exist (out of scope for this patch):
> > > ```
> > > int placeholder = 42;
> > > void foo() {
> > >   [](int x = placeholder {};
> > >   extern void bar(int x = placeholder);
> > > }
> > > ```
> > > ```
> > > struct X {
> > >   static inline int placeholder = 42;
> > >   void foo(int x = placeholder) {}
> > > };
> > > ```
> > > 
> > > Either way, I'll have to adjust the comment because this is not just to 
> > > stop default parameter initializers in lambdas from being extracted to a 
> > > local scope.
> > I'm having trouble following this comment. Can you give the testcase that 
> > would produce this invalid code?
> I provided test cases in lines 147-150 in ExtractVariableTests.cpp. For the 
> example given in my comment, the test case would be:
> Pre:
> ```
> void foo() {
>   [](int x = [[42]]) {};
> }
> ```
> (erroneous) Post:
> ```
> void foo() {
>   int placeholder = 42;
>   [](int x = placeholder) {};
> }
> ```
> 
Thanks. I think the reason for my confusion was that the code snippet in your 
original comment was missing a ')`, and I thought perhaps the refactoring 
introduced that syntax error, but I understand now that the actual issue is a 
semantic error where a default argument references a local variable which isn't 
allowed.

I think this is fine, the only cleanup I think is needed here is to collapse 
the "Allow all expressions..." comment at the top of the block, and the "Allow 
expressions..." comment just below, into one.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:91
+
+// Local variables declared inside of the selected lambda cannot go out of
+// scope. The DeclRefExprs that are important are the variables captured 
and

5chmidti wrote:
> nridge wrote:
> > Looking at 
> > [RecursiveASTVisitor::TraverseLambdaExpr](https://searchfox.org/llvm/rev/094539cfcb46f55824402565e5c18580df689a67/clang/include/clang/AST/RecursiveASTVisitor.h#2652-2691),
> >  there are a few things it traverses in addition to the lambda's parameters 
> > and body (which we are saying are ok to skip) and the lambda's captures 
> > (which we are traversing).
> > 
> > For example, the lambda may have an explicit result type which references a 
> > variable in scope:
> > 
> > ```
> > int main() {
> >   if (int a = 1)
> > if ([[ []() -> decltype(a){ return 1; } ]] () == 4)
> >   a = a + 1;
> > }
> > 
> > ```
> > 
> > Here, extracting the lambda succeeds, and the reference to `a` in 
> > `decltype(a)` becomes dangling.
> I'll update the diff when I've implemented this. A requires clause may 
> reference a variable like `a` as well.
> A requires clause may reference a variable like `a` as well.

Technically, an explicit template parameter list can also reference a local 
variable via e.g. a default argument for a non-type parameter.

I appreciate that we're getting into increasingly obscure edge cases here, so 
please feel free to use your judgment and draw a line somewhere; the 
refactoring introducing a compiler error when invoked on some obscure/unlikely 
piece of code is not that big of a deal.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:187
+// Allow expressions, but only allow completely selected lambda
+// expressions or unselected lambda expressions that are the parent of
+// the originally selected node, not partially selected lambda

I think it's worth adding to the comment *why* we allow unselected lambda 
expressions (to allow extracting from capture initializers), as it's not obvious



Comment at: 
clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp:149
+  [](int x = [[10]]){};
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [[ [i = [](){}](){} ]]) {};

It's easy to 

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-14 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti marked an inline comment as done.
5chmidti added inline comments.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:91
+
+// Local variables declared inside of the selected lambda cannot go out of
+// scope. The DeclRefExprs that are important are the variables captured 
and

nridge wrote:
> Looking at 
> [RecursiveASTVisitor::TraverseLambdaExpr](https://searchfox.org/llvm/rev/094539cfcb46f55824402565e5c18580df689a67/clang/include/clang/AST/RecursiveASTVisitor.h#2652-2691),
>  there are a few things it traverses in addition to the lambda's parameters 
> and body (which we are saying are ok to skip) and the lambda's captures 
> (which we are traversing).
> 
> For example, the lambda may have an explicit result type which references a 
> variable in scope:
> 
> ```
> int main() {
>   if (int a = 1)
> if ([[ []() -> decltype(a){ return 1; } ]] () == 4)
>   a = a + 1;
> }
> 
> ```
> 
> Here, extracting the lambda succeeds, and the reference to `a` in 
> `decltype(a)` becomes dangling.
I'll update the diff when I've implemented this. A requires clause may 
reference a variable like `a` as well.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:182-184
+if (InsertionPoint->Parent->ASTNode.get() != nullptr) {
+  return false;
+}

nridge wrote:
> 5chmidti wrote:
> > This is supposed to stop the following invalid code from happening:
> > ```
> > void foo() {
> >   int placeholder = 42;
> >   [](int x = placeholder {};
> >   extern void bar(int x = placeholder);
> > }
> > ```
> > 
> > clangd does not seem to support extracting from the initializers of 
> > defaulted parameters, should I keep the condition as is, or should I do 
> > something different here? It is legal to have default arguments in global 
> > scope (examples below).
> > 
> > The following insertions could exist (out of scope for this patch):
> > ```
> > int placeholder = 42;
> > void foo() {
> >   [](int x = placeholder {};
> >   extern void bar(int x = placeholder);
> > }
> > ```
> > ```
> > struct X {
> >   static inline int placeholder = 42;
> >   void foo(int x = placeholder) {}
> > };
> > ```
> > 
> > Either way, I'll have to adjust the comment because this is not just to 
> > stop default parameter initializers in lambdas from being extracted to a 
> > local scope.
> I'm having trouble following this comment. Can you give the testcase that 
> would produce this invalid code?
I provided test cases in lines 147-150 in ExtractVariableTests.cpp. For the 
example given in my comment, the test case would be:
Pre:
```
void foo() {
  [](int x = [[42]]) {};
}
```
(erroneous) Post:
```
void foo() {
  int placeholder = 42;
  [](int x = placeholder) {};
}
```



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-14 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

Haven't looked at everything yet, but wanted to mention one thing I noticed.




Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:91
+
+// Local variables declared inside of the selected lambda cannot go out of
+// scope. The DeclRefExprs that are important are the variables captured 
and

Looking at 
[RecursiveASTVisitor::TraverseLambdaExpr](https://searchfox.org/llvm/rev/094539cfcb46f55824402565e5c18580df689a67/clang/include/clang/AST/RecursiveASTVisitor.h#2652-2691),
 there are a few things it traverses in addition to the lambda's parameters and 
body (which we are saying are ok to skip) and the lambda's captures (which we 
are traversing).

For example, the lambda may have an explicit result type which references a 
variable in scope:

```
int main() {
  if (int a = 1)
if ([[ []() -> decltype(a){ return 1; } ]] () == 4)
  a = a + 1;
}

```

Here, extracting the lambda succeeds, and the reference to `a` in `decltype(a)` 
becomes dangling.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:182-184
+if (InsertionPoint->Parent->ASTNode.get() != nullptr) {
+  return false;
+}

5chmidti wrote:
> This is supposed to stop the following invalid code from happening:
> ```
> void foo() {
>   int placeholder = 42;
>   [](int x = placeholder {};
>   extern void bar(int x = placeholder);
> }
> ```
> 
> clangd does not seem to support extracting from the initializers of defaulted 
> parameters, should I keep the condition as is, or should I do something 
> different here? It is legal to have default arguments in global scope 
> (examples below).
> 
> The following insertions could exist (out of scope for this patch):
> ```
> int placeholder = 42;
> void foo() {
>   [](int x = placeholder {};
>   extern void bar(int x = placeholder);
> }
> ```
> ```
> struct X {
>   static inline int placeholder = 42;
>   void foo(int x = placeholder) {}
> };
> ```
> 
> Either way, I'll have to adjust the comment because this is not just to stop 
> default parameter initializers in lambdas from being extracted to a local 
> scope.
I'm having trouble following this comment. Can you give the testcase that would 
produce this invalid code?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-10 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

I promise I haven't forgotten about this. It's just been a challenge finding a 
large enough chunk of time to page in all the relevant context and think 
through the issues. Maybe this weekend...


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-08-10 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti added a comment.

Ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-07-26 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti added a comment.

Ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-07-07 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti updated this revision to Diff 538289.
5chmidti added a comment.

Ping, and:

- removed mention of captures from the condition about blocking extraction 
because that is allowed
- removed `(of a lambda)` from the following comment because it is not just 
about defaulted parameters of lambdas, but of all functions


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -66,6 +66,11 @@
 Code completion
 ^^^
 
+Code actions
+
+
+- The extract variable tweak gained support for extracting lambda expressions to a variable.
+
 Signature help
 ^^
 
Index: clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
===
--- clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -131,7 +131,43 @@
   goto label;
   label:
 a = [[1]];
-}
+
+  // lambdas
+  [][[(){}]];
+
+  // lambdas: captures
+  int x = 0;
+  [ [[=]] ](){};
+  [ [[&]] ](){};
+  [ [[x]] ](){};
+  [ [[] ]](){};
+  [y = [[x]] ](){};
+  [ [[y = x]] ](){};
+
+  // lambdas: default args
+  [](int x = [[10]]){};
+  [](auto h = [i = [[ [](){} ]]](){}) {};
+  [](auto h = [[ [i = [](){}](){} ]]) {};
+
+  // lambdas: scope
+  if (int a = 1)
+if ([[ [&](){ return a + 1; } ]]() == 4)
+  a = a + 1;
+
+  for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) {
+  }
+  for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) {
+  }
+
+  // lambdas: scope with structured binding
+  struct Coordinates {
+int x{};
+int y{};
+  };
+  Coordinates c{};
+  if (const auto [x, y] = c; x > y)
+auto f = [[ [&]() { return x + y; } ]];
+  }
   )cpp";
   EXPECT_UNAVAILABLE(UnavailableCases);
 
@@ -282,6 +318,209 @@
  void f() {
auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5);
  })cpp"},
+  // lambda expressions
+  {R"cpp(template  void f(T) {}
+void f2() {
+  f([[ [](){ return 42; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2() {
+  auto placeholder = [](){ return 42; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(auto foo(int VarA) {
+  return [VarA]() {
+return [[ [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }]];
+  };
+}
+)cpp",
+   R"cpp(auto foo(int VarA) {
+  return [VarA]() {
+auto placeholder = [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }; return  placeholder;
+  };
+}
+)cpp"},
+  {R"cpp(template  void f(T) {}
+void f2(int var) {
+  f([[ [](){ auto internal_val = 42; return var + internal_val; }]]);
+}
+)cpp",
+   R"cpp(template  void f(T) {}
+void f2(int var) {
+  auto placeholder = [](){ auto internal_val = 42; return var + internal_val; }; f( placeholder);
+}
+)cpp"},
+  {R"cpp(template  void f(T) { }
+struct A {
+void f2(int& var) {
+auto local_var = 42;
+f([[ [, _var, this]() {
+auto internal_val = 42;
+return var + local_var + internal_val + member;
+}]]);
+}
+
+int member = 42;
+};
+)cpp",
+   R"cpp(template  void f(T) { }
+struct A {
+void f2(int& var) {
+auto local_var = 42;
+auto placeholder = [, _var, this]() {
+auto internal_val = 42;
+return var + local_var + internal_val + member;
+}; f( placeholder);
+}
+
+int member = 42;
+};
+)cpp"},
+  {R"cpp(void f() { auto x = [[ [](){ return 42; }]]; })cpp",
+   R"cpp(void f() { auto placeholder = [](){ return 42; }; auto x =  placeholder; })cpp"},
+  {R"cpp(
+

[PATCH] D141757: [clangd] allow extracting to variable for lambda expressions

2023-04-29 Thread Julian Schmidt via Phabricator via cfe-commits
5chmidti added inline comments.



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:178
+  // Allow all expressions except partial LambdaExpr selections since we
+  // don't want to extract from the captures/default arguments of a lambda
+  if (isa(Stmt)) {

Noticed that this can be removed because extracting from captures is allowed. 
Will change in the next update



Comment at: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp:182-184
+if (InsertionPoint->Parent->ASTNode.get() != nullptr) {
+  return false;
+}

This is supposed to stop the following invalid code from happening:
```
void foo() {
  int placeholder = 42;
  [](int x = placeholder {};
  extern void bar(int x = placeholder);
}
```

clangd does not seem to support extracting from the initializers of defaulted 
parameters, should I keep the condition as is, or should I do something 
different here? It is legal to have default arguments in global scope (examples 
below).

The following insertions could exist (out of scope for this patch):
```
int placeholder = 42;
void foo() {
  [](int x = placeholder {};
  extern void bar(int x = placeholder);
}
```
```
struct X {
  static inline int placeholder = 42;
  void foo(int x = placeholder) {}
};
```

Either way, I'll have to adjust the comment because this is not just to stop 
default parameter initializers in lambdas from being extracted to a local scope.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D141757/new/

https://reviews.llvm.org/D141757

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits