Move parametersMap.kt to 'cli-common'
Also reformat and slightly refactor it. This allows to get rid of dependency of 'util' on 'kotlin-reflect-api'.
This commit is contained in:
committed by
Alexander Udalov
parent
92534eadaa
commit
87da4be9bb
+63
-59
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -10,23 +10,20 @@ import kotlin.reflect.full.isSubclassOf
|
|||||||
import kotlin.reflect.jvm.jvmErasure
|
import kotlin.reflect.jvm.jvmErasure
|
||||||
|
|
||||||
fun tryConstructClassFromStringArgs(clazz: Class<*>, args: List<String>): Any? {
|
fun tryConstructClassFromStringArgs(clazz: Class<*>, args: List<String>): Any? {
|
||||||
|
return try {
|
||||||
try {
|
clazz.getConstructor(Array<String>::class.java).newInstance(args.toTypedArray())
|
||||||
return clazz.getConstructor(Array<String>::class.java).newInstance(args.toTypedArray())
|
} catch (e: NoSuchMethodException) {
|
||||||
}
|
|
||||||
catch (e: NoSuchMethodException) {
|
|
||||||
for (ctor in clazz.kotlin.constructors) {
|
for (ctor in clazz.kotlin.constructors) {
|
||||||
val mapping = tryCreateCallableMappingFromStringArgs(ctor, args)
|
val mapping = tryCreateCallableMappingFromStringArgs(ctor, args)
|
||||||
if (mapping != null) {
|
if (mapping != null) {
|
||||||
try {
|
try {
|
||||||
return ctor.callBy(mapping)
|
return ctor.callBy(mapping)
|
||||||
}
|
} catch (e: Exception) { // TODO: find the exact exception type thrown then callBy fails
|
||||||
catch (e: Exception) { // TODO: find the exact exception type thrown then callBy fails
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryCreateCallableMapping(callable: KCallable<*>, args: List<Any?>): Map<KParameter, Any?>? =
|
fun tryCreateCallableMapping(callable: KCallable<*>, args: List<Any?>): Map<KParameter, Any?>? =
|
||||||
@@ -60,11 +57,11 @@ fun tryCreateCallableMappingFromNamedArgs(callable: KCallable<*>, args: List<Pai
|
|||||||
private data class NamedArgument<out T>(val name: String?, val value: T?)
|
private data class NamedArgument<out T>(val name: String?, val value: T?)
|
||||||
|
|
||||||
private interface ArgsConverter<T> {
|
private interface ArgsConverter<T> {
|
||||||
|
|
||||||
sealed class Result {
|
sealed class Result {
|
||||||
object Failure : Result()
|
object Failure : Result()
|
||||||
class Success(val v: Any?) : Result()
|
class Success(val v: Any?) : Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryConvertSingle(parameter: KParameter, arg: NamedArgument<T>): Result
|
fun tryConvertSingle(parameter: KParameter, arg: NamedArgument<T>): Result
|
||||||
fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<T>, restArgsIt: Iterator<NamedArgument<T>>): Result
|
fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<T>, restArgsIt: Iterator<NamedArgument<T>>): Result
|
||||||
fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<T>, restArgsIt: Iterator<NamedArgument<T>>): Result
|
fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<T>, restArgsIt: Iterator<NamedArgument<T>>): Result
|
||||||
@@ -72,7 +69,11 @@ private interface ArgsConverter<T> {
|
|||||||
|
|
||||||
private enum class ArgsTraversalState { UNNAMED, NAMED, TAIL }
|
private enum class ArgsTraversalState { UNNAMED, NAMED, TAIL }
|
||||||
|
|
||||||
private fun <T> tryCreateCallableMapping(callable: KCallable<*>, args: Iterator<NamedArgument<T>>, converter: ArgsConverter<T>): Map<KParameter, Any?>? {
|
private fun <T> tryCreateCallableMapping(
|
||||||
|
callable: KCallable<*>,
|
||||||
|
args: Iterator<NamedArgument<T>>,
|
||||||
|
converter: ArgsConverter<T>
|
||||||
|
): Map<KParameter, Any?>? {
|
||||||
val res = mutableMapOf<KParameter, Any?>()
|
val res = mutableMapOf<KParameter, Any?>()
|
||||||
var state = ArgsTraversalState.UNNAMED
|
var state = ArgsTraversalState.UNNAMED
|
||||||
val unboundParams = callable.parameters.toMutableList()
|
val unboundParams = callable.parameters.toMutableList()
|
||||||
@@ -98,28 +99,24 @@ private fun <T> tryCreateCallableMapping(callable: KCallable<*>, args: Iterator<
|
|||||||
// if we do not allow to overload on nullability, drop this check
|
// if we do not allow to overload on nullability, drop this check
|
||||||
return null // failed to match: null for a non-nullable value
|
return null // failed to match: null for a non-nullable value
|
||||||
}
|
}
|
||||||
res.put(par, cvtRes.v)
|
res[par] = cvtRes.v
|
||||||
}
|
} else if (par.type.jvmErasure.java.isArray) {
|
||||||
else if (par.type.jvmErasure.java.isArray) {
|
|
||||||
// try vararg
|
// try vararg
|
||||||
val cvtVRes = converter.tryConvertVararg(par, arg, argIt)
|
val cvtVRes = converter.tryConvertVararg(par, arg, argIt)
|
||||||
if (cvtVRes is ArgsConverter.Result.Success) {
|
if (cvtVRes is ArgsConverter.Result.Success) {
|
||||||
res.put(par, cvtVRes.v)
|
res[par] = cvtVRes.v
|
||||||
}
|
} else return null // failed to match: no suitable param for unnamed arg
|
||||||
else return null // failed to match: no suitable param for unnamed arg
|
} else return null // failed to match: no suitable param for unnamed arg
|
||||||
}
|
|
||||||
else return null // failed to match: no suitable param for unnamed arg
|
|
||||||
}
|
}
|
||||||
ArgsTraversalState.NAMED -> {
|
ArgsTraversalState.NAMED -> {
|
||||||
assert(arg.name != null)
|
assert(arg.name != null)
|
||||||
val parIdx = unboundParams.indexOfFirst { it.name == arg.name }.takeIf { it >= 0 }
|
val parIdx = unboundParams.indexOfFirst { it.name == arg.name }.takeIf { it >= 0 }
|
||||||
?: return null // failed to match: no matching named parameter found
|
?: return null // failed to match: no matching named parameter found
|
||||||
val par = unboundParams.removeAt(parIdx)
|
val par = unboundParams.removeAt(parIdx)
|
||||||
val cvtRes = converter.tryConvertSingle(par, arg)
|
val cvtRes = converter.tryConvertSingle(par, arg)
|
||||||
if (cvtRes is ArgsConverter.Result.Success) {
|
if (cvtRes is ArgsConverter.Result.Success) {
|
||||||
res.put(par, cvtRes.v)
|
res[par] = cvtRes.v
|
||||||
}
|
} else return null // failed to match: cannot convert arg to param's type
|
||||||
else return null // failed to match: cannot convert arg to param's type
|
|
||||||
}
|
}
|
||||||
ArgsTraversalState.TAIL -> {
|
ArgsTraversalState.TAIL -> {
|
||||||
assert(arg.name == null)
|
assert(arg.name == null)
|
||||||
@@ -127,9 +124,8 @@ private fun <T> tryCreateCallableMapping(callable: KCallable<*>, args: Iterator<
|
|||||||
val cvtVRes = converter.tryConvertTail(par, arg, argIt)
|
val cvtVRes = converter.tryConvertTail(par, arg, argIt)
|
||||||
if (cvtVRes is ArgsConverter.Result.Success) {
|
if (cvtVRes is ArgsConverter.Result.Success) {
|
||||||
if (argIt.hasNext()) return null // failed to match: not all tail args are consumed
|
if (argIt.hasNext()) return null // failed to match: not all tail args are consumed
|
||||||
res.put(par, cvtVRes.v)
|
res[par] = cvtVRes.v
|
||||||
}
|
} else return null // failed to match: no suitable param for tail arg(s)
|
||||||
else return null // failed to match: no suitable param for tail arg(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,12 +136,10 @@ private fun <T> tryCreateCallableMapping(callable: KCallable<*>, args: Iterator<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KType.allowsNulls(): Boolean =
|
private fun KType.allowsNulls(): Boolean =
|
||||||
isMarkedNullable ||
|
isMarkedNullable || classifier.let { it is KTypeParameter && it.upperBounds.any(KType::allowsNulls) }
|
||||||
classifier.let { it is KTypeParameter && it.upperBounds.any(KType::allowsNulls) }
|
|
||||||
|
|
||||||
|
|
||||||
private class StringArgsConverter : ArgsConverter<String> {
|
private class StringArgsConverter : ArgsConverter<String> {
|
||||||
|
|
||||||
override fun tryConvertSingle(parameter: KParameter, arg: NamedArgument<String>): ArgsConverter.Result {
|
override fun tryConvertSingle(parameter: KParameter, arg: NamedArgument<String>): ArgsConverter.Result {
|
||||||
val value = arg.value ?: return ArgsConverter.Result.Success(null)
|
val value = arg.value ?: return ArgsConverter.Result.Success(null)
|
||||||
|
|
||||||
@@ -165,20 +159,23 @@ private class StringArgsConverter : ArgsConverter<String> {
|
|||||||
return if (primitive != null) ArgsConverter.Result.Success(primitive) else ArgsConverter.Result.Failure
|
return if (primitive != null) ArgsConverter.Result.Success(primitive) else ArgsConverter.Result.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<String>, restArgsIt: Iterator<NamedArgument<String>>): ArgsConverter.Result {
|
override fun tryConvertVararg(
|
||||||
|
parameter: KParameter,
|
||||||
|
firstArg: NamedArgument<String>,
|
||||||
|
restArgsIt: Iterator<NamedArgument<String>>
|
||||||
|
): ArgsConverter.Result {
|
||||||
fun convertPrimitivesArray(type: KType, args: Sequence<String?>): Any? =
|
fun convertPrimitivesArray(type: KType, args: Sequence<String?>): Any? =
|
||||||
when (type.classifier) {
|
when (type.classifier) {
|
||||||
IntArray::class -> args.map { it?.toIntOrNull() }
|
IntArray::class -> args.map { it?.toIntOrNull() }
|
||||||
LongArray::class -> args.map { it?.toLongOrNull() }
|
LongArray::class -> args.map { it?.toLongOrNull() }
|
||||||
ShortArray::class -> args.map { it?.toShortOrNull() }
|
ShortArray::class -> args.map { it?.toShortOrNull() }
|
||||||
ByteArray::class -> args.map { it?.toByteOrNull() }
|
ByteArray::class -> args.map { it?.toByteOrNull() }
|
||||||
CharArray::class -> args.map { it?.singleOrNull() }
|
CharArray::class -> args.map { it?.singleOrNull() }
|
||||||
FloatArray::class -> args.map { it?.toFloatOrNull() }
|
FloatArray::class -> args.map { it?.toFloatOrNull() }
|
||||||
DoubleArray::class -> args.map { it?.toDoubleOrNull() }
|
DoubleArray::class -> args.map { it?.toDoubleOrNull() }
|
||||||
BooleanArray::class -> args.map { it?.toBoolean() }
|
BooleanArray::class -> args.map { it?.toBoolean() }
|
||||||
else -> null
|
else -> null
|
||||||
}?.toList()?.takeUnless { null in it }?.toTypedArray()
|
}?.toList()?.takeUnless { null in it }?.toTypedArray()
|
||||||
|
|
||||||
val parameterType = parameter.type
|
val parameterType = parameter.type
|
||||||
if (parameterType.jvmErasure.java.isArray) {
|
if (parameterType.jvmErasure.java.isArray) {
|
||||||
@@ -195,8 +192,12 @@ private class StringArgsConverter : ArgsConverter<String> {
|
|||||||
return ArgsConverter.Result.Failure
|
return ArgsConverter.Result.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<String>, restArgsIt: Iterator<NamedArgument<String>>): ArgsConverter.Result =
|
override fun tryConvertTail(
|
||||||
tryConvertVararg(parameter, firstArg, restArgsIt)
|
parameter: KParameter,
|
||||||
|
firstArg: NamedArgument<String>,
|
||||||
|
restArgsIt: Iterator<NamedArgument<String>>
|
||||||
|
): ArgsConverter.Result =
|
||||||
|
tryConvertVararg(parameter, firstArg, restArgsIt)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnyArgsConverter : ArgsConverter<Any> {
|
private class AnyArgsConverter : ArgsConverter<Any> {
|
||||||
@@ -205,28 +206,27 @@ private class AnyArgsConverter : ArgsConverter<Any> {
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun convertPrimitivesArray(type: KType?, arg: Any?): Any? =
|
fun convertPrimitivesArray(type: KType?, arg: Any?): Any? =
|
||||||
when (type?.classifier) {
|
when (type?.classifier) {
|
||||||
IntArray::class -> (arg as? Array<Int>)?.toIntArray()
|
IntArray::class -> (arg as? Array<Int>)?.toIntArray()
|
||||||
LongArray::class -> (arg as? Array<Long>)?.toLongArray()
|
LongArray::class -> (arg as? Array<Long>)?.toLongArray()
|
||||||
ShortArray::class -> (arg as? Array<Short>)?.toShortArray()
|
ShortArray::class -> (arg as? Array<Short>)?.toShortArray()
|
||||||
ByteArray::class -> (arg as? Array<Byte>)?.toByteArray()
|
ByteArray::class -> (arg as? Array<Byte>)?.toByteArray()
|
||||||
CharArray::class -> (arg as? Array<Char>)?.toCharArray()
|
CharArray::class -> (arg as? Array<Char>)?.toCharArray()
|
||||||
FloatArray::class -> (arg as? Array<Float>)?.toFloatArray()
|
FloatArray::class -> (arg as? Array<Float>)?.toFloatArray()
|
||||||
DoubleArray::class -> (arg as? Array<Double>)?.toDoubleArray()
|
DoubleArray::class -> (arg as? Array<Double>)?.toDoubleArray()
|
||||||
BooleanArray::class -> (arg as? Array<Boolean>)?.toBooleanArray()
|
BooleanArray::class -> (arg as? Array<Boolean>)?.toBooleanArray()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value::class.isSubclassOf(parameter.type.jvmErasure)) return ArgsConverter.Result.Success(value)
|
if (value::class.isSubclassOf(parameter.type.jvmErasure)) return ArgsConverter.Result.Success(value)
|
||||||
|
|
||||||
return convertPrimitivesArray(parameter.type, value)?.let { ArgsConverter.Result.Success(it) }
|
return convertPrimitivesArray(parameter.type, value)?.let { ArgsConverter.Result.Success(it) }
|
||||||
?: ArgsConverter.Result.Failure
|
?: ArgsConverter.Result.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryConvertVararg(
|
override fun tryConvertVararg(
|
||||||
parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>
|
parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>
|
||||||
): ArgsConverter.Result {
|
): ArgsConverter.Result {
|
||||||
|
|
||||||
val parameterType = parameter.type
|
val parameterType = parameter.type
|
||||||
if (parameterType.jvmErasure.java.isArray) {
|
if (parameterType.jvmErasure.java.isArray) {
|
||||||
val argsSequence = sequenceOf(firstArg.value) + restArgsIt.asSequence().map { it.value }
|
val argsSequence = sequenceOf(firstArg.value) + restArgsIt.asSequence().map { it.value }
|
||||||
@@ -239,8 +239,12 @@ private class AnyArgsConverter : ArgsConverter<Any> {
|
|||||||
return ArgsConverter.Result.Failure
|
return ArgsConverter.Result.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>): ArgsConverter.Result =
|
override fun tryConvertTail(
|
||||||
tryConvertSingle(parameter, firstArg)
|
parameter: KParameter,
|
||||||
|
firstArg: NamedArgument<Any>,
|
||||||
|
restArgsIt: Iterator<NamedArgument<Any>>
|
||||||
|
): ArgsConverter.Result =
|
||||||
|
tryConvertSingle(parameter, firstArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@@ -7,7 +7,6 @@ dependencies {
|
|||||||
api(kotlinStdlib())
|
api(kotlinStdlib())
|
||||||
api(project(":compiler:compiler.version"))
|
api(project(":compiler:compiler.version"))
|
||||||
|
|
||||||
compileOnly(project(":kotlin-reflect-api"))
|
|
||||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) }
|
compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) }
|
||||||
compileOnly(jpsStandalone()) { includeJars("jps-model") }
|
compileOnly(jpsStandalone()) { includeJars("jps-model") }
|
||||||
|
|||||||
Reference in New Issue
Block a user