From 96866a108ff86bc1aec9db65a1ca71708ff47fad Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 19 Dec 2014 20:40:17 +0300 Subject: [PATCH] Change Signature: Support conversion between extension and non-extension functions --- .../jetbrains/kotlin/psi/TypeRefHelpers.kt | 22 ++ .../changeSignature/JetChangeInfo.kt | 84 ++++++- .../changeSignature/JetChangeSignatureData.kt | 55 +++-- .../JetChangeSignatureDialog.java | 2 +- .../JetChangeSignatureUsageProcessor.java | 206 +++++++++++++++++- .../changeSignature/JetMethodDescriptor.kt | 7 +- .../usages/JetFunctionCallUsage.java | 108 +++++++-- .../usages/JetFunctionDefinitionUsage.java | 30 ++- .../usages/JetImplicitThisToParameterUsage.kt | 65 ++++++ .../usages/JetParameterUsage.kt | 48 +++- .../changeSignature/usages/JetUsageInfo.java | 8 + .../AddNewReceiverAfter.1.java | 5 + .../changeSignature/AddNewReceiverAfter.kt | 9 + .../AddNewReceiverBefore.1.java | 5 + .../changeSignature/AddNewReceiverBefore.kt | 9 + .../AddNewReceiverConflictBefore.kt | 13 ++ .../AddNewReceiverConflictMessages.txt | 1 + .../AddNewReceiverForMemberAfter.1.java | 5 + .../AddNewReceiverForMemberAfter.kt | 19 ++ .../AddNewReceiverForMemberBefore.1.java | 5 + .../AddNewReceiverForMemberBefore.kt | 19 ++ .../AddNewReceiverForMemberConflictBefore.kt | 20 ++ ...ddNewReceiverForMemberConflictMessages.txt | 1 + ...eceiverToGenericsWithOverridesAfter.1.java | 18 ++ ...AddReceiverToGenericsWithOverridesAfter.kt | 17 ++ ...ceiverToGenericsWithOverridesBefore.1.java | 18 ++ ...ddReceiverToGenericsWithOverridesBefore.kt | 17 ++ .../ChangeReceiverAfter.1.java | 5 + .../changeSignature/ChangeReceiverAfter.kt | 9 + .../ChangeReceiverBefore.1.java | 5 + .../changeSignature/ChangeReceiverBefore.kt | 9 + .../ChangeReceiverForMemberAfter.1.java | 5 + .../ChangeReceiverForMemberAfter.kt | 19 ++ .../ChangeReceiverForMemberBefore.1.java | 5 + .../ChangeReceiverForMemberBefore.kt | 19 ++ .../ConvertParameterToReceiver1After.1.java | 5 + .../ConvertParameterToReceiver1After.kt | 9 + .../ConvertParameterToReceiver1Before.1.java | 5 + .../ConvertParameterToReceiver1Before.kt | 9 + .../ConvertParameterToReceiver2After.1.java | 5 + .../ConvertParameterToReceiver2After.kt | 9 + .../ConvertParameterToReceiver2Before.1.java | 5 + .../ConvertParameterToReceiver2Before.kt | 9 + ...tParameterToReceiverForMember1After.1.java | 5 + ...nvertParameterToReceiverForMember1After.kt | 19 ++ ...ParameterToReceiverForMember1Before.1.java | 5 + ...vertParameterToReceiverForMember1Before.kt | 19 ++ ...tParameterToReceiverForMember2After.1.java | 5 + ...nvertParameterToReceiverForMember2After.kt | 19 ++ ...ParameterToReceiverForMember2Before.1.java | 5 + ...vertParameterToReceiverForMember2Before.kt | 19 ++ ...ameterToReceiverForMemberConflictBefore.kt | 20 ++ ...terToReceiverForMemberConflictMessages.txt | 1 + .../ConvertReceiverToParameter1After.1.java | 5 + .../ConvertReceiverToParameter1After.kt | 14 ++ .../ConvertReceiverToParameter1Before.1.java | 5 + .../ConvertReceiverToParameter1Before.kt | 14 ++ .../ConvertReceiverToParameter2After.1.java | 5 + .../ConvertReceiverToParameter2After.kt | 14 ++ .../ConvertReceiverToParameter2Before.1.java | 5 + .../ConvertReceiverToParameter2Before.kt | 14 ++ ...rtReceiverToParameterAndChangeNameAfter.kt | 5 + ...tReceiverToParameterAndChangeNameBefore.kt | 5 + ...tReceiverToParameterForMember1After.1.java | 5 + ...nvertReceiverToParameterForMember1After.kt | 19 ++ ...ReceiverToParameterForMember1Before.1.java | 5 + ...vertReceiverToParameterForMember1Before.kt | 19 ++ ...tReceiverToParameterForMember2After.1.java | 5 + ...nvertReceiverToParameterForMember2After.kt | 19 ++ ...ReceiverToParameterForMember2Before.1.java | 5 + ...vertReceiverToParameterForMember2Before.kt | 19 ++ ...rtReceiverToParameterWithNameClashAfter.kt | 7 + ...tReceiverToParameterWithNameClashBefore.kt | 7 + .../RemoveReceiverAfter.1.java | 5 + .../changeSignature/RemoveReceiverAfter.kt | 14 ++ .../RemoveReceiverBefore.1.java | 5 + .../changeSignature/RemoveReceiverBefore.kt | 14 ++ .../RemoveReceiverForMemberAfter.1.java | 5 + .../RemoveReceiverForMemberAfter.kt | 19 ++ .../RemoveReceiverForMemberBefore.1.java | 5 + .../RemoveReceiverForMemberBefore.kt | 19 ++ .../JetChangeSignatureTest.java | 142 +++++++++++- 82 files changed, 1425 insertions(+), 64 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverConflictBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverConflictMessages.txt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictMessages.txt create mode 100644 idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictMessages.txt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.1.java create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/TypeRefHelpers.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/TypeRefHelpers.kt index 8a440814ff2..c73bec46ead 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/TypeRefHelpers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/TypeRefHelpers.kt @@ -54,3 +54,25 @@ fun setTypeReference(declaration: JetCallableDeclaration, addAfter: PsiElement?, return null } } + +fun JetCallableDeclaration.setReceiverTypeReference(typeRef: JetTypeReference?): JetTypeReference? { + val oldTypeRef = getReceiverTypeReference() + if (typeRef != null) { + if (oldTypeRef != null) { + return oldTypeRef.replace(typeRef) as JetTypeReference + } + else { + val anchor = getNameIdentifier() + val newTypeRef = addBefore(typeRef, anchor) as JetTypeReference + addAfter(JetPsiFactory(getProject()).createDot(), newTypeRef) + return newTypeRef + } + } + else { + if (oldTypeRef != null) { + val dot = oldTypeRef.siblings(forward = true).firstOrNull { it.getNode().getElementType() == JetTokens.DOT } + deleteChildRange(oldTypeRef, dot ?: oldTypeRef) + } + return null + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt index 026c486e951..76c78b818c5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt @@ -17,21 +17,28 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature import com.intellij.lang.Language +import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.PsiModifier import com.intellij.psi.PsiType import com.intellij.refactoring.changeSignature.* import com.intellij.usageView.UsageInfo +import com.intellij.util.Function import com.intellij.util.VisibilityUtil +import com.intellij.util.containers.ContainerUtil +import kotlin.Function1 +import kotlin.Pair import org.jetbrains.kotlin.asJava.* import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.psi.JetFunction import org.jetbrains.kotlin.psi.JetFunctionLiteral import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.idea.JetLanguage @@ -40,6 +47,9 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionD import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import java.util.HashMap import kotlin.properties.Delegates +import java.util.ArrayList +import java.util.Collections +import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList public class JetChangeInfo( val methodDescriptor: JetMethodDescriptor, @@ -48,8 +58,17 @@ public class JetChangeInfo( var newReturnTypeText: String, var newVisibility: Visibility, parameterInfos: List, + receiver: JetParameterInfo?, val context: PsiElement ): ChangeInfo { + var receiverParameterInfo: JetParameterInfo? = receiver + set(value: JetParameterInfo?) { + if (value != null && value !in newParameters) { + newParameters.add(value) + } + $receiverParameterInfo = value + } + private val newParameters = parameterInfos.toArrayList() private val originalPsiMethod: PsiMethod? = getCurrentPsiMethod() @@ -63,8 +82,10 @@ public class JetChangeInfo( } public val isParameterSetOrOrderChanged: Boolean by Delegates.lazy { - newParameters.size() != methodDescriptor.getParametersCount() || - newParameters.indices.any { i -> newParameters.get(i).getOldIndex() != i } + val signatureParameters = getNonReceiverParameters() + methodDescriptor.receiver != receiverParameterInfo || + signatureParameters.size() != methodDescriptor.getParametersCount() || + signatureParameters.indices.any { i -> signatureParameters[i].getOldIndex() != i } } private var isPrimaryMethodUpdated: Boolean = false @@ -88,6 +109,12 @@ public class JetChangeInfo( override fun getNewParameters(): Array = newParameters.copyToArray() + fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0) + + fun getNonReceiverParameters(): List { + return receiverParameterInfo?.let { receiver -> newParameters.filter { it != receiver } } ?: newParameters + } + public fun setNewParameter(index: Int, parameterInfo: JetParameterInfo) { newParameters.set(index, parameterInfo) } @@ -97,9 +124,15 @@ public class JetChangeInfo( } public fun removeParameter(index: Int) { - newParameters.remove(index); + val parameterInfo = newParameters.remove(index); + if (parameterInfo == receiverParameterInfo) { + receiverParameterInfo = null + } } + public fun hasParameter(parameterInfo: JetParameterInfo): Boolean = + parameterInfo in newParameters + override fun isGenerateDelegate(): Boolean = false override fun getNewName(): String = name @@ -118,6 +151,8 @@ public class JetChangeInfo( override fun isReturnTypeChanged(): Boolean = newReturnTypeText != methodDescriptor.renderOriginalReturnType() + fun isReceiverTypeChanged(): Boolean = receiverParameterInfo?.getTypeText() != methodDescriptor.renderOriginalReceiverType() + override fun getLanguage(): Language = JetLanguage.INSTANCE public fun getNewSignature(inheritedFunction: JetFunctionDefinitionUsage): String { @@ -135,9 +170,15 @@ public class JetChangeInfo( buffer.append(newVisibility).append(' ') } - buffer.append(JetTokens.FUN_KEYWORD).append(' ').append(name) + buffer.append(JetTokens.FUN_KEYWORD).append(' ') } + receiverParameterInfo?.let { + buffer.append(it.currentTypeText).append('.') + } + + buffer.append(name) + buffer.append(getNewParametersSignature(inheritedFunction)) if (newReturnType != null && !KotlinBuiltIns.isUnit(newReturnType) && !isConstructor) @@ -152,16 +193,25 @@ public class JetChangeInfo( } public fun getNewParametersSignature(inheritedFunction: JetFunctionDefinitionUsage): String { + val signatureParameters = getNonReceiverParameters() + val isLambda = inheritedFunction.getDeclaration() is JetFunctionLiteral - if (isLambda && newParameters.size() == 1 && !newParameters.get(0).requiresExplicitType(inheritedFunction)) { - return newParameters.get(0).getDeclarationSignature(0, inheritedFunction) + if (isLambda && signatureParameters.size() == 1 && !signatureParameters.get(0).requiresExplicitType(inheritedFunction)) { + return signatureParameters.get(0).getDeclarationSignature(0, inheritedFunction) } - return newParameters.indices - .map { i -> newParameters[i].getDeclarationSignature(i, inheritedFunction) } + return signatureParameters.indices + .map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedFunction) } .joinToString(prefix = "(", separator = ", ", postfix = ")") } + public fun renderReceiverType(inheritedFunction: JetFunctionDefinitionUsage): String? { + val receiverTypeText = receiverParameterInfo?.currentTypeText ?: return null + val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return receiverTypeText + val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return receiverTypeText + return currentBaseFunction.getExtensionReceiverParameter()!!.getType().renderTypeWithSubstitution(typeSubstitutor, receiverTypeText, false) + } + public fun renderReturnType(inheritedFunction: JetFunctionDefinitionUsage): String { val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return newReturnTypeText val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return newReturnTypeText @@ -190,13 +240,24 @@ public class JetChangeInfo( else PsiModifier.PACKAGE_LOCAL - val newJavaParameters = newParameters.withIndex().map { pair -> + val newParameterList = receiverParameterInfo.singletonOrEmptyList() + getNonReceiverParameters() + val newJavaParameters = newParameterList.withIndex().map { pair -> val (i, info) = pair + val type = if (isPrimaryMethodUpdated) currentPsiMethod.getParameterList().getParameters()[i].getType() else PsiType.VOID - ParameterInfoImpl(info.getOldIndex(), info.getName(), type, info.defaultValueForCall) + + val oldIndex = info.getOldIndex() + val javaOldIndex = when { + methodDescriptor.receiver == null -> oldIndex + info == methodDescriptor.receiver -> 0 + oldIndex >= 0 -> oldIndex + 1 + else -> -1 + } + + ParameterInfoImpl(javaOldIndex, info.getName(), type, info.defaultValueForCall) }.copyToArray() val returnType = if (isPrimaryMethodUpdated) currentPsiMethod.getReturnType() else PsiType.VOID @@ -257,5 +318,6 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth returnTypeText, functionDescriptor.getVisibility(), newParameters, + null, method) -} +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt index 52522129f31..a286288d8de 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,10 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionD import java.util.* import kotlin.properties.Delegates +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.idea.refactoring.CollectingValidator +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.idea.refactoring.JetNameSuggester public class JetChangeSignatureData( override val baseDescriptor: FunctionDescriptor, @@ -39,24 +43,49 @@ public class JetChangeSignatureData( private val descriptorsForSignatureChange: Collection ) : JetMethodDescriptor { private val parameters: MutableList + override var receiver: JetParameterInfo? + set(value: JetParameterInfo?) { + if (value != null && value !in parameters) { + parameters.add(value) + } + $receiver = value + } + + ;{ + $receiver = createReceiverInfoIfNeeded() - ;{ val valueParameters = when { baseDeclaration is JetFunction -> baseDeclaration.getValueParameters() baseDeclaration is JetClass -> baseDeclaration.getPrimaryConstructorParameters() else -> null } - parameters = baseDescriptor.getValueParameters().mapTo(ArrayList()) { parameterDescriptor -> - val jetParameter = valueParameters?.get(parameterDescriptor.getIndex()) - JetParameterInfo( - originalIndex = parameterDescriptor.getIndex(), - name = parameterDescriptor.getName().asString(), - type = parameterDescriptor.getType(), - defaultValueForParameter = jetParameter?.getDefaultValue(), - valOrVarNode = jetParameter?.getValOrVarNode(), - modifierList = jetParameter?.getModifierList() - ) - } + parameters = baseDescriptor.getValueParameters() + .mapTo(receiver?.let{ arrayListOf(it) } ?: arrayListOf()) { parameterDescriptor -> + val jetParameter = valueParameters?.get(parameterDescriptor.getIndex()) + JetParameterInfo( + originalIndex = parameterDescriptor.getIndex(), + name = parameterDescriptor.getName().asString(), + type = parameterDescriptor.getType(), + defaultValueForParameter = jetParameter?.getDefaultValue(), + valOrVarNode = jetParameter?.getValOrVarNode(), + modifierList = jetParameter?.getModifierList() + ) + } + } + + private fun createReceiverInfoIfNeeded(): JetParameterInfo? { + val function = baseDeclaration as? JetFunction ?: return null + val bodyScope = function.getBodyExpression()?.let { it.analyze()[BindingContext.RESOLUTION_SCOPE, it] } + val paramNames = baseDescriptor.getValueParameters().map { it.getName().asString() } + val validator = bodyScope?.let { bodyScope -> + CollectingValidator(paramNames) { + val name = Name.identifier(it) + bodyScope.getLocalVariable(name) == null && bodyScope.getProperties(name).isEmpty() + } + } ?: CollectingValidator(paramNames) + val receiverType = baseDescriptor.getExtensionReceiverParameter()?.getType() ?: return null + val receiverName = JetNameSuggester.suggestNames(receiverType, validator, "receiver").first() + return JetParameterInfo(name = receiverName, type = receiverType) } override val primaryFunctions: Collection> by Delegates.lazy { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java index 7a882d825d4..3d1c587e898 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java @@ -420,7 +420,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : ""; return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText, - getVisibility(), parameters, myDefaultValueContext + getVisibility(), parameters, null, myDefaultValueContext ); } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java index 195a9d33a41..49897082641 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -25,31 +25,43 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.changeSignature.*; import com.intellij.refactoring.rename.ResolveSnapshotProvider; +import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.MoveRenameUsageInfo; +import com.intellij.refactoring.util.RefactoringUIUtil; import com.intellij.refactoring.util.TextOccurrencesUtil; import com.intellij.usageView.UsageInfo; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil; +import org.jetbrains.kotlin.idea.codeInsight.JetFileReferencesResolver; import org.jetbrains.kotlin.idea.refactoring.RefactoringPackage; import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*; import org.jetbrains.kotlin.idea.references.JetSimpleNameReference; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage; import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; +import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.scopes.JetScope; +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver; import org.jetbrains.kotlin.types.JetType; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor { @@ -79,7 +91,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } private static void findOneMethodUsages( - @NotNull JetFunctionDefinitionUsage functionUsageInfo, + @NotNull JetFunctionDefinitionUsage functionUsageInfo, JetChangeInfo changeInfo, Set result ) { @@ -92,7 +104,6 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro PsiElement functionPsi = functionUsageInfo.getElement(); if (functionPsi == null) return; - for (PsiReference reference : ReferencesSearch.search(functionPsi, functionPsi.getUseScope())) { PsiElement element = reference.getElement(); @@ -119,12 +130,14 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro ? ((JetFunction) functionPsi).getValueParameters() : ((JetClass) functionPsi).getPrimaryConstructorParameters(); + JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); + for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) { if (parameterInfo.getOldIndex() >= 0 && parameterInfo.getOldIndex() < oldParameters.size()) { JetParameter oldParam = oldParameters.get(parameterInfo.getOldIndex()); String oldParamName = oldParam.getName(); - if (oldParamName != null && !oldParamName.equals(parameterInfo.getName())) { + if (parameterInfo == newReceiverInfo || (oldParamName != null && !oldParamName.equals(parameterInfo.getName()))) { for (PsiReference reference : ReferencesSearch.search(oldParam, oldParam.getUseScope())) { PsiElement element = reference.getElement(); @@ -140,6 +153,10 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } } + if (functionPsi instanceof JetFunction && newReceiverInfo != changeInfo.getMethodDescriptor().getReceiver()) { + findOriginalReceiversUsages(functionUsageInfo, result, changeInfo); + } + if (functionPsi instanceof JetClass && ((JetClass) functionPsi).isEnum()) { for (JetDeclaration declaration : ((JetClass) functionPsi).getDeclarations()) { if (declaration instanceof JetEnumEntry && ((JetEnumEntry) declaration).getDelegationSpecifierList() == null) { @@ -149,6 +166,90 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } } + private static void processInternalReferences( + JetFunctionDefinitionUsage functionUsageInfo, + JetTreeVisitor visitor + ) { + JetFunction jetFunction = (JetFunction) functionUsageInfo.getDeclaration(); + JetExpression body = jetFunction.getBodyExpression(); + if (body != null) { + body.accept(visitor, ResolvePackage.analyze(body)); + } + for (JetParameter parameter : jetFunction.getValueParameters()) { + JetExpression defaultValue = parameter.getDefaultValue(); + if (defaultValue != null) { + defaultValue.accept(visitor, ResolvePackage.analyze(defaultValue)); + } + } + } + + private static void findOriginalReceiversUsages( + @NotNull final JetFunctionDefinitionUsage functionUsageInfo, + @NotNull final Set result, + @NotNull final JetChangeInfo changeInfo + ) { + final JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); + final FunctionDescriptor functionDescriptor = functionUsageInfo.getOriginalFunctionDescriptor(); + processInternalReferences( + functionUsageInfo, + new JetTreeVisitor() { + private void processExplicitThis( + @NotNull JetSimpleNameExpression expression, + @NotNull ReceiverParameterDescriptor receiverDescriptor + ) { + if (originalReceiverInfo != null && !changeInfo.hasParameter(originalReceiverInfo)) return; + if (!(expression.getParent() instanceof JetThisExpression)) return; + + if (receiverDescriptor == functionDescriptor.getExtensionReceiverParameter()) { + assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText(); + result.add(new JetParameterUsage(expression, originalReceiverInfo, functionUsageInfo)); + } + else { + ClassifierDescriptor targetDescriptor = receiverDescriptor.getType().getConstructor().getDeclarationDescriptor(); + assert targetDescriptor != null : "Receiver type has no descriptor: " + functionUsageInfo.getDeclaration().getText(); + result.add(new JetNonQualifiedOuterThisUsage((JetThisExpression) expression.getParent(), targetDescriptor)); + } + } + + private void processImplicitThis( + @NotNull JetElement callElement, + @NotNull ThisReceiver receiverValue + ) { + DeclarationDescriptor targetDescriptor = receiverValue.getDeclarationDescriptor(); + if (targetDescriptor == functionDescriptor) { + assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText(); + result.add(new JetImplicitThisToParameterUsage(callElement, originalReceiverInfo, functionUsageInfo)); + } + else { + result.add(new JetImplicitOuterThisToQualifiedThisUsage(callElement, targetDescriptor)); + } + } + + @Override + public Void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, BindingContext context) { + ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(expression, context); + if (resolvedCall == null) return null; + + CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); + if (resultingDescriptor instanceof ReceiverParameterDescriptor) { + processExplicitThis(expression, (ReceiverParameterDescriptor) resultingDescriptor); + return null; + } + + ReceiverValue receiverValue = resolvedCall.getExtensionReceiver(); + if (!(receiverValue instanceof ThisReceiver)) { + receiverValue = resolvedCall.getDispatchReceiver(); + } + if (receiverValue instanceof ThisReceiver) { + processImplicitThis(resolvedCall.getCall().getCallElement(), (ThisReceiver) receiverValue); + } + + return null; + } + } + ); + } + private static void findSAMUsages(ChangeInfo changeInfo, Set result) { PsiElement method = changeInfo.getMethod(); if (!RefactoringPackage.isTrueJavaMethod(method)) return; @@ -203,9 +304,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro PsiElement element = function != null ? function : changeInfo.getContext(); BindingContext bindingContext = ResolvePackage.analyze((JetElement) element); FunctionDescriptor oldDescriptor = ChangeSignaturePackage.getOriginalBaseFunctionDescriptor(changeInfo); - JetScope parametersScope = null; - DeclarationDescriptor containingDeclaration = oldDescriptor != null ? oldDescriptor.getContainingDeclaration() : null; + DeclarationDescriptor containingDeclaration = oldDescriptor.getContainingDeclaration(); + JetScope parametersScope = null; if (oldDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptorWithResolutionScopes) parametersScope = ((ClassDescriptorWithResolutionScopes) containingDeclaration).getScopeForInitializerResolution(); else if (function instanceof JetFunction) @@ -256,9 +357,104 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } } + JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); + JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); + if (function instanceof JetNamedFunction && newReceiverInfo != originalReceiverInfo) { + findReceiverIntroducingConflicts(result, function, newReceiverInfo); + findInternalExplicitReceiverConflicts(refUsages.get(), result, originalReceiverInfo); + } + return result; } + private static void findInternalExplicitReceiverConflicts( + UsageInfo[] usages, + MultiMap result, + JetParameterInfo originalReceiverInfo + ) { + if (originalReceiverInfo == null) { + for (UsageInfo usageInfo : usages) { + if (!(usageInfo instanceof JetFunctionCallUsage)) continue; + + JetFunctionCallUsage callUsage = (JetFunctionCallUsage) usageInfo; + JetElement callElement = callUsage.getElement(); + if (callElement == null) continue; + + PsiElement parent = callElement.getParent(); + if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == callElement) { + String message = "Explicit receiver is already present in call element: " + + CommonRefactoringUtil.htmlEmphasize(parent.getText()); + result.putValue(callElement, message); + } + } + } + } + + private static void findReceiverIntroducingConflicts( + MultiMap result, + PsiElement callable, + JetParameterInfo newReceiverInfo + ) { + if (newReceiverInfo != null && ((JetNamedFunction) callable).getBodyExpression() != null) { + Map noReceiverRefToContext = KotlinPackage.filter( + JetFileReferencesResolver.INSTANCE$.resolve((JetNamedFunction) callable, true, true), + new Function1, Boolean>() { + @Override + public Boolean invoke(Map.Entry entry) { + ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(entry.getKey(), entry.getValue()); + return resolvedCall != null + && !resolvedCall.getDispatchReceiver().exists() + && !resolvedCall.getExtensionReceiver().exists(); + } + } + ); + + JetPsiFactory psiFactory = new JetPsiFactory(callable.getProject()); + JetFile tempFile = RefactoringPackage.createTempCopy( + (JetFile) callable.getContainingFile(), + new Function1() { + @Override + public String invoke(String s) { + return s; + } + } + ); + JetNamedFunction functionWithReceiver = + PsiTreeUtil.getParentOfType(tempFile.findElementAt(callable.getTextOffset()), JetNamedFunction.class); + JetTypeReference receiverTypeRef = psiFactory.createType(newReceiverInfo.getCurrentTypeText()); + TypeRefHelpersPackage.setReceiverTypeReference(functionWithReceiver, receiverTypeRef); + //noinspection ConstantConditions + BindingContext newContext = ResolvePackage.analyze(functionWithReceiver.getBodyExpression()); + + //noinspection ConstantConditions + int originalOffset = ((JetNamedFunction) callable).getBodyExpression().getTextOffset(); + JetExpression newBody = functionWithReceiver.getBodyExpression(); + for (Map.Entry entry : noReceiverRefToContext.entrySet()) { + JetReferenceExpression originalRef = entry.getKey(); + BindingContext originalContext = entry.getValue(); + //noinspection ConstantConditions + JetReferenceExpression newRef = PsiTreeUtil.getParentOfType( + newBody.findElementAt(originalRef.getTextOffset() - originalOffset), + JetReferenceExpression.class + ); + ResolvedCall newResolvedCall = CallUtilPackage.getResolvedCall(newRef, newContext); + if (newResolvedCall == null + || newResolvedCall.getExtensionReceiver().exists() + || newResolvedCall.getDispatchReceiver().exists()) { + //noinspection ConstantConditions + CallableDescriptor descriptor = + CallUtilPackage.getResolvedCall(originalRef, originalContext).getCandidateDescriptor(); + PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(callable.getProject(), descriptor); + String prefix = declaration != null ? RefactoringUIUtil.getDescription(declaration, true) : originalRef.getText(); + result.putValue( + originalRef, + KotlinPackage.capitalize(prefix + " will no longer be accessible after signature change") + ); + } + } + } + } + private static List getFunctionParameterTypes(FunctionDescriptor descriptor) { return ContainerUtil.map(descriptor.getValueParameters(), new Function() { @Override diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt index 1c62d2014a6..987440b11e0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,8 @@ public trait JetMethodDescriptor : MethodDescriptor val primaryFunctions: Collection> val affectedFunctions: Collection + + val receiver: JetParameterInfo? } val JetMethodDescriptor.isConstructor: Boolean @@ -39,3 +41,6 @@ val JetMethodDescriptor.isConstructor: Boolean fun JetMethodDescriptor.renderOriginalReturnType(): String = baseDescriptor.getReturnType()?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } ?: "" + +fun JetMethodDescriptor.renderOriginalReceiverType(): String? = + baseDescriptor.getExtensionReceiverParameter()?.getType()?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java index bff48cffd90..ebdc1cdffaa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java @@ -18,9 +18,19 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.descriptors.CallableDescriptor; +import org.jetbrains.kotlin.descriptors.ClassDescriptor; +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; +import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver; import java.util.HashMap; import java.util.List; @@ -29,42 +39,48 @@ import java.util.Map; import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory; public class JetFunctionCallUsage extends JetUsageInfo { - private final JetFunctionDefinitionUsage callee; + private final JetFunctionDefinitionUsage callee; + private final ResolvedCall resolvedCall; public JetFunctionCallUsage(@NotNull JetCallElement element, JetFunctionDefinitionUsage callee) { super(element); this.callee = callee; + this.resolvedCall = CallUtilPackage.getResolvedCall(element, ResolvePackage.analyze(element)); } @Override public boolean processUsage(JetChangeInfo changeInfo, JetCallElement element) { - JetValueArgumentList arguments = element.getValueArgumentList(); - if (changeInfo.isNameChanged()) { JetExpression callee = element.getCalleeExpression(); - if (callee instanceof JetSimpleNameExpression) + if (callee instanceof JetSimpleNameExpression) { callee.replace(JetPsiFactory(getProject()).createSimpleName(changeInfo.getNewName())); + } } - if (arguments != null) { - List oldArguments = arguments.getArguments(); - - if (changeInfo.isParameterSetOrOrderChanged()) - arguments.replace(generateNewArgumentList(changeInfo, oldArguments)); - else - changeArgumentNames(changeInfo, oldArguments); + if (element.getValueArgumentList() != null) { + if (changeInfo.isParameterSetOrOrderChanged()) { + updateArgumentsAndReceiver(changeInfo, element); + } + else { + changeArgumentNames(changeInfo, element); + } } return true; } - private JetValueArgumentList generateNewArgumentList(JetChangeInfo changeInfo, List oldArguments) { + private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element) { + JetValueArgumentList arguments = element.getValueArgumentList(); + assert arguments != null : "Argument list is expected: " + element.getText(); + List oldArguments = arguments.getArguments(); + boolean isNamedCall = oldArguments.size() > 1 && oldArguments.get(0).getArgumentName() != null; StringBuilder parametersBuilder = new StringBuilder("("); boolean isFirst = true; - for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) { + List newSignatureParameters = changeInfo.getNonReceiverParameters(); + for (JetParameterInfo parameterInfo : newSignatureParameters) { if (isFirst) isFirst = false; else @@ -86,8 +102,35 @@ public class JetFunctionCallUsage extends JetUsageInfo { Map argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments); int argIndex = 0; + JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); + JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); + + ReceiverValue extensionReceiver = resolvedCall != null ? resolvedCall.getExtensionReceiver() : ReceiverValue.NO_RECEIVER; + ReceiverValue dispatchReceiver = resolvedCall != null ? resolvedCall.getDispatchReceiver() : ReceiverValue.NO_RECEIVER; + + JetPsiFactory psiFactory = new JetPsiFactory(element.getProject()); + + PsiElement elementToReplace = element; + PsiElement parent = element.getParent(); + if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == element) { + elementToReplace = parent; + } + + // Do not add extension receiver to calls with explicit dispatch receiver + if (newReceiverInfo != null + && elementToReplace instanceof JetQualifiedExpression + && dispatchReceiver instanceof ExpressionReceiver) return; + for (JetValueArgument newArgument : newArguments.getArguments()) { - JetParameterInfo parameterInfo = changeInfo.getNewParameters()[argIndex++]; + JetParameterInfo parameterInfo = newSignatureParameters.get(argIndex++); + if (parameterInfo == originalReceiverInfo) { + JetExpression receiverExpression = getReceiverExpression(extensionReceiver, psiFactory); + if (receiverExpression != null) { + newArgument.replace(receiverExpression); + } + continue; + } + JetValueArgument oldArgument = argumentMap.get(parameterInfo.getOldIndex()); if (oldArgument != null) { @@ -100,7 +143,38 @@ public class JetFunctionCallUsage extends JetUsageInfo { newArgument.delete(); } - return newArguments; + arguments.replace(newArguments); + + if (newReceiverInfo == originalReceiverInfo) return; + + PsiElement replacingElement = element; + if (newReceiverInfo != null) { + JetValueArgument receiverArgument = argumentMap.get(newReceiverInfo.getOldIndex()); + JetExpression extensionReceiverExpression = receiverArgument != null ? receiverArgument.getArgumentExpression() : null; + String receiverText = extensionReceiverExpression != null + ? extensionReceiverExpression.getText() + : newReceiverInfo.getDefaultValueForCall(); + if (receiverText.isEmpty()) { + receiverText = "_"; + } + + replacingElement = psiFactory.createExpression(receiverText + "." + element.getText()); + } + + elementToReplace.replace(replacingElement); + } + + @Nullable + private static JetExpression getReceiverExpression(@NotNull ReceiverValue receiver, @NotNull JetPsiFactory psiFactory) { + if (receiver instanceof ExpressionReceiver) { + return ((ExpressionReceiver) receiver).getExpression(); + } + else if (receiver instanceof ThisReceiver) { + DeclarationDescriptor descriptor = ((ThisReceiver) receiver).getDeclarationDescriptor(); + String thisText = descriptor instanceof ClassDescriptor ? "this@" + descriptor.getName().asString() : "this"; + return psiFactory.createExpression(thisText); + } + return null; } private static Map getParamIndexToArgumentMap(JetChangeInfo changeInfo, List oldArguments) { @@ -125,8 +199,8 @@ public class JetFunctionCallUsage extends JetUsageInfo { return argumentMap; } - private void changeArgumentNames(JetChangeInfo changeInfo, List oldArguments) { - for (JetValueArgument argument : oldArguments) { + private void changeArgumentNames(JetChangeInfo changeInfo, JetCallElement element) { + for (ValueArgument argument : element.getValueArguments()) { JetValueArgumentName argumentName = argument.getArgumentName(); JetSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null; diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java index 957f36b1aa3..f67ac60f5a9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,11 +26,19 @@ import kotlin.KotlinPackage; import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; +import org.jetbrains.kotlin.idea.util.ShortenReferences; +import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage; +import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; +import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.types.TypeSubstitutor; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.util.ShortenReferences.Options; import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage; @@ -39,12 +47,6 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePack import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar; -import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; -import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.TypeSubstitutor; import java.util.List; @@ -212,6 +214,16 @@ public class JetFunctionDefinitionUsage extends JetUsageIn ShortenPackage.addToShorteningWaitSet(parameterList, Options.DEFAULT); } + if (element instanceof JetFunction && changeInfo.isReceiverTypeChanged()) { + //noinspection unchecked + String receiverTypeText = changeInfo.renderReceiverType((JetFunctionDefinitionUsage) this); + JetTypeReference receiverTypeRef = receiverTypeText != null ? psiFactory.createType(receiverTypeText) : null; + JetTypeReference newReceiverTypeRef = TypeRefHelpersPackage.setReceiverTypeReference((JetFunction) element, receiverTypeRef); + if (newReceiverTypeRef != null) { + ShortenPackage.addToShorteningWaitSet(newReceiverTypeRef, ShortenReferences.Options.DEFAULT); + } + } + if (changeInfo.isVisibilityChanged() && !JetPsiUtil.isLocal((JetDeclaration) element)) { changeVisibility(changeInfo, element); } @@ -225,7 +237,7 @@ public class JetFunctionDefinitionUsage extends JetUsageIn JetParameterList parameterList, JetPsiFactory psiFactory ) { - int parametersCount = changeInfo.getNewParametersCount(); + int parametersCount = changeInfo.getNonReceiverParametersCount(); boolean isLambda = element instanceof JetFunctionLiteral; boolean canReplaceEntireList = false; diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt new file mode 100644 index 00000000000..9c255963baf --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages + +import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo +import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.psi.JetQualifiedExpression +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.JetElement +import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet +import org.jetbrains.kotlin.idea.util.ShortenReferences.Options + +public abstract class JetImplicitReceiverUsage(callElement: JetElement): JetUsageInfo(callElement) { + protected abstract fun getNewReceiverText(): String + + protected open fun processReplacedElement(element: JetElement) { + + } + + override fun processUsage(changeInfo: JetChangeInfo, element: JetElement): Boolean { + val newQualifiedCall = JetPsiFactory(element.getProject()).createExpression( + "${getNewReceiverText()}.${element.getText()}" + ) as JetQualifiedExpression + processReplacedElement(element.replace(newQualifiedCall) as JetElement) + return false + } +} + +public class JetImplicitThisToParameterUsage( + callElement: JetElement, + val parameterInfo: JetParameterInfo, + val containingFunction: JetFunctionDefinitionUsage<*> +): JetImplicitReceiverUsage(callElement) { + override fun getNewReceiverText(): String = parameterInfo.getInheritedName(containingFunction) + + override fun processReplacedElement(element: JetElement) { + element.addToShorteningWaitSet(Options(removeThisLabels = true)) + } +} + +public class JetImplicitOuterThisToQualifiedThisUsage( + callElement: JetElement, + val targetDescriptor: DeclarationDescriptor +): JetImplicitReceiverUsage(callElement) { + override fun getNewReceiverText(): String = "this@${targetDescriptor.getName().asString()}" + + override fun processReplacedElement(element: JetElement) { + element.addToShorteningWaitSet(Options(removeThisLabels = true, removeThis = true)) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt index 770fa7eed9f..c7e76ca6614 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,51 @@ import org.jetbrains.kotlin.psi.JetSimpleNameExpression import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet +import org.jetbrains.kotlin.psi.JetQualifiedExpression +import org.jetbrains.kotlin.psi.JetElement +import org.jetbrains.kotlin.psi.JetThisExpression +import org.jetbrains.kotlin.idea.util.ShortenReferences.Options + +// Explicit reference to function parameter or outer this +public abstract class JetExplicitReferenceUsage(element: T) : JetUsageInfo(element) { + protected abstract fun getReplacementText(changeInfo: JetChangeInfo): String + + protected open fun processReplacedElement(element: JetElement) { + + } + + override fun processUsage(changeInfo: JetChangeInfo, element: T): Boolean { + val newElement = JetPsiFactory(element.getProject()).createExpression(getReplacementText(changeInfo)) + processReplacedElement(element.replace(newElement) as JetElement) + return false + } +} public class JetParameterUsage( element: JetSimpleNameExpression, private val parameterInfo: JetParameterInfo, private val containingFunction: JetFunctionDefinitionUsage<*> -) : JetUsageInfo(element) { - override fun processUsage(changeInfo: JetChangeInfo, element: JetSimpleNameExpression): Boolean { - val newName = parameterInfo.getInheritedName(containingFunction) - element.replace(JetPsiFactory(element.getProject()).createSimpleName(newName)) - return false +) : JetExplicitReferenceUsage(element) { + override fun processReplacedElement(element: JetElement) { + val qualifiedExpression = element.getParent() as? JetQualifiedExpression + if (qualifiedExpression?.getReceiverExpression() == element) { + qualifiedExpression!!.addToShorteningWaitSet(Options(removeThis = true)) + } } + + override fun getReplacementText(changeInfo: JetChangeInfo): String = + if (changeInfo.receiverParameterInfo != parameterInfo) parameterInfo.getInheritedName(containingFunction) else "this" } + +public class JetNonQualifiedOuterThisUsage( + element: JetThisExpression, + val targetDescriptor: DeclarationDescriptor +) : JetExplicitReferenceUsage(element) { + override fun processReplacedElement(element: JetElement) { + element.addToShorteningWaitSet(Options(removeThisLabels = true)) + } + + override fun getReplacementText(changeInfo: JetChangeInfo): String = "this@${targetDescriptor.getName().asString()}" +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetUsageInfo.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetUsageInfo.java index b64edd03f4f..118926c7b7a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetUsageInfo.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetUsageInfo.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.usageView.UsageInfo; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo; public abstract class JetUsageInfo extends UsageInfo { @@ -31,5 +32,12 @@ public abstract class JetUsageInfo extends UsageInfo { super(reference); } + @Nullable + @Override + public T getElement() { + //noinspection unchecked + return (T) super.getElement(); + } + public abstract boolean processUsage(JetChangeInfo changeInfo, T element); } diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.1.java new file mode 100644 index 00000000000..4af16b713c8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.kt new file mode 100644 index 00000000000..56a08b091d0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverAfter.kt @@ -0,0 +1,9 @@ +fun X.foo(s: String, k: Int): Boolean { + return s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + X(0).foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.1.java new file mode 100644 index 00000000000..d8c56b45e33 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo("1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.kt new file mode 100644 index 00000000000..d649f0ec86c --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverBefore.kt @@ -0,0 +1,9 @@ +fun foo(s: String, k: Int): Boolean { + return s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverConflictBefore.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverConflictBefore.kt new file mode 100644 index 00000000000..90e39d69f04 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverConflictBefore.kt @@ -0,0 +1,13 @@ +fun length(): Int = 1 + +fun foo(k: Int): Boolean { + return length() - k > 0 +} + +class X(val k: Int) { + fun length() = 2 +} + +fun test() { + foo(2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverConflictMessages.txt b/idea/testData/refactoring/changeSignature/AddNewReceiverConflictMessages.txt new file mode 100644 index 00000000000..a46d2af2029 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverConflictMessages.txt @@ -0,0 +1 @@ +Function length will no longer be accessible after signature change \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.1.java b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.1.java new file mode 100644 index 00000000000..fe2930ccb86 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.kt new file mode 100644 index 00000000000..076001c7e7a --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberAfter.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, n: Int): Boolean { + return s.length() * this@A.k - n.inc() + this@A.k > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.1.java b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.1.java new file mode 100644 index 00000000000..0e3997be310 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo("1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.kt new file mode 100644 index 00000000000..d5aff63d1c2 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberBefore.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(s: String, n: Int): Boolean { + return s.length() * this.k - n.inc() + k > 0 + } + + fun test() { + foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictBefore.kt b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictBefore.kt new file mode 100644 index 00000000000..73f5da431f0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictBefore.kt @@ -0,0 +1,20 @@ +class A(val k: Int) { + fun foo(s: String, n: Int): Boolean { + return s.length()*this.k - n.inc() + k > 0 + } + + fun test() { + foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + A(3).foo("1", 2) + with(A(3)) { + foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictMessages.txt b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictMessages.txt new file mode 100644 index 00000000000..6b755d5bdec --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddNewReceiverForMemberConflictMessages.txt @@ -0,0 +1 @@ +Explicit receiver is already present in call element: A(3).foo("1", 2) \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.1.java b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.1.java new file mode 100644 index 00000000000..631c8c226ce --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.1.java @@ -0,0 +1,18 @@ +interface J extends T { + @Override + int foofoofoo(U a, B b); +} + +abstract class J1 implements J> { + @Override + public int foofoofoo(U> xu, C c) { + throw new UnsupportedOperationException(); + } +} + +abstract class J2 extends J1 { + @Override + public int foofoofoo(U> xu, C c) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.kt b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.kt new file mode 100644 index 00000000000..58c6f2a75c1 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesAfter.kt @@ -0,0 +1,17 @@ +class U + +trait T { + fun U.foofoofoo(b: B): Int +} + +abstract class T1 : T> { + override fun U>.foofoofoo(b: B): Int { + throw UnsupportedOperationException() + } +} + +abstract class T2 : T1() { + override fun U>.foofoofoo(b: C): Int { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.1.java b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.1.java new file mode 100644 index 00000000000..cb844e55a38 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.1.java @@ -0,0 +1,18 @@ +interface J extends T { + @Override + int foofoofoo(A a, B b); +} + +abstract class J1 implements J> { + @Override + public int foofoofoo(U xu, C c) { + throw new UnsupportedOperationException(); + } +} + +abstract class J2 extends J1 { + @Override + public int foofoofoo(U xu, C c) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.kt b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.kt new file mode 100644 index 00000000000..34bb8231cfb --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddReceiverToGenericsWithOverridesBefore.kt @@ -0,0 +1,17 @@ +class U + +trait T { + fun foofoofoo(a: A, b: B): Int +} + +abstract class T1 : T> { + override fun foofoofoo(a: U, b: B): Int { + throw UnsupportedOperationException() + } +} + +abstract class T2 : T1() { + override fun foofoofoo(a: U, b: C): Int { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.1.java new file mode 100644 index 00000000000..9e2fd4a9954 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.kt b/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.kt new file mode 100644 index 00000000000..cf30fdeb921 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverAfter.kt @@ -0,0 +1,9 @@ +fun String.foo(x: X, k: Int): Boolean { + return x.k + length() - k > 0 +} + +class X(val k: Int) + +fun test() { + "1".foo(X(0), 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.kt b/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.kt new file mode 100644 index 00000000000..7025ce39359 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverBefore.kt @@ -0,0 +1,9 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + X(0).foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.1.java b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.1.java new file mode 100644 index 00000000000..a963b790f67 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.kt b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.kt new file mode 100644 index 00000000000..3a25e6d7502 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberAfter.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun String.foo(x: X, k: Int): Boolean { + return x.k + length() - k + this@A.k/2 > 0 + } + + fun test() { + "1".foo(X(0), 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + "1".foo(X(0), 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.1.java b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.kt b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.kt new file mode 100644 index 00000000000..4d056b66e96 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeReceiverForMemberBefore.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k + this@A.k/2 > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.kt new file mode 100644 index 00000000000..ca30af21c0c --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1After.kt @@ -0,0 +1,9 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + X(0).foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.kt new file mode 100644 index 00000000000..98b9a274a9a --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver1Before.kt @@ -0,0 +1,9 @@ +fun foo(x: X, s: String, k: Int): Boolean { + return x.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + foo(X(0), "1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.kt new file mode 100644 index 00000000000..ca30af21c0c --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2After.kt @@ -0,0 +1,9 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + X(0).foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.1.java new file mode 100644 index 00000000000..9e2fd4a9954 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.kt new file mode 100644 index 00000000000..499141e4a8d --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiver2Before.kt @@ -0,0 +1,9 @@ +fun foo(s: String, x: X, k: Int): Boolean { + return x.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun test() { + foo("1", X(0), 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.kt new file mode 100644 index 00000000000..5206fa61448 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1After.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k + this@A.k/2 > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.kt new file mode 100644 index 00000000000..bae82c496cc --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember1Before.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(x: X, s: String, k: Int): Boolean { + return x.k + s.length() - k + this.k/2 > 0 + } + + fun test() { + foo(X(0), "1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo(X(0), "1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.kt new file mode 100644 index 00000000000..5206fa61448 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2After.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k + this@A.k/2 > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.1.java b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.1.java new file mode 100644 index 00000000000..a963b790f67 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.kt new file mode 100644 index 00000000000..a95562544e5 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMember2Before.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(s: String, x: X, k: Int): Boolean { + return x.k + s.length() - k + this.k/2 > 0 + } + + fun test() { + foo("1", X(0), 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo("1", X(0), 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictBefore.kt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictBefore.kt new file mode 100644 index 00000000000..26d1929ad4e --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictBefore.kt @@ -0,0 +1,20 @@ +class A(val k: Int) { + fun foo(x: X, s: String, k: Int): Boolean { + return x.k + s.length() - k + this.k/2 > 0 + } + + fun test() { + foo(X(0), "1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + A(3).foo(X(0), "1", 2) + with(A(3)) { + foo(X(0), "1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictMessages.txt b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictMessages.txt new file mode 100644 index 00000000000..fe9e54ad5fc --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertParameterToReceiverForMemberConflictMessages.txt @@ -0,0 +1 @@ +Explicit receiver is already present in call element: A(3).foo(X(0), "1", 2) \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.kt new file mode 100644 index 00000000000..d530e82a29a --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1After.kt @@ -0,0 +1,14 @@ +fun foo(x: X, s: String, k: Int): Boolean { + return x.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + foo(X(0), "1", 2) + with(X(0)) { + foo(this, "1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.kt new file mode 100644 index 00000000000..7d5cd45ea83 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter1Before.kt @@ -0,0 +1,14 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + X(0).foo("1", 2) + with(X(0)) { + foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.1.java new file mode 100644 index 00000000000..9e2fd4a9954 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.kt new file mode 100644 index 00000000000..319c82ec7d8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2After.kt @@ -0,0 +1,14 @@ +fun foo(s: String, x: X, k: Int): Boolean { + return x.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + foo("1", X(0), 2) + with(X(0)) { + foo("1", this, 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.kt new file mode 100644 index 00000000000..7d5cd45ea83 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameter2Before.kt @@ -0,0 +1,14 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + X(0).foo("1", 2) + with(X(0)) { + foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameAfter.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameAfter.kt new file mode 100644 index 00000000000..05174437e9a --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameAfter.kt @@ -0,0 +1,5 @@ +class X(val k: Int) + +fun foo(abc: X, n: Int): Boolean { + return abc.k > n +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameBefore.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameBefore.kt new file mode 100644 index 00000000000..d9e3ab2ecff --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterAndChangeNameBefore.kt @@ -0,0 +1,5 @@ +class X(val k: Int) + +fun X.foo(n: Int): Boolean { + return this.k > n +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.kt new file mode 100644 index 00000000000..d1f496d2bd6 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1After.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(x: X, s: String, k: Int): Boolean { + return x.k + s.length() - k + this.k/2 > 0 + } + + fun test() { + foo(X(0), "1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo(X(0), "1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.kt new file mode 100644 index 00000000000..4d056b66e96 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember1Before.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k + this@A.k/2 > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.1.java new file mode 100644 index 00000000000..a963b790f67 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo("1", new X(0), 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.kt new file mode 100644 index 00000000000..afb255d5293 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2After.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(s: String, x: X, k: Int): Boolean { + return x.k + s.length() - k + this.k/2 > 0 + } + + fun test() { + foo("1", X(0), 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo("1", X(0), 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.1.java b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.1.java new file mode 100644 index 00000000000..d789386f98b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.kt new file mode 100644 index 00000000000..4d056b66e96 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterForMember2Before.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k + this@A.k/2 > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashAfter.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashAfter.kt new file mode 100644 index 00000000000..0e6946829c9 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashAfter.kt @@ -0,0 +1,7 @@ +val x1: Int + +class X(val x: Int) + +fun foo(x2: X, x: Int): Boolean { + return x2.x + x > x1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashBefore.kt b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashBefore.kt new file mode 100644 index 00000000000..37c8f654dfe --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ConvertReceiverToParameterWithNameClashBefore.kt @@ -0,0 +1,7 @@ +val x1: Int + +class X(val x: Int) + +fun X.foo(x: Int): Boolean { + return this.x + x > x1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.1.java new file mode 100644 index 00000000000..d8c56b45e33 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo("1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.kt b/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.kt new file mode 100644 index 00000000000..0e17b87b953 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverAfter.kt @@ -0,0 +1,14 @@ +fun foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(X(0)) { + foo("1", 2) + } + foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.1.java new file mode 100644 index 00000000000..32ee9b5ddb0 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + _DefaultPackage.foo(new X(0), "1", 2); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.kt b/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.kt new file mode 100644 index 00000000000..f2d66b1a50b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverBefore.kt @@ -0,0 +1,14 @@ +fun X.foo(s: String, k: Int): Boolean { + return this.k + s.length() - k > 0 +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(X(0)) { + foo("1", 2) + } + X(0).foo("1", 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.1.java b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.1.java new file mode 100644 index 00000000000..b0b6551ef0c --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(1, "2"); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.kt b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.kt new file mode 100644 index 00000000000..f3340fe4ef6 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberAfter.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun foo(s: String, n: Int): Boolean { + return s.length() * this.k - n.inc() + this@A.k > 0 + } + + fun test() { + foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.1.java b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.1.java new file mode 100644 index 00000000000..fed19c640cd --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.1.java @@ -0,0 +1,5 @@ +class J { + void test() { + new A(3).foo(new X(0), 1, "2"); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.kt b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.kt new file mode 100644 index 00000000000..4cfef972081 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveReceiverForMemberBefore.kt @@ -0,0 +1,19 @@ +class A(val k: Int) { + fun X.foo(s: String, n: Int): Boolean { + return s.length() * this.k - n.inc() + this@A.k > 0 + } + + fun test() { + X(0).foo("1", 2) + } +} + +class X(val k: Int) + +fun with(receiver: T, f: T.() -> R): R = receiver.f() + +fun test() { + with(A(3)) { + X(0).foo("1", 2) + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java index 2630df29829..152eae7537f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java @@ -318,7 +318,8 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { public void testFunctionJavaUsagesAndOverridesAddParam() throws Exception { JetChangeInfo changeInfo = getChangeInfo(); changeInfo.addParameter(new JetParameterInfo(-1, "s", KotlinBuiltIns.getInstance().getStringType(), null, "\"abc\"", null, null)); - changeInfo.addParameter(new JetParameterInfo(-1, "o", KotlinBuiltIns.getInstance().getNullableAnyType(), null, "\"def\"", null, null)); + changeInfo.addParameter( + new JetParameterInfo(-1, "o", KotlinBuiltIns.getInstance().getNullableAnyType(), null, "\"def\"", null, null)); doTest(changeInfo); } @@ -360,6 +361,16 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { doTest(changeInfo); } + public void testAddReceiverToGenericsWithOverrides() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + + JetParameterInfo parameterInfo = changeInfo.getNewParameters()[0]; + parameterInfo.setCurrentTypeText("U"); + changeInfo.setReceiverParameterInfo(parameterInfo); + + doTest(changeInfo); + } + public void testJavaMethodKotlinUsages() throws Exception { doJavaTest( new JavaRefactoringProvider() { @@ -582,6 +593,135 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { doTest(changeInfo); } + public void testAddNewReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null); + parameterInfo.setCurrentTypeText("X"); + changeInfo.setReceiverParameterInfo(parameterInfo); + doTest(changeInfo); + } + + public void testAddNewReceiverForMember() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null); + parameterInfo.setCurrentTypeText("X"); + changeInfo.setReceiverParameterInfo(parameterInfo); + doTest(changeInfo); + } + + public void testAddNewReceiverForMemberConflict() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null); + parameterInfo.setCurrentTypeText("X"); + changeInfo.setReceiverParameterInfo(parameterInfo); + doTestConflict(changeInfo); + } + + public void testAddNewReceiverConflict() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null); + parameterInfo.setCurrentTypeText("X"); + changeInfo.setReceiverParameterInfo(parameterInfo); + doTestConflict(changeInfo); + } + + public void testRemoveReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.removeParameter(0); + doTest(changeInfo); + } + + public void testRemoveReceiverForMember() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.removeParameter(0); + doTest(changeInfo); + } + + public void testConvertParameterToReceiver1() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]); + doTest(changeInfo); + } + + public void testConvertParameterToReceiver2() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]); + doTest(changeInfo); + } + + public void testConvertReceiverToParameter1() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + doTest(changeInfo); + } + + public void testConvertReceiverToParameter2() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + JetParameterInfo[] parameters = changeInfo.getNewParameters(); + changeInfo.setNewParameter(0, parameters[1]); + changeInfo.setNewParameter(1, parameters[0]); + doTest(changeInfo); + } + + public void testConvertParameterToReceiverForMember1() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]); + doTest(changeInfo); + } + + public void testConvertParameterToReceiverForMember2() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]); + doTest(changeInfo); + } + + public void testConvertParameterToReceiverForMemberConflict() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]); + doTestConflict(changeInfo); + } + + public void testConvertReceiverToParameterForMember1() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + doTest(changeInfo); + } + + public void testConvertReceiverToParameterForMember2() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + JetParameterInfo[] parameters = changeInfo.getNewParameters(); + changeInfo.setNewParameter(0, parameters[1]); + changeInfo.setNewParameter(1, parameters[0]); + doTest(changeInfo); + } + + public void testConvertReceiverToParameterWithNameClash() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + doTest(changeInfo); + } + + public void testConvertReceiverToParameterAndChangeName() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + changeInfo.getNewParameters()[0].setName("abc"); + doTest(changeInfo); + } + + public void testChangeReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]); + doTest(changeInfo); + } + + public void testChangeReceiverForMember() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]); + doTest(changeInfo); + } + @NotNull @Override protected String getTestDataPath() {