DeprecatedSymbolUsageFix: refactored code for easier handling of optional arguments

This commit is contained in:
Valentin Kipyatkov
2015-05-29 18:49:52 +03:00
parent 1fdb4429c3
commit 07cb0a0b08
@@ -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<JetExpression> { 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<JetValueArgument> {
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<ValueArgument>()
// 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 ->
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 {
return when {
KotlinBuiltIns.isInt(elementType) -> "kotlin.intArrayOf"
@@ -589,11 +571,11 @@ public abstract class DeprecatedSymbolUsageFixBase(
private val USER_CODE_KEY = Key<Unit>("USER_CODE")
private val PARAMETER_VALUE_KEY = Key<ValueParameterDescriptor>("PARAMETER_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")
// 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 DEFAULT_PARAMETER_VALUE_KEY = Key<Unit>("DEFAULT_PARAMETER_VALUE")
}
class ConstructedExpressionWrapper(