diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index 174da3d5d6fc..9d318fee236f 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -91,7 +91,10 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { ref = element.getReference(); } if (ref != null) { - renamedReferences.add(ref.handleElementRename(newName)); + PsiElement e = processRef(ref, newName); + if (e != null) { + renamedReferences.add(e); + } } } else { @@ -119,6 +122,17 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { qualifyStaticImportReferences(staticImportHides); } + /** + * handles rename of refs + * @param ref + * @param newName + * @return + */ + @Nullable + protected PsiElement processRef(PsiReference ref, String newName) { + return ref.handleElementRename(newName); + } + private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element, final String newName, final Set methodAndOverriders, final Set containingClasses, final boolean isStatic) throws IncorrectOperationException { @@ -176,7 +190,7 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { } } - private static void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { + private void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { final PsiClass containingClass = methodToRename.getContainingClass(); if (containingClass != null) { final PsiMethod prototype = getPrototypeWithNewName(methodToRename, newName); @@ -191,7 +205,8 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { if (((PsiReferenceExpression)element).resolve() == methodToRename) { final PsiMethodCallExpression copy = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(element.getProject()) .createExpressionFromText(element.getParent().getText(), element); - final PsiReferenceExpression expression = (PsiReferenceExpression)copy.getMethodExpression().handleElementRename(newName); + final PsiReferenceExpression expression = (PsiReferenceExpression)processRef(copy.getMethodExpression(), newName); + if (expression == null) continue; final JavaResolveResult resolveResult = expression.advancedResolve(true); final PsiMember resolveResultElement = (PsiMember)resolveResult.getElement(); if (resolveResult.isValidResult() && resolveResultElement != null) { diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 5c12a87bf099..6c859cfc3554 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -158,6 +158,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrReferenceElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrReferenceElementImpl.java index 7b18471390ed..6ae074d56866 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrReferenceElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrReferenceElementImpl.java @@ -82,7 +82,14 @@ public abstract class GrReferenceElementImpl extends Groov PsiElement nameElement = getReferenceNameElement(); if (nameElement != null) { ASTNode node = nameElement.getNode(); - ASTNode newNameNode = GroovyPsiElementFactory.getInstance(getProject()).createReferenceNameFromText(newElementName).getNode(); + GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject()); + ASTNode newNameNode; + try { + newNameNode = factory.createReferenceNameFromText(newElementName).getNode(); + } + catch (IncorrectOperationException e) { + newNameNode = factory.createLiteralFromValue(newElementName).getFirstChild().getNode(); + } assert newNameNode != null && node != null; node.getTreeParent().replaceChild(node, newNameNode); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index 03a0052d57a0..1d8b1d0ec8af 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -399,7 +399,17 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase i } public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { - PsiImplUtil.setName(name, getNameIdentifierGroovy()); + PsiElement nameElement = getNameIdentifierGroovy(); + + GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(nameElement.getProject()); + PsiElement newNameElement; + try { + newNameElement = factory.createReferenceNameFromText(name); + } + catch (IncorrectOperationException e) { + newNameElement = factory.createLiteralFromValue(name).getFirstChild(); + } + nameElement.replace(newNameElement); return this; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties index 689c645e8730..9f2aac09e770 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties @@ -169,3 +169,4 @@ rename.implicit.closure.parameter.to=Rename implicit closure parameter to\: implicit.closure.parameter=Implicit closure parameter selected.expression.should.not.be.lvalue=Selected expression should not be left hand side of assignment column.name.use.any.var=Use any var +rename.groovy.method=Rename Groovy method diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GrMethodRenameHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GrMethodRenameHandler.java new file mode 100644 index 000000000000..eac040ad8b36 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GrMethodRenameHandler.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.refactoring.rename; + +import com.intellij.ide.TitledHandler; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.RenameDialog; +import com.intellij.refactoring.rename.RenameHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; + +/** + * @author Max Medvedev + */ +public class GrMethodRenameHandler implements RenameHandler, TitledHandler { + public boolean isAvailableOnDataContext(DataContext dataContext) { + final PsiElement element = getElement(dataContext); + if (element instanceof GrMethod) return true; + return false; + } + + @Nullable + private static PsiElement getElement(DataContext dataContext) { + return LangDataKeys.PSI_ELEMENT.getData(dataContext); + } + + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file, @Nullable DataContext dataContext) { + final PsiElement element = getElement(dataContext); + invokeInner(project, editor, element); + } + + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, @Nullable DataContext dataContext) { + PsiElement element = elements.length == 1 ? elements[0] : null; + if (element == null) element = getElement(dataContext); + Editor editor = dataContext == null ? null : PlatformDataKeys.EDITOR.getData(dataContext); + invokeInner(project, editor, element); + } + + private static void invokeInner(Project project, Editor editor, PsiElement element) { + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + new RenameGroovyMethodDialog(project, element, element, editor).show(); + } + + @Override + public String getActionTitle() { + return GroovyRefactoringBundle.message("rename.groovy.method"); + } + + private static class RenameGroovyMethodDialog extends RenameDialog { + public RenameGroovyMethodDialog(@NotNull Project project, + @NotNull PsiElement psiElement, + @Nullable PsiElement nameSuggestionContext, + Editor editor) { + super(project, psiElement, nameSuggestionContext, editor); + } + + @Override + protected boolean areButtonsValid() { + return true; + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasImportedMethodProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasImportedMethodProcessor.java index bda190722ccb..79cea2de2558 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasImportedMethodProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasImportedMethodProcessor.java @@ -15,9 +15,9 @@ */ package org.jetbrains.plugins.groovy.refactoring.rename; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiReference; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.rename.RenameJavaMethodProcessor; @@ -26,6 +26,8 @@ import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; @@ -73,7 +75,9 @@ public class RenameAliasImportedMethodProcessor extends RenameJavaMethodProcesso methodAccess.add(usage); } } + super.renameElement(psiElement, newName, methodAccess.toArray(new UsageInfo[methodAccess.size()]), listener); + final String propertyName; if (isGetter) { propertyName = getPropertyNameByGetterName(newName, true); @@ -128,7 +132,7 @@ public class RenameAliasImportedMethodProcessor extends RenameJavaMethodProcesso while (iterator.hasNext()) { final UsageInfo info = iterator.next(); final PsiElement ref = info.getElement(); - if (ref == null) continue; + if (ref instanceof GrReferenceExpression || ref == null) continue; if (!RenameUtil.isValidName(element.getProject(), ref, newName)) { iterator.add(new UnresolvableCollisionUsageInfo(ref, element) { @Override @@ -139,4 +143,26 @@ public class RenameAliasImportedMethodProcessor extends RenameJavaMethodProcesso } } } + + @Nullable + @Override + protected PsiElement processRef(PsiReference ref, String newName) { + PsiElement element = ref.getElement(); + if (RenameUtil.isValidName(element.getProject(), element, newName) || element instanceof GrReferenceElement) { + return super.processRef(ref, newName); + } + + PsiElement nameElement; + if (element instanceof PsiReferenceExpression) { + nameElement = ((PsiReferenceExpression)element).getReferenceNameElement(); + } + else { + return null; + } + TextRange range = nameElement.getTextRange(); + Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(nameElement.getContainingFile()); + document.replaceString(range.getStartOffset(), range.getEndOffset(), newName); + + return null; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy index 1bc8a1928ce2..7fc6d22388a5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy @@ -10,7 +10,9 @@ import com.intellij.refactoring.rename.RenameUtil import com.intellij.testFramework.fixtures.CodeInsightTestUtil import org.jetbrains.plugins.groovy.GroovyFileType import org.jetbrains.plugins.groovy.LightGroovyTestCase +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod import org.jetbrains.plugins.groovy.refactoring.rename.inplace.GrVariableInplaceRenameHandler @@ -521,4 +523,54 @@ class J { myFixture.renameElementAtCaret('getAbc') assertEquals('''print new J().abc''', groovyFile.text) } + + void testMethodWithSpacesRename() { + def file = myFixture.configureByText('_A.groovy', '''\ +class X { + def foo(){} +} + +new X().foo() +''') as GroovyFile + + def method = (file.classes[0] as GrTypeDefinition).groovyMethods[0] + + myFixture.renameElement(method, 'f oo'); + + myFixture.checkResult('''\ +class X { + def 'f oo'(){} +} + +new X().'f oo'() +''') + } + + void testMethodWithSpacesRenameInJava() { + def file = myFixture.addFileToProject('_A.groovy', '''\ +class X { + def foo(){} +} + +new X().foo() +''') as GroovyFile + + def method = (file.classes[0] as GrTypeDefinition).groovyMethods[0] + + myFixture.configureByText('Java.java', '''\ +class Java { + void ab() { + new X().foo() + } +}''') + + try { + myFixture.renameElement(method, 'f oo'); + assert false + } + catch (ConflictsInTestsException ignored) { + assert true + } + + } }