[Compiler CLI] Implement reading language version settings from environment variable
^KT-51306 Fixed
This commit is contained in:
committed by
teamcity
parent
43a0876c26
commit
683a3e74a0
@@ -38,6 +38,7 @@ enum class CompilerSystemProperties(val property: String, val alwaysDirectAccess
|
||||
COMPILE_INCREMENTAL_WITH_CLASSPATH_SNAPSHOTS("kotlin.incremental.classpath.snapshot.enabled"),
|
||||
COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM("kotlin.incremental.useClasspathSnapshot"),
|
||||
KOTLIN_COLORS_ENABLED_PROPERTY("kotlin.colors.enabled"),
|
||||
LANGUAGE_VERSION_SETTINGS("kotlin.language.settings"),
|
||||
|
||||
OS_NAME("os.name", alwaysDirectAccess = true),
|
||||
TMP_DIR("java.io.tmpdir"),
|
||||
|
||||
+41
-7
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
@@ -63,13 +64,24 @@ data class ArgumentParseErrors(
|
||||
)
|
||||
|
||||
// Parses arguments into the passed [result] object. Errors related to the parsing will be collected into [CommonToolArguments.errors].
|
||||
fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, result: A) {
|
||||
fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, result: A, overrideArguments: Boolean = false) {
|
||||
val errors = result.errors ?: ArgumentParseErrors().also { result.errors = it }
|
||||
val preprocessed = preprocessCommandLineArguments(args, errors)
|
||||
parsePreprocessedCommandLineArguments(preprocessed, result, errors)
|
||||
parsePreprocessedCommandLineArguments(preprocessed, result, errors, overrideArguments)
|
||||
}
|
||||
|
||||
private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(args: List<String>, result: A, errors: ArgumentParseErrors) {
|
||||
fun <A : CommonToolArguments> parseCommandLineArgumentsFromEnvironment(arguments: A) {
|
||||
val settingsFromEnvironment = CompilerSystemProperties.LANGUAGE_VERSION_SETTINGS.value?.takeIf { it.isNotEmpty() }
|
||||
?.split(Regex("""\s""")) ?: return
|
||||
parseCommandLineArguments(settingsFromEnvironment, arguments, overrideArguments = true)
|
||||
}
|
||||
|
||||
private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(
|
||||
args: List<String>,
|
||||
result: A,
|
||||
errors: ArgumentParseErrors,
|
||||
overrideArguments: Boolean
|
||||
) {
|
||||
data class ArgumentField(val property: KMutableProperty1<A, Any?>, val argument: Argument)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -183,14 +195,36 @@ private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(args
|
||||
errors.duplicateArguments[argument.value] = value
|
||||
}
|
||||
|
||||
updateField(property, result, value, argument.delimiter)
|
||||
updateField(property, result, value, argument.delimiter, overrideArguments)
|
||||
}
|
||||
|
||||
result.freeArgs += freeArgs
|
||||
result.internalArguments += internalArguments
|
||||
result.updateInternalArguments(internalArguments, overrideArguments)
|
||||
}
|
||||
|
||||
private fun <A : CommonToolArguments> updateField(property: KMutableProperty1<A, Any?>, result: A, value: Any, delimiter: String) {
|
||||
private fun <A : CommonToolArguments> A.updateInternalArguments(
|
||||
newInternalArguments: ArrayList<InternalArgument>,
|
||||
overrideArguments: Boolean
|
||||
) {
|
||||
val filteredExistingArguments = if (overrideArguments) {
|
||||
internalArguments.filter { existingArgument ->
|
||||
existingArgument !is ManualLanguageFeatureSetting ||
|
||||
newInternalArguments.none {
|
||||
it is ManualLanguageFeatureSetting && it.languageFeature == existingArgument.languageFeature
|
||||
}
|
||||
}
|
||||
} else internalArguments
|
||||
|
||||
internalArguments = filteredExistingArguments + newInternalArguments
|
||||
}
|
||||
|
||||
private fun <A : CommonToolArguments> updateField(
|
||||
property: KMutableProperty1<A, Any?>,
|
||||
result: A,
|
||||
value: Any,
|
||||
delimiter: String,
|
||||
overrideArguments: Boolean
|
||||
) {
|
||||
when (property.returnType.classifier) {
|
||||
Boolean::class, String::class -> property.set(result, value)
|
||||
Array<String>::class -> {
|
||||
@@ -201,7 +235,7 @@ private fun <A : CommonToolArguments> updateField(property: KMutableProperty1<A,
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val oldValue = property.get(result) as Array<String>?
|
||||
property.set(result, if (oldValue != null) arrayOf(*oldValue, *newElements) else newElements)
|
||||
property.set(result, if (oldValue != null && !overrideArguments) arrayOf(*oldValue, *newElements) else newElements)
|
||||
}
|
||||
else -> throw IllegalStateException("Unsupported argument type: ${property.returnType}")
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.common
|
||||
import org.fusesource.jansi.AnsiConsole
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArgumentsFromEnvironment
|
||||
import org.jetbrains.kotlin.cli.common.arguments.validateArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO
|
||||
@@ -47,6 +48,7 @@ abstract class CLITool<A : CommonToolArguments> {
|
||||
): ExitCode {
|
||||
val arguments = createArguments()
|
||||
parseCommandLineArguments(args.asList(), arguments)
|
||||
parseCommandLineArgumentsFromEnvironment(arguments)
|
||||
val collector = PrintingMessageCollector(errStream, messageRenderer, arguments.verbose)
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
$TESTDATA_DIR$/appendingArgs.kt
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
-Xallow-kotlin-package
|
||||
@@ -0,0 +1 @@
|
||||
-Xrender-internal-diagnostic-names
|
||||
@@ -0,0 +1,5 @@
|
||||
package kotlin
|
||||
|
||||
fun main() {
|
||||
val x = 1?.dec()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
compiler/testData/cli/jvm/readingConfigFromEnvironment/appendingArgs.kt:4:9: warning: [UNUSED_VARIABLE] Variable 'x' is never used
|
||||
val x = 1?.dec()
|
||||
^
|
||||
compiler/testData/cli/jvm/readingConfigFromEnvironment/appendingArgs.kt:4:13: warning: [SAFE_CALL_WILL_CHANGE_NULLABILITY] Safe call on a non-null receiver will have nullable type in future releases
|
||||
val x = 1?.dec()
|
||||
^
|
||||
compiler/testData/cli/jvm/readingConfigFromEnvironment/appendingArgs.kt:4:14: warning: [UNNECESSARY_SAFE_CALL] Unnecessary safe call on a non-null receiver of type Int
|
||||
val x = 1?.dec()
|
||||
^
|
||||
OK
|
||||
@@ -0,0 +1,4 @@
|
||||
public class Annotated {
|
||||
@org.jetbrains.annotations.Nullable
|
||||
public static String bar() { return ""; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
$TESTDATA_DIR$/overridingArgs.kt
|
||||
$TESTDATA_DIR$/java
|
||||
$FOREIGN_ANNOTATIONS_DIR$
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
-Xnullability-annotations=@org.jetbrains.annotations\:warn
|
||||
@@ -0,0 +1 @@
|
||||
-Xnullability-annotations=@org.jetbrains.annotations:ignore
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main() {
|
||||
Annotated.bar().length
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
OK
|
||||
@@ -0,0 +1,5 @@
|
||||
$TESTDATA_DIR$/overridingLv.kt
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
-language-version
|
||||
1.7
|
||||
@@ -0,0 +1,2 @@
|
||||
-language-version
|
||||
1.1
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
error: language version 1.1 is no longer supported; please, use version 1.3 or greater.
|
||||
COMPILATION_ERROR
|
||||
@@ -0,0 +1,4 @@
|
||||
$TESTDATA_DIR$/overridingXx.kt
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
-XXLanguage\:+ApproximateIntegerLiteralTypesInReceiverPosition
|
||||
@@ -0,0 +1 @@
|
||||
-XXLanguage:-ApproximateIntegerLiteralTypesInReceiverPosition
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo(ttlMillis: Long = 5 * 60 * 1000) {}
|
||||
|
||||
const val cacheSize: Long = 4096 * 4
|
||||
@@ -0,0 +1,13 @@
|
||||
warning: ATTENTION!
|
||||
This build uses unsafe internal compiler arguments:
|
||||
|
||||
-XXLanguage:-ApproximateIntegerLiteralTypesInReceiverPosition
|
||||
|
||||
This mode is not recommended for production use,
|
||||
as no stability/compatibility guarantees are given on
|
||||
compiler or generated code. Use it at your own risk!
|
||||
|
||||
compiler/testData/cli/jvm/readingConfigFromEnvironment/overridingXx.kt:1:9: warning: parameter 'ttlMillis' is never used
|
||||
fun foo(ttlMillis: Long = 5 * 60 * 1000) {}
|
||||
^
|
||||
OK
|
||||
@@ -0,0 +1,3 @@
|
||||
$TESTDATA_DIR$/simple.kt
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
@@ -0,0 +1 @@
|
||||
-Xrender-internal-diagnostic-names
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main() {
|
||||
val x = 1 + ""
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
compiler/testData/cli/jvm/readingConfigFromEnvironment/simple.kt:2:15: error: [NONE_APPLICABLE] None of the following functions can be called with the arguments supplied:
|
||||
public final operator fun plus(other: Byte): Int defined in kotlin.Int
|
||||
public final operator fun plus(other: Double): Double defined in kotlin.Int
|
||||
public final operator fun plus(other: Float): Float defined in kotlin.Int
|
||||
public final operator fun plus(other: Int): Int defined in kotlin.Int
|
||||
public final operator fun plus(other: Long): Long defined in kotlin.Int
|
||||
public final operator fun plus(other: Short): Int defined in kotlin.Int
|
||||
val x = 1 + ""
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.checkers.ThirdPartyAnnotationPathsKt;
|
||||
import org.jetbrains.kotlin.cli.common.CLITool;
|
||||
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties;
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode;
|
||||
import org.jetbrains.kotlin.cli.common.Usage;
|
||||
import org.jetbrains.kotlin.cli.js.K2JSCompiler;
|
||||
@@ -102,6 +103,12 @@ public abstract class AbstractCliTest extends TestCaseWithTmpdir {
|
||||
|
||||
private void doTest(@NotNull String fileName, @NotNull CLITool<?> compiler) {
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
|
||||
File environmentTestConfig = new File(fileName.replaceFirst("\\.args$", ".env"));
|
||||
if (environmentTestConfig.exists()) {
|
||||
CompilerSystemProperties.LANGUAGE_VERSION_SETTINGS.setValue(FilesKt.readText(environmentTestConfig, Charsets.UTF_8));
|
||||
}
|
||||
|
||||
Pair<String, ExitCode> outputAndExitCode = executeCompilerGrabOutput(compiler, readArgs(fileName, tmpdir.getPath()));
|
||||
String actual = getNormalizedCompilerOutput(
|
||||
outputAndExitCode.getFirst(), outputAndExitCode.getSecond(), new File(fileName).getParent()
|
||||
|
||||
+1
@@ -250,6 +250,7 @@ fun generateJUnit3CompilerTests(args: Array<String>) {
|
||||
}
|
||||
|
||||
testClass<AbstractCliTest> {
|
||||
model("cli/jvm/readingConfigFromEnvironment", extension = "args", testMethod = "doJvmTest", recursive = false)
|
||||
model("cli/jvm", extension = "args", testMethod = "doJvmTest", recursive = false)
|
||||
model("cli/js", extension = "args", testMethod = "doJsTest", recursive = false)
|
||||
model("cli/js-dce", extension = "args", testMethod = "doJsDceTest", recursive = false)
|
||||
|
||||
@@ -19,6 +19,44 @@ import java.util.regex.Pattern;
|
||||
@SuppressWarnings("all")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class CliTestGenerated extends AbstractCliTest {
|
||||
@TestMetadata("compiler/testData/cli/jvm/readingConfigFromEnvironment")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ReadingConfigFromEnvironment extends AbstractCliTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doJvmTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInReadingConfigFromEnvironment() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/cli/jvm/readingConfigFromEnvironment"), Pattern.compile("^(.+)\\.args$"), null, false);
|
||||
}
|
||||
|
||||
@TestMetadata("appendingArgs.args")
|
||||
public void testAppendingArgs() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/readingConfigFromEnvironment/appendingArgs.args");
|
||||
}
|
||||
|
||||
@TestMetadata("overridingArgs.args")
|
||||
public void testOverridingArgs() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/readingConfigFromEnvironment/overridingArgs.args");
|
||||
}
|
||||
|
||||
@TestMetadata("overridingLv.args")
|
||||
public void testOverridingLv() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/readingConfigFromEnvironment/overridingLv.args");
|
||||
}
|
||||
|
||||
@TestMetadata("overridingXx.args")
|
||||
public void testOverridingXx() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/readingConfigFromEnvironment/overridingXx.args");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.args")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/readingConfigFromEnvironment/simple.args");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/cli/jvm")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user