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.configurations.GeneralCommandLine
import com.intellij.execution.process.CapturingProcessHandler import com.intellij.execution.process.CapturingProcessHandler
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Computable
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.concurrency.NonUrgentExecutor
import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.filterClassFiles import org.jetbrains.kotlin.codegen.filterClassFiles
@@ -39,6 +42,7 @@ class KtScratchExecutionSession(
private const val TIMEOUT_MS = 30000 private const val TIMEOUT_MS = 30000
} }
@Volatile
private var backgroundProcessIndicator: ProgressIndicator? = null private var backgroundProcessIndicator: ProgressIndicator? = null
fun execute(callback: () -> Unit) { fun execute(callback: () -> Unit) {
@@ -47,57 +51,74 @@ class KtScratchExecutionSession(
val expressions = file.getExpressions() val expressions = file.getExpressions()
if (!executor.checkForErrors(psiFile, expressions)) return if (!executor.checkForErrors(psiFile, expressions)) return
when (val result = runReadAction { KtScratchSourceFileProcessor().process(expressions) }) { val project = file.project
is KtScratchSourceFileProcessor.Result.Error -> return executor.errorOccurs(result.message, isFatal = true) ReadAction.nonBlocking {
is KtScratchSourceFileProcessor.Result.OK -> { when (val result = KtScratchSourceFileProcessor().process(expressions)) {
LOG.printDebugMessage("After processing by KtScratchSourceFileProcessor:\n ${result.code}") 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) { object : Task.Backgroundable(psiFile.project, "Running Kotlin Scratch...", true) {
override fun run(indicator: ProgressIndicator) { override fun run(indicator: ProgressIndicator) {
backgroundProcessIndicator = indicator backgroundProcessIndicator = indicator
val modifiedScratchSourceFile = runReadAction { val modifiedScratchSourceFile = runReadAction {
KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile) KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile)
}
try {
val tempDir = DumbService.getInstance(project).runReadActionInSmartMode(
Computable {
compileFileToTempDir(modifiedScratchSourceFile, expressions)
} }
) ?: return
try { try {
val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path) runCommandLine(project, modifiedScratchSourceFile, expressions, psiFile, result, indicator, callback)
} catch (e: Throwable) {
if (e is ControlFlowException) throw e
LOG.printDebugMessage(commandLine.commandLineString) LOG.printDebugMessage(result.code)
executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true)
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()
} }
} catch (e: Throwable) { }.queue()
if (e is ControlFlowException) throw e
LOG.printDebugMessage(result.code)
executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true)
}
} }
}.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()
} }
} }