Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 436997 - [move method] incorrect precondition of checking references to enclosing instances in generic declaring class.
Summary: [move method] incorrect precondition of checking references to enclosing inst...
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.8.1   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 4.5 M1   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 100546
Blocks:
  Show dependency tree
 
Reported: 2014-06-09 15:43 EDT by Jongwook Kim CLA
Modified: 2014-06-12 13:15 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jongwook Kim CLA 2014-06-09 15:43:56 EDT
When the declaring class of enclosing instances is "generic", the precondition for checking references to enclosing instances does not work.

Applying move-instance-method to method m() results in an error below.

------------------------------
BEFORE
------------------------------

class A<T> {
	int i;

	class C {
		B b = null;
		void m() {
			i = 0;
		}
	}
}

------------------------------
AFTER
------------------------------

class A<T> {
	int i;

	class C {
		B b = null;
	}
}

import p.A.C;

class B{

	void m(C c) {
		i = 0;	//ERROR
	}

}

------------------------------
Here is the error location.

JDT Classic version: 4.2.2

Class Name: org.eclipse.jdt.internal.corext.refactoring.structure.MoveInstanceMethodProcessor

Source code:

...

public final class EnclosingInstanceReferenceFinder extends AstNodeFinder {

		...

		@Override
		public final boolean visit(final SimpleName node) {
			Assert.isNotNull(node);
			final IBinding binding= node.resolveBinding();
			ITypeBinding declaring= null;
			if (binding instanceof IVariableBinding) {
				final IVariableBinding variable= (IVariableBinding) binding;
				if (Flags.isStatic(variable.getModifiers()))
					return false;
				declaring= variable.getDeclaringClass();    //getDeclaringClass() returns NULL when the declaring class is "generic".

		...
Comment 1 Jongwook Kim CLA 2014-06-09 18:04:31 EDT
In the meantime, I found that member i and its reference have different type-binding keys in AST:

class A<T> {
	int i;    // Lp/A;.i)I

	class C {
		B b = null;
		void m() {
			i = 0;    // Lp/A<Lp/A;:TT;>;.i)I
		}
	}
}

Hope that it's helpful for debugging.
Comment 2 Noopur Gupta CLA 2014-06-11 05:54:03 EDT
The issue is reproducible with Eclipse 3.8.1 also.

(In reply to Jongwook Kim from comment #0)
> declaring= variable.getDeclaringClass();    //getDeclaringClass()
> returns NULL when the declaring class is "generic".
I don't see null being returned for i's declaring class in the example.

(In reply to Jongwook Kim from comment #1)
> In the meantime, I found that member i and its reference have different
> type-binding keys in AST:

For A<T> in the example, we get bindings as mentioned in bug 100546 comment #2.
But the isEqualTo method (invoked by: Bindings.equals(enclosing, declaring) at MoveInstanceMethodProcessor: line 342) returns 'false', which causes the bug.

As per bug 100546 comment #4, the wrong results from isEqualTo(..) have been clarified and fixed. Does it mean that the client should handle the difference in bindings, as in the given example?
Comment 3 Markus Keller CLA 2014-06-12 13:15:37 EDT
(In reply to Jongwook Kim from comment #1)
> In the meantime, I found that member i and its reference have different
> type-binding keys in AST:

Yes, that's expected: The reference to i has a parameterized type as declaring class.

(In reply to Noopur Gupta from comment #2)
No, that comment was referring to other bugs in isEqualTo(..) that were present at the time that bug was opened. Note that bug 100546 is about a *static* nested class, but comment 0 is about a (non-static) inner class.

The fix for comment 0 is in EnclosingInstanceReferenceFinder#visit(SimpleName): Call getTypeDeclaration() on the declaring class (or, equivalently, call getVariable|MethodDeclaration() before calling getDeclaringClass()).

I've also fixed a similar problem if the field is static, see test67.

Fixed with http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?id=cc3cd91f01de9a50ef638d7b21d42084449dcda0