From 45929fd3e3d58de74fc0201a735817963f119f5f Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 17 Apr 2017 12:34:04 +0300 Subject: [PATCH] Change Signature: Invalidate ChangeInfo after the refactoring The goal is to avoid keeping all semantic information used by KotlinChangeInfo in UndoableAction produced by the refactoring #KT-17333 Fixed --- .../KotlinChangeInfoWrapper.kt | 51 +++++++++++++++++++ .../changeSignature/KotlinChangeSignature.kt | 2 +- .../KotlinChangeSignatureProcessor.kt | 26 +++++++--- .../KotlinChangeSignatureUsageProcessor.kt | 33 ++++++------ 4 files changed, 90 insertions(+), 22 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfoWrapper.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfoWrapper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfoWrapper.kt new file mode 100644 index 00000000000..4bdd27f3782 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeInfoWrapper.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2017 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.refactoring.changeSignature.ChangeInfo + +class KotlinChangeInfoWrapper(delegate: KotlinChangeInfo) : ChangeInfo { + var delegate: KotlinChangeInfo? = delegate + private set + + private val method = delegate.method + + override fun getMethod() = method + + override fun isGenerateDelegate() = delegate!!.isGenerateDelegate + + override fun getNewName() = delegate!!.newName + + override fun isParameterTypesChanged() = delegate!!.isParameterTypesChanged + + override fun getNewParameters() = delegate!!.newParameters + + override fun isParameterSetOrOrderChanged() = delegate!!.isParameterSetOrOrderChanged + + override fun isReturnTypeChanged() = delegate!!.isReturnTypeChanged + + override fun isParameterNamesChanged() = delegate!!.isParameterNamesChanged + + override fun isNameChanged() = delegate!!.isNameChanged + + override fun getLanguage() = delegate!!.language + + // Only getMethod() may be called after invalidate() + fun invalidate() { + delegate = null + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt index 5dd8747010d..a3e68f315c6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt @@ -232,5 +232,5 @@ class KotlinChangeSignature(project: Project, adjustedDescriptor, defaultValueContext ) as KotlinChangeSignatureProcessor - return processor.changeInfo + return processor.ktChangeInfo } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureProcessor.kt index 6d2ec6e8a43..44eb378eefb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureProcessor.kt @@ -36,19 +36,24 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinUsageI import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinWrapperForJavaUsageInfos import java.util.* -class KotlinChangeSignatureProcessor(project: Project, - changeInfo: KotlinChangeInfo, - private val commandName: String) : ChangeSignatureProcessorBase(project, changeInfo) { +class KotlinChangeSignatureProcessor( + project: Project, + changeInfo: KotlinChangeInfo, + private val commandName: String +) : ChangeSignatureProcessorBase(project, KotlinChangeInfoWrapper(changeInfo)) { + val ktChangeInfo + get() = changeInfo.delegate!! + override fun createUsageViewDescriptor(usages: Array): UsageViewDescriptor { - val subject = if (changeInfo.kind.isConstructor) "constructor" else "function" + val subject = if (ktChangeInfo.kind.isConstructor) "constructor" else "function" return KotlinUsagesViewDescriptor(myChangeInfo.method, RefactoringBundle.message("0.to.change.signature", subject)) } - override fun getChangeInfo() = super.getChangeInfo() as KotlinChangeInfo + override fun getChangeInfo() = super.getChangeInfo() as KotlinChangeInfoWrapper override fun findUsages(): Array { val allUsages = ArrayList() - changeInfo.getOrCreateJavaChangeInfos()?.let { javaChangeInfos -> + ktChangeInfo.getOrCreateJavaChangeInfos()?.let { javaChangeInfos -> val javaProcessor = JavaChangeSignatureUsageProcessor() javaChangeInfos.mapTo(allUsages) { KotlinWrapperForJavaUsageInfos(it, javaProcessor.findUsages(it), changeInfo.method) @@ -107,4 +112,13 @@ class KotlinChangeSignatureProcessor(project: Project, override fun isPreviewUsages(usages: Array): Boolean = isPreviewUsages override fun getCommandName() = commandName + + override fun performRefactoring(usages: Array) { + try { + super.performRefactoring(usages) + } + finally { + changeInfo.invalidate() + } + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt index db54a97d3ec..373c5a8db32 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignatureUsageProcessor.kt @@ -100,8 +100,8 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { result.add(OriginalJavaMethodDescriptorWrapper(info.method)) - if (info is KotlinChangeInfo) { - findAllMethodUsages(info, result) + if (info is KotlinChangeInfoWrapper) { + findAllMethodUsages(info.delegate!!, result) } else { findSAMUsages(info, result) @@ -507,13 +507,15 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { refUsages.set(adjustedUsages.toTypedArray()) } - if (info !is KotlinChangeInfo) return result + if (info !is KotlinChangeInfoWrapper) return result + + val ktChangeInfo = info.delegate!! val parameterNames = HashSet() val function = info.method val element = function val bindingContext = (element as KtElement).analyze(BodyResolveMode.FULL) - val oldDescriptor = info.originalBaseFunctionDescriptor + val oldDescriptor = ktChangeInfo.originalBaseFunctionDescriptor val containingDeclaration = oldDescriptor.containingDeclaration val parametersScope = when { @@ -527,7 +529,7 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { val callableScope = oldDescriptor.getContainingScope() - val kind = info.kind + val kind = ktChangeInfo.kind if (!kind.isConstructor && callableScope != null && !info.newName.isEmpty()) { val newName = Name.identifier(info.newName) val conflicts = if (oldDescriptor is FunctionDescriptor) @@ -550,7 +552,7 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { } } - for (parameter in info.getNonReceiverParameters()) { + for (parameter in ktChangeInfo.getNonReceiverParameters()) { val valOrVar = parameter.valOrVar val parameterName = parameter.name @@ -578,19 +580,19 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { } } - val newReceiverInfo = info.receiverParameterInfo - val originalReceiverInfo = info.methodDescriptor.receiver + val newReceiverInfo = ktChangeInfo.receiverParameterInfo + val originalReceiverInfo = ktChangeInfo.methodDescriptor.receiver if (function is KtCallableDeclaration && newReceiverInfo != originalReceiverInfo) { findReceiverIntroducingConflicts(result, function, newReceiverInfo) findInternalExplicitReceiverConflicts(refUsages.get(), result, originalReceiverInfo) - findReceiverToParameterInSafeCallsConflicts(refUsages.get(), result, info) - findThisLabelConflicts(refUsages, result, info, function) + findReceiverToParameterInSafeCallsConflicts(refUsages.get(), result, ktChangeInfo) + findThisLabelConflicts(refUsages, result, ktChangeInfo, function) } for (usageInfo in usageInfos) { if (usageInfo !is KotlinCallerUsage) continue val callerDescriptor = usageInfo.element?.resolveToDescriptorIfAny() ?: continue - findParameterDuplicationInCaller(result, info, usageInfo.element!!, callerDescriptor) + findParameterDuplicationInCaller(result, ktChangeInfo, usageInfo.element!!, callerDescriptor) } return result @@ -823,9 +825,10 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { val isJavaMethodUsage = isJavaMethodUsage(usageInfo) if (usageInfo is KotlinWrapperForJavaUsageInfos) { - val javaChangeInfos = (changeInfo as KotlinChangeInfo).getOrCreateJavaChangeInfos() ?: return true + val ktChangeInfo = (changeInfo as KotlinChangeInfoWrapper).delegate!! + val javaChangeInfos = ktChangeInfo.getOrCreateJavaChangeInfos() ?: return true javaChangeInfos.firstOrNull { - changeInfo.originalToCurrentMethods[usageInfo.javaChangeInfo.method] == it.method + ktChangeInfo.originalToCurrentMethods[usageInfo.javaChangeInfo.method] == it.method }?.let { javaChangeInfo -> val nullabilityPropagator = NullabilityPropagator(javaChangeInfo.method) val javaUsageInfos = usageInfo.javaUsageInfos @@ -910,12 +913,12 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor { } @Suppress("UNCHECKED_CAST") - return (usageInfo as? KotlinUsageInfo)?.processUsage(changeInfo as KotlinChangeInfo, element, usages) ?: false + return (usageInfo as? KotlinUsageInfo)?.processUsage((changeInfo as KotlinChangeInfoWrapper).delegate!!, element, usages) ?: false } override fun processPrimaryMethod(changeInfo: ChangeInfo): Boolean { val ktChangeInfo = when (changeInfo) { - is KotlinChangeInfo -> changeInfo + is KotlinChangeInfoWrapper -> changeInfo.delegate!! is JavaChangeInfo -> { val method = changeInfo.method as? KtLightMethod ?: return false var baseFunction = method.kotlinOrigin ?: return false