From 1f46e601533cdcf48f3bf246413af75243f191f3 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Fri, 11 Oct 2019 11:10:22 +0200 Subject: [PATCH] Implement samWithReceiver support for scripts when ... it configured from script compilation configuration #KT-34294 fixed --- .../IdeSamWithReceiverComponentContributor.kt | 4 +- .../scripting/definitions/ScriptDefinition.kt | 7 +++ .../plugin/impl/compilationContext.kt | 46 ++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt b/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt index 1f3e4e16254..f06d5cc5ade 100644 --- a/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt +++ b/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt @@ -66,8 +66,8 @@ class IdeSamWithReceiverComponentContributor(val project: Project) : StorageComp val moduleInfo = moduleDescriptor.getCapability(ModuleInfo.Capability) val annotations = when (moduleInfo) { - is ScriptModuleInfo -> moduleInfo.scriptDefinition.legacyDefinition.annotationsForSamWithReceivers - is ScriptDependenciesInfo.ForFile -> moduleInfo.scriptDefinition.legacyDefinition.annotationsForSamWithReceivers + is ScriptModuleInfo -> moduleInfo.scriptDefinition.annotationsForSamWithReceivers + is ScriptDependenciesInfo.ForFile -> moduleInfo.scriptDefinition.annotationsForSamWithReceivers is ModuleProductionSourceInfo -> getAnnotationsForModule(moduleInfo.module) else -> null } ?: return diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt index 6cc6f29ee39..9a197afbaee 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt @@ -45,6 +45,7 @@ abstract class ScriptDefinition : UserDataHolderBase() { abstract val baseClassType: KotlinType abstract val compilerOptions: Iterable + abstract val annotationsForSamWithReceivers: List @Suppress("DEPRECATION") inline fun asLegacyOrNull(): T? = @@ -94,6 +95,9 @@ abstract class ScriptDefinition : UserDataHolderBase() { override val compilerOptions: Iterable get() = legacyDefinition.additionalCompilerArguments ?: emptyList() + override val annotationsForSamWithReceivers: List + get() = legacyDefinition.annotationsForSamWithReceivers + override fun equals(other: Any?): Boolean = this === other || legacyDefinition == (other as? FromLegacy)?.legacyDefinition override fun hashCode(): Int = legacyDefinition.hashCode() @@ -158,6 +162,9 @@ abstract class ScriptDefinition : UserDataHolderBase() { override val compilerOptions: Iterable get() = compilationConfiguration[ScriptCompilationConfiguration.compilerOptions].orEmpty() + override val annotationsForSamWithReceivers: List + get() = compilationConfiguration[ScriptCompilationConfiguration.annotationsForSamWithReceivers].orEmpty().map { it.typeName } + override fun equals(other: Any?): Boolean = this === other || (other as? FromConfigurations)?.let { compilationConfiguration == it.compilationConfiguration && evaluationConfiguration == it.evaluationConfiguration diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt index bb2df562f5f..6ee496a9d95 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt @@ -23,13 +23,25 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JvmTarget +import org.jetbrains.kotlin.container.StorageComponentContainer +import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.extensions.AnnotationBasedExtension +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.load.java.sam.SamWithReceiverResolver +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.ScriptsCompilationDependencies import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.collectScriptsCompilationDependencies import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider +import org.jetbrains.kotlin.scripting.definitions.annotationsForSamWithReceivers import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.compilerOptions import kotlin.script.experimental.api.dependencies @@ -64,7 +76,7 @@ internal fun createIsolatedCompilationContext( return SharedScriptCompilationContext( disposable, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState - ) + ).applyConfigure() } internal fun createCompilationContextFromEnvironment( @@ -83,7 +95,37 @@ internal fun createCompilationContextFromEnvironment( return SharedScriptCompilationContext( null, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState - ) + ).applyConfigure() +} + +// copied with minor modifications from the sam-with-receiver-cli +// TODO: consider placing into a shared jar +internal class ScriptingSamWithReceiverComponentContributor(val annotations: List) : StorageComponentContainerContributor { + + private class Extension(private val annotations: List) : SamWithReceiverResolver, AnnotationBasedExtension { + override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?) = annotations + + override fun shouldConvertFirstSamParameterToReceiver(function: FunctionDescriptor): Boolean = + (function.containingDeclaration as? ClassDescriptor)?.hasSpecialAnnotation(null) ?: false + } + + override fun registerModuleComponents( + container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor + ) { + if (platform.isJvm()) { + container.useInstance(Extension(annotations)) + } + } +} + +internal fun SharedScriptCompilationContext.applyConfigure(): SharedScriptCompilationContext = apply { + val samWithReceiverAnnotations = baseScriptCompilationConfiguration[ScriptCompilationConfiguration.annotationsForSamWithReceivers] + if (samWithReceiverAnnotations?.isEmpty() == false) { + StorageComponentContainerContributor.registerExtension( + environment.project, + ScriptingSamWithReceiverComponentContributor(samWithReceiverAnnotations.map { it.typeName }) + ) + } } internal fun createInitialConfigurations(