Community
Participate
Working Groups
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.
Moving to JDT/UI
(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.
(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.
(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.
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
Created attachment 209768 [details] Proposed fix + regression test
Running all tests.
Ayush, please take this forward for M6. TIA. Thanks a lot Olivier.
Deepak, can you please run the UI tests with the patch? I'll release if everything's green, patch looks good. Thanks!
(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.
UI tests were green Released in master via commit c5887d07050c9433ef244b9fc8d660e0afd1c02c
Verified for 3.8M6 using build I20120312-1300