diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt index b1fed57a5c8..c5f0735af05 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionSignatureFix.kt @@ -56,22 +56,10 @@ abstract class ChangeFunctionSignatureFix( override fun startInWriteAction() = false override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { - if (!super.isAvailable(project, editor, file)) { - return false - } + if (!super.isAvailable(project, editor, file)) return false val declarations = DescriptorToSourceUtilsIde.getAllDeclarations(project, functionDescriptor) - if (declarations.isEmpty()) { - return false - } - - for (declaration in declarations) { - if (!declaration.isValid || !QuickFixUtil.canModifyElement(declaration)) { - return false - } - } - - return true + return declarations.all { it.isValid && QuickFixUtil.canModifyElement(it) } } protected fun getNewArgumentName(argument: ValueArgument, validator: Function1): String { @@ -80,10 +68,12 @@ abstract class ChangeFunctionSignatureFix( if (argumentName != null) { return KotlinNameSuggester.suggestNameByName(argumentName.asName.asString(), validator) - } else if (expression != null) { + } + else if (expression != null) { val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) - return KotlinNameSuggester.suggestNamesByExpressionAndType(expression, bindingContext, validator, "param").iterator().next() - } else { + return KotlinNameSuggester.suggestNamesByExpressionAndType(expression, bindingContext, validator, "param").first() + } + else { return KotlinNameSuggester.suggestNameByName("param", validator) } } @@ -91,119 +81,75 @@ abstract class ChangeFunctionSignatureFix( protected fun getNewParameterInfo( functionDescriptor: FunctionDescriptor, argument: ValueArgument, - validator: Function1): JetParameterInfo { + validator: Function1 + ): JetParameterInfo { val name = getNewArgumentName(argument, validator) val expression = argument.getArgumentExpression() val type = expression?.let { it.analyze().getType(it) } ?: functionDescriptor.builtIns.nullableAnyType - val parameterInfo = JetParameterInfo(functionDescriptor, -1, name, type, null, null, JetValVar.None, null) - parameterInfo.currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(type) - - return parameterInfo + return JetParameterInfo(functionDescriptor, -1, name, type, null, null, JetValVar.None, null) + .apply { currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(type) } } - companion object { - - fun createFactory(): JetSingleIntentionActionFactory { - return object : JetSingleIntentionActionFactory() { - public override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { - val callElement = PsiTreeUtil.getParentOfType(diagnostic.psiElement, JetCallElement::class.java) - //noinspection unchecked - val descriptor = DiagnosticFactory.cast(diagnostic, Errors.TOO_MANY_ARGUMENTS, Errors.NO_VALUE_FOR_PARAMETER).a - - if (callElement != null) { - return createFix(callElement, callElement, descriptor) - } - - return null - } - } + object Factory : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { + val callElement = PsiTreeUtil.getParentOfType(diagnostic.psiElement, JetCallElement::class.java) ?: return null + val descriptor = DiagnosticFactory.cast(diagnostic, Errors.TOO_MANY_ARGUMENTS, Errors.NO_VALUE_FOR_PARAMETER).a + return createFix(callElement, callElement, descriptor) } + } - fun createFactoryForParametersNumberMismatch(): JetSingleIntentionActionFactory { - return object : JetSingleIntentionActionFactory() { - public override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { - val diagnosticWithParameters = EXPECTED_PARAMETERS_NUMBER_MISMATCH.cast(diagnostic) - val functionLiteral = diagnosticWithParameters.psiElement - val descriptor = functionLiteral.resolveToDescriptor() - - if (descriptor is FunctionDescriptor && functionLiteral is JetFunctionLiteral) { - return ChangeFunctionLiteralSignatureFix(functionLiteral, descriptor, - diagnosticWithParameters.b) - } else { - return null - } - } - } + object FactoryForParametersNumberMismatch: JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { + val diagnosticWithParameters = EXPECTED_PARAMETERS_NUMBER_MISMATCH.cast(diagnostic) + val functionLiteral = diagnosticWithParameters.psiElement as? JetFunctionLiteral ?: return null + val descriptor = functionLiteral.resolveToDescriptor() as? FunctionDescriptor ?: return null + return ChangeFunctionLiteralSignatureFix(functionLiteral, descriptor, diagnosticWithParameters.b) } + } - fun createFactoryForUnusedParameter(): JetSingleIntentionActionFactory { - return object : JetSingleIntentionActionFactory() { - public override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { - @SuppressWarnings("unchecked") - val descriptor = UNUSED_PARAMETER.cast(diagnostic).a - - if (descriptor is ValueParameterDescriptor) { - return createFix(null, diagnostic.psiElement, descriptor as CallableDescriptor) - } else { - return null - } - } - } - } - - private fun createFix(callElement: JetCallElement?, context: PsiElement, descriptor: CallableDescriptor): ChangeFunctionSignatureFix? { - var functionDescriptor: FunctionDescriptor? = null - - if (descriptor is FunctionDescriptor) { - functionDescriptor = descriptor - } else if (descriptor is ValueParameterDescriptor) { - val containingDescriptor = descriptor.containingDeclaration - - if (containingDescriptor is FunctionDescriptor) { - functionDescriptor = containingDescriptor - } - } - - if (functionDescriptor == null) { - return null - } - - if (functionDescriptor.kind == SYNTHESIZED) { - return null - } - - if (descriptor is ValueParameterDescriptor) { - return RemoveFunctionParametersFix(context, functionDescriptor, descriptor) - } else { - val parameters = functionDescriptor.valueParameters - val arguments = callElement!!.valueArguments - - if (arguments.size() > parameters.size()) { - val bindingContext = callElement.analyze() - val hasTypeMismatches = hasTypeMismatches(parameters, arguments, bindingContext) - return AddFunctionParametersFix(callElement, functionDescriptor, hasTypeMismatches) - } - } - - return null - } - - private fun hasTypeMismatches( - parameters: List, - arguments: List, - bindingContext: BindingContext): Boolean { - for (i in parameters.indices) { - assert(i < arguments.size()) // number of parameters must not be greater than the number of arguments (it's called only for TOO_MANY_ARGUMENTS error) - val argumentExpression = arguments.get(i).getArgumentExpression() - val argumentType = if (argumentExpression != null) bindingContext.getType(argumentExpression) else null - val parameterType = parameters.get(i).type - - if (argumentType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) { - return true - } - } - - return false + object FactoryForUnusedParameter : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): ChangeFunctionSignatureFix? { + val descriptor = UNUSED_PARAMETER.cast(diagnostic).a as? ValueParameterDescriptor ?: return null + return createFix(null, diagnostic.psiElement, descriptor) } } } + +private fun createFix(callElement: JetCallElement?, context: PsiElement, descriptor: CallableDescriptor): ChangeFunctionSignatureFix? { + val functionDescriptor = when (descriptor) { + is FunctionDescriptor -> descriptor as FunctionDescriptor + else -> if (descriptor is ValueParameterDescriptor) descriptor.containingDeclaration as? FunctionDescriptor + else null + } ?: return null + + if (functionDescriptor.kind == SYNTHESIZED) return null + + if (descriptor is ValueParameterDescriptor) { + return RemoveFunctionParametersFix(context, functionDescriptor, descriptor) + } + else { + val parameters = functionDescriptor.valueParameters + val arguments = callElement!!.valueArguments + + if (arguments.size > parameters.size) { + val hasTypeMismatches = hasTypeMismatches(parameters, arguments, callElement.analyze()) + return AddFunctionParametersFix(callElement, functionDescriptor, hasTypeMismatches) + } + } + + return null +} + +private fun hasTypeMismatches( + parameters: List, + arguments: List, + bindingContext: BindingContext +): Boolean { + assert(parameters.size <= arguments.size) // number of parameters must not be greater than the number of arguments (it's called only for TOO_MANY_ARGUMENTS error) + for ((parameter, argument) in parameters.zip(arguments)) { + val argumentType = argument.getArgumentExpression()?.let { bindingContext.getType(it) } + if (argumentType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameter.type)) return true + } + return false +} + diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index a219de21336..c07f23577b6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -222,10 +222,10 @@ public class QuickFixRegistrar : QuickFixContributor { COMPARE_TO_TYPE_MISMATCH.registerFactory(ChangeFunctionReturnTypeFix.createFactoryForCompareToTypeMismatch()) IMPLICIT_NOTHING_RETURN_TYPE.registerFactory(ChangeFunctionReturnTypeFix.createFactoryForChangingReturnTypeToNothing()) - TOO_MANY_ARGUMENTS.registerFactory(ChangeFunctionSignatureFix.createFactory()) - NO_VALUE_FOR_PARAMETER.registerFactory(ChangeFunctionSignatureFix.createFactory()) - UNUSED_PARAMETER.registerFactory(ChangeFunctionSignatureFix.createFactoryForUnusedParameter()) - EXPECTED_PARAMETERS_NUMBER_MISMATCH.registerFactory(ChangeFunctionSignatureFix.createFactoryForParametersNumberMismatch()) + TOO_MANY_ARGUMENTS.registerFactory(ChangeFunctionSignatureFix.Factory) + NO_VALUE_FOR_PARAMETER.registerFactory(ChangeFunctionSignatureFix.Factory) + UNUSED_PARAMETER.registerFactory(ChangeFunctionSignatureFix.FactoryForUnusedParameter) + EXPECTED_PARAMETERS_NUMBER_MISMATCH.registerFactory(ChangeFunctionSignatureFix.FactoryForParametersNumberMismatch) EXPECTED_PARAMETER_TYPE_MISMATCH.registerFactory(ChangeTypeFix.createFactoryForExpectedParameterTypeMismatch())