Psi2ir: improve exception stack traces

- Do not wrap exceptions resulting from generating error expressions
  multiple times, as that could lead to stack traces where the identical
  code is wrapped many times and is printed in the exception message on
  each step, which was difficult to read
- Add element location (file name, line number & position) to the
  message, similarly to exceptions from codegen, when catching and
  rethrowing exceptions at the top level
This commit is contained in:
Alexander Udalov
2020-11-04 13:30:12 +01:00
parent 3cb202f576
commit c1a292b01b
6 changed files with 45 additions and 13 deletions
@@ -0,0 +1,8 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common
class BackendException(message: String, cause: Throwable?) : IllegalStateException(message, cause)
@@ -232,12 +232,13 @@ object CodegenUtil {
}
@JvmStatic
fun reportBackendException(exception: Throwable, phase: String, fileUrl: String?): Nothing {
fun reportBackendException(exception: Throwable, phase: String, location: String?, additionalMessage: String? = null): Nothing {
// CompilationException (the only KotlinExceptionWithAttachments possible here) is already supposed
// to have all information about the context.
if (exception is KotlinExceptionWithAttachments) throw exception
throw IllegalStateException(
getExceptionMessage("Backend", "Exception during $phase", exception, fileUrl),
throw BackendException(
getExceptionMessage("Backend", "Exception during $phase", exception, location) +
additionalMessage?.let { "\n" + it }.orEmpty(),
exception
)
}
@@ -75,7 +75,7 @@ public class PackageCodegenImpl implements PackageCodegen {
}
catch (Throwable e) {
VirtualFile vFile = file.getVirtualFile();
CodegenUtil.reportBackendException(e, "file facade code generation", vFile == null ? null : vFile.getUrl());
CodegenUtil.reportBackendException(e, "file facade code generation", vFile == null ? null : vFile.getUrl(), null);
}
}
}
@@ -16,10 +16,13 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.backend.common.BackendException
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -58,13 +61,23 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration)
)
}
} catch (e: BackendException) {
throw e
} catch (e: Throwable) {
if (context.configuration.ignoreErrors) {
context.irFactory.createErrorDeclaration(
ktDeclaration.startOffsetSkippingComments, ktDeclaration.endOffset,
getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration)
)
} else throw e
when {
context.configuration.ignoreErrors -> {
context.irFactory.createErrorDeclaration(
ktDeclaration.startOffsetSkippingComments, ktDeclaration.endOffset,
getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration)
)
}
e is ErrorExpressionException ->
CodegenUtil.reportBackendException(e.cause ?: e, "psi2ir", PsiDiagnosticUtils.atLocation(e.ktElement), e.message)
else -> {
val psiFile = ktDeclaration.containingKtFile
CodegenUtil.reportBackendException(e, "psi2ir", psiFile.virtualFile?.path ?: psiFile.name)
}
}
}
}
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.types.ErrorUtils
class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
private val ignoreErrors: Boolean get() = context.configuration.ignoreErrors
private inline fun generateErrorExpression(ktElement: KtElement, e: Throwable? = null, body: () -> IrExpression) =
private inline fun generateErrorExpression(ktElement: KtElement, e: Throwable? = null, body: () -> IrExpression): IrExpression =
if (ignoreErrors)
body()
else
throw RuntimeException("${e?.message}: ${ktElement::class.java.simpleName}:\n${ktElement.text}", e)
throw ErrorExpressionException(ktElement, e)
fun generateErrorExpression(ktElement: KtElement, e: Throwable): IrExpression =
generateErrorExpression(ktElement, e) {
@@ -80,4 +80,9 @@ class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : Stateme
irErrorCall
}
}
}
class ErrorExpressionException(val ktElement: KtElement, cause: Throwable?) : RuntimeException(
"${cause?.message}: ${ktElement::class.java.simpleName}:\n${ktElement.text}",
cause
)
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.backend.common.BackendException
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -73,6 +74,10 @@ class StatementGenerator(
private fun KtElement.genStmt(): IrStatement =
try {
deparenthesize().accept(this@StatementGenerator, null)
} catch (e: BackendException) {
throw e
} catch (e: ErrorExpressionException) {
throw e
} catch (e: Throwable) {
ErrorExpressionGenerator(this@StatementGenerator).generateErrorExpression(this, e)
}