From 07cb0a0b0892fe5bc860d3179b6009e501e0af95 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 29 May 2015 18:49:52 +0300 Subject: [PATCH] DeprecatedSymbolUsageFix: refactored code for easier handling of optional arguments --- .../quickfix/DeprecatedSymbolUsageFixBase.kt | 64 +++++++------------ 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt index 45b78884bf4..9790a62c6c9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt @@ -29,10 +29,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.CommentSaver -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.* import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester import org.jetbrains.kotlin.idea.core.refactoring.JetNameValidator import org.jetbrains.kotlin.idea.intentions.setType @@ -182,10 +179,14 @@ public abstract class DeprecatedSymbolUsageFixBase( it[ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY] == parameterName } usages.forEach { + val usageArgument = it.getParent() as? JetValueArgument 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 @@ -195,8 +196,6 @@ public abstract class DeprecatedSymbolUsageFixBase( } } - unwrapDefaultValues(replacement.expression) - val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext) if (qualifiedExpression is JetSafeQualifiedExpression) { @@ -293,9 +292,9 @@ public abstract class DeprecatedSymbolUsageFixBase( private class Argument( val expression: JetExpression, - val wrapped: JetExpression, val expressionType: JetType?, - val isNamed: Boolean = false) + val isNamed: Boolean = false, + val isDefaultValue: Boolean = false) private fun argumentForParameter( parameter: ValueParameterDescriptor, @@ -311,7 +310,7 @@ public abstract class DeprecatedSymbolUsageFixBase( if (valueArgument is FunctionLiteralArgument) { 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 -> { @@ -322,14 +321,12 @@ public abstract class DeprecatedSymbolUsageFixBase( 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 wrapped = JetPsiFactory(project).createExpressionByPattern("($0)", expression) as JetParenthesizedExpression - wrapped.mark(DEFAULT_PARAMETER_VALUE_KEY) + val expressionCopy = expression.copied() // clean up user data in original expression.forEachDescendantOfType { it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY) } - return Argument(wrapped.getExpression()!!, wrapped, null/*TODO*/) + return Argument(expressionCopy, null/*TODO*/, isDefaultValue = true) } is VarargValueArgument -> { @@ -337,7 +334,7 @@ public abstract class DeprecatedSymbolUsageFixBase( val single = arguments.singleOrNull() if (single != null && single.getSpreadElement() != null) { 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()!! @@ -353,7 +350,7 @@ public abstract class DeprecatedSymbolUsageFixBase( } 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") @@ -399,11 +396,11 @@ public abstract class DeprecatedSymbolUsageFixBase( it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY) it.clear(PARAMETER_VALUE_KEY) it.clear(RECEIVER_VALUE_KEY) - it.clear(DEFAULT_PARAMETER_VALUE_KEY) it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY) } it.forEachDescendantOfType { 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() //TODO: not always correct for vararg's 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) } } @@ -445,9 +447,8 @@ public abstract class DeprecatedSymbolUsageFixBase( val argumentsToDrop = ArrayList() // 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 { callExpression -> val resolvedCall = callExpression.getResolvedCall(newBindingContext) ?: return@forEachDescendantOfType @@ -467,25 +468,6 @@ public abstract class DeprecatedSymbolUsageFixBase( } } - private fun unwrapDefaultValues(expression: JetExpression) { - val values = expression.collectDescendantsOfType { - 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 { return when { KotlinBuiltIns.isInt(elementType) -> "kotlin.intArrayOf" @@ -589,11 +571,11 @@ public abstract class DeprecatedSymbolUsageFixBase( private val USER_CODE_KEY = Key("USER_CODE") private val PARAMETER_VALUE_KEY = Key("PARAMETER_VALUE") private val RECEIVER_VALUE_KEY = Key("RECEIVER_VALUE") - private val DEFAULT_PARAMETER_VALUE_KEY = Key("DEFAULT_PARAMETER_VALUE") private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key("WAS_FUNCTION_LITERAL_ARGUMENT") - // this key is used on JetValueArgument + // these keys are used on JetValueArgument private val MAKE_ARGUMENT_NAMED_KEY = Key("MAKE_ARGUMENT_NAMED") + private val DEFAULT_PARAMETER_VALUE_KEY = Key("DEFAULT_PARAMETER_VALUE") } class ConstructedExpressionWrapper(