Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 406786

Summary: [1.8][extract method] Extract Method refactoring in interfaces not handled
Product: [Eclipse Project] JDT Reporter: Noopur Gupta <noopur_gupta>
Component: UIAssignee: Noopur Gupta <noopur_gupta>
Status: VERIFIED FIXED QA Contact:
Severity: enhancement    
Priority: P3 CC: daniel_megert, manju656, markus.kell.r, noopur_gupta, timo.kinnunen
Version: 4.3Flags: markus.kell.r: review+
Target Milestone: BETA J8   
Hardware: All   
OS: All   
Whiteboard:
Bug Depends on: 413592    
Bug Blocks: 405305, 407985    
Attachments:
Description Flags
Patch + Tests
none
Patch + Tests
none
Patch + Tests none

Description Noopur Gupta CLA 2013-04-29 07:44:40 EDT
Consider the following interfaces: I2 (having lambda expression) and I3 (having default and static methods). 
Perform "Extract Method" refactoring on the lines with comments. We get exception and no refactoring is performed.
It should be possible to extract methods in interfaces which would be created as default or static methods in those interfaces.

@FunctionalInterface
public interface I1 {
	int foo(int a);
}

interface I2 {
	I1 i1= (a) -> {
		int b= 10; // Exception on extracting to method
		return a + b;
	};
}

interface I3 {
	default int foo () {
		int a= 10; // Exception on extracting to method
		return a;
	}
	
	static int bar() {
		int a= 10; // Exception on extracting to method
		return a;
	}
}
Comment 1 Noopur Gupta CLA 2013-06-25 13:28:22 EDT
*** Bug 411608 has been marked as a duplicate of this bug. ***
Comment 2 Noopur Gupta CLA 2013-07-11 06:40:51 EDT
If the method is being extracted from a default method, then the extracted method will be default; otherwise it will be static.
 
Some open points regarding the expected behavior:
 
1. Access Modifier radio buttons:
If Destination type while opening the wizard is an interface, should 'public' be selected by default with all radio buttons disabled, or should we hide the access modifier composite itself?
And, when user changes the Destination type from an interface to non-interface and vice-versa, the composite would need to be updated accordingly.
 
2. When the expr being extracted from a default method, is also present in a static method and "Replace additional occurrences..." is checked, we get compilation error after refactoring since the new default method cannot be accessed from the static method. 
The same issue already happens in a class also.
 
3. Currently if we try to extract a method from a field initialization expr in an interface for source level < 1.8, we get NPE.
We can add a check and show error message "Cannot extract to an interface." in this case.
  
Markus, please share your thoughts.
Comment 3 Markus Keller CLA 2013-07-11 08:24:06 EDT
> 1. Access Modifier radio buttons:

We should keep the access modifier composite, but disable the modifiers that are not allowed for the selected destination. If the destination is an interface, then the extracted method should have the same keyword modifiers as the source method (i.e. if the original doesn't have a 'public' keyword, then the extracted method also shouldn't have it, although 'public' was selected in the UI).

> 2. When the expr being extracted from a default method, ...

Yeah, that's bug 393098. The "default method" variant can also be handled there.

> 3. Currently if we try to extract a method from a field initialization expr
> in an interface for source level < 1.8, we get NPE.
> We can add a check and show error message "Cannot extract to an interface."
> in this case.

Yes, please do that.
Comment 4 Noopur Gupta CLA 2013-08-22 07:01:01 EDT
Created attachment 234655 [details]
Patch + Tests

Patch contains the following major changes:

- ExtractMethodInputPage.java:
* If destination is an interface, all access modifiers in the wizard should be disabled and 'public' should be selected.
The access modifier setting for next invocation of the wizard should not be changed by the earlier forced 'public' for interface.
---------------------------------
- ExtractMethodRefactoring.java
* createChange(..) : Updated since the first type in destinations list need not be the direct parent type of code being extracted. Example:
class C {
    @interface A {
    	int i= /*[*/0;/*]*/	
    }
}
* initializeDestinations() : Updated so that combo displays only valid destination types.
* createNewMethodDeclaration() : 
  - If the user extracts an expression from a method into the directly enclosing interface, the extracted method has 'public' iff the enclosing method also was public.
  - New method will be 'static' if any of its ancestor nodes up to the destination type (excluding the destination) is static. In case of interface as destination, if method is not 'static' then it will be 'default'.
---------------------------------
- ExtractMethodAnalyzer.java:
* isValidDestination(ASTNode) : To check for interfaces < 1.8 and annotation types.
* checkInitialConditions(ImportRewrite) : check if any valid destination type exists for extraction, otherwise return with error.
* checkInput(RefactoringStatus, String, ASTNode) : Existing impl ignored the methods from direct super-interfaces hierarchies of destination type, added check for that. And added null check for super-class in interface.
---------------------------------
- Checks.java:
* checkMethodInType(ITypeBinding, String, ITypeBinding[]) : Updated as constructor warning is already added and it is not an 'error' to have a method with same name as constructor.
* checkMethodInHierarchy(ITypeBinding, String, ITypeBinding, ITypeBinding[]) : Added a different explicit warning message for constructors.
---------------------------------
- ASTResolving.java:
* Updated javadocs of #findParentType(..) methods.
---------------------------------
- TODO:
* Update test cases with formatted default methods (instead of the unformatted ones currently), once bug 413592 is fixed.
---------------------------------
- This patch also contains changes from bug 403924 in ExtractMethodRefactoring.java.

Markus, please have a look.
Comment 5 Noopur Gupta CLA 2013-10-01 08:25:10 EDT
Created attachment 236008 [details]
Patch + Tests

(In reply to Noopur Gupta from comment #4)
> - TODO:
> * Update test cases with formatted default methods (instead of the
> unformatted ones currently), once bug 413592 is fixed.

Updated the tests with formatted default methods.
Comment 6 Noopur Gupta CLA 2014-01-15 09:08:40 EST
*** Bug 425759 has been marked as a duplicate of this bug. ***
Comment 7 Martin Mathew CLA 2014-01-15 22:11:21 EST
Created attachment 239048 [details]
Patch + Tests


(In reply to Markus Keller from comment #3)
> > 2. When the expr being extracted from a default method, ...
> 
> Yeah, that's bug 393098. The "default method" variant can also be handled
> there.
This patch handles the case when code is extracted from default method and the duplicate code is present in static method also. The fix was given in bug 393098, i have merged the changes from master and added a testcase. The patch is checked in to mmathew/BETA_JAVA8 branch.
Comment 8 Markus Keller CLA 2014-02-20 11:59:33 EST
Released all necessary commits to BETA_JAVA8, see http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?id=c656ba52079370b803406e5b65ffe3b2c3f6e8f6 and 4 parent commits.
Comment 9 Martin Mathew CLA 2014-02-23 19:35:14 EST
Verified using Kepler SR2 + Java 8 RC1 +   Eclipse Java Development Tools Patch for Java 8 Support (BETA) 1.0.0.v20140220-2054