diff --git a/annotations/com/intellij/refactoring/rename/annotations.xml b/annotations/com/intellij/refactoring/rename/annotations.xml
new file mode 100644
index 00000000000..7c596a8c959
--- /dev/null
+++ b/annotations/com/intellij/refactoring/rename/annotations.xml
@@ -0,0 +1,17 @@
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 3a7073cdcc5..3350695ee65 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -216,7 +216,9 @@
-
+
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt
index 9db91bf4d33..8cf2f29b700 100644
--- a/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/rename/RenameKotlinFunctionProcessor.kt
@@ -16,34 +16,60 @@
package org.jetbrains.jet.plugin.refactoring.rename;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.psi.PsiCompiledElement;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiMethod;
-import com.intellij.psi.search.SearchScope;
-import com.intellij.refactoring.rename.RenamePsiElementProcessor;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jet.asJava.KotlinLightClass;
-import org.jetbrains.jet.lang.psi.JetFunction;
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiCompiledElement
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMethod
+import com.intellij.refactoring.rename.RenamePsiElementProcessor
+import com.intellij.psi.search.SearchScope
+import com.intellij.psi.search.searches.OverridingMethodsSearch
+import com.intellij.openapi.application.ApplicationManager
+import org.jetbrains.jet.asJava.LightClassUtil
+import org.jetbrains.jet.lang.psi.JetNamedFunction
+import com.intellij.openapi.util.Computable
+import com.intellij.psi.PsiMirrorElement
+import com.intellij.psi.SyntheticElement
+import com.intellij.refactoring.util.RefactoringUtil
+import com.intellij.refactoring.rename.RenameProcessor
+import com.intellij.refactoring.rename.RenameJavaMethodProcessor
+import com.intellij.psi.PsiNamedElement
+import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod
+import kotlin.properties.Delegates
-import java.util.Map;
+public class RenameKotlinFunctionProcessor : RenamePsiElementProcessor() {
+ private val javaMethodProcessorInstance by Delegates.lazy {
+ // KT-4250
+ // RenamePsiElementProcessor.EP_NAME.findExtension(javaClass())!!
-public class RenameKotlinFunctionProcessor extends RenamePsiElementProcessor {
- @Override
- public boolean canProcessElement(@NotNull PsiElement element) {
- if (element instanceof PsiMethod && ((PsiMethod) element).getContainingClass() instanceof KotlinLightClass) {
- return true;
- }
- return element instanceof JetFunction;
+ RenameJavaMethodProcessor()
}
- @Override
- public PsiElement substituteElementToRename(PsiElement element, @Nullable Editor editor) {
- if (element instanceof PsiMethod && element instanceof PsiCompiledElement &&
- ((PsiMethod) element).getContainingClass() instanceof KotlinLightClass) {
- return ((PsiCompiledElement) element).getMirror();
+ override fun canProcessElement(element: PsiElement): Boolean {
+ return element is JetNamedFunction || element is KotlinLightMethod
+ }
+
+ override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
+ val wrappedMethod = wrapPsiMethod(element)
+ if (wrappedMethod == null) {
+ // Cancel rename
+ return null
}
- return super.substituteElementToRename(element, editor);
+
+ // Use java dialog to ask we should rename function with the base element
+ return unwrapPsiMethod(javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor))
+ }
+
+ override fun prepareRenaming(element: PsiElement?, newName: String?, allRenames: MutableMap, scope: SearchScope) {
+ javaMethodProcessorInstance.prepareRenaming(wrapPsiMethod(element), newName, allRenames, scope)
+ }
+
+ private fun wrapPsiMethod(element: PsiElement?): PsiMethod? = when (element) {
+ is KotlinLightMethod -> element
+ is JetNamedFunction -> ApplicationManager.getApplication()!!.runReadAction(Computable { LightClassUtil.getLightClassMethod(element) })
+ else -> throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
+ }
+
+ private fun unwrapPsiMethod(element: PsiElement?): JetNamedFunction? {
+ return (element as? KotlinLightMethod)?.getOrigin() as? JetNamedFunction
}
}
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/RenameKotlinBaseMethod.kt b/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/RenameKotlinBaseMethod.kt
new file mode 100644
index 00000000000..0523cfb4116
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/RenameKotlinBaseMethod.kt
@@ -0,0 +1,27 @@
+package testing.rename
+
+trait A {
+ fun second() : Int
+}
+
+public open class B: A {
+ override fun second() = 1
+
+ fun first(a: Int) = 12
+}
+
+class C: B() {
+ override fun second() = 2
+}
+
+fun usages() {
+ val b = B()
+ val a: A = b
+ val c = C()
+
+ a.second()
+ b.second()
+ c.second()
+}
+
+
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/testing/JavaClient.java b/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/testing/JavaClient.java
new file mode 100644
index 00000000000..4908268f958
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/after/testing/JavaClient.java
@@ -0,0 +1,26 @@
+package testing;
+
+import testing.rename.*;
+
+class JavaClient {
+ public void foo(A a) {
+ a.second();
+ new B().second();
+ new C().second();
+ new D().second();
+ }
+
+ public static class D implements A {
+ @Override
+ public int second() {
+ return 3;
+ }
+ }
+
+ public static class E extends D {
+ @Override
+ public int second() {
+ return 4;
+ }
+ }
+}
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/RenameKotlinBaseMethod.kt b/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/RenameKotlinBaseMethod.kt
new file mode 100644
index 00000000000..7e5dcc2a4cc
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/RenameKotlinBaseMethod.kt
@@ -0,0 +1,27 @@
+package testing.rename
+
+trait A {
+ fun first() : Int
+}
+
+public open class B: A {
+ override fun first() = 1
+
+ fun first(a: Int) = 12
+}
+
+class C: B() {
+ override fun first() = 2
+}
+
+fun usages() {
+ val b = B()
+ val a: A = b
+ val c = C()
+
+ a.first()
+ b.first()
+ c.first()
+}
+
+
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/testing/JavaClient.java b/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/testing/JavaClient.java
new file mode 100644
index 00000000000..b10d6a38285
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/before/testing/JavaClient.java
@@ -0,0 +1,26 @@
+package testing;
+
+import testing.rename.*;
+
+class JavaClient {
+ public void foo(A a) {
+ a.first();
+ new B().first();
+ new C().first();
+ new D().first();
+ }
+
+ public static class D implements A {
+ @Override
+ public int first() {
+ return 3;
+ }
+ }
+
+ public static class E extends D {
+ @Override
+ public int first() {
+ return 4;
+ }
+ }
+}
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/javaWrapperForBaseFunction.test b/idea/testData/refactoring/rename/renameKotlinBaseMethod/javaWrapperForBaseFunction.test
new file mode 100644
index 00000000000..d9c8385f1b4
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/javaWrapperForBaseFunction.test
@@ -0,0 +1 @@
+// RENAME: JAVA_METHOD->testing.rename.A->void first()->second
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameKotlinBaseMethod/kotlinBaseFunction.test b/idea/testData/refactoring/rename/renameKotlinBaseMethod/kotlinBaseFunction.test
new file mode 100644
index 00000000000..6b1ffbd52d5
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameKotlinBaseMethod/kotlinBaseFunction.test
@@ -0,0 +1,3 @@
+// RENAME: KOTLIN_FUNCTION->testing.rename.A.first->second
+
+// KT-2836 Rename method with all its implementations
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java
index fadc48f51f2..a498481f707 100644
--- a/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/rename/RenameTestGenerated.java
@@ -41,6 +41,16 @@ public class RenameTestGenerated extends AbstractRenameTest {
doTest("idea/testData/refactoring/rename/renameJavaClass/renameJavaClass.test");
}
+ @TestMetadata("renameKotlinBaseMethod/javaWrapperForBaseFunction.test")
+ public void testRenameKotlinBaseMethod_JavaWrapperForBaseFunction() throws Exception {
+ doTest("idea/testData/refactoring/rename/renameKotlinBaseMethod/javaWrapperForBaseFunction.test");
+ }
+
+ @TestMetadata("renameKotlinBaseMethod/kotlinBaseFunction.test")
+ public void testRenameKotlinBaseMethod_KotlinBaseFunction() throws Exception {
+ doTest("idea/testData/refactoring/rename/renameKotlinBaseMethod/kotlinBaseFunction.test");
+ }
+
@TestMetadata("renameKotlinClass/javaWrapperForKotlinClass.test")
public void testRenameKotlinClass_JavaWrapperForKotlinClass() throws Exception {
doTest("idea/testData/refactoring/rename/renameKotlinClass/javaWrapperForKotlinClass.test");