From 082a38216dea9cf2f250944bff3ce683312edf79 Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Tue, 4 Apr 2023 14:43:24 +0200 Subject: [PATCH] [CLI] argumentsToStrings: Add 'compactArgumentValues' option Passing 'false' will pass Array or List based arguments multiple times instead of using the Delimiter. eg: compactArgumentValues = true: "-cp", "library1;library2;library3" compactArgumentValues = false: "-cp", "library1", "-cp", -"library2", "-cp", "library3" Using compactArgumentValues = false can be beneficial when the many compiler arguments are held in memory. In this case the raw arguments can intern individual string values, which is highly effective when the arguments refer to files on disk. KTIJ-24976 --- .../compilerRunner/argumentsToStrings.kt | 22 +++++++---- .../CompilerArgumentParsingTest.kt | 39 +++++++++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/argumentsToStrings.kt b/build-common/src/org/jetbrains/kotlin/compilerRunner/argumentsToStrings.kt index 8c69d338aed..659ee13d605 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/argumentsToStrings.kt +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/argumentsToStrings.kt @@ -17,14 +17,20 @@ import kotlin.reflect.full.memberProperties @Suppress("UNCHECKED_CAST") @JvmOverloads -fun CommonToolArguments.toArgumentStrings(useShortNames: Boolean = false): List { +fun CommonToolArguments.toArgumentStrings(shortArgumentKeys: Boolean = false, compactArgumentValues: Boolean = true): List { return toArgumentStrings( - this, this::class as KClass, useShortNames = useShortNames + this, this::class as KClass, + shortArgumentKeys = shortArgumentKeys, + compactArgumentValues = compactArgumentValues ) } @PublishedApi -internal fun toArgumentStrings(thisArguments: T, type: KClass, useShortNames: Boolean): List { +internal fun toArgumentStrings( + thisArguments: T, type: KClass, + shortArgumentKeys: Boolean, + compactArgumentValues: Boolean +): List { val defaultArguments = type.newArgumentsInstance() val result = mutableListOf() type.memberProperties.forEach { property -> @@ -41,15 +47,15 @@ internal fun toArgumentStrings(thisArguments: T, type: property.returnType.classifier == Boolean::class -> listOf(rawPropertyValue?.toString() ?: false.toString()) (property.returnType.classifier as? KClass<*>)?.java?.isArray == true -> - getArgumentStringValue(argumentAnnotation, rawPropertyValue as Array<*>?) + getArgumentStringValue(argumentAnnotation, rawPropertyValue as Array<*>?, compactArgumentValues) property.returnType.classifier == List::class -> - getArgumentStringValue(argumentAnnotation, (rawPropertyValue as List<*>?)?.toTypedArray()) + getArgumentStringValue(argumentAnnotation, (rawPropertyValue as List<*>?)?.toTypedArray(), compactArgumentValues) else -> listOf(rawPropertyValue.toString()) } - val argumentName = if (useShortNames && argumentAnnotation.shortName.isNotEmpty()) argumentAnnotation.shortName + val argumentName = if (shortArgumentKeys && argumentAnnotation.shortName.isNotEmpty()) argumentAnnotation.shortName else argumentAnnotation.value argumentStringValues.forEach { argumentStringValue -> @@ -77,10 +83,10 @@ internal fun toArgumentStrings(thisArguments: T, type: return result } -private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?): List { +private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?, compactArgumentValues: Boolean): List { if (values.isNullOrEmpty()) return emptyList() val delimiter = argumentAnnotation.resolvedDelimiter - return if (delimiter.isNullOrEmpty()) values.map { it.toString() } + return if (delimiter.isNullOrEmpty() || !compactArgumentValues) values.map { it.toString() } else listOf(values.joinToString(delimiter)) } diff --git a/build-common/test/org/jetbrains/kotlin/compilerRunner/CompilerArgumentParsingTest.kt b/build-common/test/org/jetbrains/kotlin/compilerRunner/CompilerArgumentParsingTest.kt index 7a043d8c946..d5bd6f59d32 100644 --- a/build-common/test/org/jetbrains/kotlin/compilerRunner/CompilerArgumentParsingTest.kt +++ b/build-common/test/org/jetbrains/kotlin/compilerRunner/CompilerArgumentParsingTest.kt @@ -25,14 +25,28 @@ class CompilerArgumentParsingTest { @ParameterizedTest @MethodSource("parameters") - fun `test - parsing random compiler arguments`(type: KClass, seed: Int, useShortNames: Boolean) { + fun `test - parsing random compiler arguments`( + type: KClass, + seed: Int, + shortArgumentKeys: Boolean, + compactArgumentValues: Boolean + ) { val constructor = type.constructors.find { it.parameters.isEmpty() } ?: error("Missing empty constructor on $type") val arguments = constructor.call() arguments.fillRandomValues(Random(seed)) - val argumentsAsStrings = arguments.toArgumentStrings(useShortNames) + val argumentsAsStrings = arguments.toArgumentStrings( + shortArgumentKeys = shortArgumentKeys, + compactArgumentValues = compactArgumentValues + ) val parsedArguments = parseCommandLineArguments(type, argumentsAsStrings) assertEqualArguments(arguments, parsedArguments) - assertEquals(argumentsAsStrings, parsedArguments.toArgumentStrings(useShortNames)) + assertEquals( + argumentsAsStrings, + parsedArguments.toArgumentStrings( + shortArgumentKeys = shortArgumentKeys, + compactArgumentValues = compactArgumentValues + ) + ) } companion object { @@ -40,12 +54,15 @@ class CompilerArgumentParsingTest { fun parameters(): List = getCompilerArgumentImplementations() .flatMap { clazz -> listOf(1002, 2803, 2411).flatMap { seed -> - listOf(true, false).map { useShortNames -> - Arguments.of( - Named.of("${clazz.simpleName}", clazz), - Named.of("seed: $seed", seed), - Named.of("useShortNames: $useShortNames", useShortNames) - ) + listOf(true, false).flatMap { shortArgumentKeys -> + listOf(true, false).map { compactArgumentValues -> + Arguments.of( + Named.of("${clazz.simpleName}", clazz), + Named.of("seed: $seed", seed), + Named.of("shortArgumentKeys: $shortArgumentKeys", shortArgumentKeys), + Named.of("compactArgumentValues: $compactArgumentValues", compactArgumentValues) + ) + } } } } @@ -96,14 +113,14 @@ private fun Random.randomString() = nextBytes(nextInt(8, 12)).let { data -> private fun Random.randomBoolean() = nextBoolean() private fun Random.randomStringArray(): Array { - val size = nextInt(1, 5) + val size = nextInt(5, 10) return Array(size) { randomString() } } private fun Random.randomList(elementType: KType): List? { - val size = nextInt(1, 5) + val size = nextInt(5, 10) return List(size) { randomValue(elementType) ?: return null }