From f494b4ce11b3f950199242d035ee803ac7c59a57 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Mon, 9 Sep 2019 17:46:19 +0900 Subject: [PATCH] Add 'Add JvmName annotation' quick fix for CONFLICTING_JVM_DECLARATIONS #KT-17209 --- .../messages/KotlinBundle.properties | 3 +- .../idea/quickfix/AddJvmNameAnnotationFix.kt | 60 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 + .../quickfix/addJvmNameAnnotation/basic.kt | 19 ++++++ .../addJvmNameAnnotation/basic.kt.after | 20 +++++++ .../addJvmNameAnnotation/hasAnnotation.kt | 20 +++++++ .../hasAnnotation.kt.after | 20 +++++++ .../addJvmNameAnnotation/hasAnnotation2.kt | 20 +++++++ .../hasAnnotation2.kt.after | 20 +++++++ .../QuickFixMultiFileTestGenerated.java | 13 ++++ .../idea/quickfix/QuickFixTestGenerated.java | 28 +++++++++ 11 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmNameAnnotationFix.kt create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/basic.kt create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/basic.kt.after create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt.after create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt create mode 100644 idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt.after diff --git a/idea/resources/messages/KotlinBundle.properties b/idea/resources/messages/KotlinBundle.properties index 4d5952b4bda..fc3f3678ee8 100644 --- a/idea/resources/messages/KotlinBundle.properties +++ b/idea/resources/messages/KotlinBundle.properties @@ -2206,4 +2206,5 @@ kotlin.script.definitions.model.name.pattern.extension=Pattern/Extension kotlin.script.definitions.model.name.name=Name codestyle.name.kotlin=Kotlin add.missing.class.keyword=Add missing 'class' keyword -fix.move.typealias.to.top.level=Move typealias to top level \ No newline at end of file +fix.move.typealias.to.top.level=Move typealias to top level +fix.change.jvm.name=Change JVM name \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmNameAnnotationFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmNameAnnotationFix.kt new file mode 100644 index 00000000000..13773a5ee55 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmNameAnnotationFix.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2019 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.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.core.KotlinNameSuggester +import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator +import org.jetbrains.kotlin.idea.util.addAnnotation +import org.jetbrains.kotlin.idea.util.findAnnotation +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject + +class AddJvmNameAnnotationFix(element: KtElement, private val jvmName: String) : KotlinQuickFixAction(element) { + override fun getText(): String = if (element is KtAnnotationEntry) { + KotlinBundle.message("fix.change.jvm.name") + } else { + KotlinBundle.message("fix.add.annotation.text.self", JVM_NAME_FQ_NAME.shortName()) + } + + override fun getFamilyName(): String = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val element = element ?: return + when (element) { + is KtAnnotationEntry -> { + val argList = element.valueArgumentList + val newArgList = KtPsiFactory(element).createCallArguments("(\"$jvmName\")") + if (argList != null) { + argList.replace(newArgList) + } else { + element.addAfter(newArgList, element.lastChild) + } + } + is KtFunction -> + element.addAnnotation(JVM_NAME_FQ_NAME, annotationInnerText = "\"$jvmName\"") + } + } + + companion object : KotlinSingleIntentionActionFactory() { + private val JVM_NAME_FQ_NAME = FqName("kotlin.jvm.JvmName") + + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val function = diagnostic.psiElement as? KtNamedFunction ?: return null + val functionName = function.name ?: return null + val classOrObjectBody = function.containingClassOrObject?.body ?: return null + val nameValidator = + NewDeclarationNameValidator(classOrObjectBody, function, NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES) + val jvmName = KotlinNameSuggester.suggestNameByName(functionName, nameValidator) + return AddJvmNameAnnotationFix(function.findAnnotation(JVM_NAME_FQ_NAME) ?: function, jvmName) + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index d8c7764cdae..fa4d3885c53 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -646,5 +646,7 @@ class QuickFixRegistrar : QuickFixContributor { FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS.registerFactory(RemoveModifierFix.createRemoveFunFromInterfaceFactory()) TOPLEVEL_TYPEALIASES_ONLY.registerFactory(MoveTypeAliasToTopLevelFix) + + CONFLICTING_JVM_DECLARATIONS.registerFactory(AddJvmNameAnnotationFix) } } diff --git a/idea/testData/quickfix/addJvmNameAnnotation/basic.kt b/idea/testData/quickfix/addJvmNameAnnotation/basic.kt new file mode 100644 index 00000000000..7e1bfb4d32f --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/basic.kt @@ -0,0 +1,19 @@ +// "Add '@JvmName' annotation" "true" +// WITH_RUNTIME +class Foo { + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/testData/quickfix/addJvmNameAnnotation/basic.kt.after b/idea/testData/quickfix/addJvmNameAnnotation/basic.kt.after new file mode 100644 index 00000000000..d66843ea1f8 --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/basic.kt.after @@ -0,0 +1,20 @@ +// "Add '@JvmName' annotation" "true" +// WITH_RUNTIME +class Foo { + @JvmName("bar3") + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt new file mode 100644 index 00000000000..f5ea755c957 --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt @@ -0,0 +1,20 @@ +// "Change JVM name" "true" +// WITH_RUNTIME +class Foo { + @JvmName("bar1") + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt.after b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt.after new file mode 100644 index 00000000000..2793f3b2127 --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt.after @@ -0,0 +1,20 @@ +// "Change JVM name" "true" +// WITH_RUNTIME +class Foo { + @JvmName("bar3") + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt new file mode 100644 index 00000000000..893102a9452 --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt @@ -0,0 +1,20 @@ +// "Change JVM name" "true" +// WITH_RUNTIME +class Foo { + @JvmName + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt.after b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt.after new file mode 100644 index 00000000000..2793f3b2127 --- /dev/null +++ b/idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt.after @@ -0,0 +1,20 @@ +// "Change JVM name" "true" +// WITH_RUNTIME +class Foo { + @JvmName("bar3") + fun bar(foo: List): String { + return "1" + } + + fun bar(foo: List): String { + return "2" + } + + fun bar1(foo: List): String { + return "3" + } + + fun bar2(foo: List): String { + return "4" + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 1eb96ed6893..217fce24cc3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -207,6 +207,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/addJvmNameAnnotation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddJvmNameAnnotation extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInAddJvmNameAnnotation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addJvmNameAnnotation"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true); + } + } + @TestMetadata("idea/testData/quickfix/addNewLineAfterAnnotations") @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 71d2c928ca2..f9d15609ab8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -862,6 +862,34 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/addJvmNameAnnotation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddJvmNameAnnotation extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddJvmNameAnnotation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addJvmNameAnnotation"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("idea/testData/quickfix/addJvmNameAnnotation/basic.kt"); + } + + @TestMetadata("hasAnnotation.kt") + public void testHasAnnotation() throws Exception { + runTest("idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation.kt"); + } + + @TestMetadata("hasAnnotation2.kt") + public void testHasAnnotation2() throws Exception { + runTest("idea/testData/quickfix/addJvmNameAnnotation/hasAnnotation2.kt"); + } + } + @TestMetadata("idea/testData/quickfix/addNewLineAfterAnnotations") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)