From d6c7029c777093a49ef868f71c3101cb1e9c4c55 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 23 Nov 2015 18:19:10 +0300 Subject: [PATCH] Compiler, Scripts: strip stacktrace when reporting exception on script execution --- .../compiler/KotlinToJVMBytecodeCompiler.java | 38 ++++++++++++++++--- .../smoke/scriptException/script.expected | 10 +++++ .../smoke/scriptException/script.kts | 10 +++++ .../kotlin/integration/CompilerSmokeTest.java | 4 ++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/integration/smoke/scriptException/script.expected create mode 100644 compiler/testData/integration/smoke/scriptException/script.kts diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index f267a92753e..b3264c7f23b 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -61,9 +61,13 @@ import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; import org.jetbrains.kotlin.util.PerformanceCounter; +import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.KotlinPaths; import java.io.File; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -253,15 +257,39 @@ public class KotlinToJVMBytecodeCompiler { ) { Class scriptClass = compileScript(configuration, paths, environment); if (scriptClass == null) return; + Constructor scriptConstructor = getScriptConstructor(scriptClass); try { - scriptClass.getConstructor(String[].class).newInstance(new Object[] {ArrayUtil.toStringArray(scriptArgs)}); + scriptConstructor.newInstance(new Object[] {ArrayUtil.toStringArray(scriptArgs)}); } - catch (RuntimeException e) { - throw e; + catch (Throwable e) { + reportExceptionFromScript(e); } - catch (Exception e) { - throw new RuntimeException("Failed to evaluate script: " + e, e); + } + + private static void reportExceptionFromScript(@NotNull Throwable exception) { + // expecting InvocationTargetException from constructor invocation with cause that describes the actual cause + PrintStream stream = System.err; + Throwable cause = exception.getCause(); + if (!(exception instanceof InvocationTargetException) || cause == null) { + exception.printStackTrace(stream); + return; + } + stream.println(cause); + StackTraceElement[] fullTrace = cause.getStackTrace(); + int relevantEntries = fullTrace.length - exception.getStackTrace().length; + for (int i = 0; i < relevantEntries; i++) { + stream.println("\tat " + fullTrace[i]); + } + } + + @NotNull + private static Constructor getScriptConstructor(Class scriptClass) { + try { + return scriptClass.getConstructor(String[].class); + } + catch (NoSuchMethodException e) { + throw ExceptionUtilsKt.rethrow(e); } } diff --git a/compiler/testData/integration/smoke/scriptException/script.expected b/compiler/testData/integration/smoke/scriptException/script.expected new file mode 100644 index 00000000000..81f62029d9a --- /dev/null +++ b/compiler/testData/integration/smoke/scriptException/script.expected @@ -0,0 +1,10 @@ + +ERR: +java.lang.IllegalStateException: my error + at kotlin.PreconditionsKt__PreconditionsKt.error(Preconditions.kt:142) + at kotlin.PreconditionsKt.error(Unknown Source) + at Script.main(Unknown Source) + at Script.a(Unknown Source) + at Script.(Unknown Source) + +Return code: 0 diff --git a/compiler/testData/integration/smoke/scriptException/script.kts b/compiler/testData/integration/smoke/scriptException/script.kts new file mode 100644 index 00000000000..220ffa3aac2 --- /dev/null +++ b/compiler/testData/integration/smoke/scriptException/script.kts @@ -0,0 +1,10 @@ +fun main() { + error("my error") +} + +fun a() { + main() +} + +a() + diff --git a/compiler/tests/org/jetbrains/kotlin/integration/CompilerSmokeTest.java b/compiler/tests/org/jetbrains/kotlin/integration/CompilerSmokeTest.java index 2e14136471e..bfcd62a8b14 100644 --- a/compiler/tests/org/jetbrains/kotlin/integration/CompilerSmokeTest.java +++ b/compiler/tests/org/jetbrains/kotlin/integration/CompilerSmokeTest.java @@ -87,4 +87,8 @@ public class CompilerSmokeTest extends KotlinIntegrationTestBase { public void testScriptWithClasspath() throws Exception { runCompiler("script", "-cp", new File("lib/javax.inject.jar").getAbsolutePath(), "-script", "script.kts"); } + + public void testScriptException() throws Exception { + runCompiler("script", "-script", "script.kts"); + } }