Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 368646 - [rename] rejects LocalVariable with initializer
Summary: [rename] rejects LocalVariable with initializer
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.8   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: 3.8 M6   Edit
Assignee: Ayushman Jain CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-01-16 03:35 EST by Andreas Thies CLA
Modified: 2012-03-13 10:39 EDT (History)
7 users (show)

See Also:


Attachments
Proposed fix + regression test (5.88 KB, patch)
2012-01-19 13:20 EST, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas Thies CLA 2012-01-16 03:35:46 EST
Build Identifier: 20110218-0911

When invoking a rename refactoring programmatically with a proper IJavaElement as a parameter, the refactoring reports a fatal error "A local variable declaration or reference must be selected to activate this refactoring" in case of local variables with initializer.

Reproducible: Always

Steps to Reproduce:
Build an AST from the snippet

public class A {
  public void m(String strX) {
    String strB = strX;
  }
}

and find the VariableDeclarationFragment 'strB = strX'. Resolve the according IJavaElement (LocalVariable) by

IVariableBinding binding = fragment.resolveBinding();
IJavaElement element = binding.getJavaElement();

and pass it to a rename refactoring

RefactoringContribution contribution = RefactoringCore.getRefactoringContribution(IJavaRefactorings.RENAME_LOCAL_VARIABLE);
RenameJavaElementDescriptor descriptor = (RenameJavaElementDescriptor) contribution.createDescriptor();
descriptor.setJavaElement(element);
descriptor.setNewName(name);
descriptor.setUpdateReferences(true);
RenameSupport.create(descriptor).openDialog(getShell());

This will result in the fatal error stated above which is inappropriate since a proper IJavaElement was passed.


This bug should be easy to fix: The debugger reveals that it is caused by the method

RenameLocalVariableProcessor#initAST()

where 

ASTNode name= NodeFinder.perform(fCompilationUnitNode, sourceRange);

returns the VariableDeclarationFragment 'strB=strX' for the case above. The next statemet

if (name.getParent() instanceof VariableDeclaration)
  fTempDeclarationNode= (VariableDeclaration) name.getParent();

expects 'name' to be SimpleName (as a child of VariableDeclaration). This assumption is correct for a local variable without initializer only.

There should also be a check whether 'name' is a VariableDeclarationFragment.
Comment 1 Ayushman Jain CLA 2012-01-16 03:49:41 EST
Moving to JDT/UI
Comment 2 Stephan Herrmann CLA 2012-01-16 07:01:08 EST
(In reply to comment #0)
> ASTNode name= NodeFinder.perform(fCompilationUnitNode, sourceRange);

I couldn's see how you determined sourceRange
 
> returns the VariableDeclarationFragment 'strB=strX' for the case above. The
> next statemet

This could be the culprit, with a proper sourceRange I'd expect the
NodeFinder to just return the SimpleName 'strB' and all should go well
from there on.
Comment 3 Andreas Thies CLA 2012-01-16 07:39:57 EST
(In reply to comment #2)
> > ASTNode name= NodeFinder.perform(fCompilationUnitNode, sourceRange);
> 
> I couldn's see how you determined sourceRange

This line is quoted from the method initAST() in org.eclipse.jdt.internal.corext.refactoring.rename.RenameLocalVariableProcessor.
The source range is determined the line before:

ISourceRange sourceRange= fLocalVariable.getNameRange();

> > returns the VariableDeclarationFragment 'strB=strX' for the case above. The
> > next statemet
> 
> This could be the culprit, with a proper sourceRange I'd expect the
> NodeFinder to just return the SimpleName 'strB' and all should go well
> from there on.

For the LocalVariable 

java/lang/String strB [in m(String) [in A [in [Working copy] A.java [in p [in src [in Test]]]]]]

from the example above the expression

fLocalVariable.getNameRange() 

computes [offset=72, length=11] which means that the returned source range includes the declaration and the initializer. Hence, the NodeFinder will not return a simple name if there is an initializer.
Comment 4 Stephan Herrmann CLA 2012-01-16 08:37:18 EST
(In reply to comment #3)
> (In reply to comment #2)
> > > ASTNode name= NodeFinder.perform(fCompilationUnitNode, sourceRange);
> > 
> > I couldn's see how you determined sourceRange
> 
> This line is quoted from the method initAST() in

Sorry, I missed that part. Thanks for clarifying.

> For the LocalVariable 
> 
> java/lang/String strB [in m(String) [in A [in [Working copy] A.java [in p [in
> src [in Test]]]]]]
> 
> from the example above the expression
> 
> fLocalVariable.getNameRange() 
> 
> computes [offset=72, length=11] which means that the returned source range
> includes the declaration and the initializer. Hence, the NodeFinder will not
> return a simple name if there is an initializer.

That looks bogus to me. Not sure who would be to blame. The nameRange should
only include the name, and from what I can see in the sources this range 
should be derived from LocalVariableDeclaration.sourceEnd (internal AST),
which should not include the initialization. Hm.
Comment 5 Markus Keller CLA 2012-01-16 11:15:28 EST
This is a bug in IBinding#getJavaElement().

When I use the JavaElement View [1] to create an ILocalVariable using codeSelect, then the nameRange is correct (see the Properties view). But when I use the ASTView, expand the variable binding, and then double-click the ILocalVariable (last child of the binding), the name range is too long.

After performing "Show In > JavaElement View", he other properties of the ILocalVariable look OK (except for the wrong range in the handle identifier).


[1] http://www.eclipse.org/jdt/ui/update-site
Comment 6 Olivier Thomann CLA 2012-01-19 13:20:19 EST
Created attachment 209768 [details]
Proposed fix + regression test
Comment 7 Olivier Thomann CLA 2012-01-19 13:20:46 EST
Running all tests.
Comment 8 Srikanth Sankaran CLA 2012-01-19 16:49:00 EST
Ayush, please take this forward for M6. TIA.

Thanks a lot Olivier.
Comment 9 Ayushman Jain CLA 2012-03-05 07:47:06 EST
Deepak, can you please run the UI tests with the patch? I'll release if everything's green, patch looks good. Thanks!
Comment 10 Deepak Azad CLA 2012-03-05 08:31:59 EST
(In reply to comment #9)
> Deepak, can you please run the UI tests with the patch? 

I can, but this model does not scale and nor the ensuing to-and-fro is very efficient. Is there anything that prevents JDT/Core team from running JDT/UI tests? (I think there are enough secondary machines in the team)

The steps for running JDT/UI tests are mentioned here - http://wiki.eclipse.org/JDT_UI/How_to_Contribute#Unit_Testing. If the steps are not clear, please let me know I will update them.
Comment 11 Ayushman Jain CLA 2012-03-07 03:51:57 EST
UI tests were green

Released in master via commit c5887d07050c9433ef244b9fc8d660e0afd1c02c
Comment 12 Satyam Kandula CLA 2012-03-13 10:39:22 EDT
Verified for 3.8M6 using build I20120312-1300