KtScratchExecutionSession: fix INRE

#EA-218701 Fixed
This commit is contained in:
Dmitry Gridin
2019-12-04 13:21:20 +07:00
parent 78f7ed2c27
commit 86f9253fa0
@@ -7,13 +7,16 @@ package org.jetbrains.kotlin.idea.scratch.compile
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.CapturingProcessHandler
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Computable
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.concurrency.NonUrgentExecutor
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.filterClassFiles
@@ -39,6 +42,7 @@ class KtScratchExecutionSession(
private const val TIMEOUT_MS = 30000
}
@Volatile
private var backgroundProcessIndicator: ProgressIndicator? = null
fun execute(callback: () -> Unit) {
@@ -47,57 +51,74 @@ class KtScratchExecutionSession(
val expressions = file.getExpressions()
if (!executor.checkForErrors(psiFile, expressions)) return
when (val result = runReadAction { KtScratchSourceFileProcessor().process(expressions) }) {
is KtScratchSourceFileProcessor.Result.Error -> return executor.errorOccurs(result.message, isFatal = true)
is KtScratchSourceFileProcessor.Result.OK -> {
LOG.printDebugMessage("After processing by KtScratchSourceFileProcessor:\n ${result.code}")
val project = file.project
ReadAction.nonBlocking {
when (val result = KtScratchSourceFileProcessor().process(expressions)) {
is KtScratchSourceFileProcessor.Result.Error -> return@nonBlocking executor.errorOccurs(result.message, isFatal = true)
is KtScratchSourceFileProcessor.Result.OK -> {
LOG.printDebugMessage("After processing by KtScratchSourceFileProcessor:\n ${result.code}")
object : Task.Backgroundable(psiFile.project, "Running Kotlin Scratch...", true) {
override fun run(indicator: ProgressIndicator) {
backgroundProcessIndicator = indicator
object : Task.Backgroundable(psiFile.project, "Running Kotlin Scratch...", true) {
override fun run(indicator: ProgressIndicator) {
backgroundProcessIndicator = indicator
val modifiedScratchSourceFile = runReadAction {
KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile)
}
try {
val tempDir = DumbService.getInstance(project).runReadActionInSmartMode(
Computable {
compileFileToTempDir(modifiedScratchSourceFile, expressions)
val modifiedScratchSourceFile = runReadAction {
KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile)
}
) ?: return
try {
val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path)
try {
runCommandLine(project, modifiedScratchSourceFile, expressions, psiFile, result, indicator, callback)
} catch (e: Throwable) {
if (e is ControlFlowException) throw e
LOG.printDebugMessage(commandLine.commandLineString)
val processHandler = CapturingProcessHandler(commandLine)
val executionResult = processHandler.runProcessWithProgressIndicator(indicator, TIMEOUT_MS)
when {
executionResult.isTimeout -> {
executor.errorOccurs("Couldn't get scratch execution result - stopped by timeout ($TIMEOUT_MS ms)")
}
executionResult.isCancelled -> {
// ignore
}
else -> {
executor.parseOutput(executionResult, expressions)
}
LOG.printDebugMessage(result.code)
executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true)
}
} finally {
tempDir.delete()
callback()
}
} catch (e: Throwable) {
if (e is ControlFlowException) throw e
LOG.printDebugMessage(result.code)
executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true)
}
}.queue()
}
}.queue()
}
}
.inSmartMode(project)
.expireWith(project)
.withDocumentsCommitted(project)
.submit(NonUrgentExecutor.getInstance())
}
private fun runCommandLine(
project: Project,
modifiedScratchSourceFile: KtFile,
expressions: List<ScratchExpression>,
psiFile: KtFile,
result: KtScratchSourceFileProcessor.Result.OK,
indicator: ProgressIndicator,
callback: () -> Unit
) {
val tempDir = DumbService.getInstance(project).runReadActionInSmartMode(Computable {
compileFileToTempDir(modifiedScratchSourceFile, expressions)
}) ?: return
try {
val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path)
LOG.printDebugMessage(commandLine.commandLineString)
val processHandler = CapturingProcessHandler(commandLine)
val executionResult = processHandler.runProcessWithProgressIndicator(indicator, TIMEOUT_MS)
when {
executionResult.isTimeout -> {
executor.errorOccurs("Couldn't get scratch execution result - stopped by timeout ($TIMEOUT_MS ms)")
}
executionResult.isCancelled -> {
// ignore
}
else -> {
executor.parseOutput(executionResult, expressions)
}
}
} finally {
tempDir.delete()
callback()
}
}