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
This commit is contained in:
Alexey Sedunov
2017-04-17 12:34:04 +03:00
parent b33b06722d
commit 45929fd3e3
4 changed files with 90 additions and 22 deletions
@@ -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
}
}
@@ -232,5 +232,5 @@ class KotlinChangeSignature(project: Project,
adjustedDescriptor,
defaultValueContext
) as KotlinChangeSignatureProcessor
return processor.changeInfo
return processor.ktChangeInfo
}
@@ -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<UsageInfo>): 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<UsageInfo> {
val allUsages = ArrayList<UsageInfo>()
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<out UsageInfo>): Boolean = isPreviewUsages
override fun getCommandName() = commandName
override fun performRefactoring(usages: Array<out UsageInfo>) {
try {
super.performRefactoring(usages)
}
finally {
changeInfo.invalidate()
}
}
}
@@ -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<String>()
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<PsiElement>)?.processUsage(changeInfo as KotlinChangeInfo, element, usages) ?: false
return (usageInfo as? KotlinUsageInfo<PsiElement>)?.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