Change format of -X arguments to require value after '='

Report a warning when an argument is passed in the old form (with the
whitespace)

 #KT-17264 Fixed
This commit is contained in:
Alexander Udalov
2017-04-05 16:42:43 +03:00
parent 78c0111c6e
commit f4b6db4dc0
22 changed files with 100 additions and 73 deletions
@@ -104,6 +104,9 @@ public abstract class CommonCompilerArguments implements Serializable {
public List<String> unknownExtraFlags = new SmartList<>();
// Names of extra (-X...) arguments which have been passed in an obsolete form ("-Xaaa bbb", instead of "-Xaaa=bbb")
public List<String> extraArgumentsPassedInObsoleteForm = new SmartList<>();
@NotNull
public static CommonCompilerArguments createDefaultInstance() {
DummyImpl arguments = new DummyImpl();
@@ -22,16 +22,15 @@ import java.util.*
@JvmOverloads
fun <A : CommonCompilerArguments> parseArguments(args: Array<String>, arguments: A, ignoreInvalidArguments: Boolean = false) {
val unparsedArgs = parseCommandLineArguments(args, arguments)
val (unknownExtraArgs, unknownArgs) = unparsedArgs.partition { it.startsWith("-X") }
arguments.unknownExtraFlags = unknownExtraArgs
arguments.freeArgs = if (ignoreInvalidArguments) unknownArgs.filterNot { it.startsWith("-") } else unknownArgs
parseCommandLineArguments(args, arguments)
if (!ignoreInvalidArguments) {
for (argument in unknownArgs) {
if (argument.startsWith("-")) {
throw IllegalArgumentException("Invalid argument: " + argument)
}
if (ignoreInvalidArguments) {
arguments.freeArgs.removeAll { it.startsWith("-") }
}
for (argument in arguments.freeArgs) {
if (argument.startsWith("-")) {
throw IllegalArgumentException("Invalid argument: " + argument)
}
}
}
@@ -26,41 +26,56 @@ annotation class Argument(
)
val Argument.isAdvanced: Boolean
get() = value.startsWith("-X") && value.length > 2
get() = value.startsWith(ADVANCED_ARGUMENT_PREFIX) && value.length > ADVANCED_ARGUMENT_PREFIX.length
fun <A : CommonCompilerArguments> parseCommandLineArguments(args: Array<String>, result: A): List<String> {
data class ArgumentField(val field: Field, val argumentNames: List<String>)
private val ADVANCED_ARGUMENT_PREFIX = "-X"
fun <A : CommonCompilerArguments> parseCommandLineArguments(args: Array<String>, result: A) {
data class ArgumentField(val field: Field, val argument: Argument)
val fields = result::class.java.fields.mapNotNull { field ->
val argument = field.getAnnotation(Argument::class.java)
if (argument != null)
ArgumentField(field, listOfNotNull(argument.value, argument.shortName.takeUnless(String::isEmpty)))
else null
if (argument != null) ArgumentField(field, argument) else null
}
val freeArgs = mutableListOf<String>()
var i = 0
while (i < args.size) {
val arg = args[i++]
val field = fields.firstOrNull { (_, names) -> arg in names }?.field
if (field == null) {
freeArgs.add(arg)
val argumentField = fields.firstOrNull { (_, argument) ->
argument.value == arg ||
argument.shortName.takeUnless(String::isEmpty) == arg ||
(argument.isAdvanced && arg.startsWith(argument.value + "="))
}
if (argumentField == null) {
if (arg.startsWith(ADVANCED_ARGUMENT_PREFIX)) {
result.unknownExtraFlags.add(arg)
}
else {
result.freeArgs.add(arg)
}
continue
}
val value: Any =
if (field.type == Boolean::class.java) true
else {
if (i == args.size) {
throw IllegalArgumentException("No value passed for argument $arg")
}
args[i++]
val (field, argument) = argumentField
val value: Any = when {
field.type == Boolean::class.java -> true
argument.isAdvanced && arg.startsWith(argument.value + "=") -> {
arg.substring(argument.value.length + 1)
}
else -> {
if (i == args.size) {
throw IllegalArgumentException("No value passed for argument $arg")
}
if (argument.isAdvanced) {
result.extraArgumentsPassedInObsoleteForm.add(arg)
}
args[i++]
}
}
updateField(field, result, value)
}
return freeArgs
}
private fun <A : CommonCompilerArguments> updateField(field: Field, result: A, value: Any) {
@@ -51,8 +51,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
return exec(errStream, Services.EMPTY, MessageRenderer.PLAIN_RELATIVE_PATHS, args);
}
// Used via reflection in CompilerRunnerUtil#invokeExecMethod and in Eclipse plugin (see KotlinCLICompiler)
@SuppressWarnings("UnusedDeclaration")
// Used in CompilerRunnerUtil#invokeExecMethod, in Eclipse plugin (KotlinCLICompiler) and in kotlin-gradle-plugin (GradleCompilerRunner)
@NotNull
public ExitCode execAndOutputXml(@NotNull PrintStream errStream, @NotNull Services services, @NotNull String... args) {
return exec(errStream, services, MessageRenderer.XML, args);
@@ -82,7 +81,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
return null;
}
@SuppressWarnings("WeakerAccess") // Used in maven (see KotlinCompileMojoBase.java)
// Used in kotlin-maven-plugin (KotlinCompileMojoBase) and in kotlin-gradle-plugin (KotlinJvmOptionsImpl, KotlinJsOptionsImpl)
public void parseArguments(@NotNull String[] args, @NotNull A arguments) {
ArgumentUtilsKt.parseArguments(args, arguments);
}
@@ -128,7 +127,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
}
}
@SuppressWarnings("WeakerAccess") // Used in maven (see KotlinCompileMojoBase.java)
// Used in kotlin-maven-plugin (KotlinCompileMojoBase)
@NotNull
public ExitCode exec(@NotNull MessageCollector messageCollector, @NotNull Services services, @NotNull A arguments) {
printVersionIfNeeded(messageCollector, arguments);
@@ -137,7 +136,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
messageCollector = new FilteringMessageCollector(messageCollector, Predicate.isEqual(WARNING));
}
reportUnknownExtraFlags(messageCollector, arguments);
reportUnknownAndObsoleteExtraFlags(messageCollector, arguments);
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector);
@@ -314,10 +313,14 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
@NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services
);
private void reportUnknownExtraFlags(@NotNull MessageCollector collector, @NotNull A arguments) {
private void reportUnknownAndObsoleteExtraFlags(@NotNull MessageCollector collector, @NotNull A arguments) {
for (String flag : arguments.unknownExtraFlags) {
collector.report(STRONG_WARNING, "Flag is not supported by this version of the compiler: " + flag, null);
}
for (String argument : arguments.extraArgumentsPassedInObsoleteForm) {
collector.report(STRONG_WARNING, "Advanced option value is passed in an obsolete form. Please use the '=' character " +
"to specify the value: " + argument + "=...", null);
}
}
@NotNull
@@ -75,7 +75,7 @@ class Usage {
}
if (!argument.valueDescription().isEmpty()) {
sb.append(" ");
sb.append(ParseCommandLineArgumentsKt.isAdvanced(argument) ? "=" : " ");
sb.append(argument.valueDescription());
}
+2 -2
View File
@@ -2,10 +2,10 @@ Usage: kotlinc-js <options> <source files>
where advanced options include:
-Xtypedarrays Translate primitive arrays to JS typed arrays
-Xno-inline Disable method inlining
-Xrepeat <count> Repeat compilation (for performance analysis)
-Xrepeat=<count> Repeat compilation (for performance analysis)
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
-Xallow-kotlin-package Allow compiling code in package 'kotlin'
-Xplugin <path> Load plugins from the given classpath
-Xplugin=<path> Load plugins from the given classpath
-Xmulti-platform Enable experimental language support for multi-platform projects
-Xno-check-impl Do not check presence of 'impl' modifier in multi-platform projects
-Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
@@ -0,0 +1,5 @@
-Xplugin
non-existing-file.jar
$TESTDATA_DIR$/simple.kt
-d
$TEMP_DIR$
@@ -0,0 +1,2 @@
warning: advanced option value is passed in an obsolete form. Please use the '=' character to specify the value: -Xplugin=...
OK
+4 -4
View File
@@ -6,18 +6,18 @@ where advanced options include:
-Xreport-perf Report detailed performance statistics
-Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade
-Xskip-runtime-version-check Allow Kotlin runtime libraries of incompatible versions in the classpath
-Xdump-declarations-to <path> Path to JSON file to dump Java to Kotlin declaration mappings
-Xdump-declarations-to=<path> Path to JSON file to dump Java to Kotlin declaration mappings
-Xsingle-module Combine modules for source files and binary dependencies into a single module
-Xadd-compiler-builtins Add definitions of built-in declarations to the compilation classpath (useful with -no-stdlib)
-Xload-builtins-from-dependencies
Load definitions of built-in declarations from module dependencies, instead of from the compiler
-Xscript-resolver-environment <key=value[,]>
-Xscript-resolver-environment=<key=value[,]>
Script resolver environment in key-value pairs (the value could be quoted and escaped)
-Xno-inline Disable method inlining
-Xrepeat <count> Repeat compilation (for performance analysis)
-Xrepeat=<count> Repeat compilation (for performance analysis)
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
-Xallow-kotlin-package Allow compiling code in package 'kotlin'
-Xplugin <path> Load plugins from the given classpath
-Xplugin=<path> Load plugins from the given classpath
-Xmulti-platform Enable experimental language support for multi-platform projects
-Xno-check-impl Do not check presence of 'impl' modifier in multi-platform projects
-Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
+2 -3
View File
@@ -1,10 +1,9 @@
-d
$TEMP_DIR$
-Xplugin
dist/kotlinc/lib/android-extensions-compiler.jar
-Xplugin=dist/kotlinc/lib/android-extensions-compiler.jar
-P
plugin\:org.jetbrains.kotlin.android\:package=com.myapp
-P
plugin\:org.jetbrains.kotlin.android\:variant=main;$TESTDATA_DIR$/androidPlugin/res
$TESTDATA_DIR$/pluginSimple.kt
$TESTDATA_DIR$/androidPlugin
$TESTDATA_DIR$/androidPlugin
+2 -3
View File
@@ -1,7 +1,6 @@
-d
$TEMP_DIR$
-Xplugin
dist/kotlinc/lib/android-extensions-compiler.jar
-Xplugin=dist/kotlinc/lib/android-extensions-compiler.jar
-P
plugin\:org.jetbrains.kotlin.android\:package=com.myapp
$TESTDATA_DIR$/pluginSimple.kt
@@ -11,4 +10,4 @@ $TESTDATA_DIR$/androidPlugin/androidWidget.kt
$TESTDATA_DIR$/androidPlugin/fakeAppwidgetPackage.kt
$TESTDATA_DIR$/androidPlugin/fakeInputMethodServicePackage.kt
$TESTDATA_DIR$/androidPlugin/fakeOpenglPackage.kt
$TESTDATA_DIR$/androidPlugin/fakeWebkitPackage.kt
$TESTDATA_DIR$/androidPlugin/fakeWebkitPackage.kt
@@ -188,6 +188,12 @@ public class CliTestGenerated extends AbstractCliTest {
doJvmTest(fileName);
}
@TestMetadata("extraArgumentPassedInObsoleteForm.args")
public void testExtraArgumentPassedInObsoleteForm() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/extraArgumentPassedInObsoleteForm.args");
doJvmTest(fileName);
}
@TestMetadata("extraHelp.args")
public void testExtraHelp() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/extraHelp.args");
@@ -1395,8 +1395,7 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
<apiVersion>1.0</apiVersion>
<args>
<arg>-java-parameters</arg>
<arg>-Xdump-declarations-to</arg>
<arg>dumpDir</arg>
<arg>-Xdump-declarations-to=dumpDir</arg>
</args>
</configuration>
</plugin>
@@ -1447,8 +1446,7 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
<configuration>
<jvmTarget>1.8</jvmTarget>
<args>
<arg>-Xdump-declarations-to</arg>
<arg>dumpDir2</arg>
<arg>-Xdump-declarations-to=dumpDir2</arg>
</args>
</configuration>
</plugin>
@@ -1574,7 +1572,7 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
Assert.assertEquals("1.0", apiLevel!!.description)
Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals(
listOf("-jdk-home", "temp", "-Xdump-declarations-to", "dumpDir2"),
listOf("-jdk-home", "temp", "-Xdump-declarations-to=dumpDir2"),
compilerSettings!!.additionalArgumentsAsList
)
}
@@ -1585,7 +1583,7 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
Assert.assertEquals("1.0", apiLevel!!.description)
Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals(
listOf("-jdk-home", "temp2", "-java-parameters", "-Xdump-declarations-to", "dumpDir"),
listOf("-jdk-home", "temp2", "-java-parameters", "-Xdump-declarations-to=dumpDir"),
compilerSettings!!.additionalArgumentsAsList
)
}
@@ -61,13 +61,13 @@ class GradleFacetImportTest : GradleImportingTestCase() {
compileKotlin {
kotlinOptions.jvmTarget = "1.7"
kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to=tmp"]
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.6"
kotlinOptions.apiVersion = "1.0"
kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to=tmpTest"]
}
""")
importProject()
@@ -77,7 +77,7 @@ class GradleFacetImportTest : GradleImportingTestCase() {
Assert.assertEquals("1.1", apiLevel!!.versionString)
Assert.assertEquals(TargetPlatformKind.Jvm[JvmTarget.JVM_1_8], targetPlatformKind)
Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals("-Xdump-declarations-to tmp -Xsingle-module",
Assert.assertEquals("-Xdump-declarations-to=tmp -Xsingle-module",
compilerSettings!!.additionalArguments)
}
with (testFacetSettings) {
@@ -85,7 +85,7 @@ class GradleFacetImportTest : GradleImportingTestCase() {
Assert.assertEquals("1.0", apiLevel!!.versionString)
Assert.assertEquals(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], targetPlatformKind)
Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals("-Xdump-declarations-to tmpTest",
Assert.assertEquals("-Xdump-declarations-to=tmpTest",
compilerSettings!!.additionalArguments)
}
}
@@ -130,13 +130,13 @@ class GradleFacetImportTest : GradleImportingTestCase() {
compileMyMainKotlin {
kotlinOptions.jvmTarget = "1.7"
kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to=tmp"]
}
compileMyTestKotlin {
kotlinOptions.jvmTarget = "1.6"
kotlinOptions.apiVersion = "1.0"
kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to=tmpTest"]
}
""")
importProject()
@@ -146,7 +146,7 @@ class GradleFacetImportTest : GradleImportingTestCase() {
Assert.assertEquals("1.1", apiLevel!!.versionString)
Assert.assertEquals(TargetPlatformKind.Jvm[JvmTarget.JVM_1_8], targetPlatformKind)
Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals("-Xdump-declarations-to tmp -Xsingle-module",
Assert.assertEquals("-Xdump-declarations-to=tmp -Xsingle-module",
compilerSettings!!.additionalArguments)
}
with (facetSettings("project_myTest")) {
@@ -154,7 +154,7 @@ class GradleFacetImportTest : GradleImportingTestCase() {
Assert.assertEquals("1.0", apiLevel!!.versionString)
Assert.assertEquals(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], targetPlatformKind)
Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
Assert.assertEquals("-Xdump-declarations-to tmpTest",
Assert.assertEquals("-Xdump-declarations-to=tmpTest",
compilerSettings!!.additionalArguments)
}
}
+2 -2
View File
@@ -101,7 +101,7 @@ compileBuiltinsKotlin {
freeCompilerArgs = [
"-version",
"-Xallow-kotlin-package",
"-Xdump-declarations-to", "${buildDir}/runtime-declarations.json",
"-Xdump-declarations-to=${buildDir}/runtime-declarations.json",
"-cp", "${rootDir}/../dist/builtins",
"-module-name", "kotlin-runtime"
]
@@ -113,7 +113,7 @@ compileKotlin {
"-version",
"-Xallow-kotlin-package",
"-Xmultifile-parts-inherit",
"-Xdump-declarations-to", "${buildDir}/stdlib-declarations.json",
"-Xdump-declarations-to=${buildDir}/stdlib-declarations.json",
"-module-name", project.name
]
}
+1 -1
View File
@@ -48,7 +48,7 @@ compileKotlin {
kotlinOptions.freeCompilerArgs = [
"-Xallow-kotlin-package",
"-Xmultifile-parts-inherit",
"-Xdump-declarations-to", "${buildDir}/stdlib-jre7-declarations.json",
"-Xdump-declarations-to=${buildDir}/stdlib-jre7-declarations.json",
"-module-name", project.name
]
}
+1 -1
View File
@@ -50,7 +50,7 @@ compileKotlin {
kotlinOptions.freeCompilerArgs = [
"-Xallow-kotlin-package",
"-Xmultifile-parts-inherit",
"-Xdump-declarations-to", "${buildDir}/stdlib-jre8-declarations.json",
"-Xdump-declarations-to=${buildDir}/stdlib-jre8-declarations.json",
"-module-name", project.name
]
}
@@ -17,7 +17,7 @@ sourceSets {
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xdump-declarations-to', "${buildDir}/cases-declarations.json"]
freeCompilerArgs = ["-Xdump-declarations-to=${buildDir}/cases-declarations.json"]
}
}
@@ -12,7 +12,7 @@ class KotlinJvmOptionsTest {
"-Xreport-perf",
"-Xallow-kotlin-package",
"-Xmultifile-parts-inherit",
"-Xdump-declarations-to", "declarationsPath",
"-Xdump-declarations-to=declarationsPath",
"-script-templates", "a,b,c")
val arguments = K2JVMCompilerArguments()
+1 -1
View File
@@ -74,7 +74,7 @@ compileKotlin {
freeCompilerArgs = ["-version",
"-Xallow-kotlin-package",
"-module-name", "kotlin-reflection",
"-Xdump-declarations-to", "${buildDir}/reflect-declarations.json"]
"-Xdump-declarations-to=${buildDir}/reflect-declarations.json"]
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ compileKotlin {
kotlinOptions {
freeCompilerArgs = [
"-Xallow-kotlin-package",
"-Xdump-declarations-to", "${buildDir}/runtime-declarations.json",
"-Xdump-declarations-to=${buildDir}/runtime-declarations.json",
"-cp", "${rootDir}/../dist/builtins",
"-module-name", project.name
]
@@ -173,9 +173,8 @@ class SourceSectionsTest : TestCaseWithTmpdir() {
val sourceToOutput = getTestFiles(".out")
sourceToOutput.forEach { (source, expectedOutput) ->
val args = arrayOf(source.canonicalPath, "-d", tmpdir.canonicalPath,
"-Xplugin", sourceSectionsPluginJar.canonicalPath,
"-Xplugin=${sourceSectionsPluginJar.canonicalPath}",
"-P", TEST_ALLOWED_SECTIONS.joinToString(",") { "plugin:${SourceSectionsCommandLineProcessor.PLUGIN_ID}:${SourceSectionsCommandLineProcessor.SECTIONS_OPTION.name}=$it" })
val (output, code) = captureOut {
CLICompiler.doMainNoExit(K2JVMCompiler(), args)
@@ -205,9 +204,8 @@ class SourceSectionsTest : TestCaseWithTmpdir() {
try {
sourceToOutput.forEach { (source, expectedOutput) ->
val args = arrayOf(source.canonicalPath, "-d", tmpdir.canonicalPath,
"-Xplugin", sourceSectionsPluginJar.canonicalPath,
"-Xplugin=${sourceSectionsPluginJar.canonicalPath}",
"-P", TEST_ALLOWED_SECTIONS.joinToString(",") { "plugin:${SourceSectionsCommandLineProcessor.PLUGIN_ID}:${SourceSectionsCommandLineProcessor.SECTIONS_OPTION.name}=$it" })
messageCollector.clear()