diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt index 386b2d0d957..71242a760b7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt @@ -20,14 +20,23 @@ import com.intellij.codeInsight.intention.LowPriorityAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.ScrollType import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiMethodCallExpression +import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.codeStyle.JavaCodeStyleManager +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.util.SmartList +import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention import org.jetbrains.kotlin.idea.intentions.setReceiverType import org.jetbrains.kotlin.idea.quickfix.moveCaret import org.jetbrains.kotlin.idea.quickfix.unblockDocument +import org.jetbrains.kotlin.idea.references.KtReference +import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.addIfNotNull class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention(KtCallableDeclaration::class.java, "Convert member to extension"), LowPriorityAction { override fun applicabilityRange(element: KtCallableDeclaration): TextRange? { @@ -49,11 +58,25 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention() + val javaCallsToFix = SmartList() + for (ref in ReferencesSearch.search(element)) { + when (ref) { + is KtReference -> { + val refFile = ref.element.getContainingKtFile() + if (refFile != file) { + ktFilesToAddImports.add(refFile) + } + } + is PsiReferenceExpression -> javaCallsToFix.addIfNotNull(ref.parent as? PsiMethodCallExpression) + } + } + val typeParameterList = newTypeParameterList(element) - val project = element.project val psiFactory = KtPsiFactory(element) val extension = file.addAfter(element, outermostParent) as KtCallableDeclaration @@ -75,6 +98,8 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntentionf() { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/declarations/convertMemberToExtension/final.kt.after b/idea/testData/intentions/declarations/convertMemberToExtension/final.kt.after new file mode 100644 index 00000000000..ec856036e91 --- /dev/null +++ b/idea/testData/intentions/declarations/convertMemberToExtension/final.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +class Owner { +} + +fun Owner.f() { + +} \ No newline at end of file diff --git a/idea/testData/intentions/declarations/convertMemberToExtension/open.kt b/idea/testData/intentions/declarations/convertMemberToExtension/open.kt new file mode 100644 index 00000000000..c088ca1b432 --- /dev/null +++ b/idea/testData/intentions/declarations/convertMemberToExtension/open.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +open class Owner { + open fun f() { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/declarations/convertMemberToExtension/open.kt.after b/idea/testData/intentions/declarations/convertMemberToExtension/open.kt.after new file mode 100644 index 00000000000..fe969186949 --- /dev/null +++ b/idea/testData/intentions/declarations/convertMemberToExtension/open.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +open class Owner { +} + +fun Owner.f() { + +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/addImports.test b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/addImports.test new file mode 100644 index 00000000000..485c3a76e3c --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/addImports.test @@ -0,0 +1,5 @@ +{ + "mainFile": "x/test.kt", + "intentionClass": "org.jetbrains.kotlin.idea.intentions.declarations.ConvertMemberToExtensionIntention", + "withRuntime": "true" +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/x/test.kt b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/x/test.kt new file mode 100644 index 00000000000..c3a3e501416 --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/x/test.kt @@ -0,0 +1,8 @@ +package x + +interface A { +} + +fun A.foo(n: Int) { + throw UnsupportedOperationException() +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.java b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.java new file mode 100644 index 00000000000..4dcd4bb9ba1 --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.java @@ -0,0 +1,10 @@ +package y; + +import x.A; +import x.TestKt; + +class J { + static void foo(A a) { + TestKt.foo(a, 1); + } +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.kt b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.kt new file mode 100644 index 00000000000..b1916496c88 --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/after/y/usages.kt @@ -0,0 +1,8 @@ +package y + +import x.A +import x.foo + +fun bar(a: A) { + a.foo(1) +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/x/test.kt b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/x/test.kt new file mode 100644 index 00000000000..d8b5ab0d786 --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/x/test.kt @@ -0,0 +1,5 @@ +package x + +interface A { + fun foo(n: Int) +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.java b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.java new file mode 100644 index 00000000000..24dd68817b7 --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.java @@ -0,0 +1,9 @@ +package y; + +import x.A; + +class J { + static void foo(A a) { + a.foo(1); + } +} \ No newline at end of file diff --git a/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.kt b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.kt new file mode 100644 index 00000000000..cb1dd53e5ad --- /dev/null +++ b/idea/testData/multiFileIntentions/convertMemberToExtension/addImports/before/y/usages.kt @@ -0,0 +1,7 @@ +package y + +import x.A + +fun bar(a: A) { + a.foo(1) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 932eb7c7f79..409b0e4d49c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -4741,6 +4741,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("final.kt") + public void testFinal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/declarations/convertMemberToExtension/final.kt"); + doTest(fileName); + } + @TestMetadata("funcitonNoName.kt") public void testFuncitonNoName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/declarations/convertMemberToExtension/funcitonNoName.kt"); @@ -4825,6 +4831,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("open.kt") + public void testOpen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/declarations/convertMemberToExtension/open.kt"); + doTest(fileName); + } + @TestMetadata("outsideFunction.kt") public void testOutsideFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/declarations/convertMemberToExtension/outsideFunction.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/MultiFileIntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/MultiFileIntentionTestGenerated.java index 5f66affabe9..7cc883d12d3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/MultiFileIntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/MultiFileIntentionTestGenerated.java @@ -35,6 +35,12 @@ public class MultiFileIntentionTestGenerated extends AbstractMultiFileIntentionT KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/multiFileIntentions"), Pattern.compile("^(.+)\\.test$")); } + @TestMetadata("convertMemberToExtension/addImports/addImports.test") + public void testConvertMemberToExtension_addImports_AddImports() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/convertMemberToExtension/addImports/addImports.test"); + doTest(fileName); + } + @TestMetadata("implementAbstractMember/implementFunctionInJava/implementAllInJava.test") public void testImplementAbstractMember_implementFunctionInJava_ImplementAllInJava() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/implementAbstractMember/implementFunctionInJava/implementAllInJava.test");