From e2cd983d4909db1f50cd0f9bd4960094c09f4e32 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 6 May 2015 19:39:38 +0300 Subject: [PATCH] Add quickfix for replacing deprecated annotations --- .../quickfix/DeprecatedAnnotationSyntaxFix.kt | 71 +++++++++++++++++++ .../idea/quickfix/QuickFixRegistrar.java | 3 + .../bracketsAnnotations/afterBasic.kt | 5 ++ .../bracketsAnnotations/beforeBasic.kt | 5 ++ .../manyFilesMuitliple.after.data.Sample.kt | 3 + .../manyFilesMuitliple.after.kt | 31 ++++++++ .../manyFilesMuitliple.before.Main.kt | 31 ++++++++ .../manyFilesMuitliple.before.data.Sample.kt | 3 + .../QuickFixMultiFileTestGenerated.java | 15 ++++ .../idea/quickfix/QuickFixTestGenerated.java | 15 ++++ 10 files changed, 182 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedAnnotationSyntaxFix.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/afterBasic.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/beforeBasic.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.data.Sample.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.Main.kt create mode 100644 idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.data.Sample.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedAnnotationSyntaxFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedAnnotationSyntaxFix.kt new file mode 100644 index 00000000000..c84ef1570c6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedAnnotationSyntaxFix.kt @@ -0,0 +1,71 @@ +/* + * 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.PsiElement +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +import org.jetbrains.kotlin.psi.JetAnnotation +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.JetPsiFactory + +public class DeprecatedAnnotationSyntaxFix(element: JetAnnotation) : JetIntentionAction(element) { + override fun getFamilyName(): String = "Replace with '@' annotations" + override fun getText(): String = "Replace with '@' annotations" + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) = replaceWithAtAnnotationEntries(element) + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? = + diagnostic.createIntentionForFirstParentOfType(::DeprecatedAnnotationSyntaxFix) + + public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory { + JetWholeProjectForEachElementOfTypeFix.createByPredicate( + predicate = { it.isDeprecated() }, + taskProcessor = { replaceWithAtAnnotationEntries(it) }, + modalTitle = "Replacing deprecated annotations syntax", + name = "Replace with '@' annotations in whole project", + familyName = "Replace with '@' annotations in whole project" + ) + } + + private fun replaceWithAtAnnotationEntries(annotation: JetAnnotation) { + val psiFactory = JetPsiFactory(annotation) + + val parent = annotation.getParent() + var prevElement: PsiElement = annotation + + for (entry in annotation.getEntries()) { + val newEntry = psiFactory.createAnnotationEntry("@" + entry.getText()) + val added = parent.addAfter(newEntry, prevElement) + + if (prevElement != annotation) { + parent.addBefore(psiFactory.createWhiteSpace(), added) + } + + prevElement = added + } + + annotation.delete() + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java index 1560d3c4098..aa33b9ded62 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -321,5 +321,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION, ReplaceJavaClassAsAnnotationParameterFix.Companion); QuickFixes.factories.put(JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION, ReplaceJavaClassAsAnnotationParameterFix.Companion.createWholeProjectFixFactory()); + + QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion); + QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion.createWholeProjectFixFactory()); } } diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/afterBasic.kt b/idea/testData/quickfix/migration/bracketsAnnotations/afterBasic.kt new file mode 100644 index 00000000000..331d7ef7e0e --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/afterBasic.kt @@ -0,0 +1,5 @@ +// "Replace with '@' annotations" "true" + +annotation class Ann(val x: Int = 1) + +@Ann @Ann(2) class MyClass \ No newline at end of file diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/beforeBasic.kt b/idea/testData/quickfix/migration/bracketsAnnotations/beforeBasic.kt new file mode 100644 index 00000000000..2c019819e39 --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/beforeBasic.kt @@ -0,0 +1,5 @@ +// "Replace with '@' annotations" "true" + +annotation class Ann(val x: Int = 1) + +[Ann Ann(2)] class MyClass \ No newline at end of file diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.data.Sample.kt b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.data.Sample.kt new file mode 100644 index 00000000000..ca2b83ce9eb --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.data.Sample.kt @@ -0,0 +1,3 @@ +[file: Ann] + +@Ann class B [Ann(1)]() diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.kt b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.kt new file mode 100644 index 00000000000..eec78bf475d --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.after.kt @@ -0,0 +1,31 @@ +// "Replace with '@' annotations in whole project" "true" + +annotation class Ann(val x: Int = 1) + +@Ann @Ann(2) class MyClass { + @Ann(3) @Ann /* abc */fun foo(x: @Ann Int) { + @Ann class Local { + @Ann init {} + + private @Ann @Ann(4) fun foo() {} + } + + @Ann var x = 1 + + 1+ @Ann(5) 2 + + 3+ @Ann(55)4 + + 5+ @Ann @Ann(6)/* cde */7 + + label@@Ann(7) @Ann for (i in 1..100) {} + } +} +@Ann(1) @Ann +class Q1 + +@Ann(2) + +@Ann(3) + +fun bar() {} diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.Main.kt b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.Main.kt new file mode 100644 index 00000000000..66556d1bf6c --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.Main.kt @@ -0,0 +1,31 @@ +// "Replace with '@' annotations in whole project" "true" + +annotation class Ann(val x: Int = 1) + +[Ann Ann(2)] class MyClass { + [Ann(3) Ann]/* abc */fun foo(x: [Ann] Int) { + [Ann] class Local { + [Ann] init {} + + private[Ann Ann(4)]fun foo() {} + } + + [Ann]var x = 1 + + 1+[Ann(5)] 2 + + 3+[Ann(55)]4 + + 5+[Ann Ann(6)]/* cde */7 + + label@[Ann(7) Ann] for (i in 1..100) {} + } +} +[Ann(1) Ann] +class Q1 + +[Ann(2)] + +[Ann(3)] + +fun bar() {} diff --git a/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.data.Sample.kt b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.data.Sample.kt new file mode 100644 index 00000000000..888aa006c63 --- /dev/null +++ b/idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.data.Sample.kt @@ -0,0 +1,3 @@ +[file: Ann] + +[Ann] class B [Ann(1)]() diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 9a2171ed64e..9c7e9a2e966 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -852,6 +852,21 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); } + @TestMetadata("idea/testData/quickfix/migration/bracketsAnnotations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BracketsAnnotations extends AbstractQuickFixMultiFileTest { + public void testAllFilesPresentInBracketsAnnotations() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/bracketsAnnotations"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); + } + + @TestMetadata("manyFilesMuitliple.before.Main.kt") + public void testManyFilesMuitliple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/bracketsAnnotations/manyFilesMuitliple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration/lambdaSyntax") @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 e8c120d0266..ed25a63074f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3016,6 +3016,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^before(\\w+)\\.kt$"), true); } + @TestMetadata("idea/testData/quickfix/migration/bracketsAnnotations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BracketsAnnotations extends AbstractQuickFixTest { + public void testAllFilesPresentInBracketsAnnotations() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/bracketsAnnotations"), Pattern.compile("^before(\\w+)\\.kt$"), true); + } + + @TestMetadata("beforeBasic.kt") + public void testBasic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/bracketsAnnotations/beforeBasic.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration/lambdaSyntax") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)