diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index 0960f192d99..33fb5f98f21 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -78,7 +78,11 @@ public class JetPsiFactory(private val project: Project) { } public fun createType(type: String): JetTypeReference { - return createProperty("val x : $type").getTypeReference()!! + val typeReference = createProperty("val x : $type").typeReference + if (typeReference == null || typeReference.text != type) { + throw IllegalArgumentException("Incorrect type: $type") + } + return typeReference } public fun createStar(): PsiElement { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt index 0a80261a82d..1c63ac9e4a9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.analysis.computeTypeInContext import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention @@ -45,6 +46,7 @@ import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import org.jetbrains.kotlin.resolve.scopes.utils.asJetScope import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.utils.addIfNotNull @@ -70,24 +72,24 @@ private fun performCallReplacement( bindingContext: BindingContext, resolvedCall: ResolvedCall, replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression -): JetExpression { +): JetElement { val project = element.project val psiFactory = JetPsiFactory(project) val descriptor = resolvedCall.resultingDescriptor - val callExpression = resolvedCall.call.callElement as JetExpression - val qualifiedExpression = callExpression.getQualifiedExpressionForSelector() - val expressionToBeReplaced = qualifiedExpression ?: callExpression + val callElement = resolvedCall.call.callElement + val qualifiedExpression = callElement.getQualifiedExpressionForSelector() + val elementToBeReplaced = qualifiedExpression ?: callElement - val commentSaver = CommentSaver(expressionToBeReplaced, saveLineBreaks = true) + val commentSaver = CommentSaver(elementToBeReplaced, saveLineBreaks = true) var receiver = element.getReceiverExpression()?.marked(USER_CODE_KEY) var receiverType = if (receiver != null) bindingContext.getType(receiver) else null if (receiver == null) { val receiverValue = if (descriptor.isExtension) resolvedCall.extensionReceiver else resolvedCall.dispatchReceiver - val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, expressionToBeReplaced] - if (receiverValue is ThisReceiver && resolutionScope != null) { + val resolutionScope = elementToBeReplaced.getResolutionScope(bindingContext, elementToBeReplaced.getResolutionFacade()).asJetScope() + if (receiverValue is ThisReceiver) { receiver = receiverValue.asExpression(resolutionScope, psiFactory) receiverType = receiverValue.type } @@ -95,7 +97,10 @@ private fun performCallReplacement( receiver?.mark(RECEIVER_VALUE_KEY) - val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext) + val wrapper = if (elementToBeReplaced is JetExpression) + ConstructedExpressionWrapperWithIntroduceFeature(replacement.expression, bindingContext, elementToBeReplaced) + else + ConstructedExpressionWrapper(replacement.expression, bindingContext) //TODO: this@ for (thisExpression in replacement.expression.collectDescendantsOfType()) { @@ -112,41 +117,57 @@ private fun performCallReplacement( wrapper.processTypeParameterUsages(resolvedCall) if (qualifiedExpression is JetSafeQualifiedExpression) { - wrapper.wrapExpressionForSafeCall(receiver!!, receiverType) + (wrapper as ConstructedExpressionWrapperWithIntroduceFeature).wrapExpressionForSafeCall(receiver!!, receiverType) } - else if (callExpression is JetBinaryExpression && callExpression.operationToken == JetTokens.IDENTIFIER) { + else if (callElement is JetBinaryExpression && callElement.operationToken == JetTokens.IDENTIFIER) { wrapper.keepInfixFormIfPossible() } - if (receiver != null) { + if (receiver != null && wrapper is ConstructedExpressionWrapperWithIntroduceFeature) { val thisReplaced = wrapper.expression.collectDescendantsOfType { it[RECEIVER_VALUE_KEY] } - if (receiver.shouldKeepValue(thisReplaced.size())) { + if (receiver.shouldKeepValue(thisReplaced.size)) { wrapper.introduceValue(receiver, receiverType, thisReplaced) } } - for ((parameter, value, valueType) in introduceValuesForParameters) { - val usagesReplaced = wrapper.expression.collectDescendantsOfType { it[PARAMETER_VALUE_KEY] == parameter } - wrapper.introduceValue(value, valueType, usagesReplaced, nameSuggestion = parameter.name.asString()) + if (wrapper is ConstructedExpressionWrapperWithIntroduceFeature) { + for ((parameter, value, valueType) in introduceValuesForParameters) { + val usagesReplaced = wrapper.expression.collectDescendantsOfType { it[PARAMETER_VALUE_KEY] == parameter } + wrapper.introduceValue(value, valueType, usagesReplaced, nameSuggestion = parameter.name.asString()) + } } - var result = expressionToBeReplaced.replace(wrapper.expression) as JetExpression + var result = elementToBeReplaced.replaceCallElement(wrapper.expression) val file = result.getContainingJetFile() replacement.fqNamesToImport .flatMap { file.resolveImportReference(it) } .forEach { ImportInsertHelper.getInstance(project).importDescriptor(file, it) } - var resultRange = if (wrapper.addedStatements.isEmpty()) + var resultRange = if (wrapper !is ConstructedExpressionWrapperWithIntroduceFeature || wrapper.addedStatements.isEmpty()) PsiChildRange.singleElement(result) else PsiChildRange(wrapper.addedStatements.first(), result) - resultRange = postProcessInsertedExpression(resultRange) + resultRange = postProcessInsertedCode(resultRange) commentSaver.restore(resultRange) - return resultRange.last as JetExpression + return resultRange.last as JetElement +} + +private fun JetElement.replaceCallElement(generatedExpression: JetExpression): JetElement { + when (this) { + is JetExpression -> return replace(generatedExpression) as JetExpression + + is JetAnnotationEntry -> { + //TODO: bad techinique!! + val annotationEntry = JetPsiFactory(project).createAnnotationEntry("@" + generatedExpression.text) + return replace(annotationEntry) as JetElement + } + + else -> throw UnsupportedOperationException() //TODO: check it before!! + } } private fun ConstructedExpressionWrapper.processValueParameterUsages( @@ -243,7 +264,7 @@ private fun ConstructedExpressionWrapper.processTypeParameterUsages(resolvedCall } } -private fun ConstructedExpressionWrapper.wrapExpressionForSafeCall(receiver: JetExpression, receiverType: JetType?) { +private fun ConstructedExpressionWrapperWithIntroduceFeature.wrapExpressionForSafeCall(receiver: JetExpression, receiverType: JetType?) { val qualified = expression as? JetQualifiedExpression if (qualified != null) { if (qualified.receiverExpression[RECEIVER_VALUE_KEY]) { @@ -363,10 +384,10 @@ private fun argumentForParameter( } } -private fun postProcessInsertedExpression(range: PsiChildRange): PsiChildRange { - val expressions = range.filterIsInstance().toList() +private fun postProcessInsertedCode(range: PsiChildRange): PsiChildRange { + val elements = range.filterIsInstance().toList() - expressions.forEach { + elements.forEach { introduceNamedArguments(it) restoreFunctionLiteralArguments(it) @@ -393,11 +414,11 @@ private fun postProcessInsertedExpression(range: PsiChildRange): PsiChildRange { } } - val newExpressions = expressions.map { - ShortenReferences({ ShortenReferences.Options(removeThis = true) }).process(it, shortenFilter) as JetExpression + val newElements = elements.map { + ShortenReferences({ ShortenReferences.Options(removeThis = true) }).process(it, shortenFilter) } - newExpressions.forEach { + newElements.forEach { // clean up user data it.forEachDescendantOfType { it.clear(USER_CODE_KEY) @@ -413,10 +434,10 @@ private fun postProcessInsertedExpression(range: PsiChildRange): PsiChildRange { } } - return PsiChildRange(newExpressions.first(), newExpressions.last()) + return PsiChildRange(newElements.first(), newElements.last()) } -private fun introduceNamedArguments(result: JetExpression) { +private fun introduceNamedArguments(result: JetElement) { val callsToProcess = LinkedHashSet() result.forEachDescendantOfType { if (it[MAKE_ARGUMENT_NAMED_KEY] && !it.isNamed()) { @@ -450,7 +471,7 @@ private fun introduceNamedArguments(result: JetExpression) { } } -private fun dropArgumentsForDefaultValues(result: JetExpression) { +private fun dropArgumentsForDefaultValues(result: JetElement) { val project = result.project val newBindingContext = result.analyze() val argumentsToDrop = ArrayList() @@ -492,18 +513,18 @@ private fun arrayOfFunctionName(elementType: JetType): String { } } -private fun removeExplicitTypeArguments(result: JetExpression) { +private fun removeExplicitTypeArguments(result: JetElement) { result.collectDescendantsOfType(canGoInside = { !it[USER_CODE_KEY] }) { RemoveExplicitTypeArgumentsIntention.isApplicableTo(it, approximateFlexible = true) }.forEach { it.delete() } } -private fun simplifySpreadArrayOfArguments(expression: JetExpression) { +private fun simplifySpreadArrayOfArguments(result: JetElement) { //TODO: test for nested val argumentsToExpand = ArrayList>>() - expression.forEachDescendantOfType(canGoInside = { !it[USER_CODE_KEY] }) { argument -> + result.forEachDescendantOfType(canGoInside = { !it[USER_CODE_KEY] }) { argument -> if (argument.getSpreadElement() != null && !argument.isNamed()) { val argumentExpression = argument.getArgumentExpression() ?: return@forEachDescendantOfType val resolvedCall = argumentExpression.getResolvedCall(argumentExpression.analyze(BodyResolveMode.PARTIAL)) ?: return@forEachDescendantOfType @@ -533,10 +554,10 @@ private fun JetValueArgument.replaceByMultiple(arguments: Collection() - expression.forEachDescendantOfType(fun (expr: JetExpression) { + expression.forEachDescendantOfType(fun (expr) { if (!expr[WAS_FUNCTION_LITERAL_ARGUMENT_KEY]) return assert(expr.unpackFunctionLiteral() != null) @@ -559,8 +580,8 @@ private fun restoreFunctionLiteralArguments(expression: JetExpression) { callExpressions.forEach { it.moveFunctionLiteralOutsideParentheses() } } -internal fun PsiElement.get(key: Key): T? = getCopyableUserData(key) -internal fun PsiElement.get(key: Key): Boolean = getCopyableUserData(key) != null +internal operator fun PsiElement.get(key: Key): T? = getCopyableUserData(key) +internal operator fun PsiElement.get(key: Key): Boolean = getCopyableUserData(key) != null private fun JetElement.clear(key: Key) = putCopyableUserData(key, null) private fun JetElement.put(key: Key, value: T) = putCopyableUserData(key, value) private fun JetElement.mark(key: Key) = putCopyableUserData(key, Unit) @@ -580,14 +601,11 @@ private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key("WAS_FUNCTION_LITERAL_ private val MAKE_ARGUMENT_NAMED_KEY = Key("MAKE_ARGUMENT_NAMED") private val DEFAULT_PARAMETER_VALUE_KEY = Key("DEFAULT_PARAMETER_VALUE") -private class ConstructedExpressionWrapper( +private open class ConstructedExpressionWrapper( var expression: JetExpression, - val expressionToBeReplaced: JetExpression, val bindingContext: BindingContext ) { - val addedStatements = ArrayList() - - val psiFactory = JetPsiFactory(expressionToBeReplaced) + val psiFactory = JetPsiFactory(expression) public fun replaceExpression(oldExpression: JetExpression, newExpression: JetExpression): JetExpression { assert(expression.isAncestor(oldExpression)) @@ -597,6 +615,14 @@ private class ConstructedExpressionWrapper( } return result } +} + +private class ConstructedExpressionWrapperWithIntroduceFeature( + expression: JetExpression, + bindingContext: BindingContext, + val expressionToBeReplaced: JetExpression +) : ConstructedExpressionWrapper(expression, bindingContext) { + val addedStatements = ArrayList() public fun introduceValue( value: JetExpression, @@ -683,3 +709,4 @@ private class ConstructedExpressionWrapper( private fun collectNameUsages(scope: JetExpression, name: String) = scope.collectDescendantsOfType { it.getReceiverExpression() == null && it.getReferencedName() == name } } + diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ClassUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ClassUsageReplacementStrategy.kt index 40e8a854a93..b3bb85ed43f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ClassUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ClassUsageReplacementStrategy.kt @@ -16,46 +16,60 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith +import com.intellij.openapi.project.Project import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis +import org.jetbrains.kotlin.utils.addToStdlib.check class ClassUsageReplacementStrategy( - private val replacement: JetUserType + typeReplacement: JetUserType?, + constructorReplacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression?, + private val project: Project ) : UsageReplacementStrategy { - private val factory = JetPsiFactory(replacement) - private val qualifierAsExpression = replacement.qualifier?.let { factory.createExpression(it.text) } + private val factory = JetPsiFactory(project) + + private val typeReplacement = typeReplacement?.check { it.referenceExpression != null } + private val typeReplacementQualifierAsExpression = typeReplacement?.qualifier?.let { factory.createExpression(it.text) } + + private val constructorReplacementStrategy = constructorReplacement?.let { CallableUsageReplacementStrategy(it) } override fun createReplacer(usage: JetSimpleNameExpression): (() -> JetElement)? { if (usage !is JetNameReferenceExpression) return null - if (replacement.referenceExpression == null) return null + + constructorReplacementStrategy?.createReplacer(usage)?.let { return it } val parent = usage.parent when (parent) { is JetUserType -> { + if (typeReplacement == null) return null return { - val replaced = parent.replaced(replacement) + val replaced = parent.replaced(typeReplacement) ShortenReferences.DEFAULT.process(replaced) } //TODO: type arguments and type arguments of outer class are lost } is JetCallExpression -> { if (usage != parent.calleeExpression) return null - return { replaceConstructorCall(parent) } + when { +// constructorReplacementStrategy != null -> return constructorReplacementStrategy.createReplacer(usage) + constructorReplacementStrategy == null && typeReplacement != null -> return { replaceConstructorCallWithOtherTypeConstruction(parent) } + else -> return null + } } else -> return null //TODO } } - private fun replaceConstructorCall(callExpression: JetCallExpression): JetElement { - callExpression.calleeExpression!!.replace(replacement.referenceExpression!!) + private fun replaceConstructorCallWithOtherTypeConstruction(callExpression: JetCallExpression): JetElement { + callExpression.calleeExpression!!.replace(typeReplacement!!.referenceExpression!!) val expressionToReplace = callExpression.getQualifiedExpressionForSelectorOrThis() - val newExpression = if (qualifierAsExpression != null) - factory.createExpressionByPattern("$0.$1", qualifierAsExpression, callExpression) + val newExpression = if (typeReplacementQualifierAsExpression != null) + factory.createExpressionByPattern("$0.$1", typeReplacementQualifierAsExpression, callExpression) else callExpression diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/UsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/UsageReplacementStrategy.kt index 2c490a8fb1f..faa838a0bb7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/UsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/UsageReplacementStrategy.kt @@ -54,8 +54,15 @@ interface UsageReplacementStrategy { } is ClassDescriptor -> { - val replacement = ReplaceWithAnnotationAnalyzer.analyzeClassReplacement(replaceWith, target, resolutionFacade) ?: return null - return ClassUsageReplacementStrategy(replacement) + val replacementType = ReplaceWithAnnotationAnalyzer.analyzeClassReplacement(replaceWith, target, resolutionFacade) + if (replacementType != null) { //TODO: check that it's really resolved and is not an object otherwise it can be expression as well + return ClassUsageReplacementStrategy(replacementType, null, element.project) + } + else { + val constructor = target.unsubstitutedPrimaryConstructor ?: return null + val replacementExpression = ReplaceWithAnnotationAnalyzer.analyzeCallableReplacement(replaceWith, constructor, resolutionFacade) ?: return null + return ClassUsageReplacementStrategy(null, replacementExpression, element.project) + } } else -> return null diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt new file mode 100644 index 00000000000..c8652c341ff --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt @@ -0,0 +1,10 @@ +// "Replace with 'test.Bar(1)'" "true" + +package test + +@Deprecated("Replace with bar", ReplaceWith("test.Bar(1)")) +annotation class Foo + +annotation class Bar(val p: Int) + +@Foo class C {} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt.after new file mode 100644 index 00000000000..e2db915cda4 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'test.Bar(1)'" "true" + +package test + +@Deprecated("Replace with bar", ReplaceWith("test.Bar(1)")) +annotation class Foo + +annotation class Bar(val p: Int) + +@Bar(1) class C {} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt new file mode 100644 index 00000000000..a05b3b56ec7 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt @@ -0,0 +1,10 @@ +// "Replace with 'test.Bar(p, "")'" "true" + +package test + +@Deprecated("Replace with bar", ReplaceWith("test.Bar(p, \"\")")) +annotation class Foo(val p: Int) + +annotation class Bar(val p: Int, val s: String) + +@Foo(1) class C {} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt.after new file mode 100644 index 00000000000..76f17395310 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'test.Bar(p, "")'" "true" + +package test + +@Deprecated("Replace with bar", ReplaceWith("test.Bar(p, \"\")")) +annotation class Foo(val p: Int) + +annotation class Bar(val p: Int, val s: String) + +@Bar(1, "") class C {} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt new file mode 100644 index 00000000000..45dc7365d24 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt @@ -0,0 +1,11 @@ +// "Replace with 'NewClass(p + 1)'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass(p + 1)")) +class OldClass(p: Int) + +class NewClass(p: Int) + +fun foo() { + OldClass(1) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt.after new file mode 100644 index 00000000000..1d7a4b9e4da --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt.after @@ -0,0 +1,11 @@ +// "Replace with 'NewClass(p + 1)'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass(p + 1)")) +class OldClass(p: Int) + +class NewClass(p: Int) + +fun foo() { + NewClass(1 + 1) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 62090e34df7..65b54ae7b21 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3423,6 +3423,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("annotation3.kt") + public void testAnnotation3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation3.kt"); + doTest(fileName); + } + + @TestMetadata("annotation4.kt") + public void testAnnotation4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/annotation4.kt"); + doTest(fileName); + } + @TestMetadata("constructorUsage1.kt") public void testConstructorUsage1() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage1.kt"); @@ -3441,6 +3453,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("constructorUsage4.kt") + public void testConstructorUsage4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt"); + doTest(fileName); + } + @TestMetadata("imports.kt") public void testImports() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/imports.kt");