Add quickfix for java.lang.Class as annotation parameter

This commit is contained in:
Denis Zharkov
2015-04-20 15:29:44 +03:00
parent fc5236244b
commit 1fc742ffeb
24 changed files with 379 additions and 22 deletions
@@ -531,3 +531,6 @@ inline fun <reified T : JetElement, R> flatMapDescendantsOfTypeVisitor(
accumulator: MutableCollection<R>,
noinline map: (T) -> Collection<R>
): JetVisitorVoid = forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
inline fun <reified T : JetElement> PsiElement.forEachDescendantsOfType(noinline block: (T) -> Unit) =
accept(forEachDescendantOfTypeVisitor(block))
@@ -334,6 +334,12 @@ replace.java.class.argument.in.whole.project=Replace javaClass<T>() with T::clas
replace.java.class.argument.in.whole.project.family=Replace javaClass<T>() with T::class in whole project
replace.java.class.argument.in.whole.project.modal.title=Replacing javaClass<T>() with T::class in whole project
replace.java.class.parameter=Replace Class<T> with KClass<T> in whole annotation
replace.java.class.parameter.family=Replace Class<T> with KClass<T> in whole annotation
replace.java.class.parameter.in.whole.project=Replace Class<T> with KClass<T> for each annotation in project
replace.java.class.parameter.in.whole.project.family=Replace Class<T> with KClass<T> for each annotation in project
replace.java.class.parameter.in.whole.project.modal.title=Replacing Class<T> with KClass<T> 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 <br/>
@@ -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());
}
}
@@ -47,8 +47,8 @@ public class ReplaceJavaClassAsAnnotationArgumentFix(
diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationArgumentFix)
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
JetWholeProjectForEachElementOfTypeFix.createForMultiTask(
tasksFactory = ::createReplacementTasks,
JetWholeProjectForEachElementOfTypeFix.createForMultiTask<JetAnnotationEntry, ReplacementTask>(
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"),
@@ -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<JetClass>(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")
)
}
}
}
@@ -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<ReplacementTask> {
fun createReplacementTasks(element: JetElement, anyJavaClass: Boolean = false): List<ReplacementTask> {
val replacementTasks = arrayListOf<ReplacementTask>()
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<ReplacementTask> {
if (!element.isAnnotation()) return emptyList()
val replacementTasks = arrayListOf<ReplacementTask>()
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<JetClassOrObject>(element))
UsagesSearch.search(request).forEach {
ref ->
val refElement = ref?.getElement()?.getNonStrictParentOfType<JetAnnotationEntry>()
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<ReplacementTask>) {
val elementsToShorten = arrayListOf<JetElement>()
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)
@@ -0,0 +1,8 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
import kotlin.reflect.KClass
annotation class Ann(val arg: Array<KClass<*>>)
Ann(arg = array(String::class, Double::class)) class MyClass
@@ -0,0 +1,8 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
import kotlin.reflect.KClass
annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any?>)
Ann(String::class, Int::class) class MyClass
@@ -0,0 +1,16 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
import kotlin.reflect.KClass
annotation class Ann(
val arg1: Int,
val arg2: KClass<*> = Int::class,
val arg3: Array<KClass<out Any?>> = array(String::class),
vararg val arg4: KClass<out Any?> = 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
@@ -0,0 +1,16 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// ERROR: <html>Type inference failed. Expected type mismatch: <table><tr><td>required: </td><td><b>kotlin.reflect.KClass&lt;*&gt;</b></td></tr><tr><td>found: </td><td><font color=red><b>java.lang.Class&lt;???&gt;</b></font></td></tr></table></html>
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.reflect.KClass&lt;*&gt;</td></tr><tr><td>Found:</td><td>java.lang.Class&lt;[ERROR : Err]&gt;</td></tr></table></html>
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.reflect.KClass&lt;*&gt;</td></tr><tr><td>Found:</td><td>java.lang.Class&lt;kotlin.Double&gt;</td></tr></table></html>
// ERROR: Unresolved reference: Err
// WITH_RUNTIME
import kotlin.reflect.KClass
annotation class Ann(vararg val arg: KClass<*>)
Ann(String::class, javaClass<Err>()) class MyClass1
Ann(String::class, javaClass()) class MyClass2
val x = javaClass<Double>()
Ann(String::class, x) class MyClass3
@@ -0,0 +1,8 @@
// "Replace Class<T> with KClass<T> 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
@@ -0,0 +1,6 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
annotation class Ann(val arg: Array<Class<*>><caret>)
Ann(arg = array(javaClass<String>(), javaClass<Double>())) class MyClass
@@ -0,0 +1,6 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
annotation class Ann(val arg1: Class<*><caret>, val arg2: Class<out Any?>)
Ann(javaClass<String>(), javaClass<Int>()) class MyClass
@@ -0,0 +1,14 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
annotation class Ann(
val arg1: Int,
val arg2: Class<*><caret> = javaClass<Int>(),
val arg3: Array<Class<out Any?>> = array(javaClass<String>()),
vararg val arg4: Class<out Any?> = array(javaClass<Double>())
)
Ann(arg1 = 1) class MyClass1
Ann(arg1 = 2, arg2 = javaClass<Boolean>()) class MyClass2
Ann(arg1 = 3, arg3 = array(javaClass<Boolean>())) class MyClass3
Ann(arg1 = 4, arg4 = javaClass<String>()) class MyClass4
@@ -0,0 +1,14 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// ERROR: <html>Type inference failed. Expected type mismatch: <table><tr><td>required: </td><td><b>kotlin.reflect.KClass&lt;*&gt;</b></td></tr><tr><td>found: </td><td><font color=red><b>java.lang.Class&lt;???&gt;</b></font></td></tr></table></html>
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.reflect.KClass&lt;*&gt;</td></tr><tr><td>Found:</td><td>java.lang.Class&lt;[ERROR : Err]&gt;</td></tr></table></html>
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.reflect.KClass&lt;*&gt;</td></tr><tr><td>Found:</td><td>java.lang.Class&lt;kotlin.Double&gt;</td></tr></table></html>
// ERROR: Unresolved reference: Err
// WITH_RUNTIME
annotation class Ann(vararg val arg: Class<*><caret>)
Ann(javaClass<String>(), javaClass<Err>()) class MyClass1
Ann(javaClass<String>(), javaClass()) class MyClass2
val x = javaClass<Double>()
Ann(javaClass<String>(), x) class MyClass3
@@ -0,0 +1,6 @@
// "Replace Class<T> with KClass<T> in whole annotation" "true"
// WITH_RUNTIME
annotation class Ann(vararg val arg: Class<*><caret>)
Ann(javaClass<String>(), javaClass<Double>(), *array(javaClass<Char>())) class MyClass
@@ -0,0 +1,7 @@
import kotlin.reflect.KClass
annotation class AnnO(val arg: KClass<*>)
AnnO(Int::class)
Ann1(String::class)
class MyClassO
@@ -0,0 +1,26 @@
// "Replace Class<T> with KClass<T> 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<KClass<*>>)
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
@@ -0,0 +1,24 @@
// "Replace Class<T> with KClass<T> for each annotation in project" "true"
// WITH_RUNTIME
annotation class Ann1(val arg: Class<*><caret>)
Ann1(javaClass<String>()) class MyClass1
Ann1(javaClass<MyClass1>()) class MyClass2
annotation class Ann2(val arg: Array<Class<*>>)
Ann2(arg = array(javaClass<Double>())) class MyClass3 [Ann1(javaClass<Char>())] () {
annotation class Ann3(val arg: Class<*> = javaClass<Any>())
Ann3(javaClass<String>()) class Nested {
Ann1(arg = javaClass<String>()) fun foo1() {
annotation class LocalAnn(val arg: Class<*>)
[LocalAnn(javaClass<Class<*>>())] val x = 1
}
}
inner AnnO(javaClass<Double>()) class Inner
}
AnnO(javaClass<Boolean>()) class Another
@@ -0,0 +1,5 @@
annotation class AnnO(val arg: Class<*>)
AnnO(javaClass<Int>())
Ann1(javaClass<String>())
class MyClassO
@@ -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)
@@ -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")