Fix leak in matchAndConvert (loopToCallChain)

This commit is contained in:
Mikhail Glukhikh
2017-12-12 19:42:19 +03:00
parent 479f293edc
commit 83ae34bb29
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.intentions.loopToCallChain package org.jetbrains.kotlin.idea.intentions.loopToCallChain
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.Ref
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
@@ -244,19 +245,27 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe
val bindingContext = loop.analyze(BodyResolveMode.FULL) val bindingContext = loop.analyze(BodyResolveMode.FULL)
// we declare these keys locally to avoid possible race-condition problems if this code is executed in 2 threads simultaneously // we declare these keys locally to avoid possible race-condition problems if this code is executed in 2 threads simultaneously
val SMARTCAST_KEY = Key<ExplicitSmartCasts>("SMARTCAST_KEY") val SMARTCAST_KEY = Key<Ref<ExplicitSmartCasts>>("SMARTCAST_KEY")
val IMPLICIT_RECEIVER_SMARTCAST_KEY = Key<ImplicitSmartCasts>("IMPLICIT_RECEIVER_SMARTCAST") val IMPLICIT_RECEIVER_SMARTCAST_KEY = Key<Ref<ImplicitSmartCasts>>("IMPLICIT_RECEIVER_SMARTCAST")
val storedUserData = mutableListOf<Ref<*>>()
var smartCastCount = 0 var smartCastCount = 0
try { try {
loop.forEachDescendantOfType<KtExpression> { expression -> loop.forEachDescendantOfType<KtExpression> { expression ->
bindingContext[BindingContext.SMARTCAST, expression]?.let { bindingContext[BindingContext.SMARTCAST, expression]?.let { explicitSmartCasts ->
expression.putCopyableUserData(SMARTCAST_KEY, it) Ref(explicitSmartCasts).apply {
expression.putCopyableUserData(SMARTCAST_KEY, this)
storedUserData += this
}
smartCastCount++ smartCastCount++
} }
bindingContext[BindingContext.IMPLICIT_RECEIVER_SMARTCAST, expression]?.let { bindingContext[BindingContext.IMPLICIT_RECEIVER_SMARTCAST, expression]?.let { implicitSmartCasts ->
expression.putCopyableUserData(IMPLICIT_RECEIVER_SMARTCAST_KEY, it) Ref(implicitSmartCasts).apply {
expression.putCopyableUserData(IMPLICIT_RECEIVER_SMARTCAST_KEY, this)
storedUserData += this
}
smartCastCount++ smartCastCount++
} }
} }
@@ -269,14 +278,14 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe
var preservedSmartCastCount = 0 var preservedSmartCastCount = 0
callChain.forEachDescendantOfType<KtExpression> { expression -> callChain.forEachDescendantOfType<KtExpression> { expression ->
val smartCastType = expression.getCopyableUserData(SMARTCAST_KEY) val smartCastType = expression.getCopyableUserData(SMARTCAST_KEY)?.get()
if (smartCastType != null) { if (smartCastType != null) {
if (newBindingContext[BindingContext.SMARTCAST, expression] == smartCastType || newBindingContext.getType(expression) == smartCastType) { if (newBindingContext[BindingContext.SMARTCAST, expression] == smartCastType || newBindingContext.getType(expression) == smartCastType) {
preservedSmartCastCount++ preservedSmartCastCount++
} }
} }
val implicitReceiverSmartCastType = expression.getCopyableUserData(IMPLICIT_RECEIVER_SMARTCAST_KEY) val implicitReceiverSmartCastType = expression.getCopyableUserData(IMPLICIT_RECEIVER_SMARTCAST_KEY)?.get()
if (implicitReceiverSmartCastType != null) { if (implicitReceiverSmartCastType != null) {
if (newBindingContext[BindingContext.IMPLICIT_RECEIVER_SMARTCAST, expression] == implicitReceiverSmartCastType) { if (newBindingContext[BindingContext.IMPLICIT_RECEIVER_SMARTCAST, expression] == implicitReceiverSmartCastType) {
preservedSmartCastCount++ preservedSmartCastCount++
@@ -293,6 +302,7 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe
return true return true
} }
finally { finally {
storedUserData.forEach { it.set(null) }
if (smartCastCount > 0) { if (smartCastCount > 0) {
loop.forEachDescendantOfType<KtExpression> { loop.forEachDescendantOfType<KtExpression> {
it.putCopyableUserData(SMARTCAST_KEY, null) it.putCopyableUserData(SMARTCAST_KEY, null)