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:
Mikhail Zarechenskiy
2017-10-24 01:32:53 +03:00
parent 1ed8aa1cc5
commit 7a934d74e5
4 changed files with 111 additions and 70 deletions
@@ -222,7 +222,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
}
}
return result ?: BaseDiagnosticsTest.DiagnosticTestLanguageVersionSettings(
return result ?: CompilerTestLanguageVersionSettings(
BaseDiagnosticsTest.DEFAULT_DIAGNOSTIC_TESTS_FEATURES,
LanguageVersionSettingsImpl.DEFAULT.apiVersion,
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.CheckerTestUtil.ActualDiagnostic
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.diagnostics.*
import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer
@@ -111,19 +113,6 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
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(
val module: TestModule?,
fileName: String,
@@ -293,15 +282,10 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
CheckerTestUtil.DebugInfoDiagnosticFactory.UNRESOLVED_WITH_TARGET
)
val LANGUAGE_DIRECTIVE = "LANGUAGE"
private val LANGUAGE_PATTERN = Pattern.compile("(\\+|\\-|warn:)(\\w+)\\s*")
val DEFAULT_DIAGNOSTIC_TESTS_FEATURES = mapOf(
LanguageFeature.Coroutines to LanguageFeature.State.ENABLED
)
val API_VERSION_DIRECTIVE = "API_VERSION"
val CHECK_TYPE_DIRECTIVE = "CHECK_TYPE"
val CHECK_TYPE_PACKAGE = "tests._checkType"
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"
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> {
val directives = directiveMap[DIAGNOSTICS_DIRECTIVE]
val initialCondition =
@@ -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.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.codegen.CodegenTestUtil.*;
import static org.jetbrains.kotlin.codegen.TestUtilsKt.*;
@@ -161,8 +162,10 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
@NotNull List<TestFile> testFilesWithConfigurationDirectives,
@NotNull CompilerConfiguration configuration
) {
List<String> kotlinConfigurationFlags = new ArrayList<>(0);
LanguageVersionSettings explicitLanguageVersionSettings = null;
LanguageVersion explicitLanguageVersion = null;
List<String> kotlinConfigurationFlags = new ArrayList<>(0);
for (TestFile testFile : testFilesWithConfigurationDirectives) {
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:");
if (version != null) {
assert explicitLanguageVersion == null : "Should not specify LANGUAGE_VERSION twice";
assertDirectivesToNull(explicitLanguageVersionSettings, explicitLanguageVersion);
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(
configuration,
new LanguageVersionSettingsImpl(explicitLanguageVersion, ApiVersion.createByLanguageVersion(explicitLanguageVersion))
@@ -191,6 +204,10 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
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(
"CLI", CLIConfigurationKeys.class,
"JVM", JVMConfigurationKeys.class