5chmidti updated this revision to Diff 491319. 5chmidti added a comment. Herald added a subscriber: ChuanqiXu.
1. addressed comments 2 bugfix (sorry, should've said something) Local variables inside the lambda were previously added to the ReferencedDecls vector and would block the action inside of exprIsValidOutside (declarations are inside of the lambda). Now only consider DeclRefExprs in the lambda captures. 3. I don't have commit access, someone else would need to commit this. I don't know if you want to delay this patch due to the bugfix or not, either way is fine with me. 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 complete 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; } + template <typename T> 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,67 @@ void f() { auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5); })cpp"}, + // Complete lambda expressions + {R"cpp(template <typename T> void f(T) {} + void f2() { + f([[ [](){ return 42; }]]); + } + )cpp", + R"cpp(template <typename T> 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 <typename T> void f(T) {} + void f2(int var) { + f([[ [&var](){ auto internal_val = 42; return var + internal_val; }]]); + } + )cpp", + R"cpp(template <typename T> void f(T) {} + void f2(int var) { + auto placeholder = [&var](){ auto internal_val = 42; return var + internal_val; }; f( placeholder); + } + )cpp"}, + {R"cpp(template <typename T> void f(T) { } + struct A { + void f2(int& var) { + auto local_var = 42; + f([[ [&var, &local_var, this]() { + auto internal_val = 42; + return var + local_var + internal_val + member; + }]]); + } + + int member = 42; +}; + )cpp", + R"cpp(template <typename T> void f(T) { } + struct A { + void f2(int& var) { + auto local_var = 42; + auto placeholder = [&var, &local_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"}, // 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 Index: clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp =================================================================== --- clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp +++ clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp @@ -12,6 +12,7 @@ #include "SourceCode.h" #include "refactor/Tweak.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/OperationKinds.h" @@ -78,6 +79,23 @@ return true; } }; + + // Local variables declared inside of the selected lambda cannot go out of + // scope. The DeclRefExprs that are important are the lambda captures and + // capture var intitializers. + if (const auto *const LExpr = llvm::dyn_cast<LambdaExpr>(Expr)) { + FindDeclRefsVisitor Visitor; + for (const auto &Capture : LExpr->captures()) { + if (Capture.capturesVariable()) { + auto *const CapturedVar = Capture.getCapturedVar(); + if (auto *const VDecl = llvm::dyn_cast<VarDecl>(CapturedVar)) { + Visitor.TraverseStmt(VDecl->getInit()); + } + } + } + return Visitor.ReferencedDecls; + } + FindDeclRefsVisitor Visitor; Visitor.TraverseStmt(const_cast<Stmt *>(cast<Stmt>(Expr))); return Visitor.ReferencedDecls; @@ -152,10 +170,12 @@ auto CanExtractOutside = [](const SelectionTree::Node *InsertionPoint) -> bool { if (const clang::Stmt *Stmt = InsertionPoint->ASTNode.get<clang::Stmt>()) { - // 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<clang::Expr>(Stmt)) - return !isa<LambdaExpr>(Stmt); + return !isa<LambdaExpr>(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.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits