Create deep descriptors copy for Change signature

It's needed to prevent accesses to invalid PSI
after changes has been applied
This commit is contained in:
Denis Zharkov
2016-02-05 17:19:52 +03:00
parent c879f83037
commit cd3f7df28c
2 changed files with 20 additions and 5 deletions
@@ -831,7 +831,7 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
val descriptorWrapper = usages.firstIsInstanceOrNull<OriginalJavaMethodDescriptorWrapper>() val descriptorWrapper = usages.firstIsInstanceOrNull<OriginalJavaMethodDescriptorWrapper>()
if (descriptorWrapper == null || descriptorWrapper.originalJavaMethodDescriptor != null) return true if (descriptorWrapper == null || descriptorWrapper.originalJavaMethodDescriptor != null) return true
val methodDescriptor = method.getJavaMethodDescriptor() ?: return false val methodDescriptor = method.getJavaMethodDescriptor()?.createDeepCopy() ?: return false
descriptorWrapper.originalJavaMethodDescriptor = KotlinChangeSignatureData(methodDescriptor, method, listOf(methodDescriptor)) descriptorWrapper.originalJavaMethodDescriptor = KotlinChangeSignatureData(methodDescriptor, method, listOf(methodDescriptor))
// This change info is used as a placeholder before primary method update // This change info is used as a placeholder before primary method update
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
import com.intellij.refactoring.changeSignature.CallerUsageInfo import com.intellij.refactoring.changeSignature.CallerUsageInfo
import com.intellij.refactoring.changeSignature.OverriderUsageInfo import com.intellij.refactoring.changeSignature.OverriderUsageInfo
import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.DeferredJavaMethodKotlinCallerUsage import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.DeferredJavaMethodKotlinCallerUsage
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JavaMethodKotlinUsageWithDelegate import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JavaMethodKotlinUsageWithDelegate
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage
@@ -27,10 +28,9 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCaller
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.substitutions.getCallableSubstitutor import org.jetbrains.kotlin.types.substitutions.getCallableSubstitutor
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
fun KtNamedDeclaration.getDeclarationBody(): KtElement? { fun KtNamedDeclaration.getDeclarationBody(): KtElement? {
return when { return when {
@@ -78,3 +78,18 @@ fun KotlinType.renderTypeWithSubstitution(substitutor: TypeSubstitutor?, default
val renderer = if (inArgumentPosition) IdeDescriptorRenderers.SOURCE_CODE_FOR_TYPE_ARGUMENTS else IdeDescriptorRenderers.SOURCE_CODE val renderer = if (inArgumentPosition) IdeDescriptorRenderers.SOURCE_CODE_FOR_TYPE_ARGUMENTS else IdeDescriptorRenderers.SOURCE_CODE
return renderer.renderType(newType) return renderer.renderType(newType)
} }
// This method is used to create full copies of functions (including copies of all types)
// It's needed to prevent accesses to PSI (e.g. using LazyJavaClassifierType properties) when Change signature invalidates it
// See KotlinChangeSignatureTest.testSAMChangeMethodReturnType
fun FunctionDescriptor.createDeepCopy() = substitute(TypeSubstitutor.create(ForceTypeCopySubstitution))
private object ForceTypeCopySubstitution : TypeSubstitution() {
override fun get(key: KotlinType) =
with(key) {
KotlinTypeImpl.create(
annotations, constructor, isMarkedNullable, arguments, substitution, memberScope, capabilities).asTypeProjection()
}
override fun isEmpty() = false
}