diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MigrateAnnotationMethodCallFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MigrateAnnotationMethodCallFix.kt new file mode 100644 index 00000000000..40838b7a53f --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MigrateAnnotationMethodCallFix.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2015 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.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +import org.jetbrains.kotlin.psi.JetCallExpression +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm +import org.jetbrains.kotlin.utils.addIfNotNull + +public class MigrateAnnotationMethodCallFix( + expression: JetCallExpression +) : JetIntentionAction(expression) { + override fun getText() = "Replace method call with property access" + override fun getFamilyName() = getText() + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) = replaceWithSimpleCall(element) + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic) = diagnostic.createIntentionForFirstParentOfType(::MigrateAnnotationMethodCallFix) + fun replaceWithSimpleCall(expression: JetCallExpression) { + val simpleName = expression.getCalleeExpression()?.getText() ?: return + expression.replace(JetPsiFactory(expression).createSimpleName(simpleName)) + } + } +} + +class MigrateAnnotationMethodCallInWholeFile : IntentionAction { + override fun getText() = "Replace deprecated method calls with property access in current file" + override fun getFamilyName() = getText() + + override fun startInWriteAction(): Boolean = true + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = true + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?) = (file as? JetFile)?.let { + it.analyzeFully().getDiagnostics(). + filter { it.getFactory() == ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL }. + forEach { + (it.getPsiElement() as? JetCallExpression)?.let { MigrateAnnotationMethodCallFix.replaceWithSimpleCall(it) } + } + } + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic) = MigrateAnnotationMethodCallInWholeFile() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java index 24adcf315e3..80aa6862468 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -320,5 +320,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion); QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion.createWholeProjectFixFactory()); + + QuickFixes.factories.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, MigrateAnnotationMethodCallFix.Companion); + QuickFixes.factories.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, MigrateAnnotationMethodCallInWholeFile.Companion); } } diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.after.kt b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.after.kt new file mode 100644 index 00000000000..0423b06ed65 --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.after.kt @@ -0,0 +1,6 @@ +// "Replace method call with property access" "true" +// WITH_RUNTIME + +fun foo(ann: Ann) { + ann.value +} diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.Main.kt b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.Main.kt new file mode 100644 index 00000000000..9c938046c6a --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.Main.kt @@ -0,0 +1,6 @@ +// "Replace method call with property access" "true" +// WITH_RUNTIME + +fun foo(ann: Ann) { + ann.value() +} diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.data.Sample.java new file mode 100644 index 00000000000..56fe1176769 --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.data.Sample.java @@ -0,0 +1,3 @@ +public @interface Ann { + int value(); +} diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.after.kt b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.after.kt new file mode 100644 index 00000000000..0203c9da949 --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.after.kt @@ -0,0 +1,32 @@ +// "Replace deprecated method calls with property access in current file" "true" +// WITH_RUNTIME + +class A { + fun foo() {} +} + +fun bar(x: Int) { + javaClass().getAnnotation(javaClass()).args[0] + javaClass().getAnnotation(javaClass()).y +} + +fun foo(ann: Ann, a: A) { + ann.value + bar(ann.x + (ann).y) + + a.foo() + + a.equals(a) + a.toString() + a.hashCode() + + class Local { + val prop = ann.arg + fun baz() { + val v = ann.args + val summ = ann.x * ann.ext() + } + + fun Ann.ext(): Int = -y + } +} diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.Main.kt b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.Main.kt new file mode 100644 index 00000000000..065e81fe718 --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.Main.kt @@ -0,0 +1,32 @@ +// "Replace deprecated method calls with property access in current file" "true" +// WITH_RUNTIME + +class A { + fun foo() {} +} + +fun bar(x: Int) { + javaClass().getAnnotation(javaClass()).args()[0] + javaClass().getAnnotation(javaClass()).y() +} + +fun foo(ann: Ann, a: A) { + ann.value() + bar(ann.x() + (ann).y()) + + a.foo() + + a.equals(a) + a.toString() + a.hashCode() + + class Local { + val prop = ann.arg() + fun baz() { + val v = ann.args() + val summ = ann.x() * ann.ext() + } + + fun Ann.ext(): Int = -y() + } +} diff --git a/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.data.Sample.java new file mode 100644 index 00000000000..f750ab6fabd --- /dev/null +++ b/idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.data.Sample.java @@ -0,0 +1,7 @@ +public @interface Ann { + Class value(); + int x() default 1; + int y() default 2; + Class arg() default String; + Class[] args() default {}; +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index ef13ab4d276..8d601799049 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -879,6 +879,27 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MigrateJavaAnnotationMethodCall extends AbstractQuickFixMultiFileTest { + public void testAllFilesPresentInMigrateJavaAnnotationMethodCall() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); + } + + @TestMetadata("basicMultiple.before.Main.kt") + public void testBasicMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/basicMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("wholeFileMultiple.before.Main.kt") + public void testWholeFileMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/migrateJavaAnnotationMethodCall/wholeFileMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)