Implement script dependencies resolution directly from classloader
#KT-27956 fixed
This commit is contained in:
+59
-28
@@ -31,10 +31,7 @@ import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluato
|
||||
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.components.SamConversionResolver
|
||||
import org.jetbrains.kotlin.load.java.components.SignaturePropagator
|
||||
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
|
||||
import org.jetbrains.kotlin.load.java.lazy.JavaResolverSettings
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
|
||||
import org.jetbrains.kotlin.load.java.lazy.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -43,6 +40,7 @@ import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
|
||||
@@ -59,35 +57,29 @@ class RuntimeModuleData private constructor(
|
||||
val module = ModuleDescriptorImpl(Name.special("<runtime module for $classLoader>"), storageManager, builtIns)
|
||||
builtIns.builtInsModule = module
|
||||
|
||||
builtIns.initialize(module, isAdditionalBuiltInsFeatureSupported = true)
|
||||
|
||||
val reflectKotlinClassFinder = ReflectKotlinClassFinder(classLoader)
|
||||
val deserializedDescriptorResolver = DeserializedDescriptorResolver()
|
||||
val singleModuleClassResolver = SingleModuleClassResolver()
|
||||
val notFoundClasses = NotFoundClasses(storageManager, module)
|
||||
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, Jsr305State.DISABLED)
|
||||
val javaResolverComponents = JavaResolverComponents(
|
||||
storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver,
|
||||
SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, JavaResolverCache.EMPTY,
|
||||
JavaPropertyInitializerEvaluator.DoNothing, SamConversionResolver.Empty, RuntimeSourceElementFactory,
|
||||
singleModuleClassResolver, PackagePartProvider.Empty, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
|
||||
ReflectionTypes(module, notFoundClasses), annotationTypeQualifierResolver,
|
||||
SignatureEnhancement(annotationTypeQualifierResolver, Jsr305State.DISABLED),
|
||||
JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default
|
||||
)
|
||||
|
||||
val lazyJavaPackageFragmentProvider = LazyJavaPackageFragmentProvider(javaResolverComponents)
|
||||
val lazyJavaPackageFragmentProvider =
|
||||
makeLazyJavaPackageFragmentFromClassLoaderProvider(
|
||||
classLoader, module, storageManager, notFoundClasses,
|
||||
reflectKotlinClassFinder, deserializedDescriptorResolver, singleModuleClassResolver
|
||||
)
|
||||
|
||||
builtIns.initialize(module, isAdditionalBuiltInsFeatureSupported = true)
|
||||
val deserializationComponentsForJava =
|
||||
makeDeserializationComponentsForJava(
|
||||
module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider,
|
||||
reflectKotlinClassFinder, deserializedDescriptorResolver
|
||||
)
|
||||
|
||||
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
|
||||
|
||||
val javaDescriptorResolver = JavaDescriptorResolver(lazyJavaPackageFragmentProvider, JavaResolverCache.EMPTY)
|
||||
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
|
||||
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl(
|
||||
module, notFoundClasses, storageManager, reflectKotlinClassFinder
|
||||
)
|
||||
val deserializationComponentsForJava = DeserializationComponentsForJava(
|
||||
storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder,
|
||||
binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider, notFoundClasses,
|
||||
RuntimeErrorReporter, LookupTracker.DO_NOTHING, ContractDeserializer.DEFAULT, NewKotlinTypeChecker.Default
|
||||
)
|
||||
singleModuleClassResolver.resolver = javaDescriptorResolver
|
||||
|
||||
// .kotlin_builtins files should be found by the same class loader that loaded stdlib classes
|
||||
val stdlibClassLoader = Unit::class.java.classLoader
|
||||
@@ -96,9 +88,6 @@ class RuntimeModuleData private constructor(
|
||||
DeserializationConfiguration.Default, NewKotlinTypeChecker.Default
|
||||
)
|
||||
|
||||
singleModuleClassResolver.resolver = javaDescriptorResolver
|
||||
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
|
||||
|
||||
module.setDependencies(module)
|
||||
module.initialize(CompositePackageFragmentProvider(listOf(javaDescriptorResolver.packageFragmentProvider, builtinsProvider)))
|
||||
|
||||
@@ -109,3 +98,45 @@ class RuntimeModuleData private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun makeLazyJavaPackageFragmentFromClassLoaderProvider(
|
||||
classLoader: ClassLoader,
|
||||
module: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
notFoundClasses: NotFoundClasses,
|
||||
reflectKotlinClassFinder: KotlinClassFinder,
|
||||
deserializedDescriptorResolver: DeserializedDescriptorResolver,
|
||||
singleModuleClassResolver: ModuleClassResolver
|
||||
): LazyJavaPackageFragmentProvider {
|
||||
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, Jsr305State.DISABLED)
|
||||
val javaResolverComponents = JavaResolverComponents(
|
||||
storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver,
|
||||
SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, JavaResolverCache.EMPTY,
|
||||
JavaPropertyInitializerEvaluator.DoNothing, SamConversionResolver.Empty, RuntimeSourceElementFactory,
|
||||
singleModuleClassResolver, PackagePartProvider.Empty, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
|
||||
ReflectionTypes(module, notFoundClasses), annotationTypeQualifierResolver,
|
||||
SignatureEnhancement(annotationTypeQualifierResolver, Jsr305State.DISABLED),
|
||||
JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default
|
||||
)
|
||||
|
||||
return LazyJavaPackageFragmentProvider(javaResolverComponents)
|
||||
}
|
||||
|
||||
fun makeDeserializationComponentsForJava(
|
||||
module: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
notFoundClasses: NotFoundClasses,
|
||||
lazyJavaPackageFragmentProvider: LazyJavaPackageFragmentProvider,
|
||||
reflectKotlinClassFinder: KotlinClassFinder,
|
||||
deserializedDescriptorResolver: DeserializedDescriptorResolver
|
||||
): DeserializationComponentsForJava {
|
||||
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
|
||||
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl(
|
||||
module, notFoundClasses, storageManager, reflectKotlinClassFinder
|
||||
)
|
||||
return DeserializationComponentsForJava(
|
||||
storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder,
|
||||
binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider, notFoundClasses,
|
||||
RuntimeErrorReporter, LookupTracker.DO_NOTHING, ContractDeserializer.DEFAULT, NewKotlinTypeChecker.Default
|
||||
)
|
||||
}
|
||||
@@ -38,6 +38,7 @@ sourceSets {
|
||||
}
|
||||
|
||||
projectTest(parallel = true) {
|
||||
dependsOn(":dist")
|
||||
workingDir = rootDir
|
||||
}
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.
|
||||
*/
|
||||
|
||||
package kotlin.script.experimental.jvmhost.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.ResultValue
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.dependencies
|
||||
import kotlin.script.experimental.api.valueOrThrow
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader
|
||||
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
||||
|
||||
class ResolveFromClassloaderTest : TestCase() {
|
||||
|
||||
@Test
|
||||
fun testResolveFromClassloader() {
|
||||
val script = "${ShouldBeVisibleFromScript::class.java.name}().x".toScriptSource()
|
||||
val compilationConfiguration = ScriptCompilationConfiguration {
|
||||
dependencies(JvmDependencyFromClassLoader { ShouldBeVisibleFromScript::class.java.classLoader })
|
||||
}
|
||||
val res = BasicJvmScriptingHost().eval(script, compilationConfiguration, null).valueOrThrow().returnValue as ResultValue.Value
|
||||
assertEquals(42, res.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveFromClassloaderAndClassPath() {
|
||||
val script = """
|
||||
org.jetbrains.kotlin.mainKts.MainKtsConfigurator()
|
||||
${ShouldBeVisibleFromScript::class.java.name}().x
|
||||
""".trimIndent().toScriptSource()
|
||||
val classpath = listOf(
|
||||
File("dist/kotlinc/lib/kotlin-main-kts.jar").also {
|
||||
assertTrue("kotlin-main-kts.jar not found, run dist task: ${it.absolutePath}", it.exists())
|
||||
}
|
||||
)
|
||||
val compilationConfiguration = ScriptCompilationConfiguration {
|
||||
dependencies(
|
||||
JvmDependencyFromClassLoader { ShouldBeVisibleFromScript::class.java.classLoader },
|
||||
JvmDependency(classpath)
|
||||
)
|
||||
}
|
||||
val res = BasicJvmScriptingHost().eval(script, compilationConfiguration, null).valueOrThrow().returnValue as ResultValue.Value
|
||||
assertEquals(42, res.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
class ShouldBeVisibleFromScript {
|
||||
val x = 42
|
||||
}
|
||||
+1
-1
@@ -97,7 +97,7 @@ internal fun ScriptContents.toScriptSource(): SourceCode = when {
|
||||
else -> throw IllegalArgumentException("Unable to convert script contents $this into script source")
|
||||
}
|
||||
|
||||
fun List<ScriptDependency>?.toClassPathOrEmpty() = this?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
|
||||
fun List<ScriptDependency>?.toClassPathOrEmpty() = this?.flatMap { (it as? JvmDependency)?.classpath ?: emptyList() } ?: emptyList()
|
||||
|
||||
internal fun List<SourceCode>?.toFilesOrEmpty() = this?.map {
|
||||
val externalSource = it as? ExternalSourceCode
|
||||
|
||||
@@ -19,6 +19,12 @@ data class JvmDependency(val classpath: List<File>) : ScriptDependency {
|
||||
companion object { private const val serialVersionUID: Long = 1L }
|
||||
}
|
||||
|
||||
typealias ClassLoaderByConfiguration = (ScriptCompilationConfiguration) -> ClassLoader
|
||||
|
||||
class JvmDependencyFromClassLoader(val classLoaderGetter: ClassLoaderByConfiguration) : ScriptDependency {
|
||||
fun getClassLoader(configuration: ScriptCompilationConfiguration): ClassLoader = classLoaderGetter(configuration)
|
||||
}
|
||||
|
||||
interface JvmScriptCompilationConfigurationKeys
|
||||
|
||||
open class JvmScriptCompilationConfigurationBuilder : PropertiesCollection.Builder(), JvmScriptCompilationConfigurationKeys {
|
||||
|
||||
@@ -12,6 +12,7 @@ dependencies {
|
||||
compileOnly(project(":compiler:psi"))
|
||||
compileOnly(project(":compiler:plugin-api"))
|
||||
compileOnly(project(":compiler:cli"))
|
||||
compileOnly(project(":core:descriptors.runtime"))
|
||||
compile(project(":kotlin-scripting-common"))
|
||||
compile(project(":kotlin-scripting-jvm"))
|
||||
compile(project(":kotlin-scripting-compiler-impl"))
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.runtime.components.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.jvm.ClassLoaderByConfiguration
|
||||
|
||||
|
||||
class PackageFragmentFromClassLoaderProviderExtension(
|
||||
val classLoaderGetter: ClassLoaderByConfiguration,
|
||||
val scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
) : PackageFragmentProviderExtension {
|
||||
|
||||
override fun getPackageFragmentProvider(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
trace: BindingTrace,
|
||||
moduleInfo: ModuleInfo?,
|
||||
lookupTracker: LookupTracker
|
||||
): PackageFragmentProvider? {
|
||||
val classLoader = classLoaderGetter(scriptCompilationConfiguration)
|
||||
|
||||
val reflectKotlinClassFinder = ReflectKotlinClassFinder(classLoader)
|
||||
val deserializedDescriptorResolver = DeserializedDescriptorResolver()
|
||||
val singleModuleClassResolver = SingleModuleClassResolver()
|
||||
val notFoundClasses = NotFoundClasses(storageManager, module)
|
||||
|
||||
val lazyJavaPackageFragmentProvider =
|
||||
makeLazyJavaPackageFragmentFromClassLoaderProvider(
|
||||
classLoader, module, storageManager, notFoundClasses,
|
||||
reflectKotlinClassFinder, deserializedDescriptorResolver, singleModuleClassResolver
|
||||
)
|
||||
|
||||
val deserializationComponentsForJava =
|
||||
makeDeserializationComponentsForJava(
|
||||
module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider,
|
||||
reflectKotlinClassFinder, deserializedDescriptorResolver
|
||||
)
|
||||
|
||||
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
|
||||
|
||||
return lazyJavaPackageFragmentProvider
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -18,12 +18,14 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptJvmCompilerProxy
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.ScriptsCompilationDependencies
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader
|
||||
import kotlin.script.experimental.jvm.compilationCache
|
||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
@@ -138,6 +140,16 @@ private fun doCompile(
|
||||
messageCollector: ScriptDiagnosticsMessageCollector,
|
||||
getScriptConfiguration: (KtFile) -> ScriptCompilationConfiguration
|
||||
): ResultWithDiagnostics<KJvmCompiledScript<Any>> {
|
||||
|
||||
context.baseScriptCompilationConfiguration[ScriptCompilationConfiguration.dependencies]?.forEach { dependency ->
|
||||
if (dependency is JvmDependencyFromClassLoader) {
|
||||
PackageFragmentProviderExtension.registerExtension(
|
||||
context.environment.project,
|
||||
PackageFragmentFromClassLoaderProviderExtension(dependency.classLoaderGetter, context.baseScriptCompilationConfiguration)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val analysisResult = analyze(sourceFiles, context.environment)
|
||||
|
||||
if (!analysisResult.shouldGenerateCode) return failure(
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ private fun createInitialCompilerConfiguration(
|
||||
scriptCompilationConfiguration[ScriptCompilationConfiguration.dependencies]?.let { dependencies ->
|
||||
addJvmClasspathRoots(
|
||||
dependencies.flatMap {
|
||||
(it as JvmDependency).classpath
|
||||
(it as? JvmDependency)?.classpath ?: emptyList()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user