From 9b7bccce22e945664cd09a49a6d2ad6b10758b08 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 9 Sep 2014 13:51:23 +0400 Subject: [PATCH] Move: Move refactoring should correct constructor call when moving inner class #KT-4676 Fixed --- idea/src/META-INF/plugin.xml | 3 + .../MoveJavaInnerClassKotlinUsagesHandler.kt | 67 +++++++++++++++++++ ...lInTheSamePackageAndAddOuterInstance.test} | 0 .../after/a/X.java | 12 ++++ .../after/a/main.java | 6 ++ .../after/a/noImports.kt | 5 ++ .../after/a/onDemandImport.kt | 7 ++ .../after/a/specificImport.kt | 7 ++ .../before/a/main.java | 11 +++ .../before/a/noImports.kt | 5 ++ .../before/a/onDemandImport.kt | 7 ++ .../before/a/specificImport.kt | 7 ++ ...ePackageAndAddOuterInstanceWithLambda.test | 7 ++ .../refactoring/move/AbstractJetMoveTest.kt | 6 ++ .../move/JetMoveTestGenerated.java | 12 ++++ 15 files changed, 162 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/move/MoveJavaInnerClassKotlinUsagesHandler.kt rename idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/{moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test_todo => moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test} (100%) create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/X.java create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/main.java create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/noImports.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/onDemandImport.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/specificImport.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/main.java create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/noImports.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/onDemandImport.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/specificImport.kt create mode 100644 idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 394f16ff2a7..a2a1aac3eef 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -207,6 +207,9 @@ implementation="org.jetbrains.jet.plugin.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsHandler" order="before kotlin.moveFilesOrDirectories"/> + diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/move/MoveJavaInnerClassKotlinUsagesHandler.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/move/MoveJavaInnerClassKotlinUsagesHandler.kt new file mode 100644 index 00000000000..8ad7fb341d7 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/move/MoveJavaInnerClassKotlinUsagesHandler.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2014 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.jet.plugin.refactoring.move + +import com.intellij.refactoring.move.moveInner.MoveInnerClassUsagesHandler +import com.intellij.usageView.UsageInfo +import com.intellij.psi.PsiClass +import org.jetbrains.jet.lang.psi.JetQualifiedExpression +import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElementSelector +import org.jetbrains.jet.lang.psi.JetReferenceExpression +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.psi.JetCallExpression +import org.jetbrains.jet.lang.psi.JetPsiFactory +import java.util.Collections +import java.util.ArrayList +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.PsiWhiteSpace + +public class MoveJavaInnerClassKotlinUsagesHandler: MoveInnerClassUsagesHandler { + override fun correctInnerClassUsage(usage: UsageInfo, outerClass: PsiClass) { + val innerCall = usage.getElement()?.getParent() as? JetCallExpression + if (innerCall == null) return + + val receiver = (innerCall.getParent() as? JetQualifiedExpression)?.getReceiverExpression() + val outerClassRef = when (receiver) { + is JetCallExpression -> receiver.getCalleeExpression() + is JetQualifiedExpression -> receiver.getQualifiedElementSelector() + else -> null + } as? JetSimpleNameExpression + if (outerClassRef?.getReference()?.resolve() != outerClass) return + + val outerCall = outerClassRef!!.getParent() as? JetCallExpression + if (outerCall == null) return + + val psiFactory = JetPsiFactory(usage.getProject()) + + val argumentList = innerCall.getValueArgumentList() + if (argumentList != null) { + val newArguments = ArrayList() + newArguments.add(outerCall.getText()!!) + argumentList.getArguments().mapTo(newArguments) { it.getText()!! } + argumentList.replace(psiFactory.createCallArguments(newArguments.joinToString(prefix = "(", postfix = ")"))) + } + else { + innerCall.getFunctionLiteralArguments().firstOrNull()?.let { lambdaArg -> + val anchor = PsiTreeUtil.skipSiblingsBackward(lambdaArg, javaClass()) + innerCall.addAfter(psiFactory.createCallArguments("(${outerCall.getText()})"), anchor) + } + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test_todo b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test similarity index 100% rename from idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test_todo rename to idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/X.java b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/X.java new file mode 100644 index 00000000000..aadb4fa2a30 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/X.java @@ -0,0 +1,12 @@ +package a; + +import kotlin.Function0; + +public class X { + private A outer; + + public X(A outer, Function0 f) { + this.outer = outer; + System.out.println(f.invoke()); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/main.java b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/main.java new file mode 100644 index 00000000000..af2554f460e --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/main.java @@ -0,0 +1,6 @@ +package a; + +import kotlin.Function0; + +public class A { +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/noImports.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/noImports.kt new file mode 100644 index 00000000000..8eb18554713 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/noImports.kt @@ -0,0 +1,5 @@ +package a + +fun bar(s: String) { + val t: X = X(A()) { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/onDemandImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/onDemandImport.kt new file mode 100644 index 00000000000..d0cd1a55579 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/onDemandImport.kt @@ -0,0 +1,7 @@ +package a + +import a.A.* + +fun bar(s: String) { + val t: X = X(A()) { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/specificImport.kt new file mode 100644 index 00000000000..6ef143a0921 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/after/a/specificImport.kt @@ -0,0 +1,7 @@ +package a + +import a.X + +fun bar(s: String) { + val t: X = X(A()) { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/main.java b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/main.java new file mode 100644 index 00000000000..1755e2b24d4 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/main.java @@ -0,0 +1,11 @@ +package a; + +import kotlin.Function0; + +public class A { + public class X { + public X(Function0 f) { + System.out.println(f.invoke()); + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/noImports.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/noImports.kt new file mode 100644 index 00000000000..65e0495fb70 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/noImports.kt @@ -0,0 +1,5 @@ +package a + +fun bar(s: String) { + val t: A.X = A().X { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/onDemandImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/onDemandImport.kt new file mode 100644 index 00000000000..ec801813c17 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/onDemandImport.kt @@ -0,0 +1,7 @@ +package a + +import a.A.* + +fun bar(s: String) { + val t: X = A().X { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/specificImport.kt new file mode 100644 index 00000000000..255ce5532a3 --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/before/a/specificImport.kt @@ -0,0 +1,7 @@ +package a + +import a.A.X + +fun bar(s: String) { + val t: X = A().X { s } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test new file mode 100644 index 00000000000..3979ef41e5b --- /dev/null +++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test @@ -0,0 +1,7 @@ +{ + "mainFile": "a/main.java", + "type": "MOVE_INNER_CLASS", + "targetPackage": "a", + "outerInstanceParameterName": "outer", + "withRuntime": "true" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/AbstractJetMoveTest.kt b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/AbstractJetMoveTest.kt index 91de20d82d0..1c51314513c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/AbstractJetMoveTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/AbstractJetMoveTest.kt @@ -59,6 +59,8 @@ import org.jetbrains.jet.plugin.refactoring.move.moveTopLevelDeclarations.JetFil import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.plugin.search.allScope import org.jetbrains.jet.plugin.refactoring.runWriteAction +import org.jetbrains.jet.InTextDirectivesUtils +import org.jetbrains.jet.testing.ConfigLibraryUtil public abstract class AbstractJetMoveTest : MultiFileTestCase() { protected fun doTest(path: String) { @@ -78,6 +80,10 @@ public abstract class AbstractJetMoveTest : MultiFileTestCase() { val config = JsonParser().parse(FileUtil.loadFile(File(path), true)) as JsonObject + if (config["withRuntime"]?.getAsBoolean() ?: false) { + ConfigLibraryUtil.configureKotlinRuntime(myModule, PluginTestCaseBase.fullJdk()) + } + val action = MoveAction.valueOf(config.getString("type")) val testDir = path.substring(0, path.lastIndexOf("/")) diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java index 8950bd91e7e..a35730169cd 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java @@ -86,6 +86,18 @@ public class JetMoveTestGenerated extends AbstractJetMoveTest { doTest(fileName); } + @TestMetadata("java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test") + public void testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance.test"); + doTest(fileName); + } + + @TestMetadata("java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test") + public void testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda/moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda.test"); + doTest(fileName); + } + @TestMetadata("java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/moveNestedClassToTopLevelInTheSamePackageAndRename.test") public void testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndRename_MoveNestedClassToTopLevelInTheSamePackageAndRename() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/moveNestedClassToTopLevelInTheSamePackageAndRename.test");