diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index 03c3c4b085a..4cdf6cb7d15 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -36,7 +36,7 @@ import java.io.PrintWriter import java.io.StringWriter public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!) -public fun JetPsiFactory(contextElement: JetElement): JetPsiFactory = JetPsiFactory(contextElement.getProject()) +public fun JetPsiFactory(elementForProject: JetElement): JetPsiFactory = JetPsiFactory(elementForProject.getProject()) public var JetFile.doNotAnalyze: String? by UserDataProperty(Key.create("DO_NOT_ANALYZE")) public var JetFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT")) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt index 49b4870b03a..d78bf8dbffe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt @@ -168,9 +168,11 @@ private fun processPattern(pattern: String, args: Array): PatternData { } }.toString() - val max = ranges.keySet().max()!! - for (i in 0..max) { - check(ranges.contains(i), "no '$$i' placeholder") + if (!ranges.isEmpty()) { + val max = ranges.keySet().max()!! + for (i in 0..max) { + check(ranges.contains(i), "no '$$i' placeholder") + } } if (args.size() != ranges.size()) { diff --git a/compiler/testData/builtin-classes.txt b/compiler/testData/builtin-classes.txt index 74db9f36c66..20e11c4581a 100644 --- a/compiler/testData/builtin-classes.txt +++ b/compiler/testData/builtin-classes.txt @@ -1162,6 +1162,14 @@ public interface Range> { public open fun isEmpty(): kotlin.Boolean } +public final annotation class ReplaceWith : kotlin.Annotation { + /*primary*/ public constructor ReplaceWith(/*0*/ expression: kotlin.String, /*1*/ vararg imports: kotlin.String /*kotlin.Array*/) + internal final val expression: kotlin.String + internal final fun (): kotlin.String + internal final val imports: kotlin.Array + internal final fun (): kotlin.Array +} + public interface Set : kotlin.Collection { public abstract override /*1*/ fun contains(/*0*/ o: kotlin.Any?): kotlin.Boolean public abstract override /*1*/ fun containsAll(/*0*/ c: kotlin.Collection): kotlin.Boolean @@ -1336,7 +1344,9 @@ public final annotation class data : kotlin.Annotation { } public final annotation class deprecated : kotlin.Annotation { - /*primary*/ public constructor deprecated(/*0*/ value: kotlin.String) + /*primary*/ public constructor deprecated(/*0*/ value: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ...) + internal final val replaceWith: kotlin.ReplaceWith + internal final fun (): kotlin.ReplaceWith internal final val value: kotlin.String internal final fun (): kotlin.String } diff --git a/core/builtins/src/kotlin/Annotations.kt b/core/builtins/src/kotlin/Annotations.kt index 4136eb529b9..a20e0bd98d9 100644 --- a/core/builtins/src/kotlin/Annotations.kt +++ b/core/builtins/src/kotlin/Annotations.kt @@ -28,7 +28,10 @@ public annotation class data * Marks the annotated class, function or property as deprecated. * @property value the message explaining the deprecation and recommending an alternative API to use. */ -public annotation class deprecated(val value: String) +public annotation class deprecated(val value: String, val replaceWith: ReplaceWith = ReplaceWith("")) + +//TODO: doc-comment +public annotation class ReplaceWith(val expression: String, vararg val imports: String) /** * Signifies that the annotated functional type represents an extension function. diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt index df8d388a588..f4290c2d2eb 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt @@ -16,31 +16,35 @@ package org.jetbrains.kotlin.idea.util -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.renderer.DescriptorRenderer; -import com.intellij.psi.util.PsiTreeUtil +import com.intellij.openapi.util.Key import com.intellij.openapi.util.TextRange -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.analyzer.analyzeInContext -import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny -import java.util.LinkedHashSet -import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import java.util.ArrayList -import org.jetbrains.kotlin.psi.psiUtil.parents -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport +import org.jetbrains.kotlin.idea.imports.getImportableTargets import org.jetbrains.kotlin.idea.util.ShortenReferences.Options -import org.jetbrains.kotlin.idea.imports.* -import org.jetbrains.kotlin.resolve.* -import com.intellij.psi.* +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import java.util.ArrayList +import java.util.LinkedHashSet public class ShortenReferences(val options: (JetElement) -> Options = { Options.DEFAULT }) { public data class Options( @@ -66,12 +70,9 @@ public class ShortenReferences(val options: (JetElement) -> Options = { Options. } } - public fun process(element: JetElement) { - process(listOf(element)) - } - - public fun process(elements: Iterable) { - process(elements, { FilterResult.PROCESS }) + @overloads + public fun process(element: JetElement, elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }): JetElement { + return process(listOf(element), elementFilter).single() } public fun process(file: JetFile, startOffset: Int, endOffset: Int) { @@ -120,23 +121,23 @@ public class ShortenReferences(val options: (JetElement) -> Options = { Options. } } - private enum class FilterResult { + public enum class FilterResult { SKIP, GO_INSIDE, PROCESS } - private fun process(elements: Iterable, elementFilter: (PsiElement) -> FilterResult) { - for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) { - shortenReferencesInFile(file, fileElements, elementFilter) - } + @overloads + public fun process(elements: Iterable, elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }): Collection { + return elements.groupBy { element -> element.getContainingJetFile() } + .flatMap { shortenReferencesInFile(it.key, it.value, elementFilter) } } private fun shortenReferencesInFile( file: JetFile, elements: List, elementFilter: (PsiElement) -> FilterResult - ) { + ): Collection { //TODO: that's not correct since we have options! val elementsToUse = dropNestedElements(elements) @@ -174,6 +175,8 @@ public class ShortenReferences(val options: (JetElement) -> Options = { Options. } if (!anyChange) break } + + return elementsToUse } private fun dropNestedElements(elements: List): LinkedHashSet { @@ -323,8 +326,8 @@ public class ShortenReferences(val options: (JetElement) -> Options = { Options. val bindingContext = resolutionFacade.analyze(qualifiedExpression) val receiver = qualifiedExpression.getReceiverExpression() - when { - receiver is JetThisExpression -> { + when (receiver) { + is JetThisExpression -> { if (!options.removeThis) return false } else -> { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFix.kt new file mode 100644 index 00000000000..bb226383874 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFix.kt @@ -0,0 +1,355 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiRecursiveElementVisitor +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.analyzer.analyzeInContext +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport +import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ImportInsertHelper +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression +import org.jetbrains.kotlin.psi.psiUtil.replaced +import org.jetbrains.kotlin.psi.psiUtil.siblings +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil +import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.resolve.scopes.* +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import java.util.ArrayList +import java.util.LinkedHashSet + +//TODO: replacement of class usages +//TODO: different replacements for property accessors +//TODO: replace all in project quickfixes on usage and on deprecated annotation +public class DeprecatedSymbolUsageFix( + element: JetSimpleNameExpression/*TODO?*/, + val replaceWith: DeprecatedSymbolUsageFix.ReplaceWith +) : JetIntentionAction(element) { + + //TODO: use ReplaceWith from package kotlin + private data class ReplaceWith(val expression: String, vararg val imports: String) + + override fun getFamilyName() = "Replace deprecated symbol usage" + + override fun getText() = "Replace with '${replaceWith.expression}'" //TODO: substitute? + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { + if (!super.isAvailable(project, editor, file)) return false + + val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false + if (!resolvedCall.getStatus().isSuccess()) return false + val descriptor = resolvedCall.getResultingDescriptor() + if (replaceWithPattern(descriptor) != replaceWith) return false + + try { + JetPsiFactory(project).createExpression(replaceWith.expression) + return true + } + catch(e: Exception) { + return false + } + } + + override fun invoke(project: Project, editor: Editor?, file: JetFile) { + val psiFactory = JetPsiFactory(project) + val bindingContext = element.analyze() + val resolvedCall = element.getResolvedCall(bindingContext)!! + val descriptor = resolvedCall.getResultingDescriptor() + val callElement = resolvedCall.getCall().getCallElement() as JetExpression + val qualifiedExpression = callElement.getParent() as? JetQualifiedExpression + val expressionToReplace = qualifiedExpression ?: callElement + + val USER_CODE_KEY = Key("USER_CODE") + + val explicitReceiver = qualifiedExpression?.getReceiverExpression() + explicitReceiver?.putCopyableUserData(USER_CODE_KEY, Unit) + var thisReplacement = explicitReceiver + //TODO: infix and operator calls + + var (expression, imports) = replaceWith.toExpression(descriptor.getOriginal(), element.getResolutionFacade(), file, project) + + if (qualifiedExpression is JetSafeQualifiedExpression) { + fun processSafeCall() { + val qualified = expression as? JetQualifiedExpression + if (qualified != null) { + val thisReceiver = qualified.getReceiverExpression() as? JetThisExpression + if (thisReceiver != null && thisReceiver.getLabelName() == null) { + val selector = qualified.getSelectorExpression() + if (selector != null) { + expression = psiFactory.createExpressionByPattern("this?.$0", selector) + return + } + } + } + + if (expressionToReplace.isUsedAsExpression(bindingContext)) { + expression = psiFactory.createExpressionByPattern("$0?.let { $1 }", explicitReceiver!!, expression) + thisReplacement = psiFactory.createExpression("it") + } + else { + expression = psiFactory.createExpressionByPattern("if ($0 != null) { $1 }", explicitReceiver!!, expression) + } + } + processSafeCall() + } + + val parametersByName = descriptor.getValueParameters().toMap { it.getName().asString() } + expression.accept(object : JetVisitorVoid(){ + override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) { + val qualified = expression.getParent() as? JetDotQualifiedExpression + if (qualified != null && expression == qualified.getSelectorExpression()) return + val name = expression.getReferencedName() + val parameter = parametersByName[name] ?: return //TODO: is this always correct? Lambda inside? + val arguments = resolvedCall.getValueArguments()[parameter] ?: return //TODO: what if not? vararg? + val argumentExpression = arguments.getArguments().firstOrNull()?.getArgumentExpression() ?: return //TODO: what if multiple? + argumentExpression.putCopyableUserData(USER_CODE_KEY, Unit) + expression.replace(argumentExpression) + + //TODO: check if complex expressions are used twice + //TODO: check for dropping complex expressions + } + + override fun visitThisExpression(expression: JetThisExpression) { + if (expression.getLabelName() != null) return //TODO + if (thisReplacement != null) { + expression.replace(thisReplacement!!) + } + //TODO: implicit receiver is not always "this" + } + + override fun visitJetElement(element: JetElement) { + // we do not use acceptChildren because it does not work with replacement + var child: PsiElement? = element.getFirstChild() + while (child != null) { + // whitespace may get invalidated on replace + val next = child.siblings(withItself = false).firstOrNull { it !is PsiWhiteSpace } + child.accept(this) + child = next + } + } + }) + + var result = expressionToReplace.replaced(expression) + + //TODO: drop import of old function (if not needed anymore)? + + for (importFqName in imports) { + val descriptors = file.getResolutionFacade().resolveImportReference(file, importFqName) + val descriptorToImport = descriptors.firstOrNull() ?: continue + ImportInsertHelper.getInstance(project).importDescriptor(file, descriptorToImport) + } + + val shortenFilter = { it: PsiElement -> + if (it.getCopyableUserData(USER_CODE_KEY) != null) { + ShortenReferences.FilterResult.SKIP + } + else { + val thisReceiver = (it as? JetQualifiedExpression)?.getReceiverExpression() as? JetThisExpression + if (thisReceiver != null && thisReceiver.getCopyableUserData(USER_CODE_KEY) != null) // don't remove explicit 'this' coming from user's code + ShortenReferences.FilterResult.GO_INSIDE + else + ShortenReferences.FilterResult.PROCESS + } + } + result = ShortenReferences({ ShortenReferences.Options(removeThis = true) }).process(result, shortenFilter) as JetExpression + + // clean up user data + result.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + element.putCopyableUserData(USER_CODE_KEY, null) + } + }) + + val offset = ((result as? JetQualifiedExpression)?.getSelectorExpression() ?: result).getTextOffset() + editor?.moveCaret(offset) + } + + private fun ReplaceWith.toExpression(symbolDescriptor: CallableDescriptor, resolutionFacade: ResolutionFacade, file: JetFile/*TODO: drop it*/, project: Project): Pair> { + val psiFactory = JetPsiFactory(project) + var expression = psiFactory.createExpression(expression) + + val importFqNames = imports + .filter { FqNameUnsafe.isValid(it) } + .map { FqNameUnsafe(it) } + .filter { it.isSafe() } + .mapTo(LinkedHashSet()) { it.toSafe() } + + val symbolScope = getResolutionScope(symbolDescriptor) + val explicitlyImportedSymbols = importFqNames.flatMap { resolutionFacade.resolveImportReference(file, it) } + val scope = ChainedScope(symbolDescriptor, "ReplaceWith resolution scope", ExplicitImportsScope(explicitlyImportedSymbols), symbolScope) + + val bindingContext = expression.analyzeInContext(scope) + + val thisType = symbolDescriptor.getExtensionReceiverParameter()?.getType() + ?: (symbolDescriptor.getContainingDeclaration() as? ClassifierDescriptor)?.getDefaultType() + + val receiversToAdd = ArrayList>() + + expression.accept(object : JetVisitorVoid(){ + override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) { + val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return + + if (target.canBeReferencedViaImport()) { + if (target.isExtension || expression.getReceiverExpression() == null) { + importFqNames.addIfNotNull(target.importableFqName) + } + } + + if (expression.getReceiverExpression() == null) { + val resolvedCall = expression.getResolvedCall(bindingContext) + if (resolvedCall != null && resolvedCall.getStatus().isSuccess()) { + val receiver = if (resolvedCall.getResultingDescriptor().isExtension) + resolvedCall.getExtensionReceiver() + else + resolvedCall.getDispatchReceiver() + if (receiver is ThisReceiver) { + if (receiver.getType() == thisType) { + receiversToAdd.add(expression to "this") + } + else { + val descriptor = receiver.getDeclarationDescriptor() + if (descriptor is ClassDescriptor && descriptor.isCompanionObject()) { + receiversToAdd.add(expression to IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor)) + } + } + } + } + } + } + + override fun visitJetElement(element: JetElement) { + element.acceptChildren(this) + } + }) + + for ((expr, receiverText) in receiversToAdd) { + val expressionToReplace = expr.getParent() as? JetCallExpression ?: expr + val newExpr = expressionToReplace.replaced(psiFactory.createExpressionByPattern("$receiverText.$0", expressionToReplace)) + if (expressionToReplace == expression) { + expression = newExpr + } + } + + return expression to importFqNames + } + + private fun getResolutionScope(descriptor: DeclarationDescriptor): JetScope { + when (descriptor) { + is PackageFragmentDescriptor -> { + val moduleDescriptor = descriptor.getContainingDeclaration() + return getResolutionScope(moduleDescriptor.getPackage(descriptor.fqName)!!) + } + + is PackageViewDescriptor -> + return descriptor.getMemberScope() + + is ClassDescriptorWithResolutionScopes -> + return descriptor.getScopeForMemberDeclarationResolution() + + is FunctionDescriptor -> + return FunctionDescriptorUtil.getFunctionInnerScope(getResolutionScope(descriptor.getContainingDeclaration()), + descriptor, RedeclarationHandler.DO_NOTHING) + + is PropertyDescriptor -> + return JetScopeUtils.getPropertyDeclarationInnerScope(descriptor, + getResolutionScope(descriptor.getContainingDeclaration()!!), + RedeclarationHandler.DO_NOTHING) + + else -> throw IllegalArgumentException("Cannot find resolution scope for $descriptor") + } + } + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val nameExpression = diagnostic.getPsiElement() as? JetSimpleNameExpression ?: return null + val descriptor = Errors.DEPRECATED_SYMBOL_WITH_MESSAGE.cast(diagnostic).getA() + val replacement = replaceWithPattern(descriptor) ?: return null + return DeprecatedSymbolUsageFix(nameExpression, replacement) + } + + private fun replaceWithPattern(descriptor: DeclarationDescriptor): ReplaceWith? { + val annotationClass = descriptor.builtIns.getDeprecatedAnnotation() + val annotation = descriptor.getAnnotations().findAnnotation(DescriptorUtils.getFqNameSafe(annotationClass))!! + val replaceWithValue = annotation.getAllValueArguments().entrySet() + .singleOrNull { it.key.getName().asString() == "replaceWith"/*TODO*/ } + ?.value?.getValue() as? AnnotationDescriptor ?: return null + val pattern = replaceWithValue.getAllValueArguments().entrySet() + .singleOrNull { it.key.getName().asString() == "expression"/*TODO*/ } + ?.value?.getValue() as? String ?: return null + if (pattern.isEmpty()) return null + val argument = replaceWithValue.getAllValueArguments().entrySet().singleOrNull { it.key.getName().asString() == "imports"/*TODO*/ }?.value + val imports = (argument?.getValue() as? List>)?.map { it.getValue() } ?: emptyList() + return ReplaceWith(pattern, *imports.toTypedArray()) + } + } + + private class ExplicitImportsScope(val descriptors: Collection) : JetScope { + override fun getClassifier(name: Name) = descriptors.filter { it.getName() == name }.firstIsInstanceOrNull() + + override fun getPackage(name: Name)= descriptors.filter { it.getName() == name }.firstIsInstanceOrNull() + + override fun getProperties(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance() + + override fun getLocalVariable(name: Name): VariableDescriptor? = null + + override fun getFunctions(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance() + + override fun getContainingDeclaration(): DeclarationDescriptor { + throw UnsupportedOperationException() + } + + override fun getDeclarationsByLabel(labelName: Name): Collection = emptyList() + + override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = descriptors + + override fun getImplicitReceiversHierarchy(): List = emptyList() + + override fun getOwnDeclaredDescriptors(): Collection = emptyList() + + override fun printScopeStructure(p: Printer) { + p.println(javaClass.getName()) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java index 62971ea8b8a..5d3fdd3309f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -343,5 +343,7 @@ public class QuickFixRegistrar { QuickFixes.factories.put(UNRESOLVED_REFERENCE, ReplaceObsoleteLabelSyntaxFix.Companion); QuickFixes.factories.put(UNRESOLVED_REFERENCE, ReplaceObsoleteLabelSyntaxFix.Companion.createWholeProjectFixFactory()); + + QuickFixes.factories.put(DEPRECATED_SYMBOL_WITH_MESSAGE, DeprecatedSymbolUsageFix.Companion); } } diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.after.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.after.kt new file mode 100644 index 00000000000..dfe9d86410c --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.after.kt @@ -0,0 +1,8 @@ +// "Replace with 's.newFun()'" "true" + +import dependency.newFun +import dependency.oldFun + +fun foo() { + "a".newFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Declaration.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Declaration.kt new file mode 100644 index 00000000000..b116c861441 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Declaration.kt @@ -0,0 +1,6 @@ +package dependency + +@deprecated("", ReplaceWith("s.newFun()")) +fun oldFun(s: String) {} + +fun String.newFun() {} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Main.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Main.kt new file mode 100644 index 00000000000..95133cff6b5 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Main.kt @@ -0,0 +1,7 @@ +// "Replace with 's.newFun()'" "true" + +import dependency.oldFun + +fun foo() { + oldFun("a") +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.after.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.after.kt new file mode 100644 index 00000000000..628729488b6 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.after.kt @@ -0,0 +1,9 @@ +// "Replace with 's.extension().newFun()'" "true" + +import dependency.newFun +import dependency.oldFun +import dependency2.extension + +fun foo() { + "a".extension().newFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Declaration.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Declaration.kt new file mode 100644 index 00000000000..2ba57279966 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Declaration.kt @@ -0,0 +1,6 @@ +package dependency + +@deprecated("", ReplaceWith("s.extension().newFun()", "dependency2.extension")) +fun oldFun(s: String) {} + +fun String.newFun() {} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Dependency2.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Dependency2.kt new file mode 100644 index 00000000000..d9b2bffeb95 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Dependency2.kt @@ -0,0 +1,3 @@ +package dependency2 + +fun String.extension(): String = this \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Main.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Main.kt new file mode 100644 index 00000000000..35692726283 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Main.kt @@ -0,0 +1,7 @@ +// "Replace with 's.extension().newFun()'" "true" + +import dependency.oldFun + +fun foo() { + oldFun("a") +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.after.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.after.kt new file mode 100644 index 00000000000..4ac220137e4 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.after.kt @@ -0,0 +1,8 @@ +// "Replace with 'newFun()'" "true" + +import dependency.newFun +import dependency.oldFun + +fun foo() { + newFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Declaration.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Declaration.kt new file mode 100644 index 00000000000..9b57250fa2c --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Declaration.kt @@ -0,0 +1,6 @@ +package dependency + +@deprecated("", ReplaceWith("newFun()")) +fun oldFun() {} + +fun newFun() {} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Main.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Main.kt new file mode 100644 index 00000000000..0bf2eab613b --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Main.kt @@ -0,0 +1,7 @@ +// "Replace with 'newFun()'" "true" + +import dependency.oldFun + +fun foo() { + oldFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt new file mode 100644 index 00000000000..bd1d4498968 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun(n + java.math.BigInteger(s))'" "true" + +import java.math.BigInteger + +@deprecated("", ReplaceWith("newFun(n + java.math.BigInteger(s))", "kotlin.math.plus")) +fun oldFun(n: BigInteger, s: String) {} + +fun newFun(n: BigInteger) {} + +fun foo() { + oldFun(BigInteger("2"), "1") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt.after new file mode 100644 index 00000000000..7b82676e950 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt.after @@ -0,0 +1,13 @@ +// "Replace with 'newFun(n + java.math.BigInteger(s))'" "true" + +import java.math.BigInteger +import kotlin.math.plus + +@deprecated("", ReplaceWith("newFun(n + java.math.BigInteger(s))", "kotlin.math.plus")) +fun oldFun(n: BigInteger, s: String) {} + +fun newFun(n: BigInteger) {} + +fun foo() { + newFun(BigInteger("2") + BigInteger("1")) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImports.after.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.after.kt new file mode 100644 index 00000000000..5f8eae57566 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.after.kt @@ -0,0 +1,9 @@ +// "Replace with 's.extension1().extension2'" "true" + +import dependency.oldFun +import dependency2.extension1 +import dependency2.extension2 + +fun foo() { + "a".extension1().extension2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Declaration.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Declaration.kt new file mode 100644 index 00000000000..c1577e04d00 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Declaration.kt @@ -0,0 +1,4 @@ +package dependency + +@deprecated("", ReplaceWith("s.extension1().extension2", "dependency2.extension1", "dependency2.extension2")) +fun oldFun(s: String) {} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Dependency2.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Dependency2.kt new file mode 100644 index 00000000000..9c7938cf0bd --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Dependency2.kt @@ -0,0 +1,4 @@ +package dependency2 + +fun String.extension1(): String = this +val String.extension2: String get() = this \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Main.kt b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Main.kt new file mode 100644 index 00000000000..3cd57a725a1 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Main.kt @@ -0,0 +1,7 @@ +// "Replace with 's.extension1().extension2'" "true" + +import dependency.oldFun + +fun foo() { + oldFun("a") +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/callWithError.kt b/idea/testData/quickfix/deprecatedSymbolUsage/callWithError.kt new file mode 100644 index 00000000000..7b2a6b8c13d --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/callWithError.kt @@ -0,0 +1,12 @@ +// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false" +// ERROR: Too many arguments for kotlin.deprecated internal fun oldFun(): kotlin.Unit defined in root package + +@deprecated("", ReplaceWith("newFun()")) +fun oldFun() { +} + +fun newFun(){} + +fun foo() { + oldFun(123) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt new file mode 100644 index 00000000000..8f424bb5661 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt @@ -0,0 +1,12 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} +} + +fun String.newFun(x: X){} + +fun foo(x: X) { + x.oldFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt.after new file mode 100644 index 00000000000..1985951a847 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt.after @@ -0,0 +1,12 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} +} + +fun String.newFun(x: X){} + +fun foo(x: X) { + "a".newFun(x) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt new file mode 100644 index 00000000000..ad5312d7495 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt @@ -0,0 +1,12 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} +} + +fun String.newFun(x: X){} + +fun X.foo() { + oldFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt.after new file mode 100644 index 00000000000..27f281c9c37 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt.after @@ -0,0 +1,12 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} +} + +fun String.newFun(x: X){} + +fun X.foo() { + "a".newFun(this) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt new file mode 100644 index 00000000000..1ef9524cf72 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt @@ -0,0 +1,12 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String): String = s.newFun(this) +} + +fun String.newFun(x: X): String = this + +fun foo(x: X?) { + x?.oldFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt.after new file mode 100644 index 00000000000..3cfa659eb62 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt.after @@ -0,0 +1,14 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String): String = s.newFun(this) +} + +fun String.newFun(x: X): String = this + +fun foo(x: X?) { + if (x != null) { + "a".newFun(x) + } +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt new file mode 100644 index 00000000000..2365247b7b1 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt @@ -0,0 +1,15 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String): String = s.newFun(this) +} + +fun String.newFun(x: X): String = this + +fun foo(x: X?, p: Boolean) { + val v = if (p) + x?.oldFun("a") + else + null +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt.after new file mode 100644 index 00000000000..f5feed0b2c1 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt.after @@ -0,0 +1,15 @@ +// "Replace with 's.newFun(this)'" "true" + +class X { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String): String = s.newFun(this) +} + +fun String.newFun(x: X): String = this + +fun foo(x: X?, p: Boolean) { + val v = if (p) + x?.let { "a".newFun(it) } + else + null +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt new file mode 100644 index 00000000000..c0dff89c595 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt @@ -0,0 +1,18 @@ +// "Replace with 's.newFun(this)'" "true" + +open class Base { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} + + open inner class Inner +} + +class Derived : Base() { + inner class InnerDerived : Base.Inner() { + fun foo() { + oldFun("a") + } + } +} + +fun String.newFun(x: Base){} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt.after new file mode 100644 index 00000000000..c7768185d8b --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt.after @@ -0,0 +1,18 @@ +// "Replace with 's.newFun(this)'" "true" + +open class Base { + @deprecated("", ReplaceWith("s.newFun(this)")) + fun oldFun(s: String){} + + open inner class Inner +} + +class Derived : Base() { + inner class InnerDerived : Base.Inner() { + fun foo() { + "a".newFun(this@Derived) + } + } +} + +fun String.newFun(x: Base){} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt new file mode 100644 index 00000000000..84e1ad5de28 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt @@ -0,0 +1,10 @@ +// "Replace with 'newFun(c)'" "true" + +@deprecated("", ReplaceWith("newFun(c)")) +fun oldFun(c: Char){} + +fun newFun(c: Char){} + +fun foo() { + oldFun(java.io.File.separatorChar) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt.after new file mode 100644 index 00000000000..9e60068d798 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'newFun(c)'" "true" + +@deprecated("", ReplaceWith("newFun(c)")) +fun oldFun(c: Char){} + +fun newFun(c: Char){} + +fun foo() { + newFun(java.io.File.separatorChar) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt new file mode 100644 index 00000000000..054ed074d16 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt @@ -0,0 +1,14 @@ +// "Replace with 'newFun(p)'" "true" + +class X { + @deprecated("", ReplaceWith("newFun(p)")) + fun oldFun(p: Any) { + newFun(p) + } + + fun newFun(p: Any){} +} + +fun X.foo() { + this.oldFun(this.toString()) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt.after new file mode 100644 index 00000000000..bf1835b5109 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt.after @@ -0,0 +1,14 @@ +// "Replace with 'newFun(p)'" "true" + +class X { + @deprecated("", ReplaceWith("newFun(p)")) + fun oldFun(p: Any) { + newFun(p) + } + + fun newFun(p: Any){} +} + +fun X.foo() { + this.newFun(this.toString()) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt new file mode 100644 index 00000000000..b8b43f2d90c --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} +} + +fun newFun(){} + +fun foo(x: X) { + x.oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt.after new file mode 100644 index 00000000000..0f6aed2559d --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} +} + +fun newFun(){} + +fun foo(x: X) { + newFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt new file mode 100644 index 00000000000..922155bf3dc --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} +} + +fun newFun(){} + +fun foo(x: X) { + x?.oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt.after new file mode 100644 index 00000000000..e4369d15724 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt.after @@ -0,0 +1,14 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} +} + +fun newFun(){} + +fun foo(x: X) { + if (x != null) { + newFun() + } +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt b/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt new file mode 100644 index 00000000000..d7b0c2d5f11 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun(t)'" "true" + +class C + +@deprecated("", ReplaceWith("newFun(t)")) +fun C.oldFun(t: T){} + +fun C.newFun(t: T){} + +fun foo(x: C) { + x.oldFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt.after new file mode 100644 index 00000000000..eb35b3464ee --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun(t)'" "true" + +class C + +@deprecated("", ReplaceWith("newFun(t)")) +fun C.oldFun(t: T){} + +fun C.newFun(t: T){} + +fun foo(x: C) { + x.newFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/incorrectReplacement.kt b/idea/testData/quickfix/deprecatedSymbolUsage/incorrectReplacement.kt new file mode 100644 index 00000000000..324ed70b491 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/incorrectReplacement.kt @@ -0,0 +1,9 @@ +// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false" + +@deprecated("", ReplaceWith("=")) +fun oldFun() { +} + +fun foo() { + oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt new file mode 100644 index 00000000000..0a6097450cb --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt @@ -0,0 +1,14 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun() { + newFun() + } + + fun newFun(){} +} + +fun foo(x: X) { + x.oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt.after new file mode 100644 index 00000000000..51614342211 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt.after @@ -0,0 +1,14 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun() { + newFun() + } + + fun newFun(){} +} + +fun foo(x: X) { + x.newFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt new file mode 100644 index 00000000000..894ba0ae757 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt @@ -0,0 +1,14 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun() { + newFun() + } + + fun newFun(){} +} + +fun X.foo() { + oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt.after new file mode 100644 index 00000000000..419216d0f55 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt.after @@ -0,0 +1,14 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun() { + newFun() + } + + fun newFun(){} +} + +fun X.foo() { + newFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt new file mode 100644 index 00000000000..3b6bcb73ef5 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun(t)'" "true" + +interface X { + @deprecated("", ReplaceWith("newFun(t)")) + fun oldFun(t: T) + + fun newFun(t: T) +} + +fun foo(x: X) { + x.oldFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt.after new file mode 100644 index 00000000000..32820a997f6 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun(t)'" "true" + +interface X { + @deprecated("", ReplaceWith("newFun(t)")) + fun oldFun(t: T) + + fun newFun(t: T) +} + +fun foo(x: X) { + x.newFun("a") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt b/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt new file mode 100644 index 00000000000..a58dade923e --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt @@ -0,0 +1,12 @@ +// "Replace with 'x'" "true" + +trait X { + @deprecated("", ReplaceWith("x")) + fun getX(): String + + val x: String +} + +fun foo(x: X): String { + return x.getX() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt.after new file mode 100644 index 00000000000..579569557f3 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'x'" "true" + +trait X { + @deprecated("", ReplaceWith("x")) + fun getX(): String + + val x: String +} + +fun foo(x: X): String { + return x.x +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/noReplacement.kt b/idea/testData/quickfix/deprecatedSymbolUsage/noReplacement.kt new file mode 100644 index 00000000000..0124dcf0140 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/noReplacement.kt @@ -0,0 +1,9 @@ +// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false" + +@deprecated("") +fun oldFun() { +} + +fun foo() { + oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt b/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt new file mode 100644 index 00000000000..eba05d17a70 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt @@ -0,0 +1,11 @@ +// "Replace with 'newFun(b, a, null)'" "true" + +@deprecated("", ReplaceWith("newFun(b, a, null)")) +fun oldFun(a: Int, b: String) { +} + +fun newFun(b: String, a: Int, x: Any?){} + +fun foo() { + oldFun(1, "x") +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt.after new file mode 100644 index 00000000000..71d4b72b856 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt.after @@ -0,0 +1,11 @@ +// "Replace with 'newFun(b, a, null)'" "true" + +@deprecated("", ReplaceWith("newFun(b, a, null)")) +fun oldFun(a: Int, b: String) { +} + +fun newFun(b: String, a: Int, x: Any?){} + +fun foo() { + newFun("x", 1, null) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt b/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt new file mode 100644 index 00000000000..d4acb5e8252 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt @@ -0,0 +1,12 @@ +// "Replace with 'getX()'" "true" + +trait X { + @deprecated("", ReplaceWith("getX()")) + val x: String + + fun getX(): String +} + +fun foo(x: X): String { + return x.x +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt.after new file mode 100644 index 00000000000..ee2d223c6c6 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'getX()'" "true" + +trait X { + @deprecated("", ReplaceWith("getX()")) + val x: String + + fun getX(): String +} + +fun foo(x: X): String { + return x.getX() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt b/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt new file mode 100644 index 00000000000..719913f1b21 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} + + fun newFun(){} +} + +fun foo(x: X?) { + x?.oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt.after new file mode 100644 index 00000000000..745c11c3f30 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +class X { + @deprecated("", ReplaceWith("newFun()")) + fun oldFun(){} + + fun newFun(){} +} + +fun foo(x: X?) { + x?.newFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt b/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt new file mode 100644 index 00000000000..f707aaa07b2 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt @@ -0,0 +1,10 @@ +// "Replace with 'newFun(java.io.File.separatorChar)'" "true" + +@deprecated("", ReplaceWith("newFun(java.io.File.separatorChar)")) +fun oldFun() { } + +fun newFun(separator: Char){} + +fun foo() { + oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt.after new file mode 100644 index 00000000000..13689241b55 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun(java.io.File.separatorChar)'" "true" + +import java.io.File + +@deprecated("", ReplaceWith("newFun(java.io.File.separatorChar)")) +fun oldFun() { } + +fun newFun(separator: Char){} + +fun foo() { + newFun(File.separatorChar) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt b/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt new file mode 100644 index 00000000000..e5adb249876 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +@deprecated("", ReplaceWith("newFun()")) +fun oldFun() { + newFun() +} + +fun newFun(){} + +fun foo() { + oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt.after new file mode 100644 index 00000000000..5cabb795142 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/simple.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'newFun()'" "true" + +@deprecated("", ReplaceWith("newFun()")) +fun oldFun() { + newFun() +} + +fun newFun(){} + +fun foo() { + newFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.after.kt b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.after.kt new file mode 100644 index 00000000000..f2e3df1218c --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.after.kt @@ -0,0 +1,7 @@ +// "Replace with 'newFun(this)'" "true" + +import dependency.C + +fun foo(c: dependency.C) { + C.newFun(c) +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Declaration.kt b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Declaration.kt new file mode 100644 index 00000000000..28c3dfba64e --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Declaration.kt @@ -0,0 +1,11 @@ +package dependency + +class C { + @deprecated("", ReplaceWith("newFun(this)")) + fun oldFun() {} + + companion object { + fun newFun(c: C) {} + } +} + diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Main.kt b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Main.kt new file mode 100644 index 00000000000..9a2df30adae --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Main.kt @@ -0,0 +1,5 @@ +// "Replace with 'newFun(this)'" "true" + +fun foo(c: dependency.C) { + c.oldFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt b/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt new file mode 100644 index 00000000000..196d5138223 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt @@ -0,0 +1,15 @@ +// "Replace with 'newFun(this)'" "true" +// ERROR: Unresolved reference: newFun + +class Outer { + inner class Inner { + @deprecated("", ReplaceWith("newFun(this)")) + fun oldFun() {} + } + + fun newFun(inner: Inner) {} +} + +fun foo(inner: Outer.Inner) { + inner.oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt.after new file mode 100644 index 00000000000..60887df28b4 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt.after @@ -0,0 +1,15 @@ +// "Replace with 'newFun(this)'" "true" +// ERROR: Unresolved reference: newFun + +class Outer { + inner class Inner { + @deprecated("", ReplaceWith("newFun(this)")) + fun oldFun() {} + } + + fun newFun(inner: Inner) {} +} + +fun foo(inner: Outer.Inner) { + newFun(inner) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt b/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt new file mode 100644 index 00000000000..c4da304cd09 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt @@ -0,0 +1,10 @@ +// "Replace with 'newFun(p1 + p2)'" "true" + +@deprecated("", ReplaceWith("newFun(p1 + p2)")) +fun oldFun(p1: Int, p2: Int) {} + +fun newFun(n: Int) {} + +fun foo() { + oldFun(1, 2) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt.after new file mode 100644 index 00000000000..513486ab8ec --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'newFun(p1 + p2)'" "true" + +@deprecated("", ReplaceWith("newFun(p1 + p2)")) +fun oldFun(p1: Int, p2: Int) {} + +fun newFun(n: Int) {} + +fun foo() { + newFun(1 + 2) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index d520aa4b33c..1b65a63221f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -844,6 +844,45 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DeprecatedSymbolUsage extends AbstractQuickFixMultiFileTest { + @TestMetadata("addImportFromSamePackage.before.Main.kt") + public void testAddImportFromSamePackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("addImportFromSamePackage2.before.Main.kt") + public void testAddImportFromSamePackage2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage2.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("addImportFromSamePackage3.before.Main.kt") + public void testAddImportFromSamePackage3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/addImportFromSamePackage3.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("addImports.before.Main.kt") + public void testAddImports() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/addImports.before.Main.kt"); + doTestWithExtraFile(fileName); + } + + public void testAllFilesPresentInDeprecatedSymbolUsage() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); + } + + @TestMetadata("toMethodFromCompanionObject.before.Main.kt") + public void testToMethodFromCompanionObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/toMethodFromCompanionObject.before.Main.kt"); + doTestWithExtraFile(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration") @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 4ff29696a11..5782becf973 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -2858,6 +2858,165 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DeprecatedSymbolUsage extends AbstractQuickFixTest { + @TestMetadata("addImportRuntime.kt") + public void testAddImportRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/addImportRuntime.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInDeprecatedSymbolUsage() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage"), Pattern.compile("^(\\w+)\\.kt$"), true); + } + + @TestMetadata("callWithError.kt") + public void testCallWithError() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/callWithError.kt"); + doTest(fileName); + } + + @TestMetadata("changeThis1.kt") + public void testChangeThis1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThis1.kt"); + doTest(fileName); + } + + @TestMetadata("changeThis2.kt") + public void testChangeThis2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThis2.kt"); + doTest(fileName); + } + + @TestMetadata("changeThisSafeCall.kt") + public void testChangeThisSafeCall() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCall.kt"); + doTest(fileName); + } + + @TestMetadata("changeThisSafeCallWithValueRuntime.kt") + public void testChangeThisSafeCallWithValueRuntime() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("changeThisToOuterThis.kt") + public void testChangeThisToOuterThis() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisToOuterThis.kt"); + doTest(fileName); + } + + @TestMetadata("doNotShortenUserReferences.kt") + public void testDoNotShortenUserReferences() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUserReferences.kt"); + doTest(fileName); + } + + @TestMetadata("doNotShortenUsersExplicitThis.kt") + public void testDoNotShortenUsersExplicitThis() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/doNotShortenUsersExplicitThis.kt"); + doTest(fileName); + } + + @TestMetadata("dropReceiver.kt") + public void testDropReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/dropReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("dropReceiverSafeCall.kt") + public void testDropReceiverSafeCall() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/dropReceiverSafeCall.kt"); + doTest(fileName); + } + + @TestMetadata("extensionForGenericClass.kt") + public void testExtensionForGenericClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/extensionForGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("incorrectReplacement.kt") + public void testIncorrectReplacement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/incorrectReplacement.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/memberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunctionImplicitReceiver.kt") + public void testMemberFunctionImplicitReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionImplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunctionInGenericClass.kt") + public void testMemberFunctionInGenericClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/memberFunctionInGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("methodToProperty.kt") + public void testMethodToProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/methodToProperty.kt"); + doTest(fileName); + } + + @TestMetadata("noReplacement.kt") + public void testNoReplacement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/noReplacement.kt"); + doTest(fileName); + } + + @TestMetadata("parameters.kt") + public void testParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/parameters.kt"); + doTest(fileName); + } + + @TestMetadata("propertyToMethod.kt") + public void testPropertyToMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/propertyToMethod.kt"); + doTest(fileName); + } + + @TestMetadata("safeCall.kt") + public void testSafeCall() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/safeCall.kt"); + doTest(fileName); + } + + @TestMetadata("shortenReferences.kt") + public void testShortenReferences() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/simple.kt"); + doTest(fileName); + } + + @TestMetadata("toOuterClassMethod.kt") + public void testToOuterClassMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/toOuterClassMethod.kt"); + doTest(fileName); + } + + @TestMetadata("twoValuesCombined.kt") + public void testTwoValuesCombined() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/twoValuesCombined.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/expressions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)