Community
Participate
Working Groups
Consider the following having lambda expressions: Class X and Interface I2. We get exception or incorrect refactoring by performing "Extract Method" refactoring on the lines with comments. It should be possible to extract methods from a lambda expression, which would be created in its enclosing type. @FunctionalInterface public interface I1 { int foo(int a); } // Error: Extracted to m1() and placed in enclosing type. // But replaced with "m1();" instead of "int b= m1();" class X { I1 i1= (int a) -> { int b= 10; // Error return a + b; }; class Y { I1 i1= (int a) -> { int b= 10; // Error return a + b; }; } void foo() { I1 i1= (int a) -> { int b= 10; // Error return a + b; }; } void bar() { Runnable r= new Runnable() { I1 i1= (int a) -> { int b= 10; // Error return a + b; }; @Override public void run() { I1 i1= (int a) -> { int b= 10; // Error return a + b; }; } }; } } // see bug 406786 for Extract Method from lambda expr in interfaces interface I2 { I1 i1= (int a) -> { int b= 10; // Exception on extracting to method return a + b; }; }
Another case is when we have an inferred type parameter in lambda expression and we use it in an expression, being extracted to a method. We get "Unknown VariableDeclaration" exception. Example: class Y { I1 i = (a) -> { int b= a; // Exception(Unknown VariableDeclaration) return b; }; }
(In reply to comment #0) > // see bug 406786 for Extract Method from lambda expr in interfaces > interface I2 { > I1 i1= (int a) -> { > /*[*/ int b= 10; /*]*/ // Exception on extracting to method > return a + b; > }; > } After bug 406786 is fixed, there will not be any exception in the above example. The code will be extracted to a static method in I2 and now the issue will be as in the other examples of comment #0: > // But replaced with "m1();" instead of "int b= m1();"
Created attachment 234907 [details] Patch for exception in comment #1 (In reply to comment #1) > Another case is when we have an inferred type parameter in lambda expression > and we use it in an expression, being extracted to a method. > We get "Unknown VariableDeclaration" exception. > > Example: > > class Y { > I1 i = (a) -> { > /*[*/ int b= a; /*]*/ // Exception(Unknown VariableDeclaration) > return b; > }; > } The attached patch fixes the issue mentioned above i.e. now there will not be any exception in the above example. The code will be extracted to a method in Y and now the issue will be as in the other examples of comment #0: > // replaced with "m1(a);" instead of "int b= m1(a);" Markus, please have a look.
Some more cases: 1. @FunctionalInterface public interface I { int foo(int a); } class C_Test { // [1] Error - return type of new method is void, should be int I i= a -> { /*[*/ return a++; /*]*/ }; String foo() { // [2] Error - return type of new method is String, should be int I i= a -> { /*[*/ return a++; /*]*/ }; return ""; } } This is because the valid enclosing body declarations for method extraction are method declaration, field declaration and initializer only. Hence, on extracting a return statement in a lambda expr, the return type of the corresponding enclosing body decl is checked, which is null in case [1] (for field) and String in case [2] (for method). If the return stmt being extracted is within a lambda expr, return type of lambda expr should be considered instead of the enclosing body decl's return type. 2. @FunctionalInterface public interface J { void foo(); } class X1 { J j1= () -> { /*[*/ return; /*]*/ }; } Results in => class X1 { J j1= () -> { extracted(); return; // Bug - 'return;' not removed. }; private void extracted() { /*[*/ return; /*]*/ } }
Created attachment 235376 [details] Patch + Tests - The patch is created from ngupta/BETA_JAVA8 branch for: http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?h=ngupta/BETA_JAVA8&id=7da82302f552442f5453a887781bf468047f8d44 It depends on the patch for bug 406786 and patch given for comment #1. - Added the following important methods: * ExtractMethodAnalyzer#endVisit(FieldDeclaration) to prevent CCE when only a variable declaration fragment is extracted from field declaration. * ExtractMethodAnalyzer#visit(LambdaExpression) to allow extraction only at valid locations in lambda expr and handle bug 408009. * ASTNodeFactory#newReturnType(LambdaExpression, AST, ImportRewrite, ImportRewriteContext) to get the Type node for return type of lambda expr. * ASTResolving#findEnclosingLambdaExpression(ASTNode node) - Paste the given example in package explorer and edit the file (example: change /*a*/ to /*b*/). Select lambda expr "(int n1, int n2) -> n1 * n2" and extract it to a method. The extracted method takes unnecessary param "int n1" and will have compilation error which is due to bug 416560. ------------------------------- package misc.test; interface FI { int foo(int s1, int s2); } class Test { FI fi= /*a*/ (int n1, int n2) -> n1 * n2; } ------------------------------- - TODO: Update tests with formatted default methods, once bug 413592 is fixed. Markus, please have a look.
Another test case to be added after bug 417017 is fixed, which currently produces wrong parameter type for the extracted method: @FunctionalInterface interface FI { int foo1(int a); } class FI_1 { void fun(int a) { FI i1 = x1-> x1; FI i2 = xxx-> { i1.foo1(a); /*]*/return xxx;/*[*/ }; } }
Created attachment 236009 [details] Patch with updated tests (In reply to Noopur Gupta from comment #5) > - TODO: Update tests with formatted default methods, once bug 413592 is > fixed. Updated the tests with formatted default methods, added the test case from comment #6, updated fReturnTypeBinding for lambda expr. - The patch is created from ngupta/BETA_JAVA8 branch for: http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?h=ngupta/BETA_JAVA8&id=fb4597d2163679af8202c37f5efc73a96ffa7db7 It depends on the patch given in comment #5.
(In reply to Noopur Gupta from comment #5) > - Paste the given example in package explorer and edit the file (example: > change /*a*/ to /*b*/). > Select lambda expr "(int n1, int n2) -> n1 * n2" and extract it to a method. > The extracted method takes unnecessary param "int n1" and will have > compilation error which is due to bug 416560. Verified that the above issue is not reproducible after bug 416560 is fixed.
Released to BETA_JAVA8 with http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?id=f09aabc28fa041d926f45d21e601d4fac0e59812 and parent commit.
Verified using Kepler SR2 + Java 8 RC1 + Eclipse Java Development Tools Patch for Java 8 Support (BETA) 1.0.0.v20140220-2054