Introduce LanguageFeature.State, drop coroutines-related pseudofeatures
Previously there were three LanguageFeature instances -- Coroutines, DoNotWarnOnCoroutines and ErrorOnCoroutines -- which were handled very awkwardly in the compiler and in the IDE to basically support a language feature with a more complex state: not just enabled/disabled, but also enabled with warning and enabled with error. Introduce a new enum LanguageFeature.State for this and allow LanguageVersionSettings to get the state of any language feature with 'getFeatureSupport'. One noticeable drawback of this approach is that looking at the API, one may assume that any language feature can be in one of the four states (enabled, warning, error, disabled). This is not true however; there's only one language feature at the moment (coroutines) for which these intermediate states (warning, error) are handled in any way. This may be refactored further by abstracting the logic that checks the language feature availability so that it would work exactly the same for any feature. Another issue is that the difference among ENABLED_WITH_ERROR and DISABLED is not clear. They are left as separate states because at the moment, different diagnostics are reported in these two cases and quick-fixes in IDE rely on that
This commit is contained in:
@@ -217,7 +217,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
}
|
||||
|
||||
return result ?: BaseDiagnosticsTest.DiagnosticTestLanguageVersionSettings(
|
||||
BaseDiagnosticsTest.DEFAULT_DIAGNOSTIC_TESTS_FEATURES.keysToMap { true },
|
||||
BaseDiagnosticsTest.DEFAULT_DIAGNOSTIC_TESTS_FEATURES,
|
||||
LanguageVersionSettingsImpl.DEFAULT.apiVersion,
|
||||
LanguageVersionSettingsImpl.DEFAULT.languageVersion
|
||||
)
|
||||
|
||||
@@ -99,20 +99,17 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
}
|
||||
|
||||
data class DiagnosticTestLanguageVersionSettings(
|
||||
private val languageFeatures: Map<LanguageFeature, Boolean>,
|
||||
private val languageFeatures: Map<LanguageFeature, LanguageFeature.State>,
|
||||
override val apiVersion: ApiVersion,
|
||||
override val languageVersion: LanguageVersion
|
||||
) : LanguageVersionSettings {
|
||||
private val delegate = LanguageVersionSettingsImpl(languageVersion, apiVersion)
|
||||
|
||||
override fun supportsFeature(feature: LanguageFeature): Boolean =
|
||||
languageFeatures[feature] ?: delegate.supportsFeature(feature)
|
||||
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
||||
languageFeatures[feature] ?: delegate.getFeatureSupport(feature)
|
||||
|
||||
override val skipMetadataVersionCheck: Boolean get() = false
|
||||
|
||||
override val additionalFeatures: Collection<LanguageFeature>
|
||||
get() = error("Must not be called")
|
||||
|
||||
override val isApiVersionExplicit: Boolean
|
||||
get() = error("Must not be called")
|
||||
}
|
||||
@@ -286,10 +283,10 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
|
||||
val LANGUAGE_DIRECTIVE = "LANGUAGE"
|
||||
val LANGUAGE_VERSION = "LANGUAGE_VERSION"
|
||||
private val LANGUAGE_PATTERN = Pattern.compile("([\\+\\-])(\\w+)\\s*")
|
||||
private val LANGUAGE_PATTERN = Pattern.compile("(\\+|\\-|warn:)(\\w+)\\s*")
|
||||
|
||||
val DEFAULT_DIAGNOSTIC_TESTS_FEATURES = listOf(
|
||||
LanguageFeature.DoNotWarnOnCoroutines
|
||||
val DEFAULT_DIAGNOSTIC_TESTS_FEATURES = mapOf(
|
||||
LanguageFeature.Coroutines to LanguageFeature.State.ENABLED
|
||||
)
|
||||
|
||||
val API_VERSION_DIRECTIVE = "API_VERSION"
|
||||
@@ -330,27 +327,32 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
return DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion, languageVersion)
|
||||
}
|
||||
|
||||
private fun collectLanguageFeatureMap(directives: String): Map<LanguageFeature, Boolean> {
|
||||
private fun collectLanguageFeatureMap(directives: String): Map<LanguageFeature, LanguageFeature.State> {
|
||||
val matcher = LANGUAGE_PATTERN.matcher(directives)
|
||||
if (!matcher.find()) {
|
||||
Assert.fail(
|
||||
"Wrong syntax in the '// !$LANGUAGE_DIRECTIVE: ...' directive:\n" +
|
||||
"found: '$directives'\n" +
|
||||
"Must be '([+-]LanguageFeatureName)+'\n" +
|
||||
"where '+' means 'enable' and '-' means 'disable'\n" +
|
||||
"Must be '((+|-|warn:)LanguageFeatureName)+'\n" +
|
||||
"where '+' means 'enable', '-' means 'disable', 'warn:' means 'enable with warning'\n" +
|
||||
"and language feature names are names of enum entries in LanguageFeature enum class"
|
||||
)
|
||||
}
|
||||
|
||||
val values = HashMap<LanguageFeature, Boolean>()
|
||||
val values = HashMap<LanguageFeature, LanguageFeature.State>()
|
||||
do {
|
||||
val enable = matcher.group(1) == "+"
|
||||
val mode = when (matcher.group(1)) {
|
||||
"+" -> LanguageFeature.State.ENABLED
|
||||
"-" -> LanguageFeature.State.DISABLED
|
||||
"warn:" -> LanguageFeature.State.ENABLED_WITH_WARNING
|
||||
else -> error("Unknown mode for language feature: ${matcher.group(1)}")
|
||||
}
|
||||
val name = matcher.group(2)
|
||||
val feature = LanguageFeature.fromString(name) ?: throw AssertionError(
|
||||
"Language feature not found, please check spelling: $name\n" +
|
||||
"Known features:\n ${LanguageFeature.values().joinToString("\n ")}"
|
||||
)
|
||||
if (values.put(feature, enable) != null) {
|
||||
if (values.put(feature, mode) != null) {
|
||||
Assert.fail("Duplicate entry for the language feature: $name")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user