From 5008682befff6023f87ca7342c00bb5fbcffdc97 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 8 Oct 2014 11:01:35 +0400 Subject: [PATCH] Better diagnostic for Element has no prototype error --- j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt | 15 ++++++++--- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 27 +++++++++++++++----- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 10 +++++++- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt index d98af7f5a68..e65a167dee7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt @@ -46,6 +46,8 @@ fun CodeBuilder.append(elements: Collection, separator: String, prefix: return append(elements.filter { !it.isEmpty }.map { { append(it) } }, separator, prefix, suffix) } +class ElementCreationStackTraceRequiredException : RuntimeException() + class CodeBuilder(private val topElement: PsiElement?) { private val builder = StringBuilder() private var endOfLineCommentAtEnd = false @@ -81,10 +83,15 @@ class CodeBuilder(private val topElement: PsiElement?) { if (element.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines if (element.prototypes == null && topElement != null) { - val s = "Element $element has no prototypes assigned.\n" + - "Use Element.assignPrototype() or Element.assignNoPrototype().\n" + - "Element created at:\n${element.createdAt}" - throw RuntimeException(s) + if (element.createdAt == null) { + throw ElementCreationStackTraceRequiredException() + } + else { + val s = "Element $element has no prototypes assigned.\n" + + "Use Element.assignPrototype() or Element.assignNoPrototype().\n" + + "Element created at:\n${element.createdAt}" + throw RuntimeException(s) + } } if (topElement == null || element.prototypes!!.isEmpty()) { diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 998cd41ee33..658fb7f187b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -99,14 +99,27 @@ public class Converter private(val project: Project, State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd)) public fun elementToKotlin(element: PsiElement): String { - val converted = convertTopElement(element) ?: return "" - val builder = CodeBuilder(element) - builder.append(converted) - if (postProcessor != null) { - return AfterConversionPass(project, postProcessor).run(builder.result) + try { + val converted = convertTopElement(element) ?: return "" + val builder = CodeBuilder(element) + builder.append(converted) + + if (postProcessor != null) { + return AfterConversionPass(project, postProcessor).run(builder.result) + } + else { + return builder.result + } } - else { - return builder.result + catch(e: ElementCreationStackTraceRequiredException) { + // if we got this exception then we need to turn element creation stack traces on to get better diagnostic + Element.saveCreationStacktraces = true + try { + return elementToKotlin(element) + } + finally { + Element.saveCreationStacktraces = false + } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 770eb970320..38a1ebb313b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -67,7 +67,11 @@ abstract class Element { $prototypes = value } - public var createdAt: String = "Element creation stacktraces turned off. Uncomment initializer of Element.createdAt." //Exception().getStackTrace().joinToString("\n") + public var createdAt: String? + = if (saveCreationStacktraces) + Exception().getStackTrace().joinToString("\n") + else + null /** This method should not be used anywhere except for CodeBuilder! Use CodeBuilder.append instead. */ public abstract fun generateCode(builder: CodeBuilder) @@ -80,4 +84,8 @@ abstract class Element { override fun generateCode(builder: CodeBuilder) { } override val isEmpty: Boolean get() = true } + + class object { + var saveCreationStacktraces = false + } }