Better diagnostic for Element has no prototype error

This commit is contained in:
Valentin Kipyatkov
2014-10-08 11:01:35 +04:00
parent 0213d37d82
commit 5008682bef
3 changed files with 40 additions and 12 deletions
+11 -4
View File
@@ -46,6 +46,8 @@ fun CodeBuilder.append(elements: Collection<Element>, separator: String, prefix:
return append(elements.filter { !it.isEmpty }.map { { append(it) } }, separator, prefix, suffix) return append(elements.filter { !it.isEmpty }.map { { append(it) } }, separator, prefix, suffix)
} }
class ElementCreationStackTraceRequiredException : RuntimeException()
class CodeBuilder(private val topElement: PsiElement?) { class CodeBuilder(private val topElement: PsiElement?) {
private val builder = StringBuilder() private val builder = StringBuilder()
private var endOfLineCommentAtEnd = false 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.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines
if (element.prototypes == null && topElement != null) { if (element.prototypes == null && topElement != null) {
val s = "Element $element has no prototypes assigned.\n" + if (element.createdAt == null) {
"Use Element.assignPrototype() or Element.assignNoPrototype().\n" + throw ElementCreationStackTraceRequiredException()
"Element created at:\n${element.createdAt}" }
throw RuntimeException(s) 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()) { if (topElement == null || element.prototypes!!.isEmpty()) {
+20 -7
View File
@@ -99,14 +99,27 @@ public class Converter private(val project: Project,
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd)) State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd))
public fun elementToKotlin(element: PsiElement): String { public fun elementToKotlin(element: PsiElement): String {
val converted = convertTopElement(element) ?: return "" try {
val builder = CodeBuilder(element) val converted = convertTopElement(element) ?: return ""
builder.append(converted) val builder = CodeBuilder(element)
if (postProcessor != null) { builder.append(converted)
return AfterConversionPass(project, postProcessor).run(builder.result)
if (postProcessor != null) {
return AfterConversionPass(project, postProcessor).run(builder.result)
}
else {
return builder.result
}
} }
else { catch(e: ElementCreationStackTraceRequiredException) {
return builder.result // 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
}
} }
} }
+9 -1
View File
@@ -67,7 +67,11 @@ abstract class Element {
$prototypes = value $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. */ /** This method should not be used anywhere except for CodeBuilder! Use CodeBuilder.append instead. */
public abstract fun generateCode(builder: CodeBuilder) public abstract fun generateCode(builder: CodeBuilder)
@@ -80,4 +84,8 @@ abstract class Element {
override fun generateCode(builder: CodeBuilder) { } override fun generateCode(builder: CodeBuilder) { }
override val isEmpty: Boolean get() = true override val isEmpty: Boolean get() = true
} }
class object {
var saveCreationStacktraces = false
}
} }