diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp --- a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp @@ -152,10 +152,11 @@ auto CanExtractOutside = [](const SelectionTree::Node *InsertionPoint) -> bool { if (const clang::Stmt *Stmt = InsertionPoint->ASTNode.get()) { - // Allow all expressions except LambdaExpr since we don't want to extract - // from the captures/default arguments of a lambda + // 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)) - return !isa(Stmt); + return !(isa(Stmt) && + InsertionPoint->Selected != SelectionTree::Complete); // We don't yet allow extraction from switch/case stmt as we would need to // jump over the switch stmt even if there is a CompoundStmt inside the // switch. And there are other Stmts which we don't care about (e.g. diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp @@ -98,6 +98,7 @@ return [[t]].bar([[t]].z); } void v() { return; } + template void callable_sink(T) {} // function default argument void f(int b = [[1]]) { // empty selection @@ -131,6 +132,21 @@ goto label; label: a = [[1]]; + + // lambdas + callable_sink([][[(){}]]); + + // captures + int x = 0; + callable_sink([ [[=]] ](){}); + callable_sink([ [[&]] ](){}); + callable_sink([ [[x]] ](){}); + callable_sink([ [[&x] ]](){}); + callable_sink([y = [[x]] ](){}); + callable_sink([ [[y = x]] ](){}); + + // default args + callable_sink([](int x = [[10]]){}); } )cpp"; EXPECT_UNAVAILABLE(UnavailableCases); @@ -282,6 +298,19 @@ void f() { auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5); })cpp"}, + // Complete 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(void f() { auto x = [[ [](){ return 42; }]]; })cpp", + R"cpp(void f() { auto placeholder = [](){ return 42; }; auto x = placeholder; })cpp"}, // Don't try to analyze across macro boundaries // FIXME: it'd be nice to do this someday (in a safe way) {R"cpp(#define ECHO(X) X