diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/JavaAnnotationCallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/JavaAnnotationCallChecker.kt index 07f917fcf74..6655bc9b592 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/JavaAnnotationCallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/JavaAnnotationCallChecker.kt @@ -33,6 +33,8 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.typeUtil.isArrayOfJavaLangClass +import org.jetbrains.kotlin.types.typeUtil.isJavaLangClass public class JavaAnnotationCallChecker : CallChecker { override fun check(resolvedCall: ResolvedCall, context: BasicCallResolutionContext) { @@ -53,15 +55,7 @@ public class JavaAnnotationCallChecker : CallChecker { } } - private fun JetType.isJavaLangClassOrArray() = isJavaLangClass() || - (KotlinBuiltIns.isArray(this) && getArguments().first().getType().isJavaLangClass()) - - private fun JetType.isJavaLangClass(): Boolean { - val classifier = getConstructor().getDeclarationDescriptor() - - if (classifier !is ClassDescriptor) return false - return DescriptorUtils.isJavaLangClass(classifier) - } + private fun JetType.isJavaLangClassOrArray() = isJavaLangClass() || isArrayOfJavaLangClass() private fun reportErrorsOnPositionedArguments( resolvedCall: ResolvedCall<*>, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index 5c1d122ee04..2ad2e483a7d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -65,6 +65,9 @@ public class JetPsiFactory(private val project: Project) { return createProperty("val x = $text").getInitializer()!! } + public fun createClassLiteral(className: String): JetClassLiteralExpression = + createExpression("$className::class") as JetClassLiteralExpression + public fun createCallArguments(text: String): JetValueArgumentList { val property = createProperty("val x = foo $text") return (property.getInitializer() as JetCallExpression).getValueArgumentList()!! diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index cb9679f5c40..b5d6f05db06 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.DelegatingType private fun JetType.getContainedTypeParameters(): Collection { @@ -83,4 +84,14 @@ fun JetType.replaceAnnotations(newAnnotations: Annotations): JetType { override fun getAnnotations() = newAnnotations } -} \ No newline at end of file +} + +public fun JetType.isJavaLangClass(): Boolean { + val classifier = getConstructor().getDeclarationDescriptor() + + if (classifier !is ClassDescriptor) return false + return DescriptorUtils.isJavaLangClass(classifier) +} + +public fun JetType.isArrayOfJavaLangClass(): Boolean = + KotlinBuiltIns.isArray(this) && getArguments().firstOrNull()?.getType()?.isJavaLangClass() ?: false diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index 61960fcf93e..662e547fede 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -328,6 +328,12 @@ make.type.implicit.in.lambda.family=Make Types Implicit In Lambda (May Break Cod invert.if.condition=Invert If Condition invert.if.condition.family=Invert If Condition +replace.java.class.argument=Replace javaClass() with T::class +replace.java.class.argument.family=Replace javaClass() with T::class +replace.java.class.argument.in.whole.project=Replace javaClass() with T::class in whole project +replace.java.class.argument.in.whole.project.family=Replace javaClass() with T::class in whole project +replace.java.class.argument.in.whole.project.modal.title=Replacing javaClass() with T::class in whole project + property.is.implemented.too.many=Has implementations property.is.overridden.too.many=Is overridden in subclasses property.is.implemented.header=Is implemented in
diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java index b14d51cba3f..714c1ad1a4a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -25,7 +25,10 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.*; import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory; import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterActionFactory; import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory; +import org.jetbrains.kotlin.idea.quickfix.replaceJavaClass.ReplaceJavaClassAsAnnotationArgumentFix; +import org.jetbrains.kotlin.idea.quickfix.replaceJavaClass.ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix; import org.jetbrains.kotlin.psi.JetClass; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.lexer.JetTokens.*; @@ -315,5 +318,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(EXPLICIT_DELEGATION_CALL_REQUIRED, InsertDelegationCallQuickfix.InsertThisDelegationCallFactory.INSTANCE$); QuickFixes.factories.put(EXPLICIT_DELEGATION_CALL_REQUIRED, InsertDelegationCallQuickfix.InsertSuperDelegationCallFactory.INSTANCE$); + + QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion); + QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix.Companion); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt new file mode 100644 index 00000000000..212aec9c483 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt @@ -0,0 +1,88 @@ +/* + * 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.replaceJavaClass + +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.JetBundle +import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction +import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory +import org.jetbrains.kotlin.idea.quickfix.JetWholeProjectModalAction +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import java.util.ArrayList + +public class ReplaceJavaClassAsAnnotationArgumentFix( + annotationEntry: JetAnnotationEntry +) : JetIntentionAction(annotationEntry) { + + private val psiFactory: JetPsiFactory = JetPsiFactory(annotationEntry) + + override fun getText() = JetBundle.message("replace.java.class.argument") + override fun getFamilyName() = JetBundle.message("replace.java.class.argument.family") + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) { + processTasks(createReplacementTasks(element), psiFactory) + } + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val entry = diagnostic.getPsiElement().getNonStrictParentOfType() ?: return null + return ReplaceJavaClassAsAnnotationArgumentFix(entry) + } + } +} + +public class ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix( + annotationEntry: JetAnnotationEntry +) : JetWholeProjectModalAction>( + annotationEntry, JetBundle.message("replace.java.class.argument.in.whole.project.modal.title") +) { + + private val psiFactory: JetPsiFactory = JetPsiFactory(annotationEntry) + + override fun getText() = JetBundle.message("replace.java.class.argument.in.whole.project") + override fun getFamilyName() = JetBundle.message("replace.java.class.argument.in.whole.project.family") + + override fun collectDataForFile(project: Project, file: JetFile): Collection? { + val result = arrayListOf() + + file.accept(object : JetTreeVisitorVoid() { + override fun visitAnnotationEntry(annotationEntry: JetAnnotationEntry) { + result.addAll(createReplacementTasks(annotationEntry)) + } + }) + + return result + } + + override fun applyChangesForFile(project: Project, file: JetFile, data: Collection) { + processTasks(data, psiFactory) + } + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val entry = diagnostic.getPsiElement().getNonStrictParentOfType() ?: return null + return ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix(entry) + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt new file mode 100644 index 00000000000..cf290d3880b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt @@ -0,0 +1,80 @@ +/* + * 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.replaceJavaClass + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm +import org.jetbrains.kotlin.types.typeUtil.isArrayOfJavaLangClass +import org.jetbrains.kotlin.types.typeUtil.isJavaLangClass + +private trait ReplacementTask +private class JavaClassCallReplacementTask( + val javaClassCall: JetExpression, + val className: String +) : ReplacementTask + +fun createReplacementTasks(element: JetAnnotationEntry): List { + val replacementTasks = arrayListOf() + + element.accept(object : JetTreeVisitorVoid() { + override fun visitCallExpression(expression: JetCallExpression) { + expression.acceptChildren(this) + + val context = expression.analyze() + val resolvedCall = expression.getResolvedCall(context) ?: return + + if (!context.getDiagnostics().any { it.isJavaLangClassArgumentInAnnotation(expression) }) return + + val returnType = resolvedCall.getResultingDescriptor().getReturnType() ?: return + if (returnType.isJavaLangClass()) { + val inferredType = returnType.getArguments().firstOrNull()?.getType() ?: return + if (inferredType.isError()) return + val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(inferredType) + replacementTasks.add(JavaClassCallReplacementTask(expression, renderedType)) + } + } + }) + + return replacementTasks +} + +private fun Diagnostic.isJavaLangClassArgumentInAnnotation(expression: JetCallExpression) = + getFactory() == ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION && + getPsiElement().isAncestor(expression) + +fun processTasks(replacementTasks: Collection, psiFactory: JetPsiFactory) { + val elementsToShorten = arrayListOf() + replacementTasks.forEach { + task -> + when (task) { + is JavaClassCallReplacementTask -> { + val newElement = task.javaClassCall.replace(psiFactory.createClassLiteral(task.className)) as JetElement + elementsToShorten.add(newElement) + } + else -> error("Unexpected task type: ${task.javaClass.getName()}") + } + } + + ShortenReferences.DEFAULT.process(elementsToShorten) +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.after.kt new file mode 100644 index 00000000000..24e9847f22e --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.after.kt @@ -0,0 +1,12 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +import java.lang.Number + +Ann(arg = array(Int::class, String::class)) class MyClass1 + +Ann(arg = array>(Number::class, String::class)) class MyClass2 + +Ann(arg = array>>(Int::class, String::class)) class MyClass3 + +Ann(arg = array>(Int::class)) class MyClass4 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.Main.kt new file mode 100644 index 00000000000..c33283a0544 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.Main.kt @@ -0,0 +1,10 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +Ann(arg = array(javaClass(), javaClass())) class MyClass1 + +Ann(arg = array>(javaClass(), javaClass())) class MyClass2 + +Ann(arg = array>>(javaClass(), javaClass())) class MyClass3 + +Ann(arg = array>(javaClass())) class MyClass4 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.data.Sample.java new file mode 100644 index 00000000000..4f2b4aa398b --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.data.Sample.java @@ -0,0 +1,3 @@ +public @interface Ann { + Class[] arg(); +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.after.kt new file mode 100644 index 00000000000..b17f27d3263 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.after.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +Ann(String::class) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.Main.kt new file mode 100644 index 00000000000..25b42ce7d7c --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.Main.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +Ann(javaClass()) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.data.Sample.java new file mode 100644 index 00000000000..fc6ee8c06e4 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.data.Sample.java @@ -0,0 +1,3 @@ +public @interface Ann { + Class value(); +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.after.kt new file mode 100644 index 00000000000..b928bf1974d --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.after.kt @@ -0,0 +1,6 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +import java.util.Random + +Ann(A::class, A::class, *array(A::class), arg1 = A.B::class, arg2 = Random::class) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.Main.kt new file mode 100644 index 00000000000..83a234397e4 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.Main.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +Ann(javaClass(), javaClass(), *array(javaClass()), arg1 = javaClass(), arg2 = javaClass()) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.data.Sample.java new file mode 100644 index 00000000000..285a01df60a --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.data.Sample.java @@ -0,0 +1,11 @@ +public @interface Ann { + Class[] value(); + Class arg1(); + Class arg2(); +} + +class A { + static class B {} +} + + diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.data.Sample.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.data.Sample.kt new file mode 100644 index 00000000000..21f54a4fdf9 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.data.Sample.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +Ann(String::class) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.kt new file mode 100644 index 00000000000..e6ba91d5634 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.after.kt @@ -0,0 +1,20 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +Ann(String::class, arg = Int::class, args = array()) class MyClass1 + +Ann(String::class, arg = Int::class, x = 1, args = array(Double::class)) class MyClass2 { + Ann(String::class, arg = Int::class, args = array(Double::class)) class Nested { + Ann(String::class, arg = Int::class, args = array(Double::class)) fun foo1() { + + [Ann(String::class, arg = Int::class, args = array(Double::class))] class Local + } + + [Ann(String::class, arg = Int::class, args = array(Double::class), x = 1)] fun foo2() { + + [Ann(String::class, arg = Int::class, args = array(Double::class))] val local = 0 + } + } + + inner Ann(Double::class) class Inner +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.Main.kt new file mode 100644 index 00000000000..a97232a4bb4 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.Main.kt @@ -0,0 +1,20 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +Ann(javaClass(), arg = javaClass(), args = array()) class MyClass1 + +Ann(javaClass(), arg = javaClass(), x = 1, args = array(javaClass())) class MyClass2 { + Ann(javaClass(), arg = javaClass(), args = array(javaClass())) class Nested { + Ann(javaClass(), arg = javaClass(), args = array(javaClass())) fun foo1() { + + [Ann(javaClass(), arg = javaClass(), args = array(javaClass()))] class Local + } + + [Ann(javaClass(), arg = javaClass(), args = array(javaClass()), x = 1)] fun foo2() { + + [Ann(javaClass(), arg = javaClass(), args = array(javaClass()))] val local = 0 + } + } + + inner Ann(javaClass()) class Inner +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.java new file mode 100644 index 00000000000..2313cf2d79d --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.java @@ -0,0 +1,7 @@ +public @interface Ann { + Class value(); + int x() default 1; + double y() default 1.0; + Class arg() default String; + Class[] args() default {}; +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.kt new file mode 100644 index 00000000000..f5294640bac --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.data.Sample.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class in whole project" "true" +// WITH_RUNTIME + +Ann(javaClass()) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.after.kt new file mode 100644 index 00000000000..4e0f4c9f285 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.after.kt @@ -0,0 +1,6 @@ +// "Replace javaClass() with T::class" "true" +// ERROR: An annotation parameter must be a `javaClass()` call +// WITH_RUNTIME + +val jClass = javaClass() +Ann(jClass, Int::class) class MyClass1 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.Main.kt new file mode 100644 index 00000000000..476acad7fdd --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.Main.kt @@ -0,0 +1,6 @@ +// "Replace javaClass() with T::class" "true" +// ERROR: An annotation parameter must be a `javaClass()` call +// WITH_RUNTIME + +val jClass = javaClass() +Ann(jClass, javaClass()) class MyClass1 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.data.Sample.java new file mode 100644 index 00000000000..dfeb4ef5573 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.data.Sample.java @@ -0,0 +1,3 @@ +public @interface Ann { + Class[] value(); +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.after.kt new file mode 100644 index 00000000000..9bae86ea5dc --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.after.kt @@ -0,0 +1,6 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +import java.lang + +Ann(String::class, x = 2, arg = (Int::class), args = array((Any::class), lang.String::class)) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.Main.kt new file mode 100644 index 00000000000..072fc83a3b4 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.Main.kt @@ -0,0 +1,4 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +Ann(javaClass(), x = 2, arg = (javaClass()), args = array((javaClass()), javaClass())) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.data.Sample.java new file mode 100644 index 00000000000..b9aaf3d1d03 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.data.Sample.java @@ -0,0 +1,7 @@ +public @interface Ann { + Class value(); + int x(); + double y() default 1.0; + Class arg(); + Class[] args(); +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.after.kt new file mode 100644 index 00000000000..2fee3f91baa --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.after.kt @@ -0,0 +1,5 @@ +// "Replace javaClass() with T::class" "true" +// ERROR: Unresolved reference: Err +// WITH_RUNTIME + +Ann(javaClass(), Int::class) class MyClass1 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.Main.kt new file mode 100644 index 00000000000..0584371952e --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.Main.kt @@ -0,0 +1,5 @@ +// "Replace javaClass() with T::class" "true" +// ERROR: Unresolved reference: Err +// WITH_RUNTIME + +Ann(javaClass(), javaClass()) class MyClass1 diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.data.Sample.java new file mode 100644 index 00000000000..dfeb4ef5573 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.data.Sample.java @@ -0,0 +1,3 @@ +public @interface Ann { + Class[] value(); +} diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.after.kt new file mode 100644 index 00000000000..63c6152cb1a --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.after.kt @@ -0,0 +1,13 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +import java.lang + +Ann( + String::class, + Int::class, +*array(Double::class), +x = 2, +arg = Int::class, +args = array(Any::class, lang.String::class)) +class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.Main.kt new file mode 100644 index 00000000000..15aca3380fc --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.Main.kt @@ -0,0 +1,11 @@ +// "Replace javaClass() with T::class" "true" +// WITH_RUNTIME + +Ann( +javaClass(), +javaClass(), +*array(javaClass()), +x = 2, +arg = javaClass(), +args = array(javaClass(), javaClass())) +class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.data.Sample.java new file mode 100644 index 00000000000..a523f61a3ff --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.data.Sample.java @@ -0,0 +1,7 @@ +public @interface Ann { + Class[] value(); + int x(); + double y() default 1.0; + Class arg(); + Class[] args(); +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 2b2df7f2d30..ef13ab4d276 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -878,6 +878,63 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } } + + @TestMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceJavaClassWithKClassForJavaAnnotation extends AbstractQuickFixMultiFileTest { + public void testAllFilesPresentInReplaceJavaClassWithKClassForJavaAnnotation() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); + } + + @TestMetadata("arrayWithExplicitTypeArgumentMultiple.before.Main.kt") + public void testArrayWithExplicitTypeArgumentMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/arrayWithExplicitTypeArgumentMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("basicMultiple.before.Main.kt") + public void testBasicMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/basicMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("implicitParameterMultiple.before.Main.kt") + public void testImplicitParameterMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/implicitParameterMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("manyFilesMultiple.before.Main.kt") + public void testManyFilesMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/manyFilesMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("nonConstMultiple.before.Main.kt") + public void testNonConstMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/nonConstMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("severalArgsMultiple.before.Main.kt") + public void testSeveralArgsMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/severalArgsMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("unresolvedMultiple.before.Main.kt") + public void testUnresolvedMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/unresolvedMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("valueAsVarargMultiple.before.Main.kt") + public void testValueAsVarargMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation/valueAsVarargMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + } } @TestMetadata("idea/testData/quickfix/modifiers") diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 58889a46858..fa73483f75a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3084,6 +3084,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } } + } @TestMetadata("idea/testData/quickfix/modifiers")