Support !LANGUAGE directive in codegen tests
LANGUAGE_VERSION directive will be removed later, for now it's left for simplicity
This commit is contained in:
@@ -222,7 +222,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result ?: BaseDiagnosticsTest.DiagnosticTestLanguageVersionSettings(
|
return result ?: CompilerTestLanguageVersionSettings(
|
||||||
BaseDiagnosticsTest.DEFAULT_DIAGNOSTIC_TESTS_FEATURES,
|
BaseDiagnosticsTest.DEFAULT_DIAGNOSTIC_TESTS_FEATURES,
|
||||||
LanguageVersionSettingsImpl.DEFAULT.apiVersion,
|
LanguageVersionSettingsImpl.DEFAULT.apiVersion,
|
||||||
LanguageVersionSettingsImpl.DEFAULT.languageVersion
|
LanguageVersionSettingsImpl.DEFAULT.languageVersion
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestFile
|
|||||||
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestModule
|
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestModule
|
||||||
import org.jetbrains.kotlin.checkers.CheckerTestUtil.ActualDiagnostic
|
import org.jetbrains.kotlin.checkers.CheckerTestUtil.ActualDiagnostic
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.config.*
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.*
|
import org.jetbrains.kotlin.diagnostics.*
|
||||||
import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer
|
import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer
|
||||||
@@ -111,19 +113,6 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
|||||||
override fun toString(): String = name
|
override fun toString(): String = name
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DiagnosticTestLanguageVersionSettings(
|
|
||||||
private val languageFeatures: Map<LanguageFeature, LanguageFeature.State>,
|
|
||||||
override val apiVersion: ApiVersion,
|
|
||||||
override val languageVersion: LanguageVersion
|
|
||||||
) : LanguageVersionSettings {
|
|
||||||
private val delegate = LanguageVersionSettingsImpl(languageVersion, apiVersion)
|
|
||||||
|
|
||||||
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
|
||||||
languageFeatures[feature] ?: delegate.getFeatureSupport(feature)
|
|
||||||
|
|
||||||
override fun <T> getFlag(flag: AnalysisFlag<T>): T = flag.defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class TestFile(
|
inner class TestFile(
|
||||||
val module: TestModule?,
|
val module: TestModule?,
|
||||||
fileName: String,
|
fileName: String,
|
||||||
@@ -293,15 +282,10 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
|||||||
CheckerTestUtil.DebugInfoDiagnosticFactory.UNRESOLVED_WITH_TARGET
|
CheckerTestUtil.DebugInfoDiagnosticFactory.UNRESOLVED_WITH_TARGET
|
||||||
)
|
)
|
||||||
|
|
||||||
val LANGUAGE_DIRECTIVE = "LANGUAGE"
|
|
||||||
private val LANGUAGE_PATTERN = Pattern.compile("(\\+|\\-|warn:)(\\w+)\\s*")
|
|
||||||
|
|
||||||
val DEFAULT_DIAGNOSTIC_TESTS_FEATURES = mapOf(
|
val DEFAULT_DIAGNOSTIC_TESTS_FEATURES = mapOf(
|
||||||
LanguageFeature.Coroutines to LanguageFeature.State.ENABLED
|
LanguageFeature.Coroutines to LanguageFeature.State.ENABLED
|
||||||
)
|
)
|
||||||
|
|
||||||
val API_VERSION_DIRECTIVE = "API_VERSION"
|
|
||||||
|
|
||||||
val CHECK_TYPE_DIRECTIVE = "CHECK_TYPE"
|
val CHECK_TYPE_DIRECTIVE = "CHECK_TYPE"
|
||||||
val CHECK_TYPE_PACKAGE = "tests._checkType"
|
val CHECK_TYPE_PACKAGE = "tests._checkType"
|
||||||
private val CHECK_TYPE_DECLARATIONS = "\npackage " + CHECK_TYPE_PACKAGE +
|
private val CHECK_TYPE_DECLARATIONS = "\npackage " + CHECK_TYPE_PACKAGE +
|
||||||
@@ -322,53 +306,6 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
|||||||
|
|
||||||
val MARK_DYNAMIC_CALLS_DIRECTIVE = "MARK_DYNAMIC_CALLS"
|
val MARK_DYNAMIC_CALLS_DIRECTIVE = "MARK_DYNAMIC_CALLS"
|
||||||
|
|
||||||
private fun parseLanguageVersionSettings(directiveMap: Map<String, String>): LanguageVersionSettings? {
|
|
||||||
val apiVersionString = directiveMap[API_VERSION_DIRECTIVE]
|
|
||||||
val directives = directiveMap[LANGUAGE_DIRECTIVE]
|
|
||||||
if (apiVersionString == null && directives == null) return null
|
|
||||||
|
|
||||||
val apiVersion = (if (apiVersionString != null) ApiVersion.parse(apiVersionString) else ApiVersion.LATEST_STABLE)
|
|
||||||
?: error("Unknown API version: $apiVersionString")
|
|
||||||
|
|
||||||
val languageFeatures = directives?.let(this::collectLanguageFeatureMap).orEmpty()
|
|
||||||
|
|
||||||
return DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion, LanguageVersion.LATEST_STABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 '((+|-|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, LanguageFeature.State>()
|
|
||||||
do {
|
|
||||||
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, mode) != null) {
|
|
||||||
Assert.fail("Duplicate entry for the language feature: $name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (matcher.find())
|
|
||||||
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseDiagnosticFilterDirective(directiveMap: Map<String, String>, allowUnderscoreUsage: Boolean): Condition<Diagnostic> {
|
private fun parseDiagnosticFilterDirective(directiveMap: Map<String, String>, allowUnderscoreUsage: Boolean): Condition<Diagnostic> {
|
||||||
val directives = directiveMap[DIAGNOSTICS_DIRECTIVE]
|
val directives = directiveMap[DIAGNOSTICS_DIRECTIVE]
|
||||||
val initialCondition =
|
val initialCondition =
|
||||||
|
|||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.checkers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.*
|
||||||
|
import org.junit.Assert
|
||||||
|
import java.util.*
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
const val LANGUAGE_DIRECTIVE = "LANGUAGE"
|
||||||
|
const val API_VERSION_DIRECTIVE = "API_VERSION"
|
||||||
|
|
||||||
|
data class CompilerTestLanguageVersionSettings(
|
||||||
|
private val languageFeatures: Map<LanguageFeature, LanguageFeature.State>,
|
||||||
|
override val apiVersion: ApiVersion,
|
||||||
|
override val languageVersion: LanguageVersion
|
||||||
|
) : LanguageVersionSettings {
|
||||||
|
private val delegate = LanguageVersionSettingsImpl(languageVersion, apiVersion)
|
||||||
|
|
||||||
|
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
||||||
|
languageFeatures[feature] ?: delegate.getFeatureSupport(feature)
|
||||||
|
|
||||||
|
override fun <T> getFlag(flag: AnalysisFlag<T>): T = flag.defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseLanguageVersionSettings(directiveMap: Map<String, String>): LanguageVersionSettings? {
|
||||||
|
val apiVersionString = directiveMap[API_VERSION_DIRECTIVE]
|
||||||
|
val directives = directiveMap[LANGUAGE_DIRECTIVE]
|
||||||
|
if (apiVersionString == null && directives == null) return null
|
||||||
|
|
||||||
|
val apiVersion = (if (apiVersionString != null) ApiVersion.parse(apiVersionString) else ApiVersion.LATEST_STABLE)
|
||||||
|
?: error("Unknown API version: $apiVersionString")
|
||||||
|
|
||||||
|
val languageFeatures = directives?.let(::collectLanguageFeatureMap).orEmpty()
|
||||||
|
|
||||||
|
return CompilerTestLanguageVersionSettings(languageFeatures, apiVersion, LanguageVersion.LATEST_STABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val languagePattern = Pattern.compile("(\\+|\\-|warn:)(\\w+)\\s*")
|
||||||
|
|
||||||
|
private fun collectLanguageFeatureMap(directives: String): Map<LanguageFeature, LanguageFeature.State> {
|
||||||
|
val matcher = languagePattern.matcher(directives)
|
||||||
|
if (!matcher.find()) {
|
||||||
|
Assert.fail(
|
||||||
|
"Wrong syntax in the '// !$LANGUAGE_DIRECTIVE: ...' directive:\n" +
|
||||||
|
"found: '$directives'\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, LanguageFeature.State>()
|
||||||
|
do {
|
||||||
|
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, mode) != null) {
|
||||||
|
Assert.fail("Duplicate entry for the language feature: $name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (matcher.find())
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
@@ -76,6 +76,7 @@ import java.util.Map;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt.parseLanguageVersionSettings;
|
||||||
import static org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt.writeAllTo;
|
import static org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt.writeAllTo;
|
||||||
import static org.jetbrains.kotlin.codegen.CodegenTestUtil.*;
|
import static org.jetbrains.kotlin.codegen.CodegenTestUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.TestUtilsKt.*;
|
import static org.jetbrains.kotlin.codegen.TestUtilsKt.*;
|
||||||
@@ -161,8 +162,10 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
|
|||||||
@NotNull List<TestFile> testFilesWithConfigurationDirectives,
|
@NotNull List<TestFile> testFilesWithConfigurationDirectives,
|
||||||
@NotNull CompilerConfiguration configuration
|
@NotNull CompilerConfiguration configuration
|
||||||
) {
|
) {
|
||||||
List<String> kotlinConfigurationFlags = new ArrayList<>(0);
|
LanguageVersionSettings explicitLanguageVersionSettings = null;
|
||||||
LanguageVersion explicitLanguageVersion = null;
|
LanguageVersion explicitLanguageVersion = null;
|
||||||
|
|
||||||
|
List<String> kotlinConfigurationFlags = new ArrayList<>(0);
|
||||||
for (TestFile testFile : testFilesWithConfigurationDirectives) {
|
for (TestFile testFile : testFilesWithConfigurationDirectives) {
|
||||||
kotlinConfigurationFlags.addAll(InTextDirectivesUtils.findListWithPrefixes(testFile.content, "// KOTLIN_CONFIGURATION_FLAGS:"));
|
kotlinConfigurationFlags.addAll(InTextDirectivesUtils.findListWithPrefixes(testFile.content, "// KOTLIN_CONFIGURATION_FLAGS:"));
|
||||||
|
|
||||||
@@ -176,12 +179,22 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
|
|||||||
|
|
||||||
String version = InTextDirectivesUtils.findStringWithPrefixes(testFile.content, "// LANGUAGE_VERSION:");
|
String version = InTextDirectivesUtils.findStringWithPrefixes(testFile.content, "// LANGUAGE_VERSION:");
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
assert explicitLanguageVersion == null : "Should not specify LANGUAGE_VERSION twice";
|
assertDirectivesToNull(explicitLanguageVersionSettings, explicitLanguageVersion);
|
||||||
explicitLanguageVersion = LanguageVersion.fromVersionString(version);
|
explicitLanguageVersion = LanguageVersion.fromVersionString(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, String> directives = KotlinTestUtils.parseDirectives(testFile.content);
|
||||||
|
LanguageVersionSettings fileLanguageVersionSettings = parseLanguageVersionSettings(directives);
|
||||||
|
if (fileLanguageVersionSettings != null) {
|
||||||
|
assertDirectivesToNull(explicitLanguageVersionSettings, explicitLanguageVersion);
|
||||||
|
explicitLanguageVersionSettings = fileLanguageVersionSettings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (explicitLanguageVersion != null) {
|
if (explicitLanguageVersionSettings != null) {
|
||||||
|
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, explicitLanguageVersionSettings);
|
||||||
|
}
|
||||||
|
else if (explicitLanguageVersion != null) {
|
||||||
CommonConfigurationKeysKt.setLanguageVersionSettings(
|
CommonConfigurationKeysKt.setLanguageVersionSettings(
|
||||||
configuration,
|
configuration,
|
||||||
new LanguageVersionSettingsImpl(explicitLanguageVersion, ApiVersion.createByLanguageVersion(explicitLanguageVersion))
|
new LanguageVersionSettingsImpl(explicitLanguageVersion, ApiVersion.createByLanguageVersion(explicitLanguageVersion))
|
||||||
@@ -191,6 +204,10 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
|
|||||||
updateConfigurationWithFlags(configuration, kotlinConfigurationFlags);
|
updateConfigurationWithFlags(configuration, kotlinConfigurationFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertDirectivesToNull(@Nullable LanguageVersionSettings settings, @Nullable LanguageVersion version) {
|
||||||
|
assert settings == null && version == null : "Should not specify LANGUAGE_VERSION twice or together with !LANGUAGE directive";
|
||||||
|
}
|
||||||
|
|
||||||
private static final Map<String, Class<?>> FLAG_NAMESPACE_TO_CLASS = ImmutableMap.of(
|
private static final Map<String, Class<?>> FLAG_NAMESPACE_TO_CLASS = ImmutableMap.of(
|
||||||
"CLI", CLIConfigurationKeys.class,
|
"CLI", CLIConfigurationKeys.class,
|
||||||
"JVM", JVMConfigurationKeys.class
|
"JVM", JVMConfigurationKeys.class
|
||||||
|
|||||||
Reference in New Issue
Block a user