[FIR] Verify diagnostic messages don't reference non-existent parameters

This commit is contained in:
Kirill Rakhman
2023-04-26 16:19:27 +02:00
committed by Space Team
parent c956b4aeae
commit a818c543a9
5 changed files with 39 additions and 23 deletions
@@ -1843,7 +1843,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(
WRONG_INVOCATION_KIND,
"{2} wrong invocation kind: given {3} case, but {4} case is possible",
"{0} has wrong invocation kind: given {1} case, but {2} case is possible",
SYMBOL,
TO_STRING,
TO_STRING
@@ -5,17 +5,19 @@
package org.jetbrains.kotlin.diagnostics
import com.google.common.annotations.VisibleForTesting
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
import org.jetbrains.kotlin.diagnostics.rendering.renderParameter
import java.text.MessageFormat
sealed interface KtDiagnosticRenderer {
@VisibleForTesting val message: String
fun render(diagnostic: KtDiagnostic): String
fun renderParameters(diagnostic: KtDiagnostic): Array<out Any?>
}
class SimpleKtDiagnosticRenderer(private val message: String) : KtDiagnosticRenderer {
class SimpleKtDiagnosticRenderer(override val message: String) : KtDiagnosticRenderer {
override fun render(diagnostic: KtDiagnostic): String {
require(diagnostic is KtSimpleDiagnostic)
return message
@@ -28,7 +30,7 @@ class SimpleKtDiagnosticRenderer(private val message: String) : KtDiagnosticRend
}
sealed class AbstractKtDiagnosticWithParametersRenderer(
protected val message: String
final override val message: String
) : KtDiagnosticRenderer {
private val messageFormat = MessageFormat(message)
@@ -5,29 +5,43 @@
package org.jetbrains.kotlin.test.utils
import org.jetbrains.kotlin.diagnostics.AbstractKtDiagnosticFactory
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryForDeprecation
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.*
import org.junit.Assert
import kotlin.reflect.KProperty
import kotlin.reflect.full.memberProperties
fun KtDiagnosticFactoryToRendererMap.checkMissingMessages(objectWithErrors: Any) {
for (property in objectWithErrors.javaClass.kotlin.memberProperties) {
fun KtDiagnosticFactoryToRendererMap.verifyMessages(objectWithErrors: Any) {
for (property in objectWithErrors::class.memberProperties) {
when (val factory = property.getter.call(objectWithErrors)) {
is AbstractKtDiagnosticFactory -> {
checkMissingMessagesForFactory(factory, property)
verifyMessageForFactory(factory, property)
}
is KtDiagnosticFactoryForDeprecation<*> -> {
checkMissingMessagesForFactory(factory.warningFactory, property)
checkMissingMessagesForFactory(factory.errorFactory, property)
verifyMessageForFactory(factory.warningFactory, property)
verifyMessageForFactory(factory.errorFactory, property)
}
else -> {}
}
}
}
fun KtDiagnosticFactoryToRendererMap.checkMissingMessagesForFactory(factory: AbstractKtDiagnosticFactory, property: KProperty<*>) {
if (!containsKey(factory)) {
throw IllegalStateException("No default diagnostic renderer is provided for ${property.name}")
private val messageParameterRegex = """\{\d.*?}""".toRegex()
fun KtDiagnosticFactoryToRendererMap.verifyMessageForFactory(factory: AbstractKtDiagnosticFactory, property: KProperty<*>) {
Assert.assertTrue("No default diagnostic renderer is provided for ${property.name}", containsKey(factory))
val renderer = get(factory)!!
val parameterCount = when (renderer) {
is KtDiagnosticWithParameters4Renderer<*, *, *, *> -> 4
is KtDiagnosticWithParameters3Renderer<*, *, *> -> 3
is KtDiagnosticWithParameters2Renderer<*, *> -> 2
is KtDiagnosticWithParameters1Renderer<*> -> 1
else -> 0
}
}
for (parameter in messageParameterRegex.findAll(renderer.message)) {
val index = parameter.value.substring(1, 2).toInt()
Assert.assertTrue("Message for ${property.name} references wrong parameter {$index}", index < parameterCount)
}
}
@@ -15,16 +15,16 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrorsDefaultMessages
import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors
import org.jetbrains.kotlin.fir.builder.FirSyntaxErrorsDefaultMessages
import org.jetbrains.kotlin.test.utils.checkMissingMessages
import org.jetbrains.kotlin.test.utils.verifyMessages
import org.junit.Test
class DefaultMessagesTest {
@Test
fun ensureAllMessagesPresent() {
FirErrorsDefaultMessages.MAP.checkMissingMessages(FirErrors)
FirJvmErrorsDefaultMessages.MAP.checkMissingMessages(FirJvmErrors)
FirJsErrorsDefaultMessages.MAP.checkMissingMessages(FirJsErrors)
FirNativeErrorsDefaultMessages.MAP.checkMissingMessages(FirNativeErrors)
FirSyntaxErrorsDefaultMessages.MAP.checkMissingMessages(FirSyntaxErrors)
FirErrorsDefaultMessages.MAP.verifyMessages(FirErrors)
FirJvmErrorsDefaultMessages.MAP.verifyMessages(FirJvmErrors)
FirJsErrorsDefaultMessages.MAP.verifyMessages(FirJsErrors)
FirNativeErrorsDefaultMessages.MAP.verifyMessages(FirNativeErrors)
FirSyntaxErrorsDefaultMessages.MAP.verifyMessages(FirSyntaxErrors)
}
}
@@ -7,12 +7,12 @@ package org.jetbrains.kotlin.parcelize.test
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtDefaultErrorMessagesParcelize
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize
import org.jetbrains.kotlin.test.utils.checkMissingMessages
import org.jetbrains.kotlin.test.utils.verifyMessages
import org.junit.jupiter.api.Test
class ParcelizeDefaultMessagesTest {
@Test
fun ensureAllMessagesPresent() {
KtDefaultErrorMessagesParcelize.MAP.checkMissingMessages(KtErrorsParcelize)
KtDefaultErrorMessagesParcelize.MAP.verifyMessages(KtErrorsParcelize)
}
}