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
@@ -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,11 +83,16 @@ 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) {
if (element.createdAt == null) {
throw ElementCreationStackTraceRequiredException()
}
else {
val s = "Element $element has no prototypes assigned.\n" + val s = "Element $element has no prototypes assigned.\n" +
"Use Element.assignPrototype() or Element.assignNoPrototype().\n" + "Use Element.assignPrototype() or Element.assignNoPrototype().\n" +
"Element created at:\n${element.createdAt}" "Element created at:\n${element.createdAt}"
throw RuntimeException(s) throw RuntimeException(s)
} }
}
if (topElement == null || element.prototypes!!.isEmpty()) { if (topElement == null || element.prototypes!!.isEmpty()) {
element.generateCode(this) element.generateCode(this)
@@ -99,9 +99,11 @@ 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 {
try {
val converted = convertTopElement(element) ?: return "" val converted = convertTopElement(element) ?: return ""
val builder = CodeBuilder(element) val builder = CodeBuilder(element)
builder.append(converted) builder.append(converted)
if (postProcessor != null) { if (postProcessor != null) {
return AfterConversionPass(project, postProcessor).run(builder.result) return AfterConversionPass(project, postProcessor).run(builder.result)
} }
@@ -109,6 +111,17 @@ public class Converter private(val project: Project,
return builder.result 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
}
}
}
private fun convertTopElement(element: PsiElement?): Element? = when (element) { private fun convertTopElement(element: PsiElement?): Element? = when (element) {
is PsiJavaFile -> convertFile(element) is PsiJavaFile -> convertFile(element)
+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
}
} }