From 2ff63d37c23f50646d41c07a4b62c21aaa2be21f Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 24 Jun 2015 14:17:23 +0300 Subject: [PATCH] Change Signature: Property support #KT-6599 Fixed --- .../kotlin/idea/JetBundle.properties | 2 +- .../quickfix/AddFunctionParametersFix.java | 2 +- .../CreateParameterActionFactory.kt | 2 +- ...teParameterByNamedArgumentActionFactory.kt | 2 +- .../changeSignature/JetChangeInfo.kt | 199 +++++++++++------- .../JetChangePropertySignatureDialog.kt | 174 +++++++++++++++ .../changeSignature/JetChangeSignature.kt | 78 ++++--- .../changeSignature/JetChangeSignatureData.kt | 57 ++--- .../JetChangeSignatureDialog.java | 2 +- .../JetChangeSignatureHandler.java | 66 +++--- .../JetChangeSignatureProcessor.java | 18 +- .../JetChangeSignatureUsageProcessor.java | 102 ++++----- .../changeSignature/JetMethodDescriptor.kt | 14 +- .../changeSignature/JetParameterInfo.kt | 44 ++-- .../refactoring/changeSignature/typeUtils.kt | 39 ++-- .../usages/JavaMethodDeferredKotlinUsage.kt | 4 +- .../JavaMethodKotlinUsageWithDelegate.kt | 6 +- ...e.java => JetCallableDefinitionUsage.java} | 148 +++++++------ .../JetConstructorDelegationCallUsage.kt | 2 +- .../JetEnumEntryWithoutSuperCallUsage.kt | 2 +- .../usages/JetFunctionCallUsage.java | 77 ++++++- .../usages/JetImplicitThisToParameterUsage.kt | 4 +- .../usages/JetParameterUsage.kt | 4 +- .../usages/JetPropertyCallUsage.kt | 64 ++++++ .../usages/KotlinWrapperForJavaUsageInfos.kt | 12 +- .../KotlinIntroduceParameterDialog.kt | 14 +- .../KotlinIntroduceParameterHandler.kt | 2 +- ...nIntroduceParameterMethodUsageProcessor.kt | 6 +- .../idea/refactoring/jetRefactoringUtil.kt | 12 ++ .../AddPropertyReceiverAfter.1.java | 28 +++ .../AddPropertyReceiverAfter.kt | 26 +++ .../AddPropertyReceiverBefore.1.java | 28 +++ .../AddPropertyReceiverBefore.kt | 26 +++ .../AddPropertyReceiverConflictBefore.kt | 8 + .../AddPropertyReceiverConflictMessages.txt | 2 + .../AddTopLevelPropertyReceiverAfter.1.java | 8 + .../AddTopLevelPropertyReceiverAfter.kt | 14 ++ .../AddTopLevelPropertyReceiverBefore.1.java | 8 + .../AddTopLevelPropertyReceiverBefore.kt | 14 ++ .../ChangePropertyAfter.1.java | 31 +++ .../changeSignature/ChangePropertyAfter.kt | 18 ++ .../ChangePropertyBefore.1.java | 28 +++ .../changeSignature/ChangePropertyBefore.kt | 18 ++ .../ChangePropertyReceiverAfter.1.java | 28 +++ .../ChangePropertyReceiverAfter.kt | 26 +++ .../ChangePropertyReceiverBefore.1.java | 28 +++ .../ChangePropertyReceiverBefore.kt | 26 +++ ...ChangeTopLevelPropertyReceiverAfter.1.java | 8 + .../ChangeTopLevelPropertyReceiverAfter.kt | 19 ++ ...hangeTopLevelPropertyReceiverBefore.1.java | 8 + .../ChangeTopLevelPropertyReceiverBefore.kt | 19 ++ .../RemovePropertyReceiverAfter.1.java | 28 +++ .../RemovePropertyReceiverAfter.kt | 26 +++ .../RemovePropertyReceiverBefore.1.java | 28 +++ .../RemovePropertyReceiverBefore.kt | 26 +++ ...RemoveTopLevelPropertyReceiverAfter.1.java | 8 + .../RemoveTopLevelPropertyReceiverAfter.kt | 19 ++ ...emoveTopLevelPropertyReceiverBefore.1.java | 8 + .../RemoveTopLevelPropertyReceiverBefore.kt | 19 ++ .../JetChangeSignatureTest.java | 69 +++++- 60 files changed, 1431 insertions(+), 377 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangePropertySignatureDialog.kt rename idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/{JetFunctionDefinitionUsage.java => JetCallableDefinitionUsage.java} (74%) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetPropertyCallUsage.kt create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictMessages.txt create mode 100644 idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.1.java create mode 100644 idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index c57187ff1aa..caad43ddb91 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -270,7 +270,7 @@ usageType.packageMemberAccess = Package member access x.in.y={0} in {1} x.implements.y={0} in {1} implements {2} in {3}. -x.overrides.y.in.class.list={0} in {1} overrides functions in the following classes/interfaces: {2} Do you want to {3} the base functions? +x.overrides.y.in.class.list={0} in {1} overrides declarations in the following classes/interfaces: {2} Do you want to {3} the base declarations? unused.overriding.methods.title=Unused Overriding Members there.are.unused.methods.that.override.methods.you.delete=There are unused members that override methods you delete. diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java index 3aea9c28072..1407e383106 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java @@ -147,7 +147,7 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { } else { JetParameterInfo parameterInfo = - getNewParameterInfo(originalDescriptor.getBaseDescriptor(), bindingContext, argument, validator); + getNewParameterInfo((FunctionDescriptor) originalDescriptor.getBaseDescriptor(), bindingContext, argument, validator); typesToShorten.add(parameterInfo.getOriginalType()); if (expression != null) { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt index 60bfe2d3729..b1ba8e9b60b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterActionFactory.kt @@ -115,7 +115,7 @@ object CreateParameterActionFactory: JetSingleIntentionActionFactory() { return CreateParameterFromUsageFix( functionDescriptor, context, - JetParameterInfo(functionDescriptor = functionDescriptor, + JetParameterInfo(callableDescriptor = functionDescriptor, name = refExpr.getReferencedName(), type = paramType, valOrVar = valOrVar), diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterByNamedArgumentActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterByNamedArgumentActionFactory.kt index 25c5fa9d1ac..30a354b6600 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterByNamedArgumentActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createVariable/CreateParameterByNamedArgumentActionFactory.kt @@ -60,7 +60,7 @@ public object CreateParameterByNamedArgumentActionFactory: JetSingleIntentionAct if (paramType.hasTypeParametersToAdd(functionDescriptor, context)) return null val parameterInfo = JetParameterInfo( - functionDescriptor = functionDescriptor, + callableDescriptor = functionDescriptor, name = name, type = paramType, defaultValueForCall = argumentExpression 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 88ce79e09d2..2b48e1eca63 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeInfo.kt @@ -19,28 +19,35 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature import com.intellij.lang.Language import com.intellij.lang.java.JavaLanguage import com.intellij.psi.* -import com.intellij.refactoring.changeSignature.* +import com.intellij.refactoring.changeSignature.ChangeInfo +import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor +import com.intellij.refactoring.changeSignature.JavaChangeInfo +import com.intellij.refactoring.changeSignature.ParameterInfoImpl import com.intellij.usageView.UsageInfo import com.intellij.util.VisibilityUtil -import org.jetbrains.kotlin.asJava.* -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.asJava.toLightMethods +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.codegen.PropertyCodegen +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.idea.JetLanguage +import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor +import org.jetbrains.kotlin.idea.core.refactoring.j2k +import org.jetbrains.kotlin.idea.project.ProjectStructureUtil +import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor.Kind +import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.idea.JetLanguage -import org.jetbrains.kotlin.idea.caches.resolve.* -import org.jetbrains.kotlin.idea.core.refactoring.j2k -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import java.util.HashMap -import kotlin.properties.Delegates import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList -import org.jetbrains.kotlin.idea.project.* -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor.Kind +import java.util.* +import kotlin.properties.Delegates public class JetChangeInfo( val methodDescriptor: JetMethodDescriptor, @@ -61,7 +68,7 @@ public class JetChangeInfo( } private val newParameters = parameterInfos.toArrayList() - private val originalPsiMethod: PsiMethod? = getCurrentPsiMethod() + private val originalPsiMethods: List = getMethod().toLightMethods() private val oldNameToParameterIndex: Map by Delegates.lazy { val map = HashMap() @@ -80,13 +87,7 @@ public class JetChangeInfo( } private var isPrimaryMethodUpdated: Boolean = false - private var javaChangeInfo: JavaChangeInfo? = null - - private fun getCurrentPsiMethod(): PsiMethod? { - val psiMethods = getMethod().toLightMethods() - assert(psiMethods.size() <= 1) { "Multiple light methods: " + getMethod().getText() } - return psiMethods.firstOrNull() - } + private var javaChangeInfos: List? = null public fun getOldParameterIndex(oldParameterName: String): Int? = oldNameToParameterIndex[oldParameterName] @@ -103,6 +104,7 @@ public class JetChangeInfo( fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0) fun getNonReceiverParameters(): List { + if (methodDescriptor.baseDeclaration is JetProperty) return emptyList() return receiverParameterInfo?.let { receiver -> newParameters.filter { it != receiver } } ?: newParameters } @@ -146,7 +148,7 @@ public class JetChangeInfo( override fun getLanguage(): Language = JetLanguage.INSTANCE - public fun getNewSignature(inheritedFunction: JetFunctionDefinitionUsage): String { + public fun getNewSignature(inheritedCallable: JetCallableDefinitionUsage): String { val buffer = StringBuilder() val defaultVisibility = if (kind.isConstructor) Visibilities.PUBLIC else Visibilities.INTERNAL @@ -174,7 +176,7 @@ public class JetChangeInfo( buffer.append(name) } - buffer.append(getNewParametersSignature(inheritedFunction)) + buffer.append(getNewParametersSignature(inheritedCallable)) if (newReturnType != null && !KotlinBuiltIns.isUnit(newReturnType) && kind == Kind.FUNCTION) buffer.append(": ").append(newReturnTypeText) @@ -182,63 +184,75 @@ public class JetChangeInfo( return buffer.toString() } - public fun isRefactoringTarget(inheritedFunctionDescriptor: FunctionDescriptor?): Boolean { - return inheritedFunctionDescriptor != null - && getMethod() == DescriptorToSourceUtils.descriptorToDeclaration(inheritedFunctionDescriptor) + public fun isRefactoringTarget(inheritedCallableDescriptor: CallableDescriptor?): Boolean { + return inheritedCallableDescriptor != null + && getMethod() == DescriptorToSourceUtils.descriptorToDeclaration(inheritedCallableDescriptor) } - public fun getNewParametersSignature(inheritedFunction: JetFunctionDefinitionUsage): String { + public fun getNewParametersSignature(inheritedCallable: JetCallableDefinitionUsage): String { val signatureParameters = getNonReceiverParameters() - val isLambda = inheritedFunction.getDeclaration() is JetFunctionLiteral - if (isLambda && signatureParameters.size() == 1 && !signatureParameters.get(0).requiresExplicitType(inheritedFunction)) { - return signatureParameters.get(0).getDeclarationSignature(0, inheritedFunction) + val isLambda = inheritedCallable.getDeclaration() is JetFunctionLiteral + if (isLambda && signatureParameters.size() == 1 && !signatureParameters.get(0).requiresExplicitType(inheritedCallable)) { + return signatureParameters.get(0).getDeclarationSignature(0, inheritedCallable) } return signatureParameters.indices - .map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedFunction) } + .map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedCallable) } .joinToString(prefix = "(", separator = ", ", postfix = ")") } - public fun renderReceiverType(inheritedFunction: JetFunctionDefinitionUsage): String? { + public fun renderReceiverType(inheritedCallable: JetCallableDefinitionUsage): String? { val receiverTypeText = receiverParameterInfo?.currentTypeText ?: return null - val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return receiverTypeText - val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return receiverTypeText + val typeSubstitutor = inheritedCallable.getOrCreateTypeSubstitutor() ?: return receiverTypeText + val currentBaseFunction = inheritedCallable.getBaseFunction().getCurrentCallableDescriptor() ?: 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 + public fun renderReturnType(inheritedCallable: JetCallableDefinitionUsage): String { + val typeSubstitutor = inheritedCallable.getOrCreateTypeSubstitutor() ?: return newReturnTypeText + val currentBaseFunction = inheritedCallable.getBaseFunction().getCurrentCallableDescriptor() ?: return newReturnTypeText return currentBaseFunction.getReturnType().renderTypeWithSubstitution(typeSubstitutor, newReturnTypeText, false) } public fun primaryMethodUpdated() { isPrimaryMethodUpdated = true - javaChangeInfo = null + javaChangeInfos = null } - public fun getOrCreateJavaChangeInfo(): JavaChangeInfo? { - if (ProjectStructureUtil.isJsKotlinModule(getMethod().getContainingFile() as JetFile)) return null + public fun getOrCreateJavaChangeInfos(): List? { + /* + * When primaryMethodUpdated is false, changes to the primary Kotlin declaration are already confirmed, but not yet applied. + * It means that originalPsiMethod has already expired, but new one can't be created until Kotlin declaration is updated + * (signified by primaryMethodUpdated being true). It means we can't know actual PsiType, visibility, etc. + * to use in JavaChangeInfo. However they are not actually used at this point since only parameter count and order matters here + * So we resort to this hack and pass around "default" type (void) and visibility (package-local) + */ - if (javaChangeInfo == null) { - val currentPsiMethod = getCurrentPsiMethod() - if (originalPsiMethod == null || currentPsiMethod == null) return null - - /* - * When primaryMethodUpdated is false, changes to the primary Kotlin declaration are already confirmed, but not yet applied. - * It means that originalPsiMethod has already expired, but new one can't be created until Kotlin declaration is updated - * (signified by primaryMethodUpdated being true). It means we can't know actual PsiType, visibility, etc. - * to use in JavaChangeInfo. However they are not actually used at this point since only parameter count and order matters here - * So we resort to this hack and pass around "default" type (void) and visibility (package-local) - */ - val javaVisibility = if (isPrimaryMethodUpdated) + fun createJavaChangeInfo(originalPsiMethod: PsiMethod, + currentPsiMethod: PsiMethod, + newName: String, + newReturnType: PsiType?, + newParameters: Array + ): JavaChangeInfo? { + val newVisibility = if (isPrimaryMethodUpdated) VisibilityUtil.getVisibilityModifier(currentPsiMethod.getModifierList()) else PsiModifier.PACKAGE_LOCAL + val javaChangeInfo = ChangeSignatureProcessor(getMethod().getProject(), + originalPsiMethod, + false, + newVisibility, + newName, + newReturnType ?: PsiType.VOID, + newParameters).getChangeInfo() + javaChangeInfo.updateMethod(currentPsiMethod) - val newParameterList = receiverParameterInfo.singletonOrEmptyList() + getNonReceiverParameters() - val newJavaParameters = newParameterList.withIndex().map { pair -> + return javaChangeInfo + } + + fun getJavaParameterInfos(currentPsiMethod: PsiMethod, newParameterList: List): MutableList { + return newParameterList.withIndex().mapTo(ArrayList()) { pair -> val (i, info) = pair val type = if (isPrimaryMethodUpdated) @@ -255,25 +269,66 @@ public class JetChangeInfo( } ParameterInfoImpl(javaOldIndex, info.getName(), type, info.defaultValueForCall?.getText() ?: "") - }.toTypedArray() - - val returnType = if (isPrimaryMethodUpdated) currentPsiMethod.getReturnType() else PsiType.VOID - - javaChangeInfo = ChangeSignatureProcessor(getMethod().getProject(), - originalPsiMethod, - false, - javaVisibility, - getNewName(), - returnType, - newJavaParameters).getChangeInfo() - javaChangeInfo!!.updateMethod(currentPsiMethod) + } } - return javaChangeInfo + fun createJavaChangeInfoForFunctionOrGetter( + originalPsiMethod: PsiMethod, + currentPsiMethod: PsiMethod, + isGetter: Boolean + ): JavaChangeInfo? { + val newParameterList = receiverParameterInfo.singletonOrEmptyList() + getNonReceiverParameters() + val newJavaParameters = getJavaParameterInfos(currentPsiMethod, newParameterList).toTypedArray() + val newName = if (isGetter) PropertyCodegen.getterName(Name.identifier(getNewName())) else getNewName() + return createJavaChangeInfo(originalPsiMethod, currentPsiMethod, newName, currentPsiMethod.getReturnType(), newJavaParameters) + } + + fun createJavaChangeInfoForSetter(originalPsiMethod: PsiMethod, currentPsiMethod: PsiMethod): JavaChangeInfo? { + val newJavaParameters = getJavaParameterInfos(currentPsiMethod, receiverParameterInfo.singletonOrEmptyList()) + val oldIndex = if (methodDescriptor.receiver != null) 1 else 0 + if (isPrimaryMethodUpdated) { + val newIndex = if (receiverParameterInfo != null) 1 else 0 + val setterParameter = currentPsiMethod.getParameterList().getParameters()[newIndex] + newJavaParameters.add(ParameterInfoImpl(oldIndex, setterParameter.getName(), setterParameter.getType())) + } + else { + newJavaParameters.add(ParameterInfoImpl(oldIndex, "receiver", PsiType.VOID)) + } + + val newName = PropertyCodegen.setterName(Name.identifier(getNewName())) + return createJavaChangeInfo(originalPsiMethod, currentPsiMethod, newName, PsiType.VOID, newJavaParameters.toTypedArray()) + } + + if (ProjectStructureUtil.isJsKotlinModule(getMethod().getContainingFile() as JetFile)) return null + + if (javaChangeInfos == null) { + val method = getMethod() + javaChangeInfos = (originalPsiMethods zip method.toLightMethods()).map { + val (originalPsiMethod, currentPsiMethod) = it + + when (method) { + is JetFunction, is JetClassOrObject -> + createJavaChangeInfoForFunctionOrGetter(originalPsiMethod, currentPsiMethod, false) + is JetProperty -> { + val accessorName = originalPsiMethod.getName() + when { + accessorName.startsWith(JvmAbi.GETTER_PREFIX) -> + createJavaChangeInfoForFunctionOrGetter(originalPsiMethod, currentPsiMethod, true) + accessorName.startsWith(JvmAbi.SETTER_PREFIX) -> + createJavaChangeInfoForSetter(originalPsiMethod, currentPsiMethod) + else -> null + } + } + else -> null + } + }.filterNotNull() + } + + return javaChangeInfos } } -public val JetChangeInfo.originalBaseFunctionDescriptor: FunctionDescriptor +public val JetChangeInfo.originalBaseFunctionDescriptor: CallableDescriptor get() = methodDescriptor.baseDescriptor public val JetChangeInfo.kind: Kind get() = methodDescriptor.kind @@ -281,7 +336,7 @@ public val JetChangeInfo.kind: Kind get() = methodDescriptor.kind public val JetChangeInfo.oldName: String? get() = (methodDescriptor.getMethod() as? JetFunction)?.getName() -public val JetChangeInfo.affectedFunctions: Collection get() = methodDescriptor.affectedFunctions +public val JetChangeInfo.affectedFunctions: Collection get() = methodDescriptor.affectedCallables public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMethodDescriptor): JetChangeInfo { val method = getMethod() as PsiMethod @@ -305,7 +360,7 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth } else null - with(JetParameterInfo(functionDescriptor = functionDescriptor, + with(JetParameterInfo(callableDescriptor = functionDescriptor, originalIndex = oldIndex, name = info.getName(), type = if (oldIndex >= 0) originalParameterDescriptors[oldIndex].getType() else currentType, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangePropertySignatureDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangePropertySignatureDialog.kt new file mode 100644 index 00000000000..bce53cd6946 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangePropertySignatureDialog.kt @@ -0,0 +1,174 @@ +/* + * Copyright 2010-2015 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 + +import com.intellij.openapi.options.ConfigurationException +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.refactoring.BaseRefactoringProcessor +import com.intellij.refactoring.ui.ComboBoxVisibilityPanel +import com.intellij.refactoring.ui.RefactoringDialog +import com.intellij.ui.EditorTextField +import com.intellij.ui.NonFocusableCheckBox +import com.intellij.util.ui.FormBuilder +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.idea.JetFileType +import org.jetbrains.kotlin.idea.core.refactoring.validateElement +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.psi.JetProperty +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.psi.JetTypeCodeFragment +import org.jetbrains.kotlin.resolve.AnalyzingUtils +import javax.swing.JCheckBox +import javax.swing.JComboBox +import javax.swing.JComponent +import javax.swing.JLabel +import kotlin.properties.Delegates + +public class JetChangePropertySignatureDialog( + project: Project, + private val methodDescriptor: JetMethodDescriptor, + private val commandName: String? +): RefactoringDialog(project, true) { + private val visibilityCombo = JComboBox( + arrayOf(Visibilities.INTERNAL, Visibilities.PRIVATE, Visibilities.PROTECTED, Visibilities.PUBLIC) + ) + private val nameField = EditorTextField(methodDescriptor.getName()) + private var returnTypeField: EditorTextField by Delegates.notNull() + private var receiverTypeCheckBox: JCheckBox by Delegates.notNull() + var receiverTypeLabel: JLabel by Delegates.notNull() + private var receiverTypeField: EditorTextField by Delegates.notNull() + var receiverDefaultValueLabel: JLabel? = null + private var receiverDefaultValueField: EditorTextField? = null + + init { + setTitle("Change Signature") + init() + } + + override fun getPreferredFocusedComponent() = nameField + + override fun createCenterPanel(): JComponent? { + fun updateReceiverUI() { + val withReceiver = receiverTypeCheckBox.isSelected() + receiverTypeLabel.setEnabled(withReceiver) + receiverTypeField.setEnabled(withReceiver) + receiverDefaultValueLabel?.setEnabled(withReceiver) + receiverDefaultValueField?.setEnabled(withReceiver) + } + + val documentManager = PsiDocumentManager.getInstance(myProject) + val psiFactory = JetPsiFactory(myProject) + + return with(FormBuilder.createFormBuilder()) { + if (!((methodDescriptor.baseDeclaration as? JetProperty)?.isLocal() ?: false)) { + visibilityCombo.setSelectedItem(methodDescriptor.getVisibility()) + addLabeledComponent("&Visibility: ", visibilityCombo) + } + + addLabeledComponent("&Name: ", nameField) + + val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReturnType(), + methodDescriptor.baseDeclaration) + returnTypeField = EditorTextField(documentManager.getDocument(returnTypeCodeFragment), myProject, JetFileType.INSTANCE) + addLabeledComponent("&Type: ", returnTypeField) + + addSeparator() + + val receiverTypeCheckBox = JCheckBox("Extension property: ") + receiverTypeCheckBox.setMnemonic('x') + receiverTypeCheckBox.addActionListener { updateReceiverUI() } + receiverTypeCheckBox.setSelected(methodDescriptor.receiver != null) + addComponent(receiverTypeCheckBox) + this@JetChangePropertySignatureDialog.receiverTypeCheckBox = receiverTypeCheckBox + + val receiverTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReceiverType() ?: "", + methodDescriptor.baseDeclaration) + receiverTypeField = EditorTextField(documentManager.getDocument(receiverTypeCodeFragment), myProject, JetFileType.INSTANCE) + receiverTypeLabel = JLabel("Receiver type: ") + receiverTypeLabel.setDisplayedMnemonic('t') + addLabeledComponent(receiverTypeLabel, receiverTypeField) + + if (methodDescriptor.receiver == null) { + val receiverDefaultValueCodeFragment = psiFactory.createExpressionCodeFragment("", methodDescriptor.baseDeclaration) + receiverDefaultValueField = EditorTextField(documentManager.getDocument(receiverDefaultValueCodeFragment), + myProject, + JetFileType.INSTANCE) + receiverDefaultValueLabel = JLabel("Default receiver value: ") + receiverDefaultValueLabel!!.setDisplayedMnemonic('D') + addLabeledComponent(receiverDefaultValueLabel, receiverDefaultValueField!!) + } + + updateReceiverUI() + + getPanel() + } + } + + private fun getDefaultReceiverValue(): JetExpression? { + val receiverDefaultValue = receiverDefaultValueField?.getText() ?: "" + return if (receiverDefaultValue.isNotEmpty()) JetPsiFactory(myProject).createExpression(receiverDefaultValue) else null + } + + override fun canRun() { + val psiFactory = JetPsiFactory(myProject) + + psiFactory.createSimpleName(nameField.getText()).validateElement("Invalid name") + psiFactory.createType(returnTypeField.getText()).validateElement("Invalid return type") + if (receiverTypeCheckBox.isSelected()) { + psiFactory.createType(receiverTypeField.getText()).validateElement("Invalid receiver type") + } + getDefaultReceiverValue()?.validateElement("Invalid default receiver value") + } + + override fun doAction() { + val descriptor = (methodDescriptor as? JetMutableMethodDescriptor)?.original ?: methodDescriptor + + val receiver = if (receiverTypeCheckBox.isSelected()) { + descriptor.receiver ?: JetParameterInfo(callableDescriptor = descriptor.baseDescriptor, + name = "receiver", + defaultValueForCall = getDefaultReceiverValue()) + } else null + receiver?.currentTypeText = receiverTypeField.getText() + val changeInfo = JetChangeInfo(descriptor, + nameField.getText(), + null, + returnTypeField.getText(), + visibilityCombo.getSelectedItem() as Visibility, + emptyList(), + receiver, + descriptor.getMethod()) + + invokeRefactoring(JetChangeSignatureProcessor(myProject, changeInfo, commandName ?: getTitle())) + } + + companion object { + fun createProcessorForSilentRefactoring( + project: Project, + commandName: String, + descriptor: JetMethodDescriptor + ): BaseRefactoringProcessor { + val originalDescriptor = (descriptor as? JetMutableMethodDescriptor)?.original ?: descriptor + val changeInfo = JetChangeInfo(methodDescriptor = originalDescriptor, context = originalDescriptor.getMethod()) + changeInfo.setNewName(descriptor.getName()) + changeInfo.receiverParameterInfo = descriptor.receiver + return JetChangeSignatureProcessor(project, changeInfo, commandName) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignature.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignature.kt index 69b1082d332..7abb411c31e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignature.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignature.kt @@ -23,11 +23,15 @@ import com.intellij.psi.PsiElement import com.intellij.refactoring.changeSignature.ChangeSignatureHandler import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring +import org.jetbrains.kotlin.psi.JetClass +import org.jetbrains.kotlin.psi.JetFunction +import org.jetbrains.kotlin.psi.JetProperty +import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.OverrideResolver @@ -50,55 +54,64 @@ fun JetMethodDescriptor.modify(action: (JetMutableMethodDescriptor) -> Unit): Je } public fun runChangeSignature(project: Project, - functionDescriptor: FunctionDescriptor, + callableDescriptor: CallableDescriptor, configuration: JetChangeSignatureConfiguration, bindingContext: BindingContext, defaultValueContext: PsiElement, commandName: String? = null): Boolean { - return JetChangeSignature(project, functionDescriptor, configuration, bindingContext, defaultValueContext, commandName).run() + return JetChangeSignature(project, callableDescriptor, configuration, bindingContext, defaultValueContext, commandName).run() } public class JetChangeSignature(project: Project, - functionDescriptor: FunctionDescriptor, + callableDescriptor: CallableDescriptor, val configuration: JetChangeSignatureConfiguration, bindingContext: BindingContext, val defaultValueContext: PsiElement, - commandName: String?): CallableRefactoring(project, functionDescriptor, bindingContext, commandName) { + commandName: String?): CallableRefactoring(project, callableDescriptor, bindingContext, commandName) { private val LOG = Logger.getInstance(javaClass()) override fun forcePerformForSelectedFunctionOnly() = configuration.forcePerformForSelectedFunctionOnly() - override fun performRefactoring(descriptorsForChange: Collection) { - assert (descriptorsForChange.all { it is FunctionDescriptor }) { - "Function descriptors expected: " + descriptorsForChange.joinToString(separator = "\n") + private fun runSilentRefactoring(descriptor: JetMethodDescriptor) { + val commandName = commandName ?: ChangeSignatureHandler.REFACTORING_NAME + val processor = when (descriptor.baseDeclaration) { + is JetFunction, is JetClass -> { + JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature(project, commandName, descriptor, defaultValueContext) + } + is JetProperty -> { + JetChangePropertySignatureDialog.createProcessorForSilentRefactoring(project, commandName, descriptor) + } + else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}") + } + processor.run() + } + + private fun runInteractiveRefactoring(descriptor: JetMethodDescriptor) { + val dialog = when (descriptor.baseDeclaration) { + is JetFunction, is JetClass -> JetChangeSignatureDialog(project, descriptor, defaultValueContext, commandName) + is JetProperty -> JetChangePropertySignatureDialog(project, descriptor, commandName) + else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}") } - @suppress("UNCHECKED_CAST") - val adjustedDescriptor = adjustDescriptor(descriptorsForChange as Collection) - if (adjustedDescriptor == null) return + dialog.show() + } - val affectedFunctions = adjustedDescriptor.affectedFunctions.map { it.getElement() }.filterNotNull() + override fun performRefactoring(descriptorsForChange: Collection) { + val adjustedDescriptor = adjustDescriptor(descriptorsForChange) ?: return + val affectedFunctions = adjustedDescriptor.affectedCallables.map { it.getElement() }.filterNotNull() if (affectedFunctions.any { !checkModifiable(it) }) return - if (configuration.performSilently(affectedFunctions) - || ApplicationManager.getApplication()!!.isUnitTestMode()) { - JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature( - project, - commandName ?: ChangeSignatureHandler.REFACTORING_NAME, - adjustedDescriptor, - defaultValueContext - ).run() + if (configuration.performSilently(affectedFunctions) || ApplicationManager.getApplication()!!.isUnitTestMode()) { + runSilentRefactoring(adjustedDescriptor) } else { - val dialog = JetChangeSignatureDialog(project, adjustedDescriptor, defaultValueContext, commandName) - - dialog.show() + runInteractiveRefactoring(adjustedDescriptor) } } - fun adjustDescriptor(descriptorsForSignatureChange: Collection): JetMethodDescriptor? { + fun adjustDescriptor(descriptorsForSignatureChange: Collection): JetMethodDescriptor? { val baseDescriptor = preferContainedInClass(descriptorsForSignatureChange) val functionDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, baseDescriptor) if (functionDeclaration == null) { @@ -114,7 +127,7 @@ public class JetChangeSignature(project: Project, return configuration.configure(originalDescriptor, bindingContext) } - private fun preferContainedInClass(descriptorsForSignatureChange: Collection): FunctionDescriptor { + private fun preferContainedInClass(descriptorsForSignatureChange: Collection): CallableDescriptor { for (descriptor in descriptorsForSignatureChange) { val containingDeclaration = descriptor.getContainingDeclaration() if (containingDeclaration is ClassDescriptor && containingDeclaration.getKind() != ClassKind.INTERFACE) { @@ -127,15 +140,22 @@ public class JetChangeSignature(project: Project, } TestOnly public fun createChangeInfo(project: Project, - functionDescriptor: FunctionDescriptor, + callableDescriptor: CallableDescriptor, configuration: JetChangeSignatureConfiguration, bindingContext: BindingContext, defaultValueContext: PsiElement): JetChangeInfo? { - val jetChangeSignature = JetChangeSignature(project, functionDescriptor, configuration, bindingContext, defaultValueContext, null) - val declarations = OverrideResolver.getDeepestSuperDeclarations(functionDescriptor) + val jetChangeSignature = JetChangeSignature(project, callableDescriptor, configuration, bindingContext, defaultValueContext, null) + val declarations = if (callableDescriptor is CallableMemberDescriptor) { + OverrideResolver.getDeepestSuperDeclarations(callableDescriptor) + } else listOf(callableDescriptor) val adjustedDescriptor = jetChangeSignature.adjustDescriptor(declarations) ?: return null - val processor = JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature(project, ChangeSignatureHandler.REFACTORING_NAME, adjustedDescriptor, defaultValueContext) as JetChangeSignatureProcessor + val processor = JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature( + project, + ChangeSignatureHandler.REFACTORING_NAME, + adjustedDescriptor, + defaultValueContext + ) as JetChangeSignatureProcessor return processor.getChangeInfo() } 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 0788fb1eff4..92ce4ba83f1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureData.kt @@ -23,6 +23,8 @@ import com.intellij.refactoring.changeSignature.OverriderUsageInfo import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.asJava.KotlinLightMethod import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze @@ -30,10 +32,14 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.core.CollectingNameValidator import org.jetbrains.kotlin.idea.core.KotlinNameSuggester -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage +import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage +import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest +import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.JetCallableDeclaration import org.jetbrains.kotlin.psi.JetClass import org.jetbrains.kotlin.psi.JetFunction +import org.jetbrains.kotlin.psi.JetNamedDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import java.util.Collections @@ -41,9 +47,9 @@ import java.util.HashSet import kotlin.properties.Delegates public class JetChangeSignatureData( - override val baseDescriptor: FunctionDescriptor, + override val baseDescriptor: CallableDescriptor, override val baseDeclaration: PsiElement, - private val descriptorsForSignatureChange: Collection + private val descriptorsForSignatureChange: Collection ) : JetMethodDescriptor { private val parameters: List override val receiver: JetParameterInfo? @@ -60,7 +66,7 @@ public class JetChangeSignatureData( .mapTo(receiver?.let{ arrayListOf(it) } ?: arrayListOf()) { parameterDescriptor -> val jetParameter = valueParameters?.get(parameterDescriptor.getIndex()) JetParameterInfo( - functionDescriptor = baseDescriptor, + callableDescriptor = baseDescriptor, originalIndex = parameterDescriptor.getIndex(), name = parameterDescriptor.getName().asString(), type = parameterDescriptor.getType(), @@ -72,8 +78,8 @@ public class JetChangeSignatureData( } private fun createReceiverInfoIfNeeded(): JetParameterInfo? { - val function = baseDeclaration as? JetFunction ?: return null - val bodyScope = function.getBodyExpression()?.let { it.analyze()[BindingContext.RESOLUTION_SCOPE, it] } + val callable = baseDeclaration as? JetCallableDeclaration ?: return null + val bodyScope = (callable as? JetFunction)?.getBodyExpression()?.let { it.analyze()[BindingContext.RESOLUTION_SCOPE, it] } val paramNames = baseDescriptor.getValueParameters().map { it.getName().asString() } val validator = bodyScope?.let { bodyScope -> CollectingNameValidator(paramNames) { @@ -83,34 +89,37 @@ public class JetChangeSignatureData( } ?: CollectingNameValidator(paramNames) val receiverType = baseDescriptor.getExtensionReceiverParameter()?.getType() ?: return null val receiverName = KotlinNameSuggester.suggestNamesByType(receiverType, validator, "receiver").first() - return JetParameterInfo(functionDescriptor = baseDescriptor, name = receiverName, type = receiverType) + return JetParameterInfo(callableDescriptor = baseDescriptor, name = receiverName, type = receiverType) } - override val primaryFunctions: Collection> by Delegates.lazy { + override val primaryCallables: Collection> by Delegates.lazy { descriptorsForSignatureChange.map { val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(baseDeclaration.getProject(), it) assert(declaration != null) { "No declaration found for " + baseDescriptor } - JetFunctionDefinitionUsage(declaration, it, null, null) + JetCallableDefinitionUsage(declaration, it, null, null) } } - override val originalPrimaryFunction: JetFunctionDefinitionUsage by Delegates.lazy { - primaryFunctions.first { it.getDeclaration() == baseDeclaration } + override val originalPrimaryCallable: JetCallableDefinitionUsage by Delegates.lazy { + primaryCallables.first { it.getDeclaration() == baseDeclaration } } - override val affectedFunctions: Collection by Delegates.lazy { - primaryFunctions + primaryFunctions.flatMapTo(HashSet()) { primaryFunction -> - val primaryDeclaration = primaryFunction.getDeclaration() as? JetFunction - val lightMethod = primaryDeclaration?.let { LightClassUtil.getLightClassMethod(it) } - val overrides = lightMethod?.let { OverridingMethodsSearch.search(it).findAll() } ?: Collections.emptyList() - overrides.map { method -> - if (method is KotlinLightMethod) { - val overridingDeclaration = method.getOrigin() - val overridingDescriptor = overridingDeclaration?.resolveToDescriptor() as FunctionDescriptor - JetFunctionDefinitionUsage(overridingDeclaration, overridingDescriptor, primaryFunction, null) - } - else OverriderUsageInfo(method, lightMethod, true, true, true) - }.filterNotNullTo(HashSet()) + override val affectedCallables: Collection by Delegates.lazy { + primaryCallables + primaryCallables.flatMapTo(HashSet()) { primaryFunction -> + val primaryDeclaration = primaryFunction.getDeclaration() as? JetCallableDeclaration + val lightMethods = primaryDeclaration?.toLightMethods() ?: Collections.emptyList() + lightMethods.flatMap { baseMethod -> + OverridingMethodsSearch + .search(baseMethod) + .map { overridingMethod -> + if (overridingMethod is KotlinLightMethod) { + val overridingDeclaration = overridingMethod.namedUnwrappedElement as JetNamedDeclaration + val overridingDescriptor = overridingDeclaration.resolveToDescriptor() as CallableDescriptor + JetCallableDefinitionUsage(overridingDeclaration, overridingDescriptor, primaryFunction, null) + } + else OverriderUsageInfo(overridingMethod, baseMethod, true, true, true) + }.filterNotNullTo(HashSet()) + } } } 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 b07e7ae0a73..117c64a72ef 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureDialog.java @@ -416,7 +416,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< getMethodName(), myDefaultValueContext ); - return changeInfo.getNewSignature(getMethodDescriptor().getOriginalPrimaryFunction()); + return changeInfo.getNewSignature(getMethodDescriptor().getOriginalPrimaryCallable()); } @Override diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureHandler.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureHandler.java index beeaeea3bf5..2bf88b1831d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureHandler.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureHandler.java @@ -34,10 +34,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.asJava.AsJavaPackage; -import org.jetbrains.kotlin.descriptors.ClassDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.FunctionDescriptor; -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils; import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde; @@ -57,44 +54,44 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { @Nullable public static PsiElement findTargetForRefactoring(@NotNull PsiElement element) { if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) { - return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetClass.class); + return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetProperty.class, JetClass.class); } JetTypeParameterList typeParameterList = PsiTreeUtil.getParentOfType(element, JetTypeParameterList.class); if (typeParameterList != null) { - return PsiTreeUtil.getParentOfType(typeParameterList, JetFunction.class, JetClass.class); + return PsiTreeUtil.getParentOfType(typeParameterList, JetFunction.class, JetProperty.class, JetClass.class); } PsiElement elementParent = element.getParent(); - if (elementParent instanceof JetNamedFunction && ((JetNamedFunction) elementParent).getNameIdentifier() == element) { - return elementParent; - } - if (elementParent instanceof JetClass && ((JetClass) elementParent).getNameIdentifier() == element) { - return elementParent; - } - if (elementParent instanceof JetSecondaryConstructor && - ((JetSecondaryConstructor) elementParent).getConstructorKeyword() == element) { - return elementParent; - } + if ((elementParent instanceof JetNamedFunction || elementParent instanceof JetClass || elementParent instanceof JetProperty) + && ((JetNamedDeclaration) elementParent).getNameIdentifier() == element) return elementParent; + if (elementParent instanceof JetSecondaryConstructor && + ((JetSecondaryConstructor) elementParent).getConstructorKeyword() == element) return elementParent; + + JetExpression calleeExpr; JetCallElement call = PsiTreeUtil.getParentOfType(element, JetCallExpression.class, JetDelegatorToSuperCall.class, JetConstructorDelegationCall.class); - if (call == null) return null; - - JetExpression receiverExpr = call.getCalleeExpression(); - if (receiverExpr instanceof JetConstructorCalleeExpression) { - receiverExpr = ((JetConstructorCalleeExpression) receiverExpr).getConstructorReferenceExpression(); + if (call != null) { + calleeExpr = call.getCalleeExpression(); } - if (receiverExpr instanceof JetSimpleNameExpression || receiverExpr instanceof JetConstructorDelegationReferenceExpression) { + else { + calleeExpr = PsiTreeUtil.getParentOfType(element, JetSimpleNameExpression.class); + } + + if (calleeExpr instanceof JetConstructorCalleeExpression) { + calleeExpr = ((JetConstructorCalleeExpression) calleeExpr).getConstructorReferenceExpression(); + } + if (calleeExpr instanceof JetSimpleNameExpression || calleeExpr instanceof JetConstructorDelegationReferenceExpression) { JetElement jetElement = PsiTreeUtil.getParentOfType(element, JetElement.class); if (jetElement == null) return null; BindingContext bindingContext = ResolvePackage.analyze(jetElement, BodyResolveMode.FULL); - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) receiverExpr); + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpr); - if (descriptor instanceof ClassDescriptor || descriptor instanceof FunctionDescriptor) return receiverExpr; + if (descriptor instanceof ClassDescriptor || descriptor instanceof CallableDescriptor) return calleeExpr; } return null; @@ -107,20 +104,20 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { @Nullable Editor editor ) { BindingContext bindingContext = ResolvePackage.analyze(element, BodyResolveMode.FULL); - - FunctionDescriptor functionDescriptor = findDescriptor(element, project, editor, bindingContext); - if (functionDescriptor == null) { + + CallableDescriptor callableDescriptor = findDescriptor(element, project, editor, bindingContext); + if (callableDescriptor == null) { return; } - if (functionDescriptor instanceof JavaCallableMemberDescriptor) { - PsiElement declaration = DescriptorToSourceUtilsIde.INSTANCE$.getAnyDeclaration(project, functionDescriptor); - assert declaration instanceof PsiMethod : "PsiMethod expected: " + functionDescriptor; + if (callableDescriptor instanceof JavaCallableMemberDescriptor) { + PsiElement declaration = DescriptorToSourceUtilsIde.INSTANCE$.getAnyDeclaration(project, callableDescriptor); + assert declaration instanceof PsiMethod : "PsiMethod expected: " + callableDescriptor; ChangeSignatureUtil.invokeChangeSignatureOn((PsiMethod) declaration, project); return; } - if (TasksPackage.isDynamic(functionDescriptor)) { + if (TasksPackage.isDynamic(callableDescriptor)) { if (editor != null) { CodeInsightUtils.showErrorHint( project, @@ -133,7 +130,7 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { return; } - runChangeSignature(project, functionDescriptor, emptyConfiguration(), bindingContext, context, null); + runChangeSignature(project, callableDescriptor, emptyConfiguration(), bindingContext, context, null); } @TestOnly @@ -208,7 +205,7 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { } @Nullable - public static FunctionDescriptor findDescriptor( + public static CallableDescriptor findDescriptor( @NotNull PsiElement element, @NotNull Project project, @Nullable Editor editor, @@ -244,6 +241,9 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { return (FunctionDescriptor) descriptor; } + else if (descriptor instanceof PropertyDescriptor) { + return (PropertyDescriptor) descriptor; + } else { String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message( "error.wrong.caret.position.function.or.constructor.name")); diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureProcessor.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureProcessor.java index 38864e103b0..5a9045dbf25 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureProcessor.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureProcessor.java @@ -21,7 +21,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.changeSignature.*; +import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase; +import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor; +import com.intellij.refactoring.changeSignature.JavaChangeInfo; +import com.intellij.refactoring.changeSignature.JavaChangeSignatureUsageProcessor; import com.intellij.refactoring.rename.RenameUtil; import com.intellij.refactoring.ui.ConflictsDialog; import com.intellij.usageView.UsageInfo; @@ -29,8 +32,6 @@ import com.intellij.usageView.UsageViewDescriptor; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; import kotlin.KotlinPackage; -import kotlin.Pair; -import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetUsageInfo; import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinWrapperForJavaUsageInfos; @@ -62,10 +63,13 @@ public class JetChangeSignatureProcessor extends ChangeSignatureProcessorBase { protected UsageInfo[] findUsages() { List allUsages = new ArrayList(); - JavaChangeInfo javaChangeInfo = getChangeInfo().getOrCreateJavaChangeInfo(); - if (javaChangeInfo != null) { - UsageInfo[] javaUsages = new JavaChangeSignatureUsageProcessor().findUsages(javaChangeInfo); - allUsages.add(new KotlinWrapperForJavaUsageInfos(javaUsages, getChangeInfo().getMethod())); + List javaChangeInfos = getChangeInfo().getOrCreateJavaChangeInfos(); + if (javaChangeInfos != null) { + JavaChangeSignatureUsageProcessor javaProcessor = new JavaChangeSignatureUsageProcessor(); + for (JavaChangeInfo javaChangeInfo : javaChangeInfos) { + UsageInfo[] javaUsages = javaProcessor.findUsages(javaChangeInfo); + allUsages.add(new KotlinWrapperForJavaUsageInfos(javaChangeInfo, javaUsages, getChangeInfo().getMethod())); + } } KotlinPackage.filterIsInstanceTo(super.findUsages(), allUsages, JetUsageInfo.class); 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 25c2def5e92..d9904cd5c54 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -21,9 +21,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.changeSignature.ChangeInfo; @@ -40,7 +40,6 @@ import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; -import jet.runtime.typeinfo.JetValueParameter; import kotlin.KotlinPackage; import kotlin.Unit; import kotlin.jvm.functions.Function1; @@ -56,13 +55,13 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde; import org.jetbrains.kotlin.idea.codeInsight.JetFileReferencesResolver; import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage; import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*; -import org.jetbrains.kotlin.idea.refactoring.rename.UnresolvableConventionViolationUsageInfo; import org.jetbrains.kotlin.idea.references.JetSimpleNameReference; import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchPackage; import org.jetbrains.kotlin.kdoc.psi.impl.KDocName; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage; import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.resolve.BindingContext; @@ -72,7 +71,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind; import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode; import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; @@ -80,10 +78,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor { @Override @@ -104,8 +99,8 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro private static void findAllMethodUsages(JetChangeInfo changeInfo, Set result) { for (UsageInfo functionUsageInfo : ChangeSignaturePackage.getAffectedFunctions(changeInfo)) { - if (functionUsageInfo instanceof JetFunctionDefinitionUsage) { - findOneMethodUsages((JetFunctionDefinitionUsage) functionUsageInfo, changeInfo, result); + if (functionUsageInfo instanceof JetCallableDefinitionUsage) { + findOneMethodUsages((JetCallableDefinitionUsage) functionUsageInfo, changeInfo, result); } else { result.add(functionUsageInfo); @@ -123,7 +118,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro JetCallElement callElement = PsiTreeUtil.getParentOfType(element, JetCallElement.class); JetExpression calleeExpression = callElement != null ? callElement.getCalleeExpression() : null; if (calleeExpression != null && PsiTreeUtil.isAncestor(calleeExpression, element, false)) { - result.add(new JetFunctionCallUsage(callElement, changeInfo.getMethodDescriptor().getOriginalPrimaryFunction())); + result.add(new JetFunctionCallUsage(callElement, changeInfo.getMethodDescriptor().getOriginalPrimaryCallable())); } } } @@ -131,7 +126,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } private static void findOneMethodUsages( - @NotNull JetFunctionDefinitionUsage functionUsageInfo, + @NotNull JetCallableDefinitionUsage functionUsageInfo, final JetChangeInfo changeInfo, final Set result ) { @@ -160,6 +155,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall) result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionUsageInfo)); } + else if (element instanceof JetSimpleNameExpression && functionPsi instanceof JetProperty) { + result.add(new JetPropertyCallUsage((JetSimpleNameExpression) element)); + } } } @@ -168,9 +166,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (oldName != null) TextOccurrencesUtil.findNonCodeUsages(functionPsi, oldName, true, true, changeInfo.getNewName(), result); - List oldParameters = functionPsi instanceof JetFunction - ? ((JetFunction) functionPsi).getValueParameters() - : ((JetClass) functionPsi).getPrimaryConstructorParameters(); + List oldParameters = PsiUtilPackage.getValueParameters((JetNamedDeclaration) functionPsi); JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); @@ -221,7 +217,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } private static void processInternalReferences( - JetFunctionDefinitionUsage functionUsageInfo, + JetCallableDefinitionUsage functionUsageInfo, JetTreeVisitor visitor ) { JetFunction jetFunction = (JetFunction) functionUsageInfo.getDeclaration(); @@ -238,12 +234,12 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } private static void findOriginalReceiversUsages( - @NotNull final JetFunctionDefinitionUsage functionUsageInfo, + @NotNull final JetCallableDefinitionUsage functionUsageInfo, @NotNull final Set result, @NotNull final JetChangeInfo changeInfo ) { final JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); - final FunctionDescriptor functionDescriptor = functionUsageInfo.getOriginalFunctionDescriptor(); + final CallableDescriptor callableDescriptor = functionUsageInfo.getOriginalCallableDescriptor(); processInternalReferences( functionUsageInfo, new JetTreeVisitor() { @@ -254,7 +250,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (originalReceiverInfo != null && !changeInfo.hasParameter(originalReceiverInfo)) return; if (!(expression.getParent() instanceof JetThisExpression)) return; - if (receiverDescriptor == functionDescriptor.getExtensionReceiverParameter()) { + if (receiverDescriptor == callableDescriptor.getExtensionReceiverParameter()) { assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText(); result.add(new JetParameterUsage(expression, originalReceiverInfo, functionUsageInfo)); } @@ -270,7 +266,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro @NotNull ThisReceiver receiverValue ) { DeclarationDescriptor targetDescriptor = receiverValue.getDeclarationDescriptor(); - if (targetDescriptor == functionDescriptor) { + if (targetDescriptor == callableDescriptor) { assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText(); result.add(new JetImplicitThisToParameterUsage(callElement, originalReceiverInfo, functionUsageInfo)); } @@ -407,7 +403,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro PsiElement function = info.getMethod(); PsiElement element = function != null ? function : changeInfo.getContext(); BindingContext bindingContext = ResolvePackage.analyze((JetElement) element, BodyResolveMode.FULL); - FunctionDescriptor oldDescriptor = ChangeSignaturePackage.getOriginalBaseFunctionDescriptor(changeInfo); + CallableDescriptor oldDescriptor = ChangeSignaturePackage.getOriginalBaseFunctionDescriptor(changeInfo); DeclarationDescriptor containingDeclaration = oldDescriptor.getContainingDeclaration(); JetScope parametersScope = null; @@ -416,17 +412,21 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro else if (function instanceof JetFunction) parametersScope = org.jetbrains.kotlin.idea.refactoring.RefactoringPackage.getBodyScope((JetFunction) function, bindingContext); - JetScope functionScope = org.jetbrains.kotlin.idea.refactoring.RefactoringPackage.getContainingScope(oldDescriptor, bindingContext); + JetScope callableScope = org.jetbrains.kotlin.idea.refactoring.RefactoringPackage.getContainingScope(oldDescriptor, bindingContext); JetMethodDescriptor.Kind kind = ChangeSignaturePackage.getKind(changeInfo); - if (!kind.getIsConstructor() && functionScope != null && !info.getNewName().isEmpty()) { - for (FunctionDescriptor conflict : functionScope.getFunctions(Name.identifier(info.getNewName()))) { + if (!kind.getIsConstructor() && callableScope != null && !info.getNewName().isEmpty()) { + Name newName = Name.identifier(info.getNewName()); + Collection conflicts = oldDescriptor instanceof FunctionDescriptor + ? callableScope.getFunctions(newName) + : callableScope.getProperties(newName); + for (CallableDescriptor conflict : conflicts) { if (conflict == oldDescriptor) continue; PsiElement conflictElement = DescriptorToSourceUtils.descriptorToDeclaration(conflict); if (conflictElement == changeInfo.getMethod()) continue; - if (getFunctionParameterTypes(conflict).equals(getFunctionParameterTypes(oldDescriptor))) { + if (getCallableParameterTypes(conflict).equals(getCallableParameterTypes(oldDescriptor))) { result.putValue(conflictElement, "Function already exists: '" + DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(conflict) + "'"); break; } @@ -464,7 +464,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); - if (function instanceof JetNamedFunction && newReceiverInfo != originalReceiverInfo) { + if (function instanceof JetCallableDeclaration && newReceiverInfo != originalReceiverInfo) { findReceiverIntroducingConflicts(result, function, newReceiverInfo); findInternalExplicitReceiverConflicts(refUsages.get(), result, originalReceiverInfo); findThisLabelConflicts((JetChangeInfo) info, refUsages, result, changeInfo, function); @@ -525,10 +525,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro ) { if (originalReceiverInfo == null) { for (UsageInfo usageInfo : usages) { - if (!(usageInfo instanceof JetFunctionCallUsage)) continue; + if (!(usageInfo instanceof JetFunctionCallUsage || usageInfo instanceof JetPropertyCallUsage)) continue; - JetFunctionCallUsage callUsage = (JetFunctionCallUsage) usageInfo; - JetElement callElement = callUsage.getElement(); + JetElement callElement = (JetElement) usageInfo.getElement(); if (callElement == null) continue; PsiElement parent = callElement.getParent(); @@ -546,7 +545,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro PsiElement callable, JetParameterInfo newReceiverInfo ) { - if (newReceiverInfo != null && ((JetNamedFunction) callable).getBodyExpression() != null) { + if (newReceiverInfo != null && (callable instanceof JetNamedFunction) && ((JetNamedFunction) callable).getBodyExpression() != null) { Map noReceiverRefToContext = KotlinPackage.filter( JetFileReferencesResolver.INSTANCE$.resolve((JetNamedFunction) callable, true, true), new Function1, Boolean>() { @@ -606,7 +605,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } } - private static List getFunctionParameterTypes(FunctionDescriptor descriptor) { + private static List getCallableParameterTypes(CallableDescriptor descriptor) { return ContainerUtil.map(descriptor.getValueParameters(), new Function() { @Override public JetType fun(ValueParameterDescriptor descriptor) { @@ -710,26 +709,33 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro boolean isJavaMethodUsage = isJavaMethodUsage(usageInfo); if (usageInfo instanceof KotlinWrapperForJavaUsageInfos) { - JavaChangeInfo javaChangeInfo = ((JetChangeInfo) changeInfo).getOrCreateJavaChangeInfo(); - assert javaChangeInfo != null : "JavaChangeInfo not found: " + method.getText(); - UsageInfo[] javaUsageInfos = ((KotlinWrapperForJavaUsageInfos) usageInfo).getJavaUsageInfos(); + List javaChangeInfos = ((JetChangeInfo) changeInfo).getOrCreateJavaChangeInfos(); + assert javaChangeInfos != null : "JavaChangeInfo not found: " + method.getText(); + + KotlinWrapperForJavaUsageInfos wrapperForJavaUsageInfos = (KotlinWrapperForJavaUsageInfos) usageInfo; + UsageInfo[] javaUsageInfos = wrapperForJavaUsageInfos.getJavaUsageInfos(); ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions(); - NullabilityPropagator nullabilityPropagator = new NullabilityPropagator(javaChangeInfo.getMethod()); + for (JavaChangeInfo javaChangeInfo : javaChangeInfos) { + // Match names so that getter/setter usages are not confused with each other + if (!javaChangeInfo.getOldName().equals(wrapperForJavaUsageInfos.getJavaChangeInfo().getOldName())) continue; - for (UsageInfo usage : javaUsageInfos) { - if (usage instanceof OverriderUsageInfo && beforeMethodChange) continue; - for (ChangeSignatureUsageProcessor processor : processors) { - if (processor instanceof JetChangeSignatureUsageProcessor) continue; - if (usage instanceof OverriderUsageInfo) { - processor.processUsage(javaChangeInfo, usage, true, javaUsageInfos); + NullabilityPropagator nullabilityPropagator = new NullabilityPropagator(javaChangeInfo.getMethod()); + + for (UsageInfo usage : javaUsageInfos) { + if (usage instanceof OverriderUsageInfo && beforeMethodChange) continue; + for (ChangeSignatureUsageProcessor processor : processors) { + if (processor instanceof JetChangeSignatureUsageProcessor) continue; + if (usage instanceof OverriderUsageInfo) { + processor.processUsage(javaChangeInfo, usage, true, javaUsageInfos); + } + if (processor.processUsage(javaChangeInfo, usage, beforeMethodChange, javaUsageInfos)) break; } - if (processor.processUsage(javaChangeInfo, usage, beforeMethodChange, javaUsageInfos)) break; - } - if (usage instanceof OverriderUsageInfo) { - PsiMethod overridingMethod = ((OverriderUsageInfo)usage).getOverridingMethod(); - if (overridingMethod != null && !(overridingMethod instanceof KotlinLightMethod)) { - nullabilityPropagator.processMethod(overridingMethod); + if (usage instanceof OverriderUsageInfo) { + PsiMethod overridingMethod = ((OverriderUsageInfo) usage).getOverridingMethod(); + if (overridingMethod != null && !(overridingMethod instanceof KotlinLightMethod)) { + nullabilityPropagator.processMethod(overridingMethod); + } } } } @@ -792,7 +798,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (!(changeInfo instanceof JetChangeInfo)) return false; JetChangeInfo jetChangeInfo = (JetChangeInfo) changeInfo; - for (JetFunctionDefinitionUsage primaryFunction : jetChangeInfo.getMethodDescriptor().getPrimaryFunctions()) { + for (JetCallableDefinitionUsage primaryFunction : jetChangeInfo.getMethodDescriptor().getPrimaryCallables()) { primaryFunction.processUsage(jetChangeInfo, primaryFunction.getDeclaration()); } jetChangeInfo.primaryMethodUpdated(); 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 b84a08d8949..fa2c7911a7e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMethodDescriptor.kt @@ -19,10 +19,10 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature import com.intellij.psi.PsiElement import com.intellij.refactoring.changeSignature.MethodDescriptor import com.intellij.usageView.UsageInfo -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.Visibility -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers public trait JetMethodDescriptor : MethodDescriptor { @@ -42,11 +42,11 @@ public trait JetMethodDescriptor : MethodDescriptor - val primaryFunctions: Collection> - val affectedFunctions: Collection + val originalPrimaryCallable: JetCallableDefinitionUsage + val primaryCallables: Collection> + val affectedCallables: Collection val receiver: JetParameterInfo? } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt index 2130cb187c1..9175e0610eb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.compareDescriptors -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage +import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage import org.jetbrains.kotlin.idea.references.JetReference import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.psi.* @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.types.JetType import java.util.LinkedHashMap public class JetParameterInfo( - val functionDescriptor: FunctionDescriptor, + val callableDescriptor: CallableDescriptor, val originalIndex: Int = -1, private var name: String, type: JetType? = null, @@ -61,7 +61,7 @@ public class JetParameterInfo( object : JetTreeVisitorVoid() { private fun selfParameterOrNull(parameter: DeclarationDescriptor?): ValueParameterDescriptor? { return if (parameter is ValueParameterDescriptor && - compareDescriptors(project, parameter.getContainingDeclaration(), functionDescriptor)) { + compareDescriptors(project, parameter.getContainingDeclaration(), callableDescriptor)) { parameter } else null } @@ -69,12 +69,12 @@ public class JetParameterInfo( private fun selfReceiverOrNull(receiverDescriptor: DeclarationDescriptor?): DeclarationDescriptor? { if (compareDescriptors(project, receiverDescriptor, - functionDescriptor.getExtensionReceiverParameter()?.getContainingDeclaration())) { + callableDescriptor.getExtensionReceiverParameter()?.getContainingDeclaration())) { return receiverDescriptor } if (compareDescriptors(project, receiverDescriptor, - functionDescriptor.getDispatchReceiverParameter()?.getContainingDeclaration())) { + callableDescriptor.getDispatchReceiverParameter()?.getContainingDeclaration())) { return receiverDescriptor } return null @@ -93,7 +93,7 @@ public class JetParameterInfo( val descriptor = ref.resolveToDescriptors(context).singleOrNull() if (descriptor is ValueParameterDescriptor) return selfParameterOrNull(descriptor) - if (descriptor is PropertyDescriptor && functionDescriptor is ConstructorDescriptor) { + if (descriptor is PropertyDescriptor && callableDescriptor is ConstructorDescriptor) { val parameter = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? JetParameter return parameter?.let { selfParameterOrNull(context[BindingContext.VALUE_PARAMETER, it]) } } @@ -149,20 +149,20 @@ public class JetParameterInfo( throw UnsupportedOperationException() } - public fun renderType(parameterIndex: Int, inheritedFunction: JetFunctionDefinitionUsage<*>): String { - val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return currentTypeText - val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return currentTypeText + public fun renderType(parameterIndex: Int, inheritedCallable: JetCallableDefinitionUsage<*>): String { + val typeSubstitutor = inheritedCallable.getOrCreateTypeSubstitutor() ?: return currentTypeText + val currentBaseFunction = inheritedCallable.getBaseFunction().getCurrentCallableDescriptor() ?: return currentTypeText val parameterType = currentBaseFunction.getValueParameters().get(parameterIndex).getType() return parameterType.renderTypeWithSubstitution(typeSubstitutor, currentTypeText, true) } - public fun getInheritedName(inheritedFunction: JetFunctionDefinitionUsage<*>): String { - if (!inheritedFunction.isInherited()) return name + public fun getInheritedName(inheritedCallable: JetCallableDefinitionUsage<*>): String { + if (!inheritedCallable.isInherited()) return name - val baseFunction = inheritedFunction.getBaseFunction() - val baseFunctionDescriptor = baseFunction.getOriginalFunctionDescriptor() + val baseFunction = inheritedCallable.getBaseFunction() + val baseFunctionDescriptor = baseFunction.getOriginalCallableDescriptor() - val inheritedFunctionDescriptor = inheritedFunction.getOriginalFunctionDescriptor() + val inheritedFunctionDescriptor = inheritedCallable.getOriginalCallableDescriptor() val inheritedParameterDescriptors = inheritedFunctionDescriptor.getValueParameters() if (originalIndex < 0 || originalIndex >= baseFunctionDescriptor.getValueParameters().size() @@ -177,18 +177,18 @@ public class JetParameterInfo( } } - public fun requiresExplicitType(inheritedFunction: JetFunctionDefinitionUsage): Boolean { - val inheritedFunctionDescriptor = inheritedFunction.getOriginalFunctionDescriptor() + public fun requiresExplicitType(inheritedCallable: JetCallableDefinitionUsage): Boolean { + val inheritedFunctionDescriptor = inheritedCallable.getOriginalCallableDescriptor() if (inheritedFunctionDescriptor !is AnonymousFunctionDescriptor) return true - if (originalIndex < 0) return !inheritedFunction.hasExpectedType() + if (originalIndex < 0) return !inheritedCallable.hasExpectedType() val inheritedParameterDescriptor = inheritedFunctionDescriptor.getValueParameters().get(originalIndex) val parameter = DescriptorToSourceUtils.descriptorToDeclaration(inheritedParameterDescriptor) as? JetParameter ?: return false return parameter.getTypeReference() != null } - public fun getDeclarationSignature(parameterIndex: Int, inheritedFunction: JetFunctionDefinitionUsage): String { + public fun getDeclarationSignature(parameterIndex: Int, inheritedCallable: JetCallableDefinitionUsage): String { val buffer = StringBuilder() if (modifierList != null) { @@ -199,13 +199,13 @@ public class JetParameterInfo( buffer.append(valOrVar).append(' ') } - buffer.append(getInheritedName(inheritedFunction)) + buffer.append(getInheritedName(inheritedCallable)) - if (requiresExplicitType(inheritedFunction)) { - buffer.append(": ").append(renderType(parameterIndex, inheritedFunction)) + if (requiresExplicitType(inheritedCallable)) { + buffer.append(": ").append(renderType(parameterIndex, inheritedCallable)) } - if (!inheritedFunction.isInherited()) { + if (!inheritedCallable.isInherited()) { defaultValueForParameter?.let { buffer.append(" = ").append(it.getText()) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/typeUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/typeUtils.kt index 1f4a69ec17a..fca58008fe9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/typeUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/typeUtils.kt @@ -16,18 +16,13 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.TypeConstructor -import org.jetbrains.kotlin.types.TypeProjection -import java.util.LinkedHashMap -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage -import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure +import java.util.LinkedHashMap private fun getTypeSubstitution(baseType: JetType, derivedType: JetType): LinkedHashMap? { val substitutedType = TypeCheckingProcedure.findCorrespondingSupertype(derivedType, baseType) ?: return null @@ -40,15 +35,15 @@ private fun getTypeSubstitution(baseType: JetType, derivedType: JetType): Linked return substitution } -private fun getFunctionSubstitution( - baseFunction: FunctionDescriptor, - derivedFunction: FunctionDescriptor +private fun getCallableSubstitution( + baseCallable: CallableDescriptor, + derivedCallable: CallableDescriptor ): MutableMap? { - val baseClass = baseFunction.getContainingDeclaration() as? ClassDescriptor ?: return null - val derivedClass = derivedFunction.getContainingDeclaration() as? ClassDescriptor ?: return null + val baseClass = baseCallable.getContainingDeclaration() as? ClassDescriptor ?: return null + val derivedClass = derivedCallable.getContainingDeclaration() as? ClassDescriptor ?: return null val substitution = getTypeSubstitution(baseClass.getDefaultType(), derivedClass.getDefaultType()) ?: return null - for ((baseParam, derivedParam) in baseFunction.getTypeParameters() zip derivedFunction.getTypeParameters()) { + for ((baseParam, derivedParam) in baseCallable.getTypeParameters() zip derivedCallable.getTypeParameters()) { substitution[baseParam.getTypeConstructor()] = TypeProjectionImpl(derivedParam.getDefaultType()) } @@ -59,15 +54,15 @@ fun getTypeSubstitutor(baseType: JetType, derivedType: JetType): TypeSubstitutor return getTypeSubstitution(baseType, derivedType)?.let { TypeSubstitutor.create(it) } } -fun getFunctionSubstitutor( - baseFunction: JetFunctionDefinitionUsage<*>, - derivedFunction: JetFunctionDefinitionUsage<*> +fun getCallableSubstitutor( + baseFunction: JetCallableDefinitionUsage<*>, + derivedCallable: JetCallableDefinitionUsage<*> ): TypeSubstitutor? { - val currentBaseFunction = baseFunction.getCurrentFunctionDescriptor() - val currentDerivedFunction = derivedFunction.getCurrentFunctionDescriptor() + val currentBaseFunction = baseFunction.getCurrentCallableDescriptor() + val currentDerivedFunction = derivedCallable.getCurrentCallableDescriptor() if (currentBaseFunction == null || currentDerivedFunction == null) return null - return getFunctionSubstitution(currentBaseFunction, currentDerivedFunction)?.let { TypeSubstitutor.create(it) } + return getCallableSubstitution(currentBaseFunction, currentDerivedFunction)?.let { TypeSubstitutor.create(it) } } fun JetType.renderTypeWithSubstitution(substitutor: TypeSubstitutor?, defaultText: String, inArgumentPosition: Boolean): String { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodDeferredKotlinUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodDeferredKotlinUsage.kt index 62d67a3afa8..488c88f3947 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodDeferredKotlinUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodDeferredKotlinUsage.kt @@ -35,10 +35,10 @@ public class DeferredJavaMethodOverrideOrSAMUsage( ): JavaMethodDeferredKotlinUsage(function) { override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate { return object : JavaMethodKotlinUsageWithDelegate(function, javaMethodChangeInfo) { - override val delegateUsage = JetFunctionDefinitionUsage( + override val delegateUsage = JetCallableDefinitionUsage( function, functionDescriptor, - javaMethodChangeInfo.methodDescriptor.originalPrimaryFunction, + javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable, samCallType ) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt index 10c3bfc21c8..87187080299 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JavaMethodKotlinUsageWithDelegate.kt @@ -34,7 +34,7 @@ public abstract class JavaMethodKotlinUsageWithDelegate( public class JavaMethodKotlinCallUsage( callElement: JetCallElement, javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate(callElement, javaMethodChangeInfo) { - override protected val delegateUsage = JetFunctionCallUsage(psiElement, javaMethodChangeInfo.methodDescriptor.originalPrimaryFunction) + override protected val delegateUsage = JetFunctionCallUsage(psiElement, javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable) } public class JavaMethodKotlinDerivedDefinitionUsage( @@ -42,10 +42,10 @@ public class JavaMethodKotlinDerivedDefinitionUsage( functionDescriptor: FunctionDescriptor, javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate(function, javaMethodChangeInfo) { @suppress("CAST_NEVER_SUCCEEDS") - override protected val delegateUsage = JetFunctionDefinitionUsage( + override protected val delegateUsage = JetCallableDefinitionUsage( psiElement, functionDescriptor, - javaMethodChangeInfo.methodDescriptor.originalPrimaryFunction, + javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable, 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/JetCallableDefinitionUsage.java similarity index 74% rename from idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java rename to idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetCallableDefinitionUsage.java index 0f611f11a9e..c2189182b48 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionDefinitionUsage.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetCallableDefinitionUsage.java @@ -26,9 +26,9 @@ import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.descriptors.CallableDescriptor; 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.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage; @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.idea.util.ShortenReferences; import org.jetbrains.kotlin.idea.util.ShortenReferences.Options; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; @@ -52,14 +53,14 @@ import java.util.List; import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory; -public class JetFunctionDefinitionUsage extends JetUsageInfo { +public class JetCallableDefinitionUsage extends JetUsageInfo { @NotNull - private final FunctionDescriptor originalFunctionDescriptor; + private final CallableDescriptor originalCallableDescriptor; - private FunctionDescriptor currentFunctionDescriptor; + private CallableDescriptor currentCallableDescriptor; @NotNull - private final JetFunctionDefinitionUsage baseFunction; + private final JetCallableDefinitionUsage baseFunction; private final boolean hasExpectedType; @@ -69,24 +70,25 @@ public class JetFunctionDefinitionUsage extends JetUsageIn @Nullable private TypeSubstitutor typeSubstitutor; - public JetFunctionDefinitionUsage( + public JetCallableDefinitionUsage( @NotNull T function, - @NotNull FunctionDescriptor originalFunctionDescriptor, - @Nullable JetFunctionDefinitionUsage baseFunction, - @Nullable JetType samCallType) { + @NotNull CallableDescriptor originalCallableDescriptor, + @Nullable JetCallableDefinitionUsage baseFunction, + @Nullable JetType samCallType + ) { super(function); - this.originalFunctionDescriptor = originalFunctionDescriptor; + this.originalCallableDescriptor = originalCallableDescriptor; this.baseFunction = baseFunction != null ? baseFunction : this; - this.hasExpectedType = checkIfHasExpectedType(originalFunctionDescriptor, isInherited()); + this.hasExpectedType = checkIfHasExpectedType(originalCallableDescriptor, isInherited()); this.samCallType = samCallType; } - private static boolean checkIfHasExpectedType(@NotNull FunctionDescriptor functionDescriptor, boolean isInherited) { - if (!(functionDescriptor instanceof AnonymousFunctionDescriptor && isInherited)) return false; + private static boolean checkIfHasExpectedType(@NotNull CallableDescriptor callableDescriptor, boolean isInherited) { + if (!(callableDescriptor instanceof AnonymousFunctionDescriptor && isInherited)) return false; JetFunctionLiteral functionLiteral = - (JetFunctionLiteral) DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); - assert functionLiteral != null : "No declaration found for " + functionDescriptor; + (JetFunctionLiteral) DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor); + assert functionLiteral != null : "No declaration found for " + callableDescriptor; PsiElement parent = functionLiteral.getParent(); if (!(parent instanceof JetFunctionLiteralExpression)) return false; @@ -96,7 +98,7 @@ public class JetFunctionDefinitionUsage extends JetUsageIn } @NotNull - public JetFunctionDefinitionUsage getBaseFunction() { + public JetCallableDefinitionUsage getBaseFunction() { return baseFunction; } @@ -112,10 +114,10 @@ public class JetFunctionDefinitionUsage extends JetUsageIn if (typeSubstitutor == null) { if (samCallType == null) { - typeSubstitutor = ChangeSignaturePackage.getFunctionSubstitutor(baseFunction, this); + typeSubstitutor = ChangeSignaturePackage.getCallableSubstitutor(baseFunction, this); } else { - DeclarationDescriptor currentBaseDescriptor = baseFunction.getCurrentFunctionDescriptor(); + DeclarationDescriptor currentBaseDescriptor = baseFunction.getCurrentCallableDescriptor(); DeclarationDescriptor classDescriptor = currentBaseDescriptor != null ? currentBaseDescriptor.getContainingDeclaration() : null; @@ -140,71 +142,51 @@ public class JetFunctionDefinitionUsage extends JetUsageIn } @NotNull - public final FunctionDescriptor getOriginalFunctionDescriptor() { - return originalFunctionDescriptor; + public final CallableDescriptor getOriginalCallableDescriptor() { + return originalCallableDescriptor; } @Nullable - public final FunctionDescriptor getCurrentFunctionDescriptor() { - if (currentFunctionDescriptor == null) { + public final CallableDescriptor getCurrentCallableDescriptor() { + if (currentCallableDescriptor == null) { PsiElement element = getDeclaration(); - if (element instanceof JetFunction) { - currentFunctionDescriptor = (FunctionDescriptor) ResolvePackage.resolveToDescriptor((JetFunction) element); + if (element instanceof JetFunction || element instanceof JetProperty) { + currentCallableDescriptor = (CallableDescriptor) ResolvePackage.resolveToDescriptor((JetDeclaration) element); } else if (element instanceof JetClass) { - currentFunctionDescriptor = ((ClassDescriptor) ResolvePackage.resolveToDescriptor((JetClass) element)).getUnsubstitutedPrimaryConstructor(); + currentCallableDescriptor = ((ClassDescriptor) ResolvePackage.resolveToDescriptor((JetClass) element)).getUnsubstitutedPrimaryConstructor(); } else if (element instanceof PsiMethod) { - currentFunctionDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) element); + currentCallableDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) element); } } - return currentFunctionDescriptor; + return currentCallableDescriptor; } @Override public boolean processUsage(JetChangeInfo changeInfo, PsiElement element) { - JetParameterList parameterList; + if (!(element instanceof JetNamedDeclaration)) return true; JetPsiFactory psiFactory = JetPsiFactory(element.getProject()); - if (element instanceof JetFunction) { - JetFunction function = (JetFunction) element; - parameterList = function.getValueParameterList(); - if (changeInfo.isNameChanged()) { - PsiElement identifier = function.getNameIdentifier(); + if (changeInfo.isNameChanged()) { + PsiElement identifier = ((JetCallableDeclaration) element).getNameIdentifier(); - if (identifier != null) { - identifier.replace(psiFactory.createIdentifier(changeInfo.getNewName())); - } - } - - boolean returnTypeIsNeeded = (changeInfo.isRefactoringTarget(originalFunctionDescriptor) - || !(function instanceof JetFunctionLiteral) - || function.getTypeReference() != null) && - !(function instanceof JetConstructor); - if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) { - function.setTypeReference(null); - String returnTypeText = changeInfo.renderReturnType((JetFunctionDefinitionUsage) this); - - //TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready - if (!KotlinBuiltIns.getInstance().getUnitType().toString().equals(returnTypeText)) { - ShortenPackage.addToShorteningWaitSet( - function.setTypeReference(JetPsiFactory(function).createType(returnTypeText)), - Options.DEFAULT - ); - } + if (identifier != null) { + identifier.replace(psiFactory.createIdentifier(changeInfo.getNewName())); } } - else { - parameterList = ((JetClass) element).getPrimaryConstructorParameterList(); - } + + changeReturnTypeIfNeeded(changeInfo, element); + + JetParameterList parameterList = PsiUtilPackage.getValueParameterList((JetNamedDeclaration) element); if (changeInfo.isParameterSetOrOrderChanged()) { processParameterListWithStructuralChanges(changeInfo, element, parameterList, psiFactory); } else if (parameterList != null) { - int paramIndex = originalFunctionDescriptor.getExtensionReceiverParameter() != null ? 1 : 0; + int paramIndex = originalCallableDescriptor.getExtensionReceiverParameter() != null ? 1 : 0; for (JetParameter parameter : parameterList.getParameters()) { JetParameterInfo parameterInfo = changeInfo.getNewParameters()[paramIndex]; @@ -215,11 +197,11 @@ public class JetFunctionDefinitionUsage extends JetUsageIn ShortenPackage.addToShorteningWaitSet(parameterList, Options.DEFAULT); } - if (element instanceof JetFunction && changeInfo.isReceiverTypeChanged()) { + if (element instanceof JetCallableDeclaration && changeInfo.isReceiverTypeChanged()) { //noinspection unchecked - String receiverTypeText = changeInfo.renderReceiverType((JetFunctionDefinitionUsage) this); + String receiverTypeText = changeInfo.renderReceiverType((JetCallableDefinitionUsage) this); JetTypeReference receiverTypeRef = receiverTypeText != null ? psiFactory.createType(receiverTypeText) : null; - JetTypeReference newReceiverTypeRef = TypeRefHelpersPackage.setReceiverTypeReference((JetFunction) element, receiverTypeRef); + JetTypeReference newReceiverTypeRef = TypeRefHelpersPackage.setReceiverTypeReference((JetCallableDeclaration) element, receiverTypeRef); if (newReceiverTypeRef != null) { ShortenPackage.addToShorteningWaitSet(newReceiverTypeRef, ShortenReferences.Options.DEFAULT); } @@ -232,6 +214,36 @@ public class JetFunctionDefinitionUsage extends JetUsageIn return true; } + protected void changeReturnTypeIfNeeded(JetChangeInfo changeInfo, PsiElement element) { + if (!(element instanceof JetCallableDeclaration)) return; + if (element instanceof JetConstructor) return; + + JetCallableDeclaration callable = (JetCallableDeclaration) element; + + boolean returnTypeIsNeeded; + if (element instanceof JetFunction) { + returnTypeIsNeeded = (changeInfo.isRefactoringTarget(originalCallableDescriptor) || + !(callable instanceof JetFunctionLiteral) || + callable.getTypeReference() != null); + } + else { + returnTypeIsNeeded = element instanceof JetProperty; + } + + if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) { + callable.setTypeReference(null); + String returnTypeText = changeInfo.renderReturnType((JetCallableDefinitionUsage) this); + + //TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready + if (!KotlinBuiltIns.getInstance().getUnitType().toString().equals(returnTypeText)) { + ShortenPackage.addToShorteningWaitSet( + callable.setTypeReference(JetPsiFactory(callable).createType(returnTypeText)), + Options.DEFAULT + ); + } + } + } + private void processParameterListWithStructuralChanges( JetChangeInfo changeInfo, PsiElement element, @@ -256,14 +268,14 @@ public class JetFunctionDefinitionUsage extends JetUsageIn } else { newParameterList = psiFactory.createFunctionLiteralParameterList(changeInfo.getNewParametersSignature( - (JetFunctionDefinitionUsage) this) + (JetCallableDefinitionUsage) this) ); canReplaceEntireList = true; } } - else { + else if (!(element instanceof JetProperty)) { newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature( - (JetFunctionDefinitionUsage) this) + (JetCallableDefinitionUsage) this) ); } @@ -339,14 +351,15 @@ public class JetFunctionDefinitionUsage extends JetUsageIn private static void changeVisibility(JetChangeInfo changeInfo, PsiElement element) { JetModifierKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility()); - if (element instanceof JetFunction) { - ((JetFunction)element).addModifier(newVisibilityToken); + if (element instanceof JetCallableDeclaration) { + ((JetCallableDeclaration)element).addModifier(newVisibilityToken); } - else { + else if (element instanceof JetClass) { JetPrimaryConstructor constructor = ((JetClass) element).getPrimaryConstructor(); assert constructor != null : "Primary constructor should be created before changing visibility"; constructor.addModifier(newVisibilityToken); } + else throw new AssertionError("Invalid element: " + PsiUtilPackage.getElementTextWithContext(element)); } private void changeParameter(int parameterIndex, JetParameter parameter, JetParameterInfo parameterInfo) { @@ -365,6 +378,7 @@ public class JetFunctionDefinitionUsage extends JetUsageIn } else if (valOrVar != JetValVar.None) { PsiElement firstChild = parameter.getFirstChild(); + //noinspection ConstantConditions parameter.addBefore(valOrVar.createKeyword(psiFactory), firstChild); parameter.addBefore(psiFactory.createWhiteSpace(), firstChild); } @@ -378,7 +392,7 @@ public class JetFunctionDefinitionUsage extends JetUsageIn if (identifier != null) { //noinspection unchecked - String newName = parameterInfo.getInheritedName((JetFunctionDefinitionUsage) this); + String newName = parameterInfo.getInheritedName(this); identifier.replace(psiFactory.createIdentifier(newName)); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetConstructorDelegationCallUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetConstructorDelegationCallUsage.kt index 5dfd37b2718..617b5e14139 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetConstructorDelegationCallUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetConstructorDelegationCallUsage.kt @@ -25,7 +25,7 @@ public class JetConstructorDelegationCallUsage( call: JetConstructorDelegationCall, changeInfo: JetChangeInfo ) : JetUsageInfo(call) { - val delegate = JetFunctionCallUsage(call, changeInfo.methodDescriptor.originalPrimaryFunction) + val delegate = JetFunctionCallUsage(call, changeInfo.methodDescriptor.originalPrimaryCallable) override fun processUsage(changeInfo: JetChangeInfo, element: JetConstructorDelegationCall): Boolean { val isThisCall = element.isCallToThis() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt index 24c726ab86b..d7e3f3cbd8a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetEnumEntryWithoutSuperCallUsage.kt @@ -35,7 +35,7 @@ public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsa ) as JetDelegatorToSuperCall element.addBefore(psiFactory.createColon(), delegatorToSuperCall) - return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.methodDescriptor.originalPrimaryFunction) + return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.methodDescriptor.originalPrimaryCallable) .processUsage(changeInfo, delegatorToSuperCall) } 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 f88883571d3..7468e5ea0b1 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 @@ -29,6 +29,7 @@ import kotlin.Unit; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.PropertyCodegen; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage; @@ -38,6 +39,9 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo; import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionEnginePackage; import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler; import org.jetbrains.kotlin.idea.util.ShortenReferences; +import org.jetbrains.kotlin.load.java.JvmAbi; +import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor; +import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; @@ -75,11 +79,11 @@ public class JetFunctionCallUsage extends JetUsageInfo { private static final ShortenReferences.Options SHORTEN_ARGUMENTS_OPTIONS = new ShortenReferences.Options(true, true); - private final JetFunctionDefinitionUsage callee; + private final JetCallableDefinitionUsage callee; private final BindingContext context; private final ResolvedCall resolvedCall; - public JetFunctionCallUsage(@NotNull JetCallElement element, JetFunctionDefinitionUsage callee) { + public JetFunctionCallUsage(@NotNull JetCallElement element, JetCallableDefinitionUsage callee) { super(element); this.callee = callee; this.context = ResolvePackage.analyze(element, BodyResolveMode.FULL); @@ -88,13 +92,7 @@ public class JetFunctionCallUsage extends JetUsageInfo { @Override public boolean processUsage(JetChangeInfo changeInfo, JetCallElement element) { - if (changeInfo.isNameChanged()) { - JetExpression callee = element.getCalleeExpression(); - - if (callee instanceof JetSimpleNameExpression) { - callee.replace(JetPsiFactory(getProject()).createSimpleName(changeInfo.getNewName())); - } - } + changeNameIfNeeded(changeInfo, element); if (element.getValueArgumentList() != null) { if (changeInfo.isParameterSetOrOrderChanged()) { @@ -118,6 +116,27 @@ public class JetFunctionCallUsage extends JetUsageInfo { return true; } + private boolean isPropertyJavaUsage() { + return this.callee.getElement() instanceof JetProperty + && resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof JavaMethodDescriptor; + } + + protected void changeNameIfNeeded(JetChangeInfo changeInfo, JetCallElement element) { + if (!changeInfo.isNameChanged()) return; + + JetExpression callee = element.getCalleeExpression(); + if (!(callee instanceof JetSimpleNameExpression)) return; + + String newName = changeInfo.getNewName(); + if (isPropertyJavaUsage()) { + String currentName = ((JetSimpleNameExpression) callee).getReferencedName(); + if (currentName.startsWith(JvmAbi.GETTER_PREFIX)) newName = PropertyCodegen.getterName(Name.identifier(newName)); + else if (currentName.startsWith(JvmAbi.SETTER_PREFIX)) newName = PropertyCodegen.setterName(Name.identifier(newName)); + } + + callee.replace(JetPsiFactory(getProject()).createSimpleName(newName)); + } + @Nullable private JetExpression getReceiverExpressionIfMatched( @NotNull ReceiverValue receiverValue, @@ -288,6 +307,11 @@ public class JetFunctionCallUsage extends JetUsageInfo { assert arguments != null : "Argument list is expected: " + element.getText(); List oldArguments = element.getValueArguments(); + if (isPropertyJavaUsage()) { + updateJavaPropertyCall(changeInfo, element); + return; + } + boolean isNamedCall = oldArguments.size() > 1 && oldArguments.get(0).isNamed(); StringBuilder parametersBuilder = new StringBuilder("("); boolean isFirst = true; @@ -388,7 +412,8 @@ public class JetFunctionCallUsage extends JetUsageInfo { //TODO: this is not correct! JetValueArgument lastArgument = KotlinPackage.lastOrNull(newArgumentList.getArguments()); - boolean hasTrailingLambdaInArgumentListAfter = lastArgument != null && PsiPackage.unpackFunctionLiteral(lastArgument.getArgumentExpression()) != null; + boolean hasTrailingLambdaInArgumentListAfter = + lastArgument != null && PsiPackage.unpackFunctionLiteral(lastArgument.getArgumentExpression()) != null; arguments = (JetValueArgumentList) arguments.replace(newArgumentList); @@ -435,6 +460,38 @@ public class JetFunctionCallUsage extends JetUsageInfo { } } + private static void updateJavaPropertyCall(JetChangeInfo changeInfo, JetCallElement element) { + JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo(); + JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver(); + if (newReceiverInfo == originalReceiverInfo) return; + + JetValueArgumentList arguments = element.getValueArgumentList(); + assert arguments != null : "Argument list is expected: " + element.getText(); + List oldArguments = element.getValueArguments(); + + JetPsiFactory psiFactory = new JetPsiFactory(element.getProject()); + + JetValueArgument firstArgument = oldArguments.isEmpty() ? null : (JetValueArgument) oldArguments.get(0); + + if (newReceiverInfo == null) { + if (firstArgument != null) arguments.removeArgument(firstArgument); + } + else { + JetExpression defaultValueForCall = newReceiverInfo.getDefaultValueForCall(); + if (defaultValueForCall == null) { + defaultValueForCall = psiFactory.createExpression("_"); + } + JetValueArgument newReceiverArgument = psiFactory.createArgument(defaultValueForCall, null, false); + + if (originalReceiverInfo != null) { + if (firstArgument != null) firstArgument.replace(newReceiverArgument); + } + else { + arguments.addArgumentAfter(newReceiverArgument, null); + } + } + } + @Nullable private static JetExpression getReceiverExpression(@NotNull ReceiverValue receiver, @NotNull JetPsiFactory psiFactory) { if (receiver instanceof ExpressionReceiver) { 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 index b67d7c1ce6e..72a11726f36 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetImplicitThisToParameterUsage.kt @@ -44,9 +44,9 @@ public abstract class JetImplicitReceiverUsage(callElement: JetElement): JetUsag public class JetImplicitThisToParameterUsage( callElement: JetElement, val parameterInfo: JetParameterInfo, - val containingFunction: JetFunctionDefinitionUsage<*> + val containingCallable: JetCallableDefinitionUsage<*> ): JetImplicitReceiverUsage(callElement) { - override fun getNewReceiverText(): String = parameterInfo.getInheritedName(containingFunction) + override fun getNewReceiverText(): String = parameterInfo.getInheritedName(containingCallable) override fun processReplacedElement(element: JetElement) { element.addToShorteningWaitSet(Options(removeThisLabels = true)) 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 5af65b9a57b..dbc6122a78d 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 @@ -46,7 +46,7 @@ public abstract class JetExplicitReferenceUsage(element: T) : Jet public class JetParameterUsage( element: JetElement, private val parameterInfo: JetParameterInfo, - val containingFunction: JetFunctionDefinitionUsage<*> + val containingCallable: JetCallableDefinitionUsage<*> ) : JetExplicitReferenceUsage(element) { override fun processReplacedElement(element: JetElement) { val qualifiedExpression = element.getParent() as? JetQualifiedExpression @@ -56,7 +56,7 @@ public class JetParameterUsage( override fun getReplacementText(changeInfo: JetChangeInfo): String = if (changeInfo.receiverParameterInfo != parameterInfo) { - parameterInfo.getInheritedName(containingFunction) + parameterInfo.getInheritedName(containingCallable) } else "this@${changeInfo.getNewName()}" } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetPropertyCallUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetPropertyCallUsage.kt new file mode 100644 index 00000000000..7ae906377bb --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetPropertyCallUsage.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2015 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.caches.resolve.analyze +import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.psi.JetQualifiedExpression +import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.psi.createExpressionByPattern +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver + +public class JetPropertyCallUsage(element: JetSimpleNameExpression): JetUsageInfo(element) { + private val resolvedCall = element.getResolvedCall(element.analyze()) + + override fun processUsage(changeInfo: JetChangeInfo, element: JetSimpleNameExpression): Boolean { + updateName(changeInfo, element) + updateReceiver(changeInfo, element) + return true + } + + private fun updateName(changeInfo: JetChangeInfo, element: JetSimpleNameExpression) { + if (changeInfo.isNameChanged()) { + element.getReference()?.handleElementRename(changeInfo.getNewName()) + } + } + + private fun updateReceiver(changeInfo: JetChangeInfo, element: JetSimpleNameExpression) { + val newReceiver = changeInfo.receiverParameterInfo + val oldReceiver = changeInfo.methodDescriptor.receiver + if (newReceiver == oldReceiver) return + + val elementToReplace = element.getQualifiedExpressionForSelectorOrThis() + + // Do not add extension receiver to calls with explicit dispatch receiver + if (newReceiver != null + && elementToReplace is JetQualifiedExpression + && resolvedCall?.getDispatchReceiver() is ExpressionReceiver) return + + val replacingElement = newReceiver?.let { + val psiFactory = JetPsiFactory(getProject()) + val receiver = it.defaultValueForCall ?: psiFactory.createExpression("_") + psiFactory.createExpressionByPattern("$0.$1", receiver, element) + } ?: element + + elementToReplace.replace(replacingElement) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinWrapperForJavaUsageInfos.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinWrapperForJavaUsageInfos.kt index 3d941aba020..f1ade8c2a92 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinWrapperForJavaUsageInfos.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/KotlinWrapperForJavaUsageInfos.kt @@ -17,9 +17,19 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages import com.intellij.psi.PsiElement +import com.intellij.refactoring.changeSignature.JavaChangeInfo import com.intellij.usageView.UsageInfo public class KotlinWrapperForJavaUsageInfos( + val javaChangeInfo: JavaChangeInfo, val javaUsageInfos: Array, val primaryMethod: PsiElement -): UsageInfo(primaryMethod) +): UsageInfo(primaryMethod) { + override fun hashCode(): Int { + return javaChangeInfo.getMethod().hashCode(); + } + + override fun equals(other: Any?): Boolean { + return other == this || (other is KotlinWrapperForJavaUsageInfos && javaChangeInfo.getMethod() == other.javaChangeInfo.getMethod()) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterDialog.kt index c5d2a50adb6..cbe75dba431 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterDialog.kt @@ -32,6 +32,7 @@ import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.idea.JetFileType import org.jetbrains.kotlin.idea.core.refactoring.isMultiLine import org.jetbrains.kotlin.idea.core.refactoring.runRefactoringWithPostprocessing +import org.jetbrains.kotlin.idea.core.refactoring.validateElement import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinParameterTablePanel import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* @@ -233,18 +234,9 @@ public class KotlinIntroduceParameterDialog private constructor( override fun createCenterPanel() = null override fun canRun() { - fun validateElement(e: PsiElement, errorMessage: String) { - try { - AnalyzingUtils.checkForSyntacticErrors(e) - } - catch(e: Exception) { - throw ConfigurationException(errorMessage) - } - } - val psiFactory = JetPsiFactory(myProject) - validateElement(psiFactory.createType(nameField.getEnteredName()), "Invalid parameter name") - validateElement(psiFactory.createType(typeField.getEnteredName()), "Invalid parameter type") + psiFactory.createSimpleName(nameField.getEnteredName()).validateElement("Invalid parameter name") + psiFactory.createType(typeField.getEnteredName()).validateElement("Invalid parameter type") } override fun doAction() { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt index 5d35a857ab3..190a7cc24b3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt @@ -142,7 +142,7 @@ fun IntroduceParameterDescriptor.performRefactoring() { .forEach { methodDescriptor.removeParameter(it) } } - val parameterInfo = JetParameterInfo(functionDescriptor = callableDescriptor, + val parameterInfo = JetParameterInfo(callableDescriptor = callableDescriptor, name = newParameterName, defaultValueForCall = if (withDefaultValue) null else newArgumentValue, defaultValueForParameter = if (withDefaultValue) newArgumentValue else null, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterMethodUsageProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterMethodUsageProcessor.kt index 1eb345ea27f..3cbb070c9f4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterMethodUsageProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterMethodUsageProcessor.kt @@ -77,7 +77,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe // Temporarily assume that the new parameter is of Any type. Actual type is substituted during the signature update phase val defaultValueForCall = (data.getParameterInitializer().getExpression()!! as? PsiExpression)?.let { it.j2k() } - changeInfo.addParameter(JetParameterInfo(functionDescriptor = psiMethodDescriptor, + changeInfo.addParameter(JetParameterInfo(callableDescriptor = psiMethodDescriptor, name = data.getParameterName(), type = KotlinBuiltIns.getInstance().getAnyType(), defaultValueForCall = defaultValueForCall)) @@ -100,7 +100,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe .map { it.unwrapped } .filterIsInstance() return (kotlinFunctions + element).all { - JetFunctionDefinitionUsage(it, changeInfo.originalBaseFunctionDescriptor, null, null).processUsage(changeInfo, it) + JetCallableDefinitionUsage(it, changeInfo.originalBaseFunctionDescriptor, null, null).processUsage(changeInfo, it) } } @@ -114,7 +114,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe (JetConstructorDelegationCallUsage(callElement, changeInfo) as JetUsageInfo) } else { - JetFunctionCallUsage(callElement, changeInfo.methodDescriptor.originalPrimaryFunction) + JetFunctionCallUsage(callElement, changeInfo.methodDescriptor.originalPrimaryCallable) } return delegateUsage.processUsage(changeInfo, callElement) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt index 56f03c0a868..10254d376e7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt @@ -78,6 +78,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import com.intellij.lang.java.JavaLanguage import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils +import com.intellij.openapi.options.ConfigurationException import com.intellij.psi.* import com.intellij.refactoring.listeners.RefactoringEventData import com.intellij.refactoring.listeners.RefactoringEventListener @@ -88,6 +89,7 @@ import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.j2k.IdeaReferenceSearcher import org.jetbrains.kotlin.j2k.JavaToKotlinConverter import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.resolve.AnalyzingUtils fun PsiElement.getAndRemoveCopyableUserData(key: Key): T? { val data = getCopyableUserData(key) @@ -604,4 +606,14 @@ public fun (() -> Any).runRefactoringWithPostprocessing( } }) this() +} + +@throws(ConfigurationException::class) +public fun JetElement.validateElement(errorMessage: String) { + try { + AnalyzingUtils.checkForSyntacticErrors(this) + } + catch(e: Exception) { + throw ConfigurationException(errorMessage) + } } \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.1.java new file mode 100644 index 00000000000..9af0f122297 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP(String receiver) { + return p; + } + + @Override + public void setP(String receiver, int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(""); + new A().setP("", 1); + + new B().getP(""); + new B().setP("", 2); + + new J().getP(""); + new J().setP("", 3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.kt new file mode 100644 index 00000000000..fa1d413afa5 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverAfter.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var String.p: Int = 1 +} + +class B: A() { + override var String.p: Int = 2 +} + +fun test() { + with(A()) { + val t = "".p + "".p = 1 + } + + with(B()) { + val t = "".p + "".p = 2 + } + + with(J()) { + val t = getP("") + setP("", 3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.1.java new file mode 100644 index 00000000000..8dd79bb216b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP() { + return p; + } + + @Override + public void setP(int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(); + new A().setP(1); + + new B().getP(); + new B().setP(2); + + new J().getP(); + new J().setP(3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.kt new file mode 100644 index 00000000000..9e209bcf45f --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverBefore.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var p: Int = 1 +} + +class B: A() { + override var p: Int = 2 +} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + with(B()) { + val t = p + p = 2 + } + + with(J()) { + val t = getP() + setP(3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictBefore.kt b/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictBefore.kt new file mode 100644 index 00000000000..acdeca86b89 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictBefore.kt @@ -0,0 +1,8 @@ +open class A { + open var p: Int = 1 +} + +fun test() { + val t1 = A().p + A().p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictMessages.txt b/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictMessages.txt new file mode 100644 index 00000000000..65ca46ee958 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddPropertyReceiverConflictMessages.txt @@ -0,0 +1,2 @@ +Explicit receiver is already present in call element: A().p +Explicit receiver is already present in call element: A().p \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.1.java new file mode 100644 index 00000000000..efc4ff583e9 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(A()); + TestPackage.setP(A(), 1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.kt new file mode 100644 index 00000000000..5a3370a1688 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverAfter.kt @@ -0,0 +1,14 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var A.p: Int + get() = 1 + set(value: Int) {} + +fun test() { + val t = A().p + A().p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.1.java new file mode 100644 index 00000000000..f34461bb3f2 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(); + TestPackage.setP(1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.kt new file mode 100644 index 00000000000..f6f59b884c8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/AddTopLevelPropertyReceiverBefore.kt @@ -0,0 +1,14 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var p: Int + get() = 1 + set(value: Int) {} + +fun test() { + val t = p + p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyAfter.1.java b/idea/testData/refactoring/changeSignature/ChangePropertyAfter.1.java new file mode 100644 index 00000000000..a6ea52fd86f --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyAfter.1.java @@ -0,0 +1,31 @@ +import org.jetbrains.annotations.NotNull; + +import java.lang.Override; + +class J extends A { + private int p; + + @NotNull + @Override + public String getS() { + return p; + } + + @Override + public void setS(@NotNull String value) { + p = value; + } +} + +class Test { + static void test() { + new A().getS(); + new A().setS(1); + + new B().getS(); + new B().setS(2); + + new J().getS(); + new J().setS(3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyAfter.kt b/idea/testData/refactoring/changeSignature/ChangePropertyAfter.kt new file mode 100644 index 00000000000..df9f9e173de --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyAfter.kt @@ -0,0 +1,18 @@ +open class A { + open var s: String = 1 +} + +class B: A() { + override var s: String = 2 +} + +fun test() { + val t1 = A().s + A().s = 1 + + val t2 = B().s + B().s = 2 + + val t3 = J().getS() + J().setS(3) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyBefore.1.java b/idea/testData/refactoring/changeSignature/ChangePropertyBefore.1.java new file mode 100644 index 00000000000..8dd79bb216b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyBefore.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP() { + return p; + } + + @Override + public void setP(int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(); + new A().setP(1); + + new B().getP(); + new B().setP(2); + + new J().getP(); + new J().setP(3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyBefore.kt b/idea/testData/refactoring/changeSignature/ChangePropertyBefore.kt new file mode 100644 index 00000000000..3ff85c27509 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyBefore.kt @@ -0,0 +1,18 @@ +open class A { + open var p: Int = 1 +} + +class B: A() { + override var p: Int = 2 +} + +fun test() { + val t1 = A().p + A().p = 1 + + val t2 = B().p + B().p = 2 + + val t3 = J().getP() + J().setP(3) +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.1.java new file mode 100644 index 00000000000..6953ccbb4c9 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP(int receiver) { + return p; + } + + @Override + public void setP(int receiver, int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(""); + new A().setP("", 1); + + new B().getP(""); + new B().setP("", 2); + + new J().getP(""); + new J().setP("", 3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.kt new file mode 100644 index 00000000000..430766d4d34 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverAfter.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var Int.p: Int = 1 +} + +class B: A() { + override var Int.p: Int = 2 +} + +fun test() { + with(A()) { + val t = "".p + "".p = 1 + } + + with(B()) { + val t = "".p + "".p = 2 + } + + with(J()) { + val t = getP("") + setP("", 3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.1.java new file mode 100644 index 00000000000..9af0f122297 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP(String receiver) { + return p; + } + + @Override + public void setP(String receiver, int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(""); + new A().setP("", 1); + + new B().getP(""); + new B().setP("", 2); + + new J().getP(""); + new J().setP("", 3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.kt new file mode 100644 index 00000000000..8871d02caf6 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangePropertyReceiverBefore.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var String.p: Int = 1 +} + +class B: A() { + override var String.p: Int = 2 +} + +fun test() { + with(A()) { + val t = "".p + "".p = 1 + } + + with(B()) { + val t = "".p + "".p = 2 + } + + with(J()) { + val t = getP("") + setP("", 3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.1.java new file mode 100644 index 00000000000..cfe96b406b8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(new A()); + TestPackage.setP(new A(), 1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.kt new file mode 100644 index 00000000000..05320988e3e --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverAfter.kt @@ -0,0 +1,19 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var String.p: Int + get() = 1 + set(value: Int) {} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + val t1 = A().p + A().p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.1.java new file mode 100644 index 00000000000..cfe96b406b8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(new A()); + TestPackage.setP(new A(), 1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.kt new file mode 100644 index 00000000000..b4e977e4dae --- /dev/null +++ b/idea/testData/refactoring/changeSignature/ChangeTopLevelPropertyReceiverBefore.kt @@ -0,0 +1,19 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var A.p: Int + get() = 1 + set(value: Int) {} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + val t1 = A().p + A().p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.1.java new file mode 100644 index 00000000000..8dd79bb216b --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP() { + return p; + } + + @Override + public void setP(int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(); + new A().setP(1); + + new B().getP(); + new B().setP(2); + + new J().getP(); + new J().setP(3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.kt new file mode 100644 index 00000000000..9e209bcf45f --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverAfter.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var p: Int = 1 +} + +class B: A() { + override var p: Int = 2 +} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + with(B()) { + val t = p + p = 2 + } + + with(J()) { + val t = getP() + setP(3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.1.java new file mode 100644 index 00000000000..9af0f122297 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.1.java @@ -0,0 +1,28 @@ +import java.lang.Override; + +class J extends A { + private int p; + + @Override + public int getP(String receiver) { + return p; + } + + @Override + public void setP(String receiver, int value) { + p = value; + } +} + +class Test { + static void test() { + new A().getP(""); + new A().setP("", 1); + + new B().getP(""); + new B().setP("", 2); + + new J().getP(""); + new J().setP("", 3); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.kt new file mode 100644 index 00000000000..8871d02caf6 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemovePropertyReceiverBefore.kt @@ -0,0 +1,26 @@ +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +open class A { + open var String.p: Int = 1 +} + +class B: A() { + override var String.p: Int = 2 +} + +fun test() { + with(A()) { + val t = "".p + "".p = 1 + } + + with(B()) { + val t = "".p + "".p = 2 + } + + with(J()) { + val t = getP("") + setP("", 3) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.1.java b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.1.java new file mode 100644 index 00000000000..f34461bb3f2 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(); + TestPackage.setP(1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.kt b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.kt new file mode 100644 index 00000000000..09ac893e96e --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverAfter.kt @@ -0,0 +1,19 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var p: Int + get() = 1 + set(value: Int) {} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + val t1 = p + p = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.1.java b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.1.java new file mode 100644 index 00000000000..cfe96b406b8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.1.java @@ -0,0 +1,8 @@ +import test.TestPackage; + +class Test { + static void test() { + TestPackage.getP(new A()); + TestPackage.setP(new A(), 1); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.kt b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.kt new file mode 100644 index 00000000000..b4e977e4dae --- /dev/null +++ b/idea/testData/refactoring/changeSignature/RemoveTopLevelPropertyReceiverBefore.kt @@ -0,0 +1,19 @@ +package test + +public inline fun with(receiver: T, f: T.() -> R): R = receiver.f() + +class A + +open var A.p: Int + get() = 1 + set(value: Int) {} + +fun test() { + with(A()) { + val t = p + p = 1 + } + + val t1 = A().p + A().p = 1 +} \ 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 ee46b50d103..afe85398e31 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureTest.java @@ -33,7 +33,7 @@ import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.descriptors.FunctionDescriptor; +import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.Visibilities; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle; @@ -995,6 +995,67 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { ); } + public void testChangeProperty() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setNewName("s"); + changeInfo.setNewReturnTypeText("String"); + doTest(changeInfo); + } + + public void testAddPropertyReceiverConflict() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(), + -1, "receiver", KotlinBuiltIns.getInstance().getStringType(), null, + new JetPsiFactory(getProject()).createExpression("\"\""), JetValVar.None, null); + changeInfo.setReceiverParameterInfo(newParameter); + doTestConflict(changeInfo); + } + + public void testAddPropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(), + -1, "receiver", KotlinBuiltIns.getInstance().getStringType(), null, + new JetPsiFactory(getProject()).createExpression("\"\""), JetValVar.None, null); + changeInfo.setReceiverParameterInfo(newParameter); + doTest(changeInfo); + } + + public void testChangePropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + //noinspection ConstantConditions + changeInfo.getReceiverParameterInfo().setCurrentTypeText("Int"); + doTest(changeInfo); + } + + public void testRemovePropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + doTest(changeInfo); + } + + public void testAddTopLevelPropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(), + -1, "receiver", null, null, + new JetPsiFactory(getProject()).createExpression("A()"), JetValVar.None, null); + newParameter.setCurrentTypeText("test.A"); + changeInfo.setReceiverParameterInfo(newParameter); + doTest(changeInfo); + } + + public void testChangeTopLevelPropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + //noinspection ConstantConditions + changeInfo.getReceiverParameterInfo().setCurrentTypeText("String"); + doTest(changeInfo); + } + + public void testRemoveTopLevelPropertyReceiver() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + changeInfo.setReceiverParameterInfo(null); + doTest(changeInfo); + } + @NotNull @Override protected String getTestDataPath() { @@ -1039,11 +1100,11 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase { PsiElement context = file.findElementAt(editor.getCaretModel().getOffset()); assertNotNull(context); - FunctionDescriptor functionDescriptor = JetChangeSignatureHandler.findDescriptor(element, project, editor, bindingContext); - assertNotNull(functionDescriptor); + CallableDescriptor callableDescriptor = JetChangeSignatureHandler.findDescriptor(element, project, editor, bindingContext); + assertNotNull(callableDescriptor); return ChangeSignaturePackage.createChangeInfo( - project, functionDescriptor, JetChangeSignatureHandler.getConfiguration(), bindingContext, context); + project, callableDescriptor, JetChangeSignatureHandler.getConfiguration(), bindingContext, context); } private class JavaRefactoringProvider {