From c1a292b01b4167e80155c7cf14c48109807bb53c Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 4 Nov 2020 13:30:12 +0100 Subject: [PATCH] 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 --- .../kotlin/backend/common/BackendException.kt | 8 ++++++ .../kotlin/backend/common/CodegenUtil.kt | 7 +++--- .../kotlin/codegen/PackageCodegenImpl.java | 2 +- .../psi2ir/generators/DeclarationGenerator.kt | 25 ++++++++++++++----- .../generators/ErrorExpressionGenerator.kt | 11 +++++--- .../psi2ir/generators/StatementGenerator.kt | 5 ++++ 6 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 compiler/backend-common/src/org/jetbrains/kotlin/backend/common/BackendException.kt diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/BackendException.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/BackendException.kt new file mode 100644 index 00000000000..df889509b6c --- /dev/null +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/BackendException.kt @@ -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) diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt index 8b8f776ccc6..8933c7fb15c 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt @@ -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 ) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index e0d2b6466ef..0edd2925ec2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -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); } } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt index 1622ece2f5f..14831554085 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt @@ -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) + } + } } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt index e627764d0b7..7f6ef08a6c8 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt @@ -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 } -} \ No newline at end of file +} + +class ErrorExpressionException(val ktElement: KtElement, cause: Throwable?) : RuntimeException( + "${cause?.message}: ${ktElement::class.java.simpleName}:\n${ktElement.text}", + cause +) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index c3cf23c3e0f..cd6bfe7c0b5 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -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) }