[FIR] Verify diagnostic messages use single quotes correctly

This commit is contained in:
Kirill Rakhman
2023-05-24 16:03:32 +02:00
committed by Space Team
parent b760046f93
commit aacbcc9d49
3 changed files with 30 additions and 13 deletions
@@ -229,7 +229,7 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(
NON_CONSUMABLE_EXPORTED_IDENTIFIER,
"Exported declaration contains non-consumable identifier '${0}', that can't be represented inside TS definitions and ESM",
"Exported declaration contains non-consumable identifier ''${0}'', that can''t be represented inside TS definitions and ESM",
CommonRenderers.STRING,
)
}
@@ -1064,7 +1064,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
// Modifiers
map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable to this function")
map.put(INAPPLICABLE_INFIX_MODIFIER, "'infix' modifier is inapplicable to this function")
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING)
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING)
map.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", TO_STRING, TO_STRING)
@@ -1178,7 +1178,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(ITERATOR_ON_NULLABLE, "Not nullable value required to call an 'iterator()' method on for-loop range")
map.put(ITERATOR_AMBIGUITY, "Method ''iterator()'' is ambiguous for this expression: {0}", SYMBOLS)
map.put(NEXT_MISSING, "Method ''next()'' cannot be called on ''iterator()''")
map.put(NEXT_MISSING, "Method 'next()' cannot be called on 'iterator()'")
map.put(NEXT_AMBIGUITY, "Method ''next()'' is ambiguous for this expression: {0}", SYMBOLS)
map.put(AMBIGUOUS_FUNCTION_TYPE_KIND, "Multiple functional type conversions are not allowed for a single type. Detected type conversions: {0}", FUNCTIONAL_TYPE_KINDS)
map.put(NEXT_NONE_APPLICABLE, "None of the ''next()'' functions is applicable for ''iterator()'' of type ''{0}''", SYMBOLS)
@@ -1784,7 +1784,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(
LATEINIT_FIELD_IN_VAL_PROPERTY,
"Only mutable properties can have a mutable backing field. Consider changing ''val'' to ''var''"
"Only mutable properties can have a mutable backing field. Consider changing 'val' to 'var'"
)
map.put(
LATEINIT_NULLABLE_BACKING_FIELD,
@@ -2343,15 +2343,15 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(
NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND,
"''suspend'' function can only be called in a form of modifier of a lambda: suspend { ... }"
"'suspend' function can only be called in a form of modifier of a lambda: suspend { ... }"
)
map.put(
MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND,
"Calls having a form of ''suspend {}'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Surround the lambda with parentheses: ''suspend({ ... })''"
"Calls having a form of 'suspend {}' are deprecated because 'suspend' in the context will have a meaning of a modifier. Surround the lambda with parentheses: 'suspend({ ... })'"
)
map.put(
MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN,
"Calls having a form of ''suspend fun'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Surround the argument of the call with parens: ''suspend(fun() { ... })''." +
"Calls having a form of 'suspend fun' are deprecated because 'suspend' in the context will have a meaning of a modifier. Surround the argument of the call with parens: 'suspend(fun() { ... })'." +
" See https://youtrack.jetbrains.com/issue/KT-49264"
)
map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
@@ -11,24 +11,31 @@ import kotlin.reflect.KProperty
import kotlin.reflect.full.memberProperties
fun KtDiagnosticFactoryToRendererMap.verifyMessages(objectWithErrors: Any) {
val errors = mutableListOf<String>()
for (property in objectWithErrors::class.memberProperties) {
when (val factory = property.getter.call(objectWithErrors)) {
is AbstractKtDiagnosticFactory -> {
verifyMessageForFactory(factory, property)
errors += verifyMessageForFactory(factory, property)
}
is KtDiagnosticFactoryForDeprecation<*> -> {
verifyMessageForFactory(factory.warningFactory, property)
verifyMessageForFactory(factory.errorFactory, property)
errors += verifyMessageForFactory(factory.warningFactory, property)
errors += verifyMessageForFactory(factory.errorFactory, property)
}
else -> {}
}
}
if (errors.isNotEmpty()) {
Assert.fail(errors.joinToString("\n", prefix = "\n"))
}
}
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))
fun KtDiagnosticFactoryToRendererMap.verifyMessageForFactory(factory: AbstractKtDiagnosticFactory, property: KProperty<*>) = buildList {
if (!containsKey(factory)) {
add("No default diagnostic renderer is provided for ${property.name}")
}
val renderer = get(factory)!!
@@ -42,6 +49,16 @@ fun KtDiagnosticFactoryToRendererMap.verifyMessageForFactory(factory: AbstractKt
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)
if (index >= parameterCount) {
add("Message for ${property.name} references wrong parameter {$index}")
}
}
if (parameterCount > 0 && renderer.message.contains("(?<!')'(?!')".toRegex())) {
add("Renderer for ${property.name} has parameters and contains single quote. Text inside single quotes is not formatted in MessageFormat. Use double quote instead.")
}
if (parameterCount == 0 && renderer.message.contains("(?<!')''(?!')".toRegex())) {
add("Renderer for ${property.name} has no parameters and contains double quote. Single quote should be used.")
}
}