[CLI] Implement CommonToolArguments.toStringList (to replace convertArgumentsToStringList`)
KTIJ-24976
This commit is contained in:
committed by
Space Team
parent
2b893365aa
commit
d07b1b6502
@@ -16,25 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner;
|
||||
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KClass;
|
||||
import kotlin.reflect.KProperty1;
|
||||
import kotlin.reflect.KVisibility;
|
||||
import kotlin.reflect.full.KClasses;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.Argument;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.InternalArgument;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt;
|
||||
import org.jetbrains.kotlin.idea.ExplicitDefaultSubstitutor;
|
||||
import org.jetbrains.kotlin.idea.ExplicitDefaultSubstitutorsKt;
|
||||
import org.jetbrains.kotlin.utils.StringsKt;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
|
||||
public class ArgumentUtils {
|
||||
@@ -44,82 +29,18 @@ public class ArgumentUtils {
|
||||
@NotNull
|
||||
public static List<String> convertArgumentsToStringList(@NotNull CommonToolArguments arguments)
|
||||
throws InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
List<String> convertedArguments = convertArgumentsToStringListInternal(arguments);
|
||||
|
||||
Map<KClass<? extends CommonToolArguments>, Collection<ExplicitDefaultSubstitutor>> defaultSubstitutorsMap =
|
||||
ExplicitDefaultSubstitutorsKt.getDefaultSubstitutors();
|
||||
KClass<? extends CommonToolArguments> argumentsKClass = JvmClassMappingKt.getKotlinClass(arguments.getClass());
|
||||
Collection<ExplicitDefaultSubstitutor> defaultSubstitutors = defaultSubstitutorsMap.get(argumentsKClass);
|
||||
if (defaultSubstitutors != null) {
|
||||
for (ExplicitDefaultSubstitutor substitutor : defaultSubstitutors) {
|
||||
if (substitutor.isSubstitutable(convertedArguments)) convertedArguments.addAll(substitutor.getNewSubstitution());
|
||||
}
|
||||
}
|
||||
return convertedArguments;
|
||||
return convertArgumentsToStringListInternal(arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Deprecated()
|
||||
public static List<String> convertArgumentsToStringListNoDefaults(@NotNull CommonToolArguments arguments)
|
||||
throws InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
return convertArgumentsToStringListInternal(arguments);
|
||||
return convertArgumentsToStringList(arguments);
|
||||
}
|
||||
|
||||
private static List<String> convertArgumentsToStringListInternal(@NotNull CommonToolArguments arguments)
|
||||
throws InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
List<String> result = new ArrayList<>();
|
||||
Class<? extends CommonToolArguments> argumentsClass = arguments.getClass();
|
||||
convertArgumentsToStringList(arguments, argumentsClass.newInstance(), JvmClassMappingKt.getKotlinClass(argumentsClass), result);
|
||||
result.addAll(arguments.getFreeArgs());
|
||||
result.addAll(CollectionsKt.map(arguments.getInternalArguments(), InternalArgument::getStringRepresentation));
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void convertArgumentsToStringList(
|
||||
@NotNull CommonToolArguments arguments,
|
||||
@NotNull CommonToolArguments defaultArguments,
|
||||
@NotNull KClass<?> clazz,
|
||||
@NotNull List<String> result
|
||||
) throws IllegalAccessException, InstantiationException, InvocationTargetException {
|
||||
for (KProperty1 property : KClasses.getMemberProperties(clazz)) {
|
||||
Argument argument = findInstance(property.getAnnotations(), Argument.class);
|
||||
if (argument == null) continue;
|
||||
|
||||
if (property.getVisibility() != KVisibility.PUBLIC) continue;
|
||||
|
||||
Object value = property.get(arguments);
|
||||
Object defaultValue = property.get(defaultArguments);
|
||||
|
||||
if (value == null || Objects.equals(value, defaultValue)) continue;
|
||||
|
||||
Type propertyJavaType = ReflectJvmMapping.getJavaType(property.getReturnType());
|
||||
|
||||
if (propertyJavaType instanceof Class && ((Class) propertyJavaType).isArray()) {
|
||||
Object[] values = (Object[]) value;
|
||||
if (values.length == 0) continue;
|
||||
value = StringsKt.join(Arrays.asList(values), ",");
|
||||
}
|
||||
|
||||
result.add(argument.value());
|
||||
|
||||
if (propertyJavaType == boolean.class || propertyJavaType == Boolean.class) continue;
|
||||
|
||||
if (ParseCommandLineArgumentsKt.isAdvanced(argument)) {
|
||||
result.set(result.size() - 1, argument.value() + "=" + value.toString());
|
||||
}
|
||||
else {
|
||||
result.add(value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T> T findInstance(Iterable<? super T> iterable, Class<T> clazz) {
|
||||
for (Object item : iterable) {
|
||||
if (clazz.isInstance(item)) {
|
||||
return clazz.cast(item);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return ArgumentsToStrings.toArgumentStrings(arguments, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("ArgumentsToStrings")
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.Argument
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.isAdvanced
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@JvmOverloads
|
||||
fun CommonToolArguments.toArgumentStrings(useShortNames: Boolean = false): List<String> {
|
||||
return toArgumentStrings(
|
||||
this, this::class as KClass<CommonToolArguments>, useShortNames = useShortNames
|
||||
)
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type: KClass<T>, useShortNames: Boolean): List<String> {
|
||||
val defaultArguments = type.newArgumentsInstance()
|
||||
val result = mutableListOf<String>()
|
||||
type.memberProperties.forEach { property ->
|
||||
val argumentAnnotation = property.findAnnotation<Argument>() ?: return@forEach
|
||||
val rawPropertyValue = property.get(thisArguments)
|
||||
val rawDefaultValue = property.get(defaultArguments)
|
||||
|
||||
/* Default value can be omitted when not marked as 'isExplicit' */
|
||||
if (rawPropertyValue == rawDefaultValue && !argumentAnnotation.isExplicit) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val argumentStringValues = when {
|
||||
property.returnType.classifier == Boolean::class -> listOf(rawPropertyValue?.toString() ?: false.toString())
|
||||
|
||||
(property.returnType.classifier as? KClass<*>)?.java?.isArray == true ->
|
||||
getArgumentStringValue(argumentAnnotation, rawPropertyValue as Array<*>?)
|
||||
|
||||
property.returnType.classifier == List::class ->
|
||||
getArgumentStringValue(argumentAnnotation, (rawPropertyValue as List<*>?)?.toTypedArray())
|
||||
|
||||
else -> listOf(rawPropertyValue.toString())
|
||||
}
|
||||
|
||||
val argumentName = if (useShortNames && argumentAnnotation.shortName.isNotEmpty()) argumentAnnotation.shortName
|
||||
else argumentAnnotation.value
|
||||
|
||||
argumentStringValues.forEach { argumentStringValue ->
|
||||
|
||||
when {
|
||||
/* We can just enable the flag by passing the argument name like -myFlag: Value not required */
|
||||
rawPropertyValue is Boolean && rawPropertyValue -> {
|
||||
result.add(argumentName)
|
||||
}
|
||||
|
||||
/* Advanced (e.g. -X arguments) or boolean properties need to be passed using the '=' */
|
||||
argumentAnnotation.isAdvanced || property.returnType.classifier == Boolean::class -> {
|
||||
result.add("$argumentName=$argumentStringValue")
|
||||
}
|
||||
else -> {
|
||||
result.add(argumentName)
|
||||
result.add(argumentStringValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.addAll(thisArguments.freeArgs)
|
||||
result.addAll(thisArguments.internalArguments.map { it.stringRepresentation })
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?): List<String> {
|
||||
if (values.isNullOrEmpty()) return emptyList()
|
||||
val delimiter = argumentAnnotation.delimiter
|
||||
return if (delimiter.isEmpty()) values.map { it.toString() }
|
||||
else listOf(values.joinToString(delimiter))
|
||||
}
|
||||
|
||||
private fun <T : CommonToolArguments> KClass<T>.newArgumentsInstance(): T {
|
||||
val argumentConstructor = constructors.find { it.parameters.isEmpty() } ?: throw IllegalArgumentException(
|
||||
"$qualifiedName has no empty constructor"
|
||||
)
|
||||
return argumentConstructor.call()
|
||||
}
|
||||
Reference in New Issue
Block a user