Debugger: Dispose ExtractionData/ExtractionResult when necessary

This fixes memory leak due to extensive use of "Evaluate expression"
This commit is contained in:
Alexey Sedunov
2018-06-07 15:26:54 +03:00
parent 16dbc6fb4d
commit 9a3a7fbcca
3 changed files with 29 additions and 16 deletions
@@ -26,6 +26,7 @@ import com.intellij.diagnostic.LogMessageEx
import com.intellij.openapi.diagnostic.Attachment import com.intellij.openapi.diagnostic.Attachment
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.openapi.vfs.CharsetToolkit
import com.intellij.psi.JavaPsiFacade import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
@@ -214,8 +215,11 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line) val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}") ?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment) val (parametersDescriptor, extractedFunction) = try {
val extractedFunction = extractionResult.declaration as KtNamedFunction extractionResult.getParametersForDebugger(codeFragment) to extractionResult.declaration as KtNamedFunction
} finally {
Disposer.dispose(extractionResult)
}
if (LOG.isDebugEnabled) { if (LOG.isDebugEnabled) {
LOG.debug("Extracted function:\n" + runReadAction { extractedFunction.text }) LOG.debug("Extracted function:\n" + runReadAction { extractedFunction.text })
@@ -20,6 +20,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
import com.intellij.diagnostic.LogMessageEx import com.intellij.diagnostic.LogMessageEx
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Attachment import com.intellij.openapi.diagnostic.Attachment
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
@@ -97,20 +98,25 @@ fun getFunctionForExtractedFragment(
allowSpecialClassNames = true, allowSpecialClassNames = true,
captureLocalFunctions = true, captureLocalFunctions = true,
canWrapInWith = true) canWrapInWith = true)
val analysisResult = ExtractionData(tmpFile, newDebugExpressions.toRange(), targetSibling, null, options).performAnalysis() val extractionData = ExtractionData(tmpFile, newDebugExpressions.toRange(), targetSibling, null, options)
if (analysisResult.status != Status.SUCCESS) { try {
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult, tmpFile)) val analysisResult = extractionData.performAnalysis()
} if (analysisResult.status != Status.SUCCESS) {
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult, tmpFile))
}
val validationResult = analysisResult.descriptor!!.validate() val validationResult = analysisResult.descriptor!!.validate()
if (!validationResult.conflicts.isEmpty) { if (!validationResult.conflicts.isEmpty) {
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().joinToString(",") { it.text }}") throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().joinToString(",") { it.text }}")
} }
val generatorOptions = ExtractionGeneratorOptions(inTempFile = true, val generatorOptions = ExtractionGeneratorOptions(inTempFile = true,
dummyName = GENERATED_FUNCTION_NAME, dummyName = GENERATED_FUNCTION_NAME,
allowExpressionBody = false) allowExpressionBody = false)
return ExtractionGeneratorConfiguration(validationResult.descriptor, generatorOptions).generateDeclaration() return ExtractionGeneratorConfiguration(validationResult.descriptor, generatorOptions).generateDeclaration()
} finally {
Disposer.dispose(extractionData)
}
} }
return runReadAction { generateFunction() } return runReadAction { generateFunction() }
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.ExtractableSubstringInfo
import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo
import org.jetbrains.kotlin.idea.refactoring.introduce.substringContextOrThis import org.jetbrains.kotlin.idea.refactoring.introduce.substringContextOrThis
import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -270,6 +271,8 @@ data class ExtractionData(
} }
fun unmarkReferencesInside(root: PsiElement) { fun unmarkReferencesInside(root: PsiElement) {
if (!root.isValid) return runReadAction {
root.forEachDescendantOfType<KtSimpleNameExpression> { it.resolveResult = null } if (!root.isValid) return@runReadAction
root.forEachDescendantOfType<KtSimpleNameExpression> { it.resolveResult = null }
}
} }