DeprecatedSymbolUsageFix: refactored code for easier handling of optional arguments
This commit is contained in:
@@ -29,10 +29,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.CommentSaver
|
import org.jetbrains.kotlin.idea.core.*
|
||||||
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
|
|
||||||
import org.jetbrains.kotlin.idea.core.asExpression
|
|
||||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameValidator
|
import org.jetbrains.kotlin.idea.core.refactoring.JetNameValidator
|
||||||
import org.jetbrains.kotlin.idea.intentions.setType
|
import org.jetbrains.kotlin.idea.intentions.setType
|
||||||
@@ -182,10 +179,14 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
it[ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY] == parameterName
|
it[ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY] == parameterName
|
||||||
}
|
}
|
||||||
usages.forEach {
|
usages.forEach {
|
||||||
|
val usageArgument = it.getParent() as? JetValueArgument
|
||||||
if (argument.isNamed) {
|
if (argument.isNamed) {
|
||||||
(it.getParent() as? JetValueArgument)?.mark(MAKE_ARGUMENT_NAMED_KEY)
|
usageArgument?.mark(MAKE_ARGUMENT_NAMED_KEY)
|
||||||
}
|
}
|
||||||
it.replace(argument.wrapped)
|
if (argument.isDefaultValue) {
|
||||||
|
usageArgument?.mark(DEFAULT_PARAMETER_VALUE_KEY)
|
||||||
|
}
|
||||||
|
it.replace(argument.expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: sometimes we need to add explicit type arguments here because we don't have expected type in the new context
|
//TODO: sometimes we need to add explicit type arguments here because we don't have expected type in the new context
|
||||||
@@ -195,8 +196,6 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unwrapDefaultValues(replacement.expression)
|
|
||||||
|
|
||||||
val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext)
|
val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext)
|
||||||
|
|
||||||
if (qualifiedExpression is JetSafeQualifiedExpression) {
|
if (qualifiedExpression is JetSafeQualifiedExpression) {
|
||||||
@@ -293,9 +292,9 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
|
|
||||||
private class Argument(
|
private class Argument(
|
||||||
val expression: JetExpression,
|
val expression: JetExpression,
|
||||||
val wrapped: JetExpression,
|
|
||||||
val expressionType: JetType?,
|
val expressionType: JetType?,
|
||||||
val isNamed: Boolean = false)
|
val isNamed: Boolean = false,
|
||||||
|
val isDefaultValue: Boolean = false)
|
||||||
|
|
||||||
private fun argumentForParameter(
|
private fun argumentForParameter(
|
||||||
parameter: ValueParameterDescriptor,
|
parameter: ValueParameterDescriptor,
|
||||||
@@ -311,7 +310,7 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
if (valueArgument is FunctionLiteralArgument) {
|
if (valueArgument is FunctionLiteralArgument) {
|
||||||
expression.mark(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
|
expression.mark(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
return Argument(expression, expression, bindingContext.getType(expression), isNamed = valueArgument.isNamed())
|
return Argument(expression, bindingContext.getType(expression), isNamed = valueArgument.isNamed())
|
||||||
}
|
}
|
||||||
|
|
||||||
is DefaultValueArgument -> {
|
is DefaultValueArgument -> {
|
||||||
@@ -322,14 +321,12 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
usages.forEach { it.put(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY, param.getName()) }
|
usages.forEach { it.put(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY, param.getName()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// we temporary wrap default values into parenthesis so that we can safely mark them with DEFAULT_PARAMETER_VALUE_KEY
|
val expressionCopy = expression.copied()
|
||||||
val wrapped = JetPsiFactory(project).createExpressionByPattern("($0)", expression) as JetParenthesizedExpression
|
|
||||||
wrapped.mark(DEFAULT_PARAMETER_VALUE_KEY)
|
|
||||||
|
|
||||||
// clean up user data in original
|
// clean up user data in original
|
||||||
expression.forEachDescendantOfType<JetExpression> { it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY) }
|
expression.forEachDescendantOfType<JetExpression> { it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY) }
|
||||||
|
|
||||||
return Argument(wrapped.getExpression()!!, wrapped, null/*TODO*/)
|
return Argument(expressionCopy, null/*TODO*/, isDefaultValue = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
is VarargValueArgument -> {
|
is VarargValueArgument -> {
|
||||||
@@ -337,7 +334,7 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
val single = arguments.singleOrNull()
|
val single = arguments.singleOrNull()
|
||||||
if (single != null && single.getSpreadElement() != null) {
|
if (single != null && single.getSpreadElement() != null) {
|
||||||
val expression = single.getArgumentExpression()!!.marked(USER_CODE_KEY)
|
val expression = single.getArgumentExpression()!!.marked(USER_CODE_KEY)
|
||||||
return Argument(expression, expression, bindingContext.getType(expression), isNamed = single.isNamed())
|
return Argument(expression, bindingContext.getType(expression), isNamed = single.isNamed())
|
||||||
}
|
}
|
||||||
|
|
||||||
val elementType = parameter.getVarargElementType()!!
|
val elementType = parameter.getVarargElementType()!!
|
||||||
@@ -353,7 +350,7 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
}
|
}
|
||||||
appendFixedText(")")
|
appendFixedText(")")
|
||||||
}
|
}
|
||||||
return Argument(expression, expression, parameter.getType(), isNamed = single?.isNamed() ?: false)
|
return Argument(expression, parameter.getType(), isNamed = single?.isNamed() ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown argument type: $resolvedArgument")
|
else -> error("Unknown argument type: $resolvedArgument")
|
||||||
@@ -399,11 +396,11 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY)
|
it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY)
|
||||||
it.clear(PARAMETER_VALUE_KEY)
|
it.clear(PARAMETER_VALUE_KEY)
|
||||||
it.clear(RECEIVER_VALUE_KEY)
|
it.clear(RECEIVER_VALUE_KEY)
|
||||||
it.clear(DEFAULT_PARAMETER_VALUE_KEY)
|
|
||||||
it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
|
it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
it.forEachDescendantOfType<JetValueArgument> {
|
it.forEachDescendantOfType<JetValueArgument> {
|
||||||
it.clear(MAKE_ARGUMENT_NAMED_KEY)
|
it.clear(MAKE_ARGUMENT_NAMED_KEY)
|
||||||
|
it.clear(DEFAULT_PARAMETER_VALUE_KEY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +431,11 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
val name = argumentMatch.valueParameter.getName().asString()
|
val name = argumentMatch.valueParameter.getName().asString()
|
||||||
//TODO: not always correct for vararg's
|
//TODO: not always correct for vararg's
|
||||||
val newArgument = psiFactory.createArgument(argument.getArgumentExpression()!!, name, argument.getSpreadElement() != null)
|
val newArgument = psiFactory.createArgument(argument.getArgumentExpression()!!, name, argument.getSpreadElement() != null)
|
||||||
|
|
||||||
|
if (argument[DEFAULT_PARAMETER_VALUE_KEY]) {
|
||||||
|
newArgument.mark(DEFAULT_PARAMETER_VALUE_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
argument.replace(newArgument)
|
argument.replace(newArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,9 +447,8 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
val argumentsToDrop = ArrayList<ValueArgument>()
|
val argumentsToDrop = ArrayList<ValueArgument>()
|
||||||
|
|
||||||
// we drop only those arguments that added to the code from some parameter's default
|
// we drop only those arguments that added to the code from some parameter's default
|
||||||
fun canDropArgument(argument: ValueArgument) = argument.getArgumentExpression()!![DEFAULT_PARAMETER_VALUE_KEY]
|
fun canDropArgument(argument: ValueArgument) = (argument as JetValueArgument)[DEFAULT_PARAMETER_VALUE_KEY]
|
||||||
|
|
||||||
//TODO: other types of calls
|
|
||||||
result.forEachDescendantOfType<JetCallExpression> { callExpression ->
|
result.forEachDescendantOfType<JetCallExpression> { callExpression ->
|
||||||
val resolvedCall = callExpression.getResolvedCall(newBindingContext) ?: return@forEachDescendantOfType
|
val resolvedCall = callExpression.getResolvedCall(newBindingContext) ?: return@forEachDescendantOfType
|
||||||
|
|
||||||
@@ -467,25 +468,6 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unwrapDefaultValues(expression: JetExpression) {
|
|
||||||
val values = expression.collectDescendantsOfType<JetParenthesizedExpression> {
|
|
||||||
it[DEFAULT_PARAMETER_VALUE_KEY] && !it.getParent()[DEFAULT_PARAMETER_VALUE_KEY]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun JetParenthesizedExpression.unwrap(): JetExpression {
|
|
||||||
if (!this[DEFAULT_PARAMETER_VALUE_KEY]) return this
|
|
||||||
var inner = getExpression()!!
|
|
||||||
if (inner is JetParenthesizedExpression) {
|
|
||||||
inner = inner.unwrap()
|
|
||||||
}
|
|
||||||
val result = replace(inner) as JetExpression
|
|
||||||
result.mark(DEFAULT_PARAMETER_VALUE_KEY)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
values.forEach { it.unwrap() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun arrayOfFunctionName(elementType: JetType): String {
|
private fun arrayOfFunctionName(elementType: JetType): String {
|
||||||
return when {
|
return when {
|
||||||
KotlinBuiltIns.isInt(elementType) -> "kotlin.intArrayOf"
|
KotlinBuiltIns.isInt(elementType) -> "kotlin.intArrayOf"
|
||||||
@@ -589,11 +571,11 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
private val USER_CODE_KEY = Key<Unit>("USER_CODE")
|
private val USER_CODE_KEY = Key<Unit>("USER_CODE")
|
||||||
private val PARAMETER_VALUE_KEY = Key<ValueParameterDescriptor>("PARAMETER_VALUE")
|
private val PARAMETER_VALUE_KEY = Key<ValueParameterDescriptor>("PARAMETER_VALUE")
|
||||||
private val RECEIVER_VALUE_KEY = Key<Unit>("RECEIVER_VALUE")
|
private val RECEIVER_VALUE_KEY = Key<Unit>("RECEIVER_VALUE")
|
||||||
private val DEFAULT_PARAMETER_VALUE_KEY = Key<Unit>("DEFAULT_PARAMETER_VALUE")
|
|
||||||
private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key<Unit>("WAS_FUNCTION_LITERAL_ARGUMENT")
|
private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key<Unit>("WAS_FUNCTION_LITERAL_ARGUMENT")
|
||||||
|
|
||||||
// this key is used on JetValueArgument
|
// these keys are used on JetValueArgument
|
||||||
private val MAKE_ARGUMENT_NAMED_KEY = Key<Unit>("MAKE_ARGUMENT_NAMED")
|
private val MAKE_ARGUMENT_NAMED_KEY = Key<Unit>("MAKE_ARGUMENT_NAMED")
|
||||||
|
private val DEFAULT_PARAMETER_VALUE_KEY = Key<Unit>("DEFAULT_PARAMETER_VALUE")
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstructedExpressionWrapper(
|
class ConstructedExpressionWrapper(
|
||||||
|
|||||||
Reference in New Issue
Block a user