diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/JavaClassOnCompanionFixes.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/JavaClassOnCompanionFixes.kt new file mode 100644 index 00000000000..3e4d0f306d9 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/JavaClassOnCompanionFixes.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInsight.intention.LowPriorityAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object JavaClassOnCompanionFixes : KotlinIntentionActionsFactory() { + override fun doCreateActions(diagnostic: Diagnostic): List { + val expression = diagnostic.psiElement.parent as? KtDotQualifiedExpression ?: return emptyList() + val companionName = expression.receiverExpression.mainReference?.resolve()?.safeAs()?.name ?: "Companion" + return listOf( + ReplaceWithCompanionClassJavaFix(expression, companionName), + ReplaceWithClassJavaFix(expression) + ) + } +} + +class ReplaceWithCompanionClassJavaFix( + expression: KtDotQualifiedExpression, + private val companionName: String +) : KotlinQuickFixAction(expression) { + override fun getText(): String = KotlinBundle.message("replace.with.0", "$companionName::class.java") + + override fun getFamilyName(): String = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + element?.replace("$0.$companionName::class.java") + } +} + +class ReplaceWithClassJavaFix( + expression: KtDotQualifiedExpression +) : KotlinQuickFixAction(expression), LowPriorityAction { + override fun getText(): String = KotlinBundle.message("replace.with.0", "::class.java") + + override fun getFamilyName(): String = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + element?.replace("$0::class.java") + } +} + +private fun KtDotQualifiedExpression.replace(pattern: String) { + replace(KtPsiFactory(this).createExpressionByPattern(pattern, receiverExpression)) +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index caf2ffe79f1..45d12a77f21 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -668,5 +668,7 @@ class QuickFixRegistrar : QuickFixContributor { INCOMPATIBLE_THROWS_OVERRIDE.registerFactory(RemoveAnnotationFix) INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER.registerFactory(InlineClassConstructorNotValParameterFactory) + + JAVA_CLASS_ON_COMPANION.registerFactory(JavaClassOnCompanionFixes) } } diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt new file mode 100644 index 00000000000..cccce69c927 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt @@ -0,0 +1,6 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +// DISABLE-ERRORS +fun main() { + val c: Class = Int.javaClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt.after new file mode 100644 index 00000000000..855cc1db8c2 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt.after @@ -0,0 +1,6 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +// DISABLE-ERRORS +fun main() { + val c: Class = Int::class.java +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt new file mode 100644 index 00000000000..fbccacc944c --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt @@ -0,0 +1,5 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c = Int.javaClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt.after new file mode 100644 index 00000000000..86e0742ed4a --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt.after @@ -0,0 +1,5 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c = Int::class.java +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt new file mode 100644 index 00000000000..537d9bb9c48 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt @@ -0,0 +1,5 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +fun main() { + val name = Int.javaClass.name +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt.after new file mode 100644 index 00000000000..ab8e6ff7dee --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt.after @@ -0,0 +1,5 @@ +// "Replace with '::class.java'" "true" +// WITH_RUNTIME +fun main() { + val name = Int::class.java.name +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt new file mode 100644 index 00000000000..7fb2d7cb0fb --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c: Class = Int.javaClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt.after new file mode 100644 index 00000000000..6cf642ab1d9 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt.after @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c: Class = Int.Companion::class.java +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt new file mode 100644 index 00000000000..18d74271562 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt @@ -0,0 +1,9 @@ +// "Replace with 'Bar::class.java'" "true" +// WITH_RUNTIME +class Foo { + companion object Bar +} + +fun test() { + Foo.javaClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt.after new file mode 100644 index 00000000000..e56712b2d52 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt.after @@ -0,0 +1,9 @@ +// "Replace with 'Bar::class.java'" "true" +// WITH_RUNTIME +class Foo { + companion object Bar +} + +fun test() { + Foo.Bar::class.java +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt new file mode 100644 index 00000000000..3131303bcaf --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c = Int.javaClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt.after new file mode 100644 index 00000000000..754e3c3f78a --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt.after @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val c = Int.Companion::class.java +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt new file mode 100644 index 00000000000..00a0ad85677 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val name = Int.javaClass.name +} \ No newline at end of file diff --git a/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt.after b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt.after new file mode 100644 index 00000000000..7d15eb17bf4 --- /dev/null +++ b/idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt.after @@ -0,0 +1,5 @@ +// "Replace with 'Companion::class.java'" "true" +// WITH_RUNTIME +fun main() { + val name = Int.Companion::class.java.name +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 96bb1f1338d..883dba4ae5b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -3087,6 +3087,45 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaClassOnCompanion extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInJavaClassOnCompanion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true); + } + + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceWithClassJava extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInReplaceWithClassJava() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true); + } + } + + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceWithCompanionClassJava extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInReplaceWithCompanionClassJava() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true); + } + } + } + @TestMetadata("idea/testData/quickfix/kdocMissingDocumentation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index dfa48502dd2..20ac292bc02 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -8657,6 +8657,80 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaClassOnCompanion extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJavaClassOnCompanion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceWithClassJava extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInReplaceWithClassJava() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("hasType.kt") + public void testHasType() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/hasType.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/simple.kt"); + } + + @TestMetadata("withName.kt") + public void testWithName() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithClassJava/withName.kt"); + } + } + + @TestMetadata("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceWithCompanionClassJava extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInReplaceWithCompanionClassJava() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("hasType.kt") + public void testHasType() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/hasType.kt"); + } + + @TestMetadata("namedCompanion.kt") + public void testNamedCompanion() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/namedCompanion.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/simple.kt"); + } + + @TestMetadata("withName.kt") + public void testWithName() throws Exception { + runTest("idea/testData/quickfix/javaClassOnCompanion/replaceWithCompanionClassJava/withName.kt"); + } + } + } + @TestMetadata("idea/testData/quickfix/kdocMissingDocumentation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)