Cleanup warnings in scripting code

This commit is contained in:
Ilya Chernikov
2020-04-06 13:12:56 +02:00
parent d863dc04e6
commit 195a90d333
20 changed files with 134 additions and 119 deletions
@@ -45,7 +45,7 @@ public class XmlMessageRenderer implements MessageRenderer {
} }
private static String e(String str) { private static String e(String str) {
return StringUtil.escapeXml(str); return StringUtil.escapeXmlEntities(str);
} }
@Override @Override
@@ -9,6 +9,7 @@ jvmTarget = "1.6"
dependencies { dependencies {
compile(kotlinStdlib()) compile(kotlinStdlib())
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false } compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
compileOnly(project(":kotlin-reflect-api"))
testCompile(commonDep("junit")) testCompile(commonDep("junit"))
} }
@@ -50,19 +50,19 @@ open class PropertiesCollection(protected var properties: Map<Key<*>, Any?> = em
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T> get(key: PropertiesCollection.Key<T>): T? = operator fun <T> get(key: Key<T>): T? =
(properties[key] ?: if (properties.containsKey(key)) null else key.getDefaultValue(this)) as? T (properties[key] ?: if (properties.containsKey(key)) null else key.getDefaultValue(this)) as? T
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T> getNoDefault(key: PropertiesCollection.Key<T>): T? = fun <T> getNoDefault(key: Key<T>): T? =
properties[key]?.let { it as T } properties[key]?.let { it as T }
fun <T> containsKey(key: PropertiesCollection.Key<T>): Boolean = fun <T> containsKey(key: Key<T>): Boolean =
properties.containsKey(key) properties.containsKey(key)
fun entries(): Set<Map.Entry<Key<*>, Any?>> = properties.entries fun entries(): Set<Map.Entry<Key<*>, Any?>> = properties.entries
val notTransientData: Map<Key<*>, Any?> get() = properties.filterKeys { it !is TransientKey<*>} val notTransientData: Map<Key<*>, Any?> get() = properties.filterKeys { it !is TransientKey<*> }
fun isEmpty(): Boolean = properties.isEmpty() fun isEmpty(): Boolean = properties.isEmpty()
@@ -97,159 +97,162 @@ open class PropertiesCollection(protected var properties: Map<Key<*>, Any?> = em
open class Builder(baseProperties: Iterable<PropertiesCollection> = emptyList()) { open class Builder(baseProperties: Iterable<PropertiesCollection> = emptyList()) {
val data: MutableMap<PropertiesCollection.Key<*>, Any?> = LinkedHashMap<PropertiesCollection.Key<*>, Any?>().apply { val data: MutableMap<Key<*>, Any?> = LinkedHashMap<Key<*>, Any?>().apply {
baseProperties.forEach { putAll(it.properties) } baseProperties.forEach { putAll(it.properties) }
} }
// generic for all properties // generic for all properties
operator fun <T> PropertiesCollection.Key<T>.invoke(v: T) { operator fun <T> Key<T>.invoke(v: T) {
data[this] = v data[this] = v
} }
fun <T> PropertiesCollection.Key<T>.put(v: T) { fun <T> Key<T>.put(v: T) {
data[this] = v data[this] = v
} }
fun <T> PropertiesCollection.Key<T>.putIfNotNull(v: T?) { fun <T> Key<T>.putIfNotNull(v: T?) {
if (v != null) { if (v != null) {
data[this] = v data[this] = v
} }
} }
fun <T> PropertiesCollection.Key<T>.replaceOnlyDefault(v: T?) { fun <T> Key<T>.replaceOnlyDefault(v: T?) {
if (!data.containsKey(this) || data[this] == this.getDefaultValue(PropertiesCollection(data))) { if (!data.containsKey(this) || data[this] == this.getDefaultValue(PropertiesCollection(data))) {
data[this] = v data[this] = v
} }
} }
fun <T> PropertiesCollection.Key<T>.update(body: (T?) -> T?) { fun <T> Key<T>.update(body: (T?) -> T?) {
putIfNotNull(body(data[this]?.let { it as T })) putIfNotNull(body(data[this]?.let {
@Suppress("UNCHECKED_CAST")
it as T
}))
} }
// generic for lists // generic for lists
fun <T> PropertiesCollection.Key<in List<T>>.putIfAny(vals: Iterable<T>?) { fun <T> Key<in List<T>>.putIfAny(vals: Iterable<T>?) {
if (vals?.any() == true) { if (vals?.any() == true) {
data[this] = if (vals is List) vals else vals.toList() data[this] = if (vals is List) vals else vals.toList()
} }
} }
operator fun <T> PropertiesCollection.Key<in List<T>>.invoke(vararg vals: T) { operator fun <T> Key<in List<T>>.invoke(vararg vals: T) {
append(vals.asIterable()) append(vals.asIterable())
} }
// generic for maps: // generic for maps:
@JvmName("putIfAny_map") @JvmName("putIfAny_map")
fun <K, V> PropertiesCollection.Key<in Map<K, V>>.putIfAny(vals: Iterable<Pair<K, V>>?) { fun <K, V> Key<in Map<K, V>>.putIfAny(vals: Iterable<Pair<K, V>>?) {
if (vals?.any() == true) { if (vals?.any() == true) {
data[this] = vals.toMap() data[this] = vals.toMap()
} }
} }
fun <K, V> PropertiesCollection.Key<in Map<K, V>>.putIfAny(vals: Map<K, V>?) { fun <K, V> Key<in Map<K, V>>.putIfAny(vals: Map<K, V>?) {
if (vals?.isNotEmpty() == true) { if (vals?.isNotEmpty() == true) {
data[this] = vals data[this] = vals
} }
} }
operator fun <K, V> PropertiesCollection.Key<Map<K, V>>.invoke(vararg vs: Pair<K, V>) { operator fun <K, V> Key<Map<K, V>>.invoke(vararg vs: Pair<K, V>) {
append(vs.asIterable()) append(vs.asIterable())
} }
// for strings and list of strings that could be converted from other types // for strings and list of strings that could be converted from other types
@JvmName("invoke_string_fqn_from_reflected_class") @JvmName("invoke_string_fqn_from_reflected_class")
operator fun PropertiesCollection.Key<String>.invoke(kclass: KClass<*>) { operator fun Key<String>.invoke(kclass: KClass<*>) {
data[this] = kclass.java.name data[this] = kclass.java.name
} }
@JvmName("invoke_string_list_fqn_from_reflected_class") @JvmName("invoke_string_list_fqn_from_reflected_class")
operator fun PropertiesCollection.Key<in List<String>>.invoke(vararg kclasses: KClass<*>) { operator fun Key<in List<String>>.invoke(vararg kclasses: KClass<*>) {
append(kclasses.map { it.java.name }) append(kclasses.map { it.java.name })
} }
// for KotlinType: // for KotlinType:
operator fun PropertiesCollection.Key<KotlinType>.invoke(kclass: KClass<*>) { operator fun Key<KotlinType>.invoke(kclass: KClass<*>) {
data[this] = KotlinType(kclass) data[this] = KotlinType(kclass)
} }
operator fun PropertiesCollection.Key<KotlinType>.invoke(ktype: KType) { operator fun Key<KotlinType>.invoke(ktype: KType) {
data[this] = KotlinType(ktype) data[this] = KotlinType(ktype)
} }
operator fun PropertiesCollection.Key<KotlinType>.invoke(fqname: String) { operator fun Key<KotlinType>.invoke(fqname: String) {
data[this] = KotlinType(fqname) data[this] = KotlinType(fqname)
} }
// for list of KotlinTypes // for list of KotlinTypes
operator fun PropertiesCollection.Key<List<KotlinType>>.invoke(vararg classes: KClass<*>) { operator fun Key<List<KotlinType>>.invoke(vararg classes: KClass<*>) {
append(classes.map { KotlinType(it) }) append(classes.map { KotlinType(it) })
} }
operator fun PropertiesCollection.Key<List<KotlinType>>.invoke(vararg types: KType) { operator fun Key<List<KotlinType>>.invoke(vararg types: KType) {
append(types.map { KotlinType(it) }) append(types.map { KotlinType(it) })
} }
operator fun PropertiesCollection.Key<List<KotlinType>>.invoke(vararg fqnames: String) { operator fun Key<List<KotlinType>>.invoke(vararg fqnames: String) {
append(fqnames.map { KotlinType(it) }) append(fqnames.map { KotlinType(it) })
} }
// for map of generic keys to KotlinTypes: // for map of generic keys to KotlinTypes:
@JvmName("invoke_kotlintype_map_from_kclass") @JvmName("invoke_kotlintype_map_from_kclass")
operator fun <K> PropertiesCollection.Key<Map<K, KotlinType>>.invoke(vararg classes: Pair<K, KClass<*>>) { operator fun <K> Key<Map<K, KotlinType>>.invoke(vararg classes: Pair<K, KClass<*>>) {
append(classes.map { (k, v) -> k to KotlinType(v) }) append(classes.map { (k, v) -> k to KotlinType(v) })
} }
@JvmName("invoke_kotlintype_map_from_ktype") @JvmName("invoke_kotlintype_map_from_ktype")
operator fun <K> PropertiesCollection.Key<Map<K, KotlinType>>.invoke(vararg types: Pair<K, KType>) { operator fun <K> Key<Map<K, KotlinType>>.invoke(vararg types: Pair<K, KType>) {
append(types.map { (k, v) -> k to KotlinType(v) }) append(types.map { (k, v) -> k to KotlinType(v) })
} }
@JvmName("invoke_kotlintype_map_from_fqname") @JvmName("invoke_kotlintype_map_from_fqname")
operator fun <K> PropertiesCollection.Key<Map<K, KotlinType>>.invoke(vararg fqnames: Pair<K, String>) { operator fun <K> Key<Map<K, KotlinType>>.invoke(vararg fqnames: Pair<K, String>) {
append(fqnames.map { (k, v) -> k to KotlinType(v) }) append(fqnames.map { (k, v) -> k to KotlinType(v) })
} }
// direct manipulation - public - for usage in inline dsl methods and for extending dsl // direct manipulation - public - for usage in inline dsl methods and for extending dsl
operator fun <T> set(key: PropertiesCollection.Key<in T>, value: T) { operator fun <T> set(key: Key<in T>, value: T) {
data[key] = value data[key] = value
} }
fun <T> reset(key: PropertiesCollection.Key<in T>) { fun <T> reset(key: Key<in T>) {
data.remove(key) data.remove(key)
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T : Any> get(key: PropertiesCollection.Key<in T>): T? = data[key]?.let { it as T } operator fun <T : Any> get(key: Key<in T>): T? = data[key]?.let { it as T }
operator fun <T : Any> PropertiesCollection.Key<T>.invoke(): T? = get(this) operator fun <T : Any> Key<T>.invoke(): T? = get(this)
// appenders to list and map properties // appenders to list and map properties
@JvmName("appendToList") @JvmName("appendToList")
fun <V> PropertiesCollection.Key<in List<V>>.append(values: Iterable<V>) { fun <V> Key<in List<V>>.append(values: Iterable<V>) {
val newValues = get(this)?.let { it + values } ?: values.toList() val newValues = get(this)?.let { it + values } ?: values.toList()
data[this] = newValues data[this] = newValues
} }
fun <V> PropertiesCollection.Key<in List<V>>.append(vararg values: V) { fun <V> Key<in List<V>>.append(vararg values: V) {
val newValues = get(this)?.let { it + values } ?: values.toList() val newValues = get(this)?.let { it + values } ?: values.toList()
data[this] = newValues data[this] = newValues
} }
fun <K, V> PropertiesCollection.Key<in Map<K, V>>.append(values: Map<K, V>) { fun <K, V> Key<in Map<K, V>>.append(values: Map<K, V>) {
val newValues = get(this)?.let { it + values } ?: values val newValues = get(this)?.let { it + values } ?: values
data[this] = newValues data[this] = newValues
} }
@JvmName("appendToMap") @JvmName("appendToMap")
fun <K, V> PropertiesCollection.Key<in Map<K, V>>.append(values: Iterable<Pair<K, V>>) { fun <K, V> Key<in Map<K, V>>.append(values: Iterable<Pair<K, V>>) {
val newValues = get(this)?.let { it + values } ?: values.toMap() val newValues = get(this)?.let { it + values } ?: values.toMap()
data[this] = newValues data[this] = newValues
} }
@@ -155,7 +155,7 @@ obj
// assertThrows(NoSuchMethodException::class.java) { // assertThrows(NoSuchMethodException::class.java) {
// invocator!!.invokeMethod(res1, "fn", 3) // invocator!!.invokeMethod(res1, "fn", 3)
// } // }
val res3 = invocator!!.invokeMethod(res1, "fn1", 3) val res3 = invocator.invokeMethod(res1, "fn1", 3)
Assert.assertEquals(6, res3) Assert.assertEquals(6, res3)
} }
@@ -52,7 +52,7 @@ class CachingTest : TestCase() {
fun testFileCache() { fun testFileCache() {
withTempDir("scriptingTestCache") { cacheDir -> withTempDir("scriptingTestCache") { cacheDir ->
val cache = FileBasedScriptCache(cacheDir) val cache = FileBasedScriptCache(cacheDir)
Assert.assertTrue(cache.baseDir.listFiles().isEmpty()) Assert.assertEquals(true, cache.baseDir.listFiles()?.isEmpty())
checkWithCache(cache, simpleScript, simpleScriptExpectedOutput) checkWithCache(cache, simpleScript, simpleScriptExpectedOutput)
} }
@@ -62,7 +62,7 @@ class CachingTest : TestCase() {
fun testSimpleImportWithFileCache() { fun testSimpleImportWithFileCache() {
withTempDir("scriptingTestCache") { cacheDir -> withTempDir("scriptingTestCache") { cacheDir ->
val cache = FileBasedScriptCache(cacheDir) val cache = FileBasedScriptCache(cacheDir)
Assert.assertTrue(cache.baseDir.listFiles().isEmpty()) Assert.assertEquals(true, cache.baseDir.listFiles()?.isEmpty())
checkWithCache( checkWithCache(
cache, scriptWithImport, scriptWithImportExpectedOutput, cache, scriptWithImport, scriptWithImportExpectedOutput,
@@ -190,9 +190,7 @@ class CachingTest : TestCase() {
} }
} }
object Implicit { object Implicit
val ix = 0
}
private interface ScriptingCacheWithCounters : CompiledJvmScriptsCache { private interface ScriptingCacheWithCounters : CompiledJvmScriptsCache {
@@ -230,7 +228,7 @@ private class FileBasedScriptCache(val baseDir: File) : ScriptingCacheWithCounte
override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript? { override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript? {
val file = File(baseDir, uniqueScriptHash(script, scriptCompilationConfiguration)) val file = File(baseDir, uniqueScriptHash(script, scriptCompilationConfiguration))
return if (!file.exists()) null else file.readCompiledScript(scriptCompilationConfiguration)?.also { retrievedScripts++ } return if (!file.exists()) null else file.readCompiledScript().also { retrievedScripts++ }
} }
override fun store( override fun store(
@@ -254,11 +252,13 @@ private class FileBasedScriptCache(val baseDir: File) : ScriptingCacheWithCounte
private set private set
} }
class TestCompiledScriptJarsCache(val baseDir: File) : CompiledScriptJarsCache( class TestCompiledScriptJarsCache(val baseDir: File) :
{ script, scriptCompilationConfiguration -> CompiledScriptJarsCache(
File(baseDir, uniqueScriptHash(script, scriptCompilationConfiguration) + ".jar") { script, scriptCompilationConfiguration ->
}), ScriptingCacheWithCounters File(baseDir, uniqueScriptHash(script, scriptCompilationConfiguration) + ".jar")
{ }
), ScriptingCacheWithCounters {
override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript? = override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript? =
super.get(script, scriptCompilationConfiguration)?.also { retrievedScripts++ } super.get(script, scriptCompilationConfiguration)?.also { retrievedScripts++ }
@@ -289,7 +289,7 @@ internal fun uniqueScriptHash(script: SourceCode, scriptCompilationConfiguration
return digestWrapper.digest().toHexString() return digestWrapper.digest().toHexString()
} }
private fun File.readCompiledScript(scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript { private fun File.readCompiledScript(): CompiledScript {
return inputStream().use { fs -> return inputStream().use { fs ->
ObjectInputStream(fs).use { ObjectInputStream(fs).use {
it.readObject() as KJvmCompiledScript it.readObject() as KJvmCompiledScript
@@ -379,7 +379,7 @@ class ScriptingHostTest : TestCase() {
val res = compiler(script.toScriptSource(), scriptCompilationConfiguration).throwOnFailure() val res = compiler(script.toScriptSource(), scriptCompilationConfiguration).throwOnFailure()
(res as ResultWithDiagnostics.Success<CompiledScript>).value (res as ResultWithDiagnostics.Success<CompiledScript>).value
} }
val compiledScriptClass = runBlocking { compiledScript.getClass(null).throwOnFailure().valueOrNull()!! as KClass<*> } val compiledScriptClass = runBlocking { compiledScript.getClass(null).throwOnFailure().valueOrNull()!! }
val classLoader = compiledScriptClass.java.classLoader val classLoader = compiledScriptClass.java.classLoader
Assert.assertTrue(classLoader is CompiledScriptClassLoader) Assert.assertTrue(classLoader is CompiledScriptClassLoader)
@@ -394,8 +394,8 @@ class ScriptingHostTest : TestCase() {
Assert.assertNotNull(classAsResourceUrl) Assert.assertNotNull(classAsResourceUrl)
Assert.assertNotNull(classAssResourceStream) Assert.assertNotNull(classAssResourceStream)
val classAsResourceData = classAsResourceUrl.openConnection().getInputStream().readBytes() val classAsResourceData = classAsResourceUrl!!.openConnection().getInputStream().readBytes()
val classAsResourceStreamData = classAssResourceStream.readBytes() val classAsResourceStreamData = classAssResourceStream!!.readBytes()
Assert.assertArrayEquals(classAsResourceData, classAsResourceStreamData) Assert.assertArrayEquals(classAsResourceData, classAsResourceStreamData)
@@ -87,7 +87,7 @@ class JvmReplEvaluator(
} }
open class JvmReplEvaluatorState( open class JvmReplEvaluatorState(
scriptEvaluationConfiguration: ScriptEvaluationConfiguration, @Suppress("UNUSED_PARAMETER") scriptEvaluationConfiguration: ScriptEvaluationConfiguration,
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock() override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Pair<KClass<*>?, Any?>> { ) : IReplStageState<Pair<KClass<*>?, Any?>> {
override val history: IReplStageHistory<Pair<KClass<*>?, Any?>> = ReplStageHistoryWithReplace(lock) override val history: IReplStageHistory<Pair<KClass<*>?, Any?>> = ReplStageHistoryWithReplace(lock)
@@ -5,12 +5,12 @@
package org.jetbrains.kotlin.mainKts.test package org.jetbrains.kotlin.mainKts.test
import junit.framework.Assert
import org.jetbrains.kotlin.mainKts.COMPILED_SCRIPTS_CACHE_DIR_ENV_VAR import org.jetbrains.kotlin.mainKts.COMPILED_SCRIPTS_CACHE_DIR_ENV_VAR
import org.jetbrains.kotlin.mainKts.COMPILED_SCRIPTS_CACHE_DIR_PROPERTY import org.jetbrains.kotlin.mainKts.COMPILED_SCRIPTS_CACHE_DIR_PROPERTY
import org.jetbrains.kotlin.scripting.compiler.plugin.runWithK2JVMCompiler import org.jetbrains.kotlin.scripting.compiler.plugin.runWithK2JVMCompiler
import org.jetbrains.kotlin.scripting.compiler.plugin.runWithKotlinLauncherScript import org.jetbrains.kotlin.scripting.compiler.plugin.runWithKotlinLauncherScript
import org.jetbrains.kotlin.scripting.compiler.plugin.runWithKotlinc import org.jetbrains.kotlin.scripting.compiler.plugin.runWithKotlinc
import org.junit.Assert
import org.junit.Ignore import org.junit.Ignore
import org.junit.Test import org.junit.Test
import java.io.File import java.io.File
@@ -141,6 +141,7 @@ class MainKtsTest {
DataInputStream(ByteArrayInputStream(scriptClassResource.readBytes())).use { stream -> DataInputStream(ByteArrayInputStream(scriptClassResource.readBytes())).use { stream ->
val header = stream.readInt() val header = stream.readInt()
if (0xCAFEBABE.toInt() != header) throw IOException("Invalid header class header: $header") if (0xCAFEBABE.toInt() != header) throw IOException("Invalid header class header: $header")
@Suppress("UNUSED_VARIABLE")
val minor = stream.readUnsignedShort() val minor = stream.readUnsignedShort()
val major = stream.readUnsignedShort() val major = stream.readUnsignedShort()
Assert.assertTrue(major == 50) Assert.assertTrue(major == 50)
@@ -29,7 +29,7 @@ suspend fun resolveFromAnnotations(resolver: ExternalDependenciesResolver, annot
return annotations.filterIsInstance(DependsOn::class.java).flatMapSuccess { dep -> return annotations.filterIsInstance(DependsOn::class.java).flatMapSuccess { dep ->
val artifactCoordinates = val artifactCoordinates =
if (dep.value.isNotBlank()) dep.value if (dep.value.isNotBlank()) dep.value
else listOf(dep.groupId, dep.artifactId, dep.version).filter { it?.isNotBlank() ?: false }.joinToString(":") else listOf(dep.groupId, dep.artifactId, dep.version).filter { it.isNotBlank() }.joinToString(":")
resolver.resolve(artifactCoordinates) resolver.resolve(artifactCoordinates)
} }
} }
@@ -141,7 +141,7 @@ class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
return resolveResult.onSuccess { resolvedClassPath -> return resolveResult.onSuccess { resolvedClassPath ->
ScriptCompilationConfiguration(context.compilationConfiguration) { ScriptCompilationConfiguration(context.compilationConfiguration) {
if (resolvedClassPath != null) updateClasspath(resolvedClassPath) updateClasspath(resolvedClassPath)
if (importedSources.isNotEmpty()) importScripts.append(importedSources) if (importedSources.isNotEmpty()) importScripts.append(importedSources)
if (compileOptions.isNotEmpty()) compilerOptions.append(compileOptions) if (compileOptions.isNotEmpty()) compilerOptions.append(compileOptions)
}.asSuccess() }.asSuccess()
@@ -20,33 +20,34 @@ package org.jetbrains.kotlin.script.jsr223
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import org.jetbrains.kotlin.script.util.*
import javax.script.Bindings import javax.script.Bindings
import javax.script.ScriptContext import javax.script.ScriptContext
import javax.script.ScriptEngine import javax.script.ScriptEngine
import kotlin.script.experimental.jvm.util.KotlinJars
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
class KotlinJsr223JvmLocalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() { class KotlinJsr223JvmLocalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine = override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmLocalScriptEngine( KotlinJsr223JvmLocalScriptEngine(
this, this,
scriptCompilationClasspathFromContextOrStlib("kotlin-script-util.jar", wholeClasspath = true), scriptCompilationClasspathFromContext("kotlin-script-util.jar", wholeClasspath = true),
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!, KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
{ ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) }, { ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
arrayOf(Bindings::class) arrayOf(Bindings::class)
) )
} }
class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() { class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine = override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmDaemonCompileScriptEngine( KotlinJsr223JvmDaemonCompileScriptEngine(
this, this,
KotlinJars.compilerWithScriptingClasspath, KotlinJars.compilerWithScriptingClasspath,
scriptCompilationClasspathFromContextOrStlib("kotlin-script-util.jar", wholeClasspath = true), scriptCompilationClasspathFromContext("kotlin-script-util.jar", wholeClasspath = true),
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!, KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
{ ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) }, { ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
arrayOf(Bindings::class) arrayOf(Bindings::class)
) )
} }
@@ -56,6 +56,7 @@ import kotlin.script.experimental.api.onSuccess
import kotlin.script.experimental.api.valueOr import kotlin.script.experimental.api.valueOr
import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
const val KOTLIN_JAVA_RUNTIME_JAR = "kotlin-stdlib.jar" const val KOTLIN_JAVA_RUNTIME_JAR = "kotlin-stdlib.jar"
@@ -63,12 +64,12 @@ class ScriptUtilIT {
companion object { companion object {
private val argsHelloWorldOutput = private val argsHelloWorldOutput =
"""Hello, world! """Hello, world!
a1 a1
done done
""" """
private val bindingsHelloWorldOutput = private val bindingsHelloWorldOutput =
"""Hello, world! """Hello, world!
a1 = 42 a1 = 42
done done
""" """
@@ -107,8 +108,7 @@ done
try { try {
System.setErr(PrintStream(NullOutputStream())) System.setErr(PrintStream(NullOutputStream()))
Assert.assertNull(compileScript("args-junit-hello-world.kts", StandardArgsScriptTemplateWithLocalResolving::class)) Assert.assertNull(compileScript("args-junit-hello-world.kts", StandardArgsScriptTemplateWithLocalResolving::class))
} } finally {
finally {
System.setErr(savedErr) System.setErr(savedErr)
} }
@@ -127,23 +127,28 @@ done
val (out, err) = captureOutAndErr { val (out, err) = captureOutAndErr {
Assert.assertNull(compileScript("args-junit-dynver-error.kts", StandardArgsScriptTemplateWithMavenResolving::class)) Assert.assertNull(compileScript("args-junit-dynver-error.kts", StandardArgsScriptTemplateWithMavenResolving::class))
} }
Assert.assertTrue("Expecting error: unresolved reference: assertThrows, got:\nOUT:\n$out\nERR:\n$err", err.contains("error: unresolved reference: assertThrows")) Assert.assertTrue(
"Expecting error: unresolved reference: assertThrows, got:\nOUT:\n$out\nERR:\n$err",
err.contains("error: unresolved reference: assertThrows")
)
val scriptClass = compileScript("args-junit-dynver.kts", StandardArgsScriptTemplateWithMavenResolving::class) val scriptClass = compileScript("args-junit-dynver.kts", StandardArgsScriptTemplateWithMavenResolving::class)
Assert.assertNotNull(scriptClass) Assert.assertNotNull(scriptClass)
} }
private fun compileScript( private fun compileScript(
scriptFileName: String, scriptFileName: String,
scriptTemplate: KClass<out Any>, scriptTemplate: KClass<out Any>,
environment: Map<String, Any?>? = null, environment: Map<String, Any?>? = null,
suppressOutput: Boolean = false suppressOutput: Boolean = false
): Class<*>? = ): Class<*>? =
compileScriptImpl("libraries/tools/kotlin-script-util/src/test/resources/scripts/" + scriptFileName, compileScriptImpl(
KotlinScriptDefinitionFromAnnotatedTemplate( "libraries/tools/kotlin-script-util/src/test/resources/scripts/$scriptFileName",
scriptTemplate, KotlinScriptDefinitionFromAnnotatedTemplate(
environment scriptTemplate,
), suppressOutput) environment
), suppressOutput
)
private fun compileScriptImpl( private fun compileScriptImpl(
scriptPath: String, scriptPath: String,
@@ -157,9 +162,7 @@ done
val rootDisposable = Disposer.newDisposable() val rootDisposable = Disposer.newDisposable()
try { try {
val configuration = CompilerConfiguration().apply { val configuration = CompilerConfiguration().apply {
scriptCompilationClasspathFromContextOrNull(KOTLIN_JAVA_RUNTIME_JAR)?.let { addJvmClasspathRoots(scriptCompilationClasspathFromContext(KOTLIN_JAVA_RUNTIME_JAR))
addJvmClasspathRoots(it)
}
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
addKotlinSourceRoot(scriptPath) addKotlinSourceRoot(scriptPath)
@@ -185,7 +188,10 @@ done
environment.getSourceFiles().forEach { environment.getSourceFiles().forEach {
messageCollector.report(CompilerMessageSeverity.LOGGING, "file: $it -> script def: ${it.findScriptDefinition()?.name}") messageCollector.report(CompilerMessageSeverity.LOGGING, "file: $it -> script def: ${it.findScriptDefinition()?.name}")
} }
messageCollector.report(CompilerMessageSeverity.LOGGING, "compilation classpath:\n ${environment.configuration.jvmClasspathRoots.joinToString("\n ")}") messageCollector.report(
CompilerMessageSeverity.LOGGING,
"compilation classpath:\n ${environment.configuration.jvmClasspathRoots.joinToString("\n ")}"
)
val scriptCompiler = ScriptJvmCompilerFromEnvironment(environment) val scriptCompiler = ScriptJvmCompilerFromEnvironment(environment)
@@ -223,7 +229,7 @@ done
} }
private fun String.linesSplitTrim() = private fun String.linesSplitTrim() =
split('\n','\r').map(String::trim).filter(String::isNotBlank) split('\n', '\r').map(String::trim).filter(String::isNotBlank)
private fun captureOut(body: () -> Unit): String = captureOutAndErr(body).first private fun captureOut(body: () -> Unit): String = captureOutAndErr(body).first
@@ -247,8 +253,8 @@ done
} }
private class NullOutputStream : OutputStream() { private class NullOutputStream : OutputStream() {
override fun write(b: Int) { } override fun write(b: Int) {}
override fun write(b: ByteArray) { } override fun write(b: ByteArray) {}
override fun write(b: ByteArray, off: Int, len: Int) { } override fun write(b: ByteArray, off: Int, len: Int) {}
} }
@@ -300,8 +300,7 @@ internal fun makeScriptContents(
fun SourceCode.getVirtualFile(definition: ScriptDefinition): VirtualFile { fun SourceCode.getVirtualFile(definition: ScriptDefinition): VirtualFile {
if (this is VirtualFileScriptSource) return virtualFile if (this is VirtualFileScriptSource) return virtualFile
if (this is KtFileScriptSource) { if (this is KtFileScriptSource) {
val vFile = virtualFile return virtualFile
if (vFile != null) return vFile
} }
if (this is FileScriptSource) { if (this is FileScriptSource) {
val vFile = LocalFileSystem.getInstance().findFileByIoFile(file) val vFile = LocalFileSystem.getInstance().findFileByIoFile(file)
@@ -351,6 +350,7 @@ fun getScriptCollectedData(
val acceptedAnnotations = val acceptedAnnotations =
compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]?.flatMap { compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]?.flatMap {
it.annotations.mapNotNull { ann -> it.annotations.mapNotNull { ann ->
@Suppress("UNCHECKED_CAST")
jvmGetScriptingClass(ann, contextClassLoader, hostConfiguration) as? KClass<Annotation> // TODO errors jvmGetScriptingClass(ann, contextClassLoader, hostConfiguration) as? KClass<Annotation> // TODO errors
} }
}.orEmpty() }.orEmpty()
@@ -31,7 +31,3 @@ fun configureScriptDefinitions(
configuration.addAll(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, templatesFromClasspath.toList()) configuration.addAll(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, templatesFromClasspath.toList())
} }
fun makeHostConfiguration(project: Project, configuration: CompilerConfiguration): ScriptingHostConfiguration =
ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
// TODO: add jdk path and other params if needed
}
@@ -30,6 +30,8 @@ import org.jetbrains.kotlin.scripting.extensions.ScriptExtraImportsProviderExten
import org.jetbrains.kotlin.scripting.extensions.ScriptingResolveExtension import org.jetbrains.kotlin.scripting.extensions.ScriptingResolveExtension
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import java.net.URLClassLoader import java.net.URLClassLoader
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
private fun <T : Any> ProjectExtensionDescriptor<T>.registerExtensionIfRequired(project: MockProject, extension: T) { private fun <T : Any> ProjectExtensionDescriptor<T>.registerExtensionIfRequired(project: MockProject, extension: T) {
try { try {
@@ -42,7 +44,9 @@ private fun <T : Any> ProjectExtensionDescriptor<T>.registerExtensionIfRequired(
class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar { class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar {
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
val hostConfiguration = makeHostConfiguration(project, configuration) val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
// TODO: add jdk path and other params if needed
}
withClassloadingProblemsReporting(messageCollector) { withClassloadingProblemsReporting(messageCollector) {
CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project, hostConfiguration)) CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project, hostConfiguration))
CollectAdditionalSourcesExtension.registerExtension(project, CollectAdditionalSourcesExtension.registerExtension(project,
@@ -68,6 +68,7 @@ open class GenericReplCompiler(
Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder) Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder)
} }
@Suppress("DEPRECATION")
val newDependencies = val newDependencies =
ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptConfiguration(psiFile) ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptConfiguration(psiFile)
?.legacyDependencies ?.legacyDependencies
@@ -34,7 +34,7 @@ class IdeDiagnosticMessageHolder : DiagnosticMessageHolder {
reportEntry.setAttribute("severity", diagnostic.severity.toString()) reportEntry.setAttribute("severity", diagnostic.severity.toString())
reportEntry.setAttribute("rangeStart", errorRange.startOffset.toString()) reportEntry.setAttribute("rangeStart", errorRange.startOffset.toString())
reportEntry.setAttribute("rangeEnd", errorRange.endOffset.toString()) reportEntry.setAttribute("rangeEnd", errorRange.endOffset.toString())
reportEntry.appendChild(errorReport.createTextNode(StringUtil.escapeXml(message))) reportEntry.appendChild(errorReport.createTextNode(StringUtil.escapeXmlEntities(message)))
rootElement.appendChild(reportEntry) rootElement.appendChild(reportEntry)
} }
@@ -33,13 +33,15 @@ class ScriptProviderTest {
val shadedDef = FakeScriptDefinition(".x.kts") val shadedDef = FakeScriptDefinition(".x.kts")
val provider = TestCliScriptDefinitionProvider(standardDef).apply { val provider = TestCliScriptDefinitionProvider(standardDef).apply {
setScriptDefinitions(listOf(shadedDef, standardDef)) setScriptDefinitions(listOf(shadedDef, standardDef))
setScriptDefinitionsSources(listOf( setScriptDefinitionsSources(
TestScriptDefinitionSource( listOf(
genDefCounter, TestScriptDefinitionSource(
".y.kts", genDefCounter,
".x.kts" ".y.kts",
".x.kts"
)
) )
)) )
} }
Assert.assertEquals(0, genDefCounter.get()) Assert.assertEquals(0, genDefCounter.get())
@@ -74,11 +76,10 @@ class ScriptProviderTest {
} }
private open class FakeScriptDefinition(val suffix: String = ".kts") : private open class FakeScriptDefinition(val suffix: String = ".kts") :
ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, KotlinScriptDefinition(ScriptTemplateWithArgs::class)) ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, KotlinScriptDefinition(ScriptTemplateWithArgs::class)) {
{
val matchCounter = AtomicInteger() val matchCounter = AtomicInteger()
override fun isScript(script: SourceCode): Boolean { override fun isScript(script: SourceCode): Boolean {
val path =script.locationId ?: return false val path = script.locationId ?: return false
return path.endsWith(suffix).also { return path.endsWith(suffix).also {
if (it) matchCounter.incrementAndGet() if (it) matchCounter.incrementAndGet()
} }
@@ -89,13 +90,14 @@ private open class FakeScriptDefinition(val suffix: String = ".kts") :
} }
private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens: Iterable<() -> FakeScriptDefinition>) : private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens: Iterable<() -> FakeScriptDefinition>) :
ScriptDefinitionsSource ScriptDefinitionsSource {
{ constructor(counter: AtomicInteger, vararg suffixes: String) : this(counter, suffixes.map {
constructor(counter: AtomicInteger, vararg suffixes: String) : this(counter, suffixes.map { { {
FakeScriptDefinition( FakeScriptDefinition(
it it
) )
} }) }
})
override val definitions: Sequence<ScriptDefinition> = sequence { override val definitions: Sequence<ScriptDefinition> = sequence {
for (gen in defGens) { for (gen in defGens) {
@@ -106,5 +108,6 @@ private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens
} }
private class TestCliScriptDefinitionProvider(private val standardDef: ScriptDefinition) : CliScriptDefinitionProvider() { private class TestCliScriptDefinitionProvider(private val standardDef: ScriptDefinition) : CliScriptDefinitionProvider() {
@Suppress("DEPRECATION", "OverridingDeprecatedMember")
override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef.legacyDefinition override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef.legacyDefinition
} }
@@ -54,7 +54,6 @@ class ScriptingCompilerPluginTest : TestCase() {
paths paths
} }
val compilerClasspath = listOf(kotlinPaths.compilerPath)
val runtimeClasspath = listOf( kotlinPaths.stdlibPath, kotlinPaths.scriptRuntimePath, kotlinPaths.reflectPath) val runtimeClasspath = listOf( kotlinPaths.stdlibPath, kotlinPaths.scriptRuntimePath, kotlinPaths.reflectPath)
val scriptingClasspath = listOf("kotlin-scripting-common.jar").map { File(kotlinPaths.libPath, it) } val scriptingClasspath = listOf("kotlin-scripting-common.jar").map { File(kotlinPaths.libPath, it) }