diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index c88d5d03c30..3537e055824 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -531,3 +531,6 @@ inline fun flatMapDescendantsOfTypeVisitor( accumulator: MutableCollection, noinline map: (T) -> Collection ): JetVisitorVoid = forEachDescendantOfTypeVisitor { accumulator.addAll(map(it)) } + +inline fun PsiElement.forEachDescendantsOfType(noinline block: (T) -> Unit) = + accept(forEachDescendantOfTypeVisitor(block)) 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 662e547fede..326c7710e51 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -334,6 +334,12 @@ replace.java.class.argument.in.whole.project=Replace javaClass() with T::clas 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 +replace.java.class.parameter=Replace Class with KClass in whole annotation +replace.java.class.parameter.family=Replace Class with KClass in whole annotation +replace.java.class.parameter.in.whole.project=Replace Class with KClass for each annotation in project +replace.java.class.parameter.in.whole.project.family=Replace Class with KClass for each annotation in project +replace.java.class.parameter.in.whole.project.modal.title=Replacing Class with KClass for each annotation in 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 c718dab8646..c9f3965513f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateL 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.ReplaceJavaClassAsAnnotationParameterFix; import org.jetbrains.kotlin.psi.JetClass; import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; @@ -321,5 +322,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, MigrateAnnotationMethodCallFix.Companion); QuickFixes.factories.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, MigrateAnnotationMethodCallInWholeFile.Companion); + + QuickFixes.factories.put(JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION, ReplaceJavaClassAsAnnotationParameterFix.Companion); + QuickFixes.factories.put(JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION, ReplaceJavaClassAsAnnotationParameterFix.Companion.createWholeProjectFixFactory()); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt index 498cb04c8da..e8bcdcdca46 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationArgumentFix.kt @@ -47,8 +47,8 @@ public class ReplaceJavaClassAsAnnotationArgumentFix( diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationArgumentFix) public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory { - JetWholeProjectForEachElementOfTypeFix.createForMultiTask( - tasksFactory = ::createReplacementTasks, + JetWholeProjectForEachElementOfTypeFix.createForMultiTask( + tasksFactory = { createReplacementTasks(it) }, tasksProcessor = ::processTasks, modalTitle = JetBundle.message("replace.java.class.argument.in.whole.project.modal.title"), name = JetBundle.message("replace.java.class.argument.in.whole.project"), diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationParameterFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationParameterFix.kt new file mode 100644 index 00000000000..125e8585853 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/ReplaceJavaClassAsAnnotationParameterFix.kt @@ -0,0 +1,62 @@ +/* + * 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.JetWholeProjectForEachElementOfTypeFix +import org.jetbrains.kotlin.idea.quickfix.JetWholeProjectModalAction +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +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 ReplaceJavaClassAsAnnotationParameterFix( + annotationClass: JetClass +) : JetIntentionAction(annotationClass) { + + override fun getText() = JetBundle.message("replace.java.class.parameter") + override fun getFamilyName() = JetBundle.message("replace.java.class.parameter.family") + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) { + processTasks(createReplacementTasksForAnnotationClass(element)) + } + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic) = + diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationParameterFix) + + public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory { + JetWholeProjectForEachElementOfTypeFix.createForMultiTask( + tasksFactory = ::createReplacementTasksForAnnotationClass, + tasksProcessor = ::processTasks, + modalTitle = JetBundle.message("replace.java.class.parameter.in.whole.project.modal.title"), + name = JetBundle.message("replace.java.class.parameter.in.whole.project"), + familyName = JetBundle.message("replace.java.class.parameter.in.whole.project.family") + ) + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt index 12c6bb1c76a..103693a5901 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceJavaClass/common.kt @@ -17,11 +17,18 @@ package org.jetbrains.kotlin.idea.quickfix.replaceJavaClass import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.search.usagesSearch.ClassUsagesSearchHelper +import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch +import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchTarget +import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor 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.forEachDescendantsOfType +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm @@ -37,32 +44,83 @@ private class JavaClassCallReplacementTask( ) : ReplacementTask { override val element: JetElement = javaClassCall } +private class JavaClassParameterReplacementTask( + val typeReference: JetTypeReference, + val projectionText: String +) : ReplacementTask { + override val element: JetElement = typeReference +} -fun createReplacementTasks(element: JetAnnotationEntry): List { +fun createReplacementTasks(element: JetElement, anyJavaClass: Boolean = false): List { val replacementTasks = arrayListOf() - element.accept(object : JetTreeVisitorVoid() { - override fun visitCallExpression(expression: JetCallExpression) { - expression.acceptChildren(this) + element.forEachDescendantsOfType(fun(expression: JetCallExpression) { + val context = expression.analyze() + val resolvedCall = expression.getResolvedCall(context) ?: return - val context = expression.analyze() - val resolvedCall = expression.getResolvedCall(context) ?: return + if (!anyJavaClass && !context.getDiagnostics().any { it.isJavaLangClassArgumentInAnnotation(expression) }) 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)) - } + 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 } +fun createReplacementTasksForAnnotationClass(element: JetClass): List { + if (!element.isAnnotation()) return emptyList() + + val replacementTasks = arrayListOf() + + fun addJavaClassReplacementTaskByTypeReference(typeReference: JetTypeReference) { + val classTypeArgText = typeReference.getFirstTypeArgument()?.getText() ?: return + replacementTasks.add(JavaClassParameterReplacementTask(typeReference, classTypeArgText)) + } + + element.forEachDescendantsOfType(fun(parameter: JetParameter) { + val valueParameterDescriptor = parameter.descriptor as? ValueParameterDescriptor ?: return + val type = valueParameterDescriptor.getType() + + val parameterTypeReference = parameter.getTypeReference() ?: return + if (type.isJavaLangClass() || valueParameterDescriptor.getVarargElementType()?.isJavaLangClass() ?: false) { + addJavaClassReplacementTaskByTypeReference(parameterTypeReference) + } + else if (type.isArrayOfJavaLangClass()) { + val arrayTypeArgumentReference = parameterTypeReference.getFirstTypeArgument()?.getTypeReference() ?: return + addJavaClassReplacementTaskByTypeReference(arrayTypeArgumentReference) + } + + val defaultValue = parameter.getDefaultValue() + if (defaultValue != null) { + replacementTasks.addAll(createReplacementTasks(defaultValue, anyJavaClass = true)) + } + }) + + if (replacementTasks.isEmpty()) return emptyList() + + val request = ClassUsagesSearchHelper( + constructorUsages = true, nonConstructorUsages = false, skipImports = true + ).newRequest(UsagesSearchTarget(element)) + + UsagesSearch.search(request).forEach { + ref -> + val refElement = ref?.getElement()?.getNonStrictParentOfType() + if (refElement != null) { + replacementTasks.addAll(createReplacementTasks(refElement, anyJavaClass = true)) + } + } + + return replacementTasks +} + +private fun JetTypeReference.getFirstTypeArgument(): JetTypeProjection? = + (getTypeElement() as? JetUserType)?.getTypeArguments()?.firstOrNull() + private fun Diagnostic.isJavaLangClassArgumentInAnnotation(expression: JetCallExpression) = getFactory() == ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION && getPsiElement().isAncestor(expression) @@ -74,13 +132,15 @@ fun processTasks(replacementTasks: Collection) { val elementsToShorten = arrayListOf() replacementTasks.forEach { task -> - when (task) { - is JavaClassCallReplacementTask -> { - val newElement = task.javaClassCall.replace(psiFactory.createClassLiteral(task.className)) as JetElement - elementsToShorten.add(newElement) - } + val newElement = when (task) { + is JavaClassCallReplacementTask -> + task.javaClassCall.replace(psiFactory.createClassLiteral(task.className)) as JetElement + is JavaClassParameterReplacementTask -> + task.typeReference.replace(psiFactory.createType("kotlin.reflect.KClass<${task.projectionText}>")) as JetElement else -> error("Unexpected task type: ${task.javaClass.getName()}") } + + elementsToShorten.add(newElement) } ShortenReferences.DEFAULT.process(elementsToShorten) diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterArrayRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterArrayRuntime.kt new file mode 100644 index 00000000000..b39fab6bcdd --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterArrayRuntime.kt @@ -0,0 +1,8 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann(val arg: Array>) + +Ann(arg = array(String::class, Double::class)) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterBasicRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterBasicRuntime.kt new file mode 100644 index 00000000000..9d04888540b --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterBasicRuntime.kt @@ -0,0 +1,8 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann(val arg1: KClass<*>, val arg2: KClass) + +Ann(String::class, Int::class) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterDefaultRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterDefaultRuntime.kt new file mode 100644 index 00000000000..909dacc0876 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterDefaultRuntime.kt @@ -0,0 +1,16 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann( + val arg1: Int, + val arg2: KClass<*> = Int::class, + val arg3: Array> = array(String::class), + vararg val arg4: KClass = array(Double::class) +) + +Ann(arg1 = 1) class MyClass1 +Ann(arg1 = 2, arg2 = Boolean::class) class MyClass2 +Ann(arg1 = 3, arg3 = array(Boolean::class)) class MyClass3 +Ann(arg1 = 4, arg4 = String::class) class MyClass4 diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterUsageWithErrorRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterUsageWithErrorRuntime.kt new file mode 100644 index 00000000000..f9ddd526115 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterUsageWithErrorRuntime.kt @@ -0,0 +1,16 @@ +// "Replace Class with KClass in whole annotation" "true" +// ERROR: Type inference failed. Expected type mismatch:
required: kotlin.reflect.KClass<*>
found: java.lang.Class<???>
+// ERROR: Type mismatch.
Required:kotlin.reflect.KClass<*>
Found:java.lang.Class<[ERROR : Err]>
+// ERROR: Type mismatch.
Required:kotlin.reflect.KClass<*>
Found:java.lang.Class<kotlin.Double>
+// ERROR: Unresolved reference: Err +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann(vararg val arg: KClass<*>) + +Ann(String::class, javaClass()) class MyClass1 +Ann(String::class, javaClass()) class MyClass2 + +val x = javaClass() +Ann(String::class, x) class MyClass3 diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterVarargRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterVarargRuntime.kt new file mode 100644 index 00000000000..7657f371a75 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/afterVarargRuntime.kt @@ -0,0 +1,8 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann(vararg val arg: KClass<*>) + +Ann(String::class, Double::class, *array(Char::class)) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeArrayRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeArrayRuntime.kt new file mode 100644 index 00000000000..c5f5a90147d --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeArrayRuntime.kt @@ -0,0 +1,6 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +annotation class Ann(val arg: Array>) + +Ann(arg = array(javaClass(), javaClass())) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeBasicRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeBasicRuntime.kt new file mode 100644 index 00000000000..0581c6adee2 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeBasicRuntime.kt @@ -0,0 +1,6 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +annotation class Ann(val arg1: Class<*>, val arg2: Class) + +Ann(javaClass(), javaClass()) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeDefaultRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeDefaultRuntime.kt new file mode 100644 index 00000000000..8d66203fc81 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeDefaultRuntime.kt @@ -0,0 +1,14 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +annotation class Ann( + val arg1: Int, + val arg2: Class<*> = javaClass(), + val arg3: Array> = array(javaClass()), + vararg val arg4: Class = array(javaClass()) +) + +Ann(arg1 = 1) class MyClass1 +Ann(arg1 = 2, arg2 = javaClass()) class MyClass2 +Ann(arg1 = 3, arg3 = array(javaClass())) class MyClass3 +Ann(arg1 = 4, arg4 = javaClass()) class MyClass4 diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeUsageWithErrorRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeUsageWithErrorRuntime.kt new file mode 100644 index 00000000000..ace2bad06a9 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeUsageWithErrorRuntime.kt @@ -0,0 +1,14 @@ +// "Replace Class with KClass in whole annotation" "true" +// ERROR: Type inference failed. Expected type mismatch:
required: kotlin.reflect.KClass<*>
found: java.lang.Class<???>
+// ERROR: Type mismatch.
Required:kotlin.reflect.KClass<*>
Found:java.lang.Class<[ERROR : Err]>
+// ERROR: Type mismatch.
Required:kotlin.reflect.KClass<*>
Found:java.lang.Class<kotlin.Double>
+// ERROR: Unresolved reference: Err +// WITH_RUNTIME + +annotation class Ann(vararg val arg: Class<*>) + +Ann(javaClass(), javaClass()) class MyClass1 +Ann(javaClass(), javaClass()) class MyClass2 + +val x = javaClass() +Ann(javaClass(), x) class MyClass3 diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeVarargRuntime.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeVarargRuntime.kt new file mode 100644 index 00000000000..71850e8c7ac --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeVarargRuntime.kt @@ -0,0 +1,6 @@ +// "Replace Class with KClass in whole annotation" "true" +// WITH_RUNTIME + +annotation class Ann(vararg val arg: Class<*>) + +Ann(javaClass(), javaClass(), *array(javaClass())) class MyClass diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.java new file mode 100644 index 00000000000..c2e973154b2 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.java @@ -0,0 +1,2 @@ +@Ann1(String.class) +class A {} diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.kt new file mode 100644 index 00000000000..bf7c2efed04 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.data.Sample.kt @@ -0,0 +1,7 @@ +import kotlin.reflect.KClass + +annotation class AnnO(val arg: KClass<*>) + +AnnO(Int::class) +Ann1(String::class) +class MyClassO diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.kt new file mode 100644 index 00000000000..ab3d945db7f --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.after.kt @@ -0,0 +1,26 @@ +// "Replace Class with KClass for each annotation in project" "true" +// WITH_RUNTIME + +import kotlin.reflect.KClass + +annotation class Ann1(val arg: KClass<*>) + +Ann1(String::class) class MyClass1 +Ann1(MyClass1::class) class MyClass2 + +annotation class Ann2(val arg: Array>) + +Ann2(arg = array(Double::class)) class MyClass3 [Ann1(Char::class)] () { + annotation class Ann3(val arg: KClass<*> = Any::class) + + Ann3(String::class) class Nested { + Ann1(arg = String::class) fun foo1() { + annotation class LocalAnn(val arg: KClass<*>) + [LocalAnn(Class<*>::class)] val x = 1 + } + } + + inner AnnO(Double::class) class Inner +} + +AnnO(Boolean::class) class Another diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.Main.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.Main.kt new file mode 100644 index 00000000000..84c980b13ee --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.Main.kt @@ -0,0 +1,24 @@ +// "Replace Class with KClass for each annotation in project" "true" +// WITH_RUNTIME + +annotation class Ann1(val arg: Class<*>) + +Ann1(javaClass()) class MyClass1 +Ann1(javaClass()) class MyClass2 + +annotation class Ann2(val arg: Array>) + +Ann2(arg = array(javaClass())) class MyClass3 [Ann1(javaClass())] () { + annotation class Ann3(val arg: Class<*> = javaClass()) + + Ann3(javaClass()) class Nested { + Ann1(arg = javaClass()) fun foo1() { + annotation class LocalAnn(val arg: Class<*>) + [LocalAnn(javaClass>())] val x = 1 + } + } + + inner AnnO(javaClass()) class Inner +} + +AnnO(javaClass()) class Another diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.java b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.java new file mode 100644 index 00000000000..c2e973154b2 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.java @@ -0,0 +1,2 @@ +@Ann1(String.class) +class A {} diff --git a/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.kt b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.kt new file mode 100644 index 00000000000..7a08ce09fe1 --- /dev/null +++ b/idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.data.Sample.kt @@ -0,0 +1,5 @@ +annotation class AnnO(val arg: Class<*>) + +AnnO(javaClass()) +Ann1(javaClass()) +class MyClassO diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index a5d51dfb5a0..071d46a5b9e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -894,6 +894,21 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceJavaClassAsAnnotationParameter extends AbstractQuickFixMultiFileTest { + public void testAllFilesPresentInReplaceJavaClassAsAnnotationParameter() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); + } + + @TestMetadata("manyFilesMultiple.before.Main.kt") + public void testManyFilesMultiple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/manyFilesMultiple.before.Main.kt"); + doTestWithExtraFile(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration/replaceJavaClassWithKClassForJavaAnnotation") @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 95b79b32c73..15029633345 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3079,6 +3079,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceJavaClassAsAnnotationParameter extends AbstractQuickFixTest { + public void testAllFilesPresentInReplaceJavaClassAsAnnotationParameter() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter"), Pattern.compile("^before(\\w+)\\.kt$"), true); + } + + @TestMetadata("beforeArrayRuntime.kt") + public void testArrayRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeArrayRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("beforeBasicRuntime.kt") + public void testBasicRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeBasicRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("beforeDefaultRuntime.kt") + public void testDefaultRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeDefaultRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("beforeUsageWithErrorRuntime.kt") + public void testUsageWithErrorRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeUsageWithErrorRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("beforeVarargRuntime.kt") + public void testVarargRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/replaceJavaClassAsAnnotationParameter/beforeVarargRuntime.kt"); + doTest(fileName); + } + } + } @TestMetadata("idea/testData/quickfix/modifiers")