Partly support generics and nullable types as parameters for script templates
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.script
|
|||||||
import com.intellij.openapi.fileTypes.LanguageFileType
|
import com.intellij.openapi.fileTypes.LanguageFileType
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -30,12 +31,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
|
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.findNonGenericClassAcrossDependencies
|
import org.jetbrains.kotlin.serialization.deserialization.findNonGenericClassAcrossDependencies
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.Future
|
import java.lang.RuntimeException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.lang.UnsupportedOperationException
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.KTypeProjection
|
||||||
|
import kotlin.reflect.KVariance
|
||||||
|
|
||||||
interface KotlinScriptDefinition {
|
interface KotlinScriptDefinition {
|
||||||
val name: String get() = "Kotlin Script"
|
val name: String get() = "Kotlin Script"
|
||||||
@@ -102,3 +105,33 @@ fun getKotlinTypeByFqName(scriptDescriptor: ScriptDescriptor, fqName: String): K
|
|||||||
ClassId.topLevel(FqName(fqName)),
|
ClassId.topLevel(FqName(fqName)),
|
||||||
NotFoundClasses(LockBasedStorageManager.NO_LOCKS, scriptDescriptor.module)
|
NotFoundClasses(LockBasedStorageManager.NO_LOCKS, scriptDescriptor.module)
|
||||||
).defaultType
|
).defaultType
|
||||||
|
|
||||||
|
// TODO: support star projections
|
||||||
|
// TODO: support annotations on types and type parameters
|
||||||
|
// TODO: support type parameters on types and type projections
|
||||||
|
fun getKotlinTypeByKType(scriptDescriptor: ScriptDescriptor, kType: KType): KotlinType {
|
||||||
|
val classifier = kType.classifier
|
||||||
|
if (classifier !is KClass<*>)
|
||||||
|
throw UnsupportedOperationException("Only classes are supported as parameters in script template: $classifier")
|
||||||
|
|
||||||
|
val type = getKotlinType(scriptDescriptor, classifier)
|
||||||
|
val typeProjections = kType.arguments.map { getTypeProjection(scriptDescriptor, it) }
|
||||||
|
val isNullable = kType.isMarkedNullable
|
||||||
|
|
||||||
|
return KotlinTypeFactory.simpleType(Annotations.EMPTY, type.constructor, typeProjections, isNullable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTypeProjection(scriptDescriptor: ScriptDescriptor, kTypeProjection: KTypeProjection): TypeProjection {
|
||||||
|
val kType = kTypeProjection.type ?: throw UnsupportedOperationException("Star projections are not supported")
|
||||||
|
|
||||||
|
val type = getKotlinTypeByKType(scriptDescriptor, kType)
|
||||||
|
|
||||||
|
val variance = when (kTypeProjection.variance) {
|
||||||
|
KVariance.IN -> Variance.IN_VARIANCE
|
||||||
|
KVariance.OUT -> Variance.OUT_VARIANCE
|
||||||
|
KVariance.INVARIANT -> Variance.INVARIANT
|
||||||
|
null -> throw UnsupportedOperationException("Star projections are not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeProjectionImpl(variance, type)
|
||||||
|
}
|
||||||
@@ -85,7 +85,7 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>,
|
|||||||
override val name = template.simpleName!!
|
override val name = template.simpleName!!
|
||||||
|
|
||||||
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter> =
|
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter> =
|
||||||
template.primaryConstructor!!.parameters.map { ScriptParameter(Name.identifier(it.name!!), getKotlinTypeByFqName(scriptDescriptor, it.type.toString())) }
|
template.primaryConstructor!!.parameters.map { ScriptParameter(Name.identifier(it.name!!), getKotlinTypeByKType(scriptDescriptor, it.type)) }
|
||||||
|
|
||||||
override fun getScriptSupertypes(scriptDescriptor: ScriptDescriptor): List<KotlinType> =
|
override fun getScriptSupertypes(scriptDescriptor: ScriptDescriptor): List<KotlinType> =
|
||||||
listOf(getKotlinTypeByFqName(scriptDescriptor, template.qualifiedName!!))
|
listOf(getKotlinTypeByFqName(scriptDescriptor, template.qualifiedName!!))
|
||||||
|
|||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
val v: Array<in String> = param[0]
|
||||||
|
val s = v[0]
|
||||||
|
|
||||||
|
System.out.println("first: $s, size: ${v.size}")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
val v1 = myArgs[0]
|
||||||
|
val v2 = myArgs[1]
|
||||||
|
|
||||||
|
System.out.println("$v1 and $v2")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import java.lang.RuntimeException
|
||||||
|
|
||||||
|
val k: Int? = param
|
||||||
|
if (k == null) System.out.println("Param is null") else throw RuntimeException("param is not null")
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import java.lang.RuntimeException
|
||||||
|
|
||||||
|
val v: String? = param[0]
|
||||||
|
|
||||||
|
if (v == null) System.out.println("nullable") else RuntimeException("non nullable projection")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
val v1 = param1[0].toString()
|
||||||
|
val v2 = param2[0].toLong()
|
||||||
|
|
||||||
|
System.out.println("$v1 and $v2")
|
||||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.utils.PathUtil
|
|||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.Exception
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@@ -90,6 +91,41 @@ class ScriptTest2 {
|
|||||||
aClass!!.getConstructor(Integer.TYPE).newInstance(4)
|
aClass!!.getConstructor(Integer.TYPE).newInstance(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithArrayParam() {
|
||||||
|
val aClass = compileScript("array_parameter.kts", ScriptWithArrayParam::class, null)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Array<String>::class.java).newInstance(arrayOf("one", "two"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithNullableParam() {
|
||||||
|
val aClass = compileScript("nullable_parameter.kts", ScriptWithNullableParam::class, null)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Int::class.javaObjectType).newInstance(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptVarianceParams() {
|
||||||
|
val aClass = compileScript("variance_parameters.kts", ScriptVarianceParams::class, null)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Array<in Number>::class.java, Array<out Number>::class.java).newInstance(arrayOf("one"), arrayOf(1, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithNullableProjection() {
|
||||||
|
val aClass = compileScript("nullable_projection.kts", ScriptWithNullableProjection::class, null)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Array<String>::class.java).newInstance(arrayOf<String?>(null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithArray2DParam() {
|
||||||
|
val aClass = compileScript("array2d_param.kts", ScriptWithArray2DParam::class, null)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Array<Array<in String>>::class.java).newInstance(arrayOf(arrayOf("one"), arrayOf("two")))
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileScript(
|
private fun compileScript(
|
||||||
scriptPath: String,
|
scriptPath: String,
|
||||||
scriptBase: KClass<out Any>,
|
scriptBase: KClass<out Any>,
|
||||||
@@ -203,6 +239,21 @@ abstract class ScriptWithoutParams(num: Int)
|
|||||||
resolver = TestKotlinScriptDependenciesResolver::class)
|
resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
abstract class ScriptBaseClassWithOverridenProperty(override val num: Int) : TestClassWithOverridableProperty(num)
|
abstract class ScriptBaseClassWithOverridenProperty(override val num: Int) : TestClassWithOverridableProperty(num)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
|
abstract class ScriptWithArrayParam(val myArgs: Array<String>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
|
abstract class ScriptWithNullableParam(val param: Int?)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
|
abstract class ScriptVarianceParams(val param1: Array<in Number>, val param2: Array<out Number>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
|
abstract class ScriptWithNullableProjection(val param: Array<String?>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||||
|
abstract class ScriptWithArray2DParam(val param: Array<Array<in String>>)
|
||||||
|
|
||||||
@Target(AnnotationTarget.FILE)
|
@Target(AnnotationTarget.FILE)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class DependsOn(val path: String)
|
annotation class DependsOn(val path: String)
|
||||||
|
|||||||
Reference in New Issue
Block a user