DeprecatedSymbolUsageFix: initial implementation
This commit is contained in:
@@ -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"))
|
||||
|
||||
@@ -168,9 +168,11 @@ private fun processPattern(pattern: String, args: Array<out Any>): 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()) {
|
||||
|
||||
@@ -1162,6 +1162,14 @@ public interface Range</*0*/ T : kotlin.Comparable<T>> {
|
||||
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<out kotlin.String>*/)
|
||||
internal final val expression: kotlin.String
|
||||
internal final fun <get-expression>(): kotlin.String
|
||||
internal final val imports: kotlin.Array<out kotlin.String>
|
||||
internal final fun <get-imports>(): kotlin.Array<out kotlin.String>
|
||||
}
|
||||
|
||||
public interface Set</*0*/ out E> : kotlin.Collection<E> {
|
||||
public abstract override /*1*/ fun contains(/*0*/ o: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun containsAll(/*0*/ c: kotlin.Collection<kotlin.Any?>): 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 <get-replaceWith>(): kotlin.ReplaceWith
|
||||
internal final val value: kotlin.String
|
||||
internal final fun <get-value>(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<JetElement>) {
|
||||
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<JetElement>, elementFilter: (PsiElement) -> FilterResult) {
|
||||
for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) {
|
||||
shortenReferencesInFile(file, fileElements, elementFilter)
|
||||
}
|
||||
@overloads
|
||||
public fun process(elements: Iterable<JetElement>, elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }): Collection<JetElement> {
|
||||
return elements.groupBy { element -> element.getContainingJetFile() }
|
||||
.flatMap { shortenReferencesInFile(it.key, it.value, elementFilter) }
|
||||
}
|
||||
|
||||
private fun shortenReferencesInFile(
|
||||
file: JetFile,
|
||||
elements: List<JetElement>,
|
||||
elementFilter: (PsiElement) -> FilterResult
|
||||
) {
|
||||
): Collection<JetElement> {
|
||||
//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<JetElement>): LinkedHashSet<JetElement> {
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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<JetSimpleNameExpression>(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<Unit>("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<JetExpression, Collection<FqName>> {
|
||||
val psiFactory = JetPsiFactory(project)
|
||||
var expression = psiFactory.createExpression(expression)
|
||||
|
||||
val importFqNames = imports
|
||||
.filter { FqNameUnsafe.isValid(it) }
|
||||
.map { FqNameUnsafe(it) }
|
||||
.filter { it.isSafe() }
|
||||
.mapTo(LinkedHashSet<FqName>()) { 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<Pair<JetExpression, String>>()
|
||||
|
||||
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<CompileTimeConstant<String>>)?.map { it.getValue() } ?: emptyList()
|
||||
return ReplaceWith(pattern, *imports.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
private class ExplicitImportsScope(val descriptors: Collection<DeclarationDescriptor>) : JetScope {
|
||||
override fun getClassifier(name: Name) = descriptors.filter { it.getName() == name }.firstIsInstanceOrNull<ClassifierDescriptor>()
|
||||
|
||||
override fun getPackage(name: Name)= descriptors.filter { it.getName() == name }.firstIsInstanceOrNull<PackageViewDescriptor>()
|
||||
|
||||
override fun getProperties(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance<VariableDescriptor>()
|
||||
|
||||
override fun getLocalVariable(name: Name): VariableDescriptor? = null
|
||||
|
||||
override fun getFunctions(name: Name) = descriptors.filter { it.getName() == name }.filterIsInstance<FunctionDescriptor>()
|
||||
|
||||
override fun getContainingDeclaration(): DeclarationDescriptor {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun getDeclarationsByLabel(labelName: Name): Collection<DeclarationDescriptor> = emptyList()
|
||||
|
||||
override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = descriptors
|
||||
|
||||
override fun getImplicitReceiversHierarchy(): List<ReceiverParameterDescriptor> = emptyList()
|
||||
|
||||
override fun getOwnDeclaredDescriptors(): Collection<DeclarationDescriptor> = emptyList()
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(javaClass.getName())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace with 's.newFun()'" "true"
|
||||
|
||||
import dependency.newFun
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
"a".<caret>newFun()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package dependency
|
||||
|
||||
@deprecated("", ReplaceWith("s.newFun()"))
|
||||
fun oldFun(s: String) {}
|
||||
|
||||
fun String.newFun() {}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Replace with 's.newFun()'" "true"
|
||||
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 's.extension().newFun()'" "true"
|
||||
|
||||
import dependency.newFun
|
||||
import dependency.oldFun
|
||||
import dependency2.extension
|
||||
|
||||
fun foo() {
|
||||
"a".extension().<caret>newFun()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package dependency
|
||||
|
||||
@deprecated("", ReplaceWith("s.extension().newFun()", "dependency2.extension"))
|
||||
fun oldFun(s: String) {}
|
||||
|
||||
fun String.newFun() {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package dependency2
|
||||
|
||||
fun String.extension(): String = this
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Replace with 's.extension().newFun()'" "true"
|
||||
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
import dependency.newFun
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
<caret>newFun()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package dependency
|
||||
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {}
|
||||
|
||||
fun newFun() {}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun(BigInteger("2"), "1")
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>newFun(BigInteger("2") + BigInteger("1"))
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with 's.extension1().extension2'" "true"
|
||||
|
||||
import dependency.oldFun
|
||||
import dependency2.extension1
|
||||
import dependency2.extension2
|
||||
|
||||
fun foo() {
|
||||
"a".extension1().<caret>extension2
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package dependency
|
||||
|
||||
@deprecated("", ReplaceWith("s.extension1().extension2", "dependency2.extension1", "dependency2.extension2"))
|
||||
fun oldFun(s: String) {}
|
||||
@@ -0,0 +1,4 @@
|
||||
package dependency2
|
||||
|
||||
fun String.extension1(): String = this
|
||||
val String.extension2: String get() = this
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Replace with 's.extension1().extension2'" "true"
|
||||
|
||||
import dependency.oldFun
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun(123)
|
||||
}
|
||||
@@ -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.<caret>oldFun("a")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -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".<caret>newFun(this)
|
||||
}
|
||||
@@ -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?.<caret>oldFun("a")
|
||||
}
|
||||
@@ -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?) {
|
||||
<caret>if (x != null) {
|
||||
"a".newFun(x)
|
||||
}
|
||||
}
|
||||
@@ -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?.<caret>oldFun("a")
|
||||
else
|
||||
null
|
||||
}
|
||||
+15
@@ -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?.<caret>let { "a".newFun(it) }
|
||||
else
|
||||
null
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun String.newFun(x: Base){}
|
||||
@@ -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() {
|
||||
<caret>"a".newFun(this@Derived)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun String.newFun(x: Base){}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace with 'newFun(c)'" "true"
|
||||
|
||||
@deprecated("", ReplaceWith("newFun(c)"))
|
||||
fun oldFun(c: Char){}
|
||||
|
||||
fun newFun(c: Char){}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun(java.io.File.separatorChar)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace with 'newFun(c)'" "true"
|
||||
|
||||
@deprecated("", ReplaceWith("newFun(c)"))
|
||||
fun oldFun(c: Char){}
|
||||
|
||||
fun newFun(c: Char){}
|
||||
|
||||
fun foo() {
|
||||
<caret>newFun(java.io.File.separatorChar)
|
||||
}
|
||||
@@ -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.<caret>oldFun(this.toString())
|
||||
}
|
||||
@@ -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.<caret>newFun(this.toString())
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo(x: X) {
|
||||
x.<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo(x: X) {
|
||||
newFun()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo(x: X) {
|
||||
x?.<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo(x: X) {
|
||||
<caret>if (x != null) {
|
||||
newFun()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun(t)'" "true"
|
||||
|
||||
class C<T>
|
||||
|
||||
@deprecated("", ReplaceWith("newFun(t)"))
|
||||
fun <T> C<T>.oldFun(t: T){}
|
||||
|
||||
fun <T> C<T>.newFun(t: T){}
|
||||
|
||||
fun foo(x: C<String>) {
|
||||
x.<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun(t)'" "true"
|
||||
|
||||
class C<T>
|
||||
|
||||
@deprecated("", ReplaceWith("newFun(t)"))
|
||||
fun <T> C<T>.oldFun(t: T){}
|
||||
|
||||
fun <T> C<T>.newFun(t: T){}
|
||||
|
||||
fun foo(x: C<String>) {
|
||||
x.<caret>newFun("a")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false"
|
||||
|
||||
@deprecated("", ReplaceWith("="))
|
||||
fun oldFun() {
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun foo(x: X) {
|
||||
x.<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun foo(x: X) {
|
||||
x.newFun()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun X.foo() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun X.foo() {
|
||||
<caret>newFun()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun(t)'" "true"
|
||||
|
||||
interface X<T> {
|
||||
@deprecated("", ReplaceWith("newFun(t)"))
|
||||
fun oldFun(t: T)
|
||||
|
||||
fun newFun(t: T)
|
||||
}
|
||||
|
||||
fun foo(x: X<String>) {
|
||||
x.<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun(t)'" "true"
|
||||
|
||||
interface X<T> {
|
||||
@deprecated("", ReplaceWith("newFun(t)"))
|
||||
fun oldFun(t: T)
|
||||
|
||||
fun newFun(t: T)
|
||||
}
|
||||
|
||||
fun foo(x: X<String>) {
|
||||
x.<caret>newFun("a")
|
||||
}
|
||||
@@ -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.<caret>getX()
|
||||
}
|
||||
@@ -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.<caret>x
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false"
|
||||
|
||||
@deprecated("")
|
||||
fun oldFun() {
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun(1, "x")
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>newFun("x", 1, null)
|
||||
}
|
||||
@@ -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.<caret>x
|
||||
}
|
||||
@@ -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.<caret>getX()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun foo(x: X?) {
|
||||
x?.<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun(){}
|
||||
|
||||
fun newFun(){}
|
||||
}
|
||||
|
||||
fun foo(x: X?) {
|
||||
x?.<caret>newFun()
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>newFun(File.separatorChar)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'newFun()'" "true"
|
||||
|
||||
@deprecated("", ReplaceWith("newFun()"))
|
||||
fun oldFun() {
|
||||
newFun()
|
||||
}
|
||||
|
||||
fun newFun(){}
|
||||
|
||||
fun foo() {
|
||||
<caret>newFun()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Replace with 'newFun(this)'" "true"
|
||||
|
||||
import dependency.C
|
||||
|
||||
fun foo(c: dependency.C) {
|
||||
C.<caret>newFun(c)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package dependency
|
||||
|
||||
class C {
|
||||
@deprecated("", ReplaceWith("newFun(this)"))
|
||||
fun oldFun() {}
|
||||
|
||||
companion object {
|
||||
fun newFun(c: C) {}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Replace with 'newFun(this)'" "true"
|
||||
|
||||
fun foo(c: dependency.C) {
|
||||
c.<caret>oldFun()
|
||||
}
|
||||
@@ -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.<caret>oldFun()
|
||||
}
|
||||
@@ -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) {
|
||||
<caret>newFun(inner)
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>oldFun(1, 2)
|
||||
}
|
||||
@@ -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() {
|
||||
<caret>newFun(1 + 2)
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user