diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionReturnTypeFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionReturnTypeFix.kt index 21728675c58..489a4928620 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionReturnTypeFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionReturnTypeFix.kt @@ -21,7 +21,6 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil -import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -40,9 +39,11 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.typeUtil.isUnit import java.util.* class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinType) : KotlinQuickFixAction(element) { @@ -63,9 +64,7 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT return changeFunctionLiteralReturnTypeFix.text } - var functionName = element.name - val fqName = element.fqName - if (fqName != null) functionName = fqName.asString() + val functionName = element.fqName?.asString() ?: element.name if (KotlinBuiltIns.isUnit(type) && element.hasBlockBody()) { return if (functionName == null) @@ -73,6 +72,7 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT else KotlinBundle.message("remove.function.return.type", functionName) } + val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type) return if (functionName == null) KotlinBundle.message("change.no.name.function.return.type", renderedType) @@ -80,9 +80,7 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT KotlinBundle.message("change.function.return.type", functionName, renderedType) } - override fun getFamilyName(): String { - return KotlinBundle.message("change.type.family") - } + override fun getFamilyName() = KotlinBundle.message("change.type.family") override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { return super.isAvailable(project, editor, file) && @@ -90,17 +88,15 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT element !is KtConstructor<*> } - @Throws(IncorrectOperationException::class) - public override operator fun invoke(project: Project, editor: Editor?, file: KtFile) { + override operator fun invoke(project: Project, editor: Editor?, file: KtFile) { if (changeFunctionLiteralReturnTypeFix != null) { changeFunctionLiteralReturnTypeFix.invoke(project, editor!!, file) } else { - if (!(KotlinBuiltIns.isUnit(type) && element.hasBlockBody())) { - var newTypeRef: KtTypeReference? = KtPsiFactory(project).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)) - newTypeRef = element.setTypeReference(newTypeRef) - assert(newTypeRef != null) - ShortenReferences.DEFAULT.process(newTypeRef!!) + if (!(type.isUnit() && element.hasBlockBody())) { + var newTypeRef = KtPsiFactory(project).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)) + newTypeRef = element.setTypeReference(newTypeRef)!! + ShortenReferences.DEFAULT.process(newTypeRef) } else { element.typeReference = null @@ -121,15 +117,11 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT return object : KotlinSingleIntentionActionFactory() { public override fun createAction(diagnostic: Diagnostic): IntentionAction? { val entry = getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic) - val context = entry.analyze() + val context = entry.analyze(BodyResolveMode.PARTIAL) val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null - val componentFunction = DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as KtFunction? - val expectedType = context.get(BindingContext.TYPE, entry.typeReference!!) - if (componentFunction != null && expectedType != null) { - return ChangeFunctionReturnTypeFix(componentFunction, expectedType) - } - else - return null + val componentFunction = DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as KtFunction? ?: return null + val expectedType = context[BindingContext.TYPE, entry.typeReference!!] ?: return null + return ChangeFunctionReturnTypeFix(componentFunction, expectedType) } } } @@ -137,16 +129,13 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT fun createFactoryForHasNextFunctionTypeMismatch(): KotlinSingleIntentionActionFactory { return object : KotlinSingleIntentionActionFactory() { public override fun createAction(diagnostic: Diagnostic): IntentionAction? { - val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtExpression::class.java) ?: error("HAS_NEXT_FUNCTION_TYPE_MISMATCH reported on element that is not within any expression") - val context = expression.analyze() - val resolvedCall = context.get(BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression) ?: return null + val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtExpression::class.java) + ?: error("HAS_NEXT_FUNCTION_TYPE_MISMATCH reported on element that is not within any expression") + val context = expression.analyze(BodyResolveMode.PARTIAL) + val resolvedCall = context[BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression] ?: return null val hasNextDescriptor = resolvedCall.candidateDescriptor - val hasNextFunction = DescriptorToSourceUtils.descriptorToDeclaration(hasNextDescriptor) as KtFunction? - if (hasNextFunction != null) { - return ChangeFunctionReturnTypeFix(hasNextFunction, hasNextDescriptor.builtIns.booleanType) - } - else - return null + val hasNextFunction = DescriptorToSourceUtils.descriptorToDeclaration(hasNextDescriptor) as KtFunction? ?: return null + return ChangeFunctionReturnTypeFix(hasNextFunction, hasNextDescriptor.builtIns.booleanType) } } } @@ -155,11 +144,10 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT return object : KotlinSingleIntentionActionFactory() { public override fun createAction(diagnostic: Diagnostic): IntentionAction? { val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtBinaryExpression::class.java) ?: error("COMPARE_TO_TYPE_MISMATCH reported on element that is not within any expression") - val context = expression.analyze() + val context = expression.analyze(BodyResolveMode.PARTIAL) val resolvedCall = expression.getResolvedCall(context) ?: return null val compareToDescriptor = resolvedCall.candidateDescriptor - val compareTo = DescriptorToSourceUtils.descriptorToDeclaration(compareToDescriptor) - if (compareTo !is KtFunction) return null + val compareTo = DescriptorToSourceUtils.descriptorToDeclaration(compareToDescriptor) as? KtFunction ?: return null return ChangeFunctionReturnTypeFix(compareTo, compareToDescriptor.builtIns.intType) } } @@ -168,34 +156,34 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT fun createFactoryForReturnTypeMismatchOnOverride(): KotlinIntentionActionsFactory { return object : KotlinIntentionActionsFactory() { override fun doCreateActions(diagnostic: Diagnostic): List { + val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return emptyList() + val actions = LinkedList() - val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) - if (function != null) { - val descriptor = function.resolveToDescriptor() as FunctionDescriptor + val descriptor = function.resolveToDescriptor() as FunctionDescriptor - val matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor) - if (matchingReturnType != null) { - actions.add(ChangeFunctionReturnTypeFix(function, matchingReturnType)) - } + val matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor) + if (matchingReturnType != null) { + actions.add(ChangeFunctionReturnTypeFix(function, matchingReturnType)) + } - val functionType = descriptor.returnType ?: return actions + val functionType = descriptor.returnType ?: return actions - val overriddenMismatchingFunctions = LinkedList() - for (overriddenFunction in descriptor.overriddenDescriptors) { - val overriddenFunctionType = overriddenFunction.returnType ?: continue - if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(functionType, overriddenFunctionType)) { - overriddenMismatchingFunctions.add(overriddenFunction) - } - } - - if (overriddenMismatchingFunctions.size == 1) { - val overriddenFunction = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingFunctions[0]) - if (overriddenFunction is KtFunction) { - actions.add(ChangeFunctionReturnTypeFix(overriddenFunction, functionType)) - } + val overriddenMismatchingFunctions = LinkedList() + for (overriddenFunction in descriptor.overriddenDescriptors) { + val overriddenFunctionType = overriddenFunction.returnType ?: continue + if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(functionType, overriddenFunctionType)) { + overriddenMismatchingFunctions.add(overriddenFunction) } } + + if (overriddenMismatchingFunctions.size == 1) { + val overriddenFunction = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingFunctions[0]) + if (overriddenFunction is KtFunction) { + actions.add(ChangeFunctionReturnTypeFix(overriddenFunction, functionType)) + } + } + return actions } } @@ -213,8 +201,8 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, private val type: KotlinT fun createFactoryForChangingReturnTypeToNothing(): KotlinSingleIntentionActionFactory { return object : KotlinSingleIntentionActionFactory() { public override fun createAction(diagnostic: Diagnostic): IntentionAction? { - val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) - return if (function == null) null else ChangeFunctionReturnTypeFix(function, function.platform.builtIns.nothingType) + val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null + return ChangeFunctionReturnTypeFix(function, function.platform.builtIns.nothingType) } } }