[Analysis API] do not create multiple attachments inside exceptions

This commit is contained in:
Ilya Kirillov
2022-08-03 10:46:16 +02:00
parent ddbd89aea7
commit f45f1ba3dc
30 changed files with 319 additions and 278 deletions
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2022 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.analysis.utils.errors
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
public class ExceptionAttachmentBuilder {
private val printer = PrettyPrinter()
public fun <T> withEntry(name: String, value: T, render: (T & Any) -> String) {
withEntry(name) {
appendLine("Class: ${value?.let { it::class.java.name }}")
appendLine("Value:")
withIndent {
appendLine(value?.let(render) ?: "null")
}
}
}
public fun withEntry(name: String, value: String?) {
with(printer) {
appendLine("- $name:")
withIndent {
appendLine(value)
}
appendLine(separator)
}
}
public fun withEntry(name: String, buildValue: PrettyPrinter.() -> Unit) {
withEntry(name, prettyPrint { buildValue() })
}
public fun withEntryGroup(groupName: String, build: ExceptionAttachmentBuilder.() -> Unit) {
val builder = ExceptionAttachmentBuilder().apply(build)
withEntry(groupName, builder) { it.buildString() }
}
public fun buildString(): String = printer.toString()
private companion object {
private const val separator = "========"
}
}
public inline fun KotlinExceptionWithAttachments.buildAttachment(
name: String = "info.txt",
buildContent: ExceptionAttachmentBuilder.() -> Unit
): KotlinExceptionWithAttachments {
return withAttachment(name, ExceptionAttachmentBuilder().apply(buildContent).buildString())
}
public inline fun buildErrorWithAttachment(
message: String,
cause: Throwable? = null,
attachmentName: String = "info.txt",
buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {}
): Nothing {
val exception = KotlinExceptionWithAttachments(message, cause)
exception.buildAttachment(attachmentName) { buildAttachment() }
throw exception
}
@OptIn(ExperimentalContracts::class)
public inline fun checkWithAttachmentBuilder(
value: Boolean,
lazyMessage: () -> String,
buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {}
) {
contract { returns() implies (value) }
if (!value) {
buildErrorWithAttachment(lazyMessage(), buildAttachment = buildAttachment)
}
}
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2022 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.analysis.utils.errors
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.errorWithAttachment
import org.jetbrains.kotlin.utils.withAttachmentDetailed
public fun unexpectedElementError(elementName: String, element: Any?): Nothing {
errorWithAttachment("Unexpected $elementName ${element?.let { it::class.simpleName }}") {
withAttachment("element", element)
}
}
public inline fun <reified ELEMENT> unexpectedElementError(element: Any?): Nothing {
unexpectedElementError(ELEMENT::class.simpleName ?: ELEMENT::class.java.name, element)
}
public fun KotlinExceptionWithAttachments.withPsiAttachment(name: String, psi: PsiElement?): KotlinExceptionWithAttachments {
withAttachmentDetailed(name, psi) { psiElement ->
when (psiElement) {
is KtElement -> psiElement.getElementTextInContext()
else -> psiElement.text
}
}
return this
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2022 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.analysis.utils.errors
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
import org.jetbrains.kotlin.psi.KtElement
public fun ExceptionAttachmentBuilder.withPsiEntry(name: String, psi: PsiElement?) {
withEntry(name, psi) { psiElement ->
when (psiElement) {
is KtElement -> psiElement.getElementTextInContext()
else -> psiElement.text
}
}
}
public fun ExceptionAttachmentBuilder.withClassEntry(name: String, element: Any?) {
withEntry(name, element) { it::class.java.name }
}
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2022 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.analysis.utils.errors
public fun unexpectedElementError(elementName: String, element: Any?): Nothing {
buildErrorWithAttachment("Unexpected $elementName ${element?.let { it::class.simpleName }}") {
withEntry(elementName, element) { element.toString() }
}
}
public inline fun <reified ELEMENT> unexpectedElementError(element: Any?): Nothing {
unexpectedElementError(ELEMENT::class.simpleName ?: ELEMENT::class.java.name, element)
}