Bug 313036 - [rename] Renaming a class changes class inheritance and leads to behavioral change
Summary: [rename] Renaming a class changes class inheritance and leads to behavioral c...
Status: ASSIGNED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.8   Edit
Hardware: All All
: P5 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Martin Mathew CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 71761
Blocks:
  Show dependency tree
 
Reported: 2010-05-16 11:21 EDT by Gustavo Soares CLA
Modified: 2013-04-29 23:59 EDT (History)
3 users (show)

See Also:
markus.kell.r: review+


Attachments
Patch using InsertEdit. (3.35 KB, patch)
2013-04-29 06:52 EDT, Martin Mathew CLA
no flags Details | Diff
Patch with a strong message. (1.01 KB, patch)
2013-04-29 10:35 EDT, Martin Mathew CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Gustavo Soares CLA 2010-05-16 11:21:04 EDT
Build Identifier: 20090920-1017

Renaming a class changes class inheritance and program behavior. After the refactoring, the 'extend' expression match with a class of the same package instead of a class imported using wildcard.

Reproducible: Always

Steps to Reproduce:
1. Create the classes:

package a;
public class A {
	public int k() {
		return 20;
	}
}

package a;
import b.*;
public class B extends C {
	public int test() {
		return k();
	}
}

package b;
public class C {
	public int k() {
		return 10;
	}
}

2. The method test returns 10

3. Apply the rename class refactoring to A renaming it to C

package a;
public class C {
	public int k() {
		return 20;
	}
}

package a;
import b.*;
public class B extends C {
	public int test() {
		return k();
	}
}

package b;
public class C {
	public int k() {
		return 10;
	}
}


4. After the refactoring, the method test returns 20 instead of 10. The program behavior was changed.
Comment 1 Dani Megert CLA 2010-05-18 09:54:08 EDT
Like that since day one.
Comment 2 Martin Mathew CLA 2013-04-24 04:53:01 EDT
To avoid this behavior change during rename operation, I would propose two solutions.
1. In addition to the wild card import statement, add an explicit import statement so that the renamed class does not shadow the wild card import. For instance in the given example after the rename operation B.java will have the below import statements.
     import b.*;
     import b.C;
2. Inform the user that the renaming might result in a behavior change of the existing system. Either stop the user from performing such a rename or issue a stronger message. Note: In the current implementation we do issue an error message to the user saying "Another type named 'C' is referenced in 'B'". May be we can have a stronger message instead.

Dani, let me know if there is a better solution or which of the above can be used to solve the issue.
Comment 3 Markus Keller CLA 2013-04-24 09:26:33 EDT
Similar to bug 356677. RenameTypeProcessor#checkConflictingTypes(..) already finds similar conflicts, but it apparently misses this specific case.

Solution 1 probably cannot be implemented right now due to bug 71761.
Solution 2 is the way to go.

Not critical for 4.3.
Comment 4 Martin Mathew CLA 2013-04-29 06:52:16 EDT
Created attachment 230247 [details]
Patch using InsertEdit.

Went through bug 71761. From the bug report and the subsequent comments, ImportRewrite currently cannot handle an on demand import and an explicit import from the same package. When it encounters the on demand import, it shadows the explicit import.
The Javadoc for ImportRewrite says that  eventually all the ImportRewrites are converted to text edits and then it is applied to the compilation unit. Hence I tried with InsertEdit to add the import statement in the affected compilation unit and it seems to work. The drawback is that the complete import statement has to be added as a string during the InsertEdit. I am not aware of the implications of using TextEdit instead of ImportRewrite. Markus, the patch uses InsertEdit to add the explicit import to the affected compilation unit. What is the consequence of using InsertEdit instead of ImportRewrite? Kindly have a look when you are free.
Comment 5 Markus Keller CLA 2013-04-29 08:46:09 EDT
(In reply to comment #4)
> Created attachment 230247 [details] [diff]
> Patch using InsertEdit.

Sorry, but that's a no-go. Unless a bug is critical, we don't hack around limitations in Eclipse APIs but we fix the APIs. ImportRewrite is the only acceptable way to manipulate imports. It ensures that all preferences are properly handled, and that adding an import doesn't modify existing references to the same simple name.
Comment 6 Martin Mathew CLA 2013-04-29 10:35:48 EDT
Created attachment 230256 [details]
Patch with a strong message.

Thanks Markus. Since the issue with ImportRewrite is yet to be solved, i have implemented the second proposed solution of issuing a stronger message. The message to the user in this case will be:
'Another type named 'C' is referenced in 'B.java'. Semantics may not be preserved if you proceed.'.
If user choose to proceed, then it is up to the user to deal with the consequences.
Comment 7 Markus Keller CLA 2013-04-29 11:21:06 EDT
(In reply to comment #3)
> RenameTypeProcessor#checkConflictingTypes(..) already
> finds similar conflicts, but it apparently misses this specific case.

Nothing is missed in 3.8. Since bug 356677, we show an error. Users who proceed if they see an error are on their own.

I probably used Organize Imports, which converted the "import b.*;" to "import b.C;", which makes this whole problem go away.

(In reply to comment #6)
This looks good and can go into M7, but the bug should stay open for solution 2 (once the blocking bug 71761 made this possible).
Comment 8 Martin Mathew CLA 2013-04-29 23:59:31 EDT
Thanks Markus. Released the patch as :
http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?id=6402d5193cf61d970c798bf077f5f31fba3202d6
The bug stays open until bug 71761 is resolved and the right solution of adding the explicit import along with the on demand import can be handled by ImportRewrite.