diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfo.kt index b32d94d7a9d..e1327413f91 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfo.kt @@ -29,7 +29,6 @@ import com.intellij.util.VisibilityUtil import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.unwrapped -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Visibilities @@ -48,7 +47,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmOverloadsAnnotation -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.removeLast @@ -57,8 +56,7 @@ import java.util.* public open class KotlinChangeInfo( val methodDescriptor: KotlinMethodDescriptor, private var name: String = methodDescriptor.getName(), - val newReturnType: KotlinType? = methodDescriptor.baseDescriptor.getReturnType(), - var newReturnTypeText: String = methodDescriptor.renderOriginalReturnType(), + var newReturnTypeInfo: KotlinTypeInfo = KotlinTypeInfo(methodDescriptor.baseDescriptor.returnType), var newVisibility: Visibility = methodDescriptor.getVisibility(), parameterInfos: List = methodDescriptor.getParameters(), receiver: KotlinParameterInfo? = methodDescriptor.receiver, @@ -75,6 +73,8 @@ public open class KotlinChangeInfo( } } + private val originalReturnTypeInfo = methodDescriptor.returnTypeInfo + var receiverParameterInfo: KotlinParameterInfo? = receiver set(value: KotlinParameterInfo?) { if (value != null && value !in newParameters) { @@ -184,7 +184,8 @@ public open class KotlinChangeInfo( return methodDescriptor.getMethod() } - override fun isReturnTypeChanged(): Boolean = newReturnTypeText != methodDescriptor.renderOriginalReturnType() + + override fun isReturnTypeChanged(): Boolean = !newReturnTypeInfo.isEquivalentTo(originalReturnTypeInfo) fun isReceiverTypeChanged(): Boolean = receiverParameterInfo?.getTypeText() != methodDescriptor.renderOriginalReceiverType() @@ -226,6 +227,13 @@ public open class KotlinChangeInfo( this.primaryPropagationTargets = primaryPropagationTargets } + private fun renderReturnTypeIfNeeded(): String? { + val typeInfo = newReturnTypeInfo + if (kind != Kind.FUNCTION) return null + if (typeInfo.type?.isUnit() ?: false) return null + return typeInfo.render() + } + public fun getNewSignature(inheritedCallable: KotlinCallableDefinitionUsage): String { val buffer = StringBuilder() @@ -262,8 +270,7 @@ public open class KotlinChangeInfo( buffer.append(getNewParametersSignature(inheritedCallable)) - if (newReturnType != null && !KotlinBuiltIns.isUnit(newReturnType) && kind == Kind.FUNCTION) - buffer.append(": ").append(newReturnTypeText) + renderReturnTypeIfNeeded()?.let { buffer.append(": ").append(it) } return buffer.toString() } @@ -300,9 +307,10 @@ public open class KotlinChangeInfo( } public fun renderReturnType(inheritedCallable: KotlinCallableDefinitionUsage<*>): String { - val typeSubstitutor = inheritedCallable.typeSubstitutor ?: return newReturnTypeText - val currentBaseFunction = inheritedCallable.baseFunction.currentCallableDescriptor ?: return newReturnTypeText - return currentBaseFunction.getReturnType()!!.renderTypeWithSubstitution(typeSubstitutor, newReturnTypeText, false) + val defaultRendering = newReturnTypeInfo.render() + val typeSubstitutor = inheritedCallable.typeSubstitutor ?: return defaultRendering + val currentBaseFunction = inheritedCallable.baseFunction.currentCallableDescriptor ?: return defaultRendering + return currentBaseFunction.returnType!!.renderTypeWithSubstitution(typeSubstitutor, defaultRendering, false) } public fun primaryMethodUpdated() { @@ -545,13 +553,9 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: KotlinM } } - val returnType = functionDescriptor.getReturnType() - val returnTypeText = if (returnType != null) IdeDescriptorRenderers.SOURCE_CODE.renderType(returnType) else "" - return KotlinChangeInfo(originalChangeSignatureDescriptor, getNewName(), - returnType, - returnTypeText, + KotlinTypeInfo(functionDescriptor.returnType), functionDescriptor.getVisibility(), newParameters, null, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt index 491bc2dacbe..37e74662f51 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt @@ -91,8 +91,7 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { methodDescriptor: KotlinMethodDescriptor ) : KotlinChangeInfo(methodDescriptor = methodDescriptor, name = "", - newReturnType = null, - newReturnTypeText = "", + newReturnTypeInfo = KotlinTypeInfo(), newVisibility = Visibilities.DEFAULT_VISIBILITY, parameterInfos = emptyList(), receiver = null, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMethodDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMethodDescriptor.kt index 1c2925acdef..fe2f92cb437 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMethodDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMethodDescriptor.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.psi.KtCallableDeclaration public interface KotlinMethodDescriptor : MethodDescriptor { enum class Kind(val isConstructor: Boolean) { @@ -53,8 +54,14 @@ public interface KotlinMethodDescriptor : MethodDescriptor text + type != null -> IdeDescriptorRenderers.SOURCE_CODE.renderType(type) + else -> "" + } +} + +fun KotlinTypeInfo.isEquivalentTo(other: KotlinTypeInfo): Boolean { + return if (type != null && other.type != null) TypeUtils.equalTypes(type, other.type) else render() == other.render() +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangePropertySignatureDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangePropertySignatureDialog.kt index a847649e881..76087d9cd5a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangePropertySignatureDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangePropertySignatureDialog.kt @@ -16,15 +16,11 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature -import com.intellij.openapi.options.ConfigurationException import com.intellij.openapi.project.Project import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement import com.intellij.refactoring.BaseRefactoringProcessor -import com.intellij.refactoring.ui.ComboBoxVisibilityPanel import com.intellij.refactoring.ui.RefactoringDialog import com.intellij.ui.EditorTextField -import com.intellij.ui.NonFocusableCheckBox import com.intellij.util.ui.FormBuilder import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility @@ -33,8 +29,6 @@ import org.jetbrains.kotlin.idea.core.refactoring.validateElement import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtPsiFactory -import org.jetbrains.kotlin.psi.KtTypeCodeFragment -import org.jetbrains.kotlin.resolve.AnalyzingUtils import javax.swing.JCheckBox import javax.swing.JComboBox import javax.swing.JComponent @@ -85,7 +79,7 @@ public class KotlinChangePropertySignatureDialog( addLabeledComponent("&Name: ", nameField) - val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReturnType(), + val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.returnTypeInfo.render(), baseDeclaration) returnTypeField = EditorTextField(documentManager.getDocument(returnTypeCodeFragment), myProject, KotlinFileType.INSTANCE) addLabeledComponent("&Type: ", returnTypeField) @@ -151,8 +145,7 @@ public class KotlinChangePropertySignatureDialog( receiver?.currentTypeText = receiverTypeField.getText() val changeInfo = KotlinChangeInfo(originalDescriptor, nameField.getText(), - null, - returnTypeField.getText(), + KotlinTypeInfo(null, returnTypeField.text), visibilityCombo.getSelectedItem() as Visibility, emptyList(), receiver, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangeSignatureDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangeSignatureDialog.kt index 3564edd5832..659002217ae 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangeSignatureDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/ui/KotlinChangeSignatureDialog.kt @@ -49,13 +49,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.changeSignature.* import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.psi.KtExpressionCodeFragment import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtTypeCodeFragment import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.types.KotlinType import java.awt.BorderLayout import java.awt.Font import java.awt.Toolkit @@ -317,7 +315,8 @@ public class KotlinChangeSignatureDialog( getMethodDescriptor(), getVisibility(), getMethodName(), - myDefaultValueContext) + myDefaultValueContext, + true) return changeInfo.getNewSignature(getMethodDescriptor().originalPrimaryCallable) } @@ -365,7 +364,8 @@ public class KotlinChangeSignatureDialog( getMethodDescriptor(), getVisibility(), getMethodName(), - myDefaultValueContext) + myDefaultValueContext, + false) changeInfo.primaryPropagationTargets = myMethodsToPropagateParameters ?: emptyList(); return KotlinChangeSignatureProcessor(myProject, changeInfo, commandName ?: getTitle()) } @@ -387,7 +387,7 @@ public class KotlinChangeSignatureDialog( } private fun createReturnTypeCodeFragment(project: Project, method: KotlinMethodDescriptor) = - KtPsiFactory(project).createTypeCodeFragment(method.renderOriginalReturnType(), method.baseDeclaration) + KtPsiFactory(project).createTypeCodeFragment(method.returnTypeInfo.render(), method.baseDeclaration) public fun createRefactoringProcessorForSilentChangeSignature(project: Project, commandName: String, @@ -400,21 +400,21 @@ public class KotlinChangeSignatureDialog( method, method.getVisibility(), method.getName(), - defaultValueContext) + defaultValueContext, + false) return KotlinChangeSignatureProcessor(project, changeInfo, commandName) } - private fun PsiCodeFragment?.getTypeWithText(): Pair { - if (this !is KtTypeCodeFragment) return null to "" + private fun PsiCodeFragment?.getTypeInfo(forPreview: Boolean): KotlinTypeInfo { + if (this !is KtTypeCodeFragment) return KotlinTypeInfo() val typeRef = getContentElement() val type = typeRef?.analyze(BodyResolveMode.PARTIAL)?.get(BindingContext.TYPE, typeRef) - val typeText = when { - type != null && !type.isError -> IdeDescriptorRenderers.SOURCE_CODE.renderType(type) - typeRef != null -> typeRef.text - else -> "" + return when { + type != null && !type.isError -> KotlinTypeInfo(type, if (forPreview) typeRef?.text else null) + typeRef != null -> KotlinTypeInfo(null, typeRef.text) + else -> KotlinTypeInfo() } - return type to typeText } private fun evaluateChangeInfo(parametersModel: KotlinCallableParameterTableModel, @@ -422,11 +422,12 @@ public class KotlinChangeSignatureDialog( methodDescriptor: KotlinMethodDescriptor, visibility: Visibility?, methodName: String, - defaultValueContext: PsiElement): KotlinChangeInfo { + defaultValueContext: PsiElement, + forPreview: Boolean): KotlinChangeInfo { val parameters = parametersModel.getItems().map { parameter -> val parameterInfo = parameter.parameter - parameterInfo.currentTypeText = parameter.typeCodeFragment.getTypeWithText().second + parameterInfo.currentTypeText = parameter.typeCodeFragment.getTypeInfo(forPreview).render() val codeFragment = parameter.defaultValueCodeFragment as KtExpressionCodeFragment val oldDefaultValue = parameterInfo.defaultValueForCall @@ -437,11 +438,9 @@ public class KotlinChangeSignatureDialog( parameterInfo } - val (returnType, returnTypeText) = returnTypeCodeFragment.getTypeWithText() return KotlinChangeInfo(methodDescriptor.original, methodName, - returnType, - returnTypeText, + returnTypeCodeFragment.getTypeInfo(forPreview), visibility ?: Visibilities.DEFAULT_VISIBILITY, parameters, parametersModel.getReceiver(), diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinCallableDefinitionUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinCallableDefinitionUsage.kt index 7b49cdcf673..faf384c9788 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinCallableDefinitionUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinCallableDefinitionUsage.kt @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor +import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.sure class KotlinCallableDefinitionUsage( @@ -162,11 +163,9 @@ class KotlinCallableDefinitionUsage( if (changeInfo.isReturnTypeChanged && returnTypeIsNeeded) { element.setTypeReference(null) val returnTypeText = changeInfo.renderReturnType(this) - - //TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready - if (!(returnTypeText == "Unit" || returnTypeText == "kotlin.Unit")) { - element.setTypeReference(KtPsiFactory(element).createType(returnTypeText))!!.addToShorteningWaitSet( - Options.DEFAULT) + val returnType = changeInfo.newReturnTypeInfo.type + if (returnType == null || !returnType.isUnit()) { + element.setTypeReference(KtPsiFactory(element).createType(returnTypeText))!!.addToShorteningWaitSet(Options.DEFAULT) } } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureTest.kt index 4854bde35c1..ea4d0cb3441 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureTest.kt @@ -56,6 +56,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.utils.sure import java.io.File import java.util.* @@ -267,11 +268,11 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { fun testRenameFunction() = doTest { newName = "after" } - fun testChangeReturnType() = doTest { newReturnTypeText = "Float" } + fun testChangeReturnType() = doTest { newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.floatType) } - fun testAddReturnType() = doTest { newReturnTypeText = "Float" } + fun testAddReturnType() = doTest { newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.floatType) } - fun testRemoveReturnType() = doTest { newReturnTypeText = "Unit" } + fun testRemoveReturnType() = doTest { newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.unitType) } fun testChangeConstructorVisibility() = doTest { newVisibility = Visibilities.PROTECTED } @@ -367,7 +368,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { newParameters[1].name = "y1" addParameter(KotlinParameterInfo(originalBaseFunctionDescriptor, -1, "x", BUILT_INS.anyType)) - newReturnTypeText = "Int" + newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.intType) } fun testVarargs() = doTestConflict() @@ -427,7 +428,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { newParameters[1].currentTypeText = "String?" newParameters[2].currentTypeText = "Any" - newReturnTypeText = "String?" + newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.stringType.makeNullable()) } fun testFunctionJavaUsagesAndOverridesChangeTypes() = doTest { @@ -435,7 +436,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { newParameters[1].currentTypeText = "Int" newParameters[2].currentTypeText = "Long?" - newReturnTypeText = "Any?" + newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.nullableAnyType) } fun testGenericsWithOverrides() = doTest { @@ -443,7 +444,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { newParameters[1].currentTypeText = "A?" newParameters[2].currentTypeText = "U" - newReturnTypeText = "U?" + newReturnTypeInfo = KotlinTypeInfo(null, "U?") } fun testAddReceiverToGenericsWithOverrides() = doTest { @@ -668,7 +669,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { fun testChangeProperty() = doTest { newName = "s" - newReturnTypeText = "String" + newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.stringType) } fun testAddPropertyReceiverConflict() = doTestConflict { @@ -697,7 +698,7 @@ class KotlinChangeSignatureTest : KotlinCodeInsightTestCase() { fun testChangeClassParameter() = doTest { newName = "s" - newReturnTypeText = "String" + newReturnTypeInfo = KotlinTypeInfo(BUILT_INS.stringType) } fun testParameterPropagation() = doTest {