From 58831eacca9f9c486f1bfc33fbf94911bd6f5aa8 Mon Sep 17 00:00:00 2001 From: Ilya Muradyan Date: Tue, 5 Oct 2021 16:40:59 +0300 Subject: [PATCH] [scripting] Make properties from destructing declarations available with reflection --- .../descriptors/AbstractLazyMemberScope.kt | 11 +++++++- .../destructuringDeclarationsScript.txt | 7 +++++ ...tializerOfDestructuringDeclarationOnce.txt | 3 ++ .../resolve/LazyScriptClassMemberScope.kt | 17 +++++++++++ .../compiler/test/ScriptCompilerTest.kt | 28 +++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt index 7bc90ff9777..a64b8a6f0e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt @@ -212,6 +212,15 @@ protected constructor( }.toList() } + protected open fun collectDescriptorsFromDestructingDeclaration( + result: MutableSet, + declaration: KtDestructuringDeclaration, + nameFilter: (Name) -> Boolean, + location: LookupLocation, + ) { + // MultiDeclarations are not supported on global level by default + } + protected fun computeDescriptorsFromDeclaredElements( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, @@ -258,7 +267,7 @@ protected constructor( } } is KtDestructuringDeclaration -> { - // MultiDeclarations are not supported on global level + collectDescriptorsFromDestructingDeclaration(result, declaration, nameFilter, location) } else -> throw IllegalArgumentException("Unsupported declaration kind: " + declaration) } diff --git a/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt index bf24a3bd364..a4b21192ba4 100644 --- a/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt +++ b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt @@ -2,7 +2,14 @@ package public final class DestructuringDeclarationsScript : kotlin.script.templates.standard.ScriptTemplateWithArgs { public constructor DestructuringDeclarationsScript(/*0*/ args: kotlin.Array) + public final val a1: kotlin.Int + public final val a2: kotlin.String public final override /*1*/ /*fake_override*/ val args: kotlin.Array + public final val b1: kotlin.Int + public final val b2: kotlin.String + public final val c1: [ERROR : component1() return type] + public final val d1: kotlin.Int + public final val e1: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt index 2f226e6b53a..f2b8a41ac78 100644 --- a/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt +++ b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt @@ -2,7 +2,10 @@ package public final class ResolveInitializerOfDestructuringDeclarationOnce : kotlin.script.templates.standard.ScriptTemplateWithArgs { public constructor ResolveInitializerOfDestructuringDeclarationOnce(/*0*/ args: kotlin.Array) + public final val a: kotlin.Unit public final override /*1*/ /*fake_override*/ val args: kotlin.Array + public final val b: kotlin.Unit + public final val c: kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptClassMemberScope.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptClassMemberScope.kt index fc9521cbb47..4d4ee781076 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptClassMemberScope.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptClassMemberScope.kt @@ -6,8 +6,11 @@ package org.jetbrains.kotlin.scripting.resolve import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider @@ -53,6 +56,20 @@ class LazyScriptClassMemberScope( override fun createPropertiesFromPrimaryConstructorParameters(name: Name, result: MutableSet) { } + override fun collectDescriptorsFromDestructingDeclaration( + result: MutableSet, + declaration: KtDestructuringDeclaration, + nameFilter: (Name) -> Boolean, + location: LookupLocation + ) { + for (entry in declaration.entries) { + val name = entry.nameAsSafeName + if (nameFilter(name) && name.identifierOrNullIfSpecial != "_") { + result.addAll(getContributedVariables(name, location)) + } + } + } + companion object { const val IMPLICIT_RECEIVER_PARAM_NAME_PREFIX = "\$\$implicitReceiver" const val IMPORTED_SCRIPT_PARAM_NAME_PREFIX = "\$\$importedScript" diff --git a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/test/ScriptCompilerTest.kt b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/test/ScriptCompilerTest.kt index 76f144595f7..36e56132081 100644 --- a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/test/ScriptCompilerTest.kt +++ b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/test/ScriptCompilerTest.kt @@ -9,6 +9,9 @@ import junit.framework.TestCase import kotlinx.coroutines.runBlocking import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerIsolated import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.full.createInstance +import kotlin.reflect.full.declaredMembers import kotlin.script.experimental.api.* import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration @@ -46,6 +49,31 @@ class ScriptCompilerTest : TestCase() { assertEquals("Clazz", nestedClasses[0].simpleName) } + fun testDestructingDeclarations() { + val res = compileToClass( + """ + val c = 3 + val (a, b) = 1 to 2 + val (_, d, _) = listOf('1', '2', '3') + """.trimIndent().toScriptSource() + ) + + val kClass = res.valueOrThrow() + val scriptInstance = kClass.createInstance() + val members = kClass.declaredMembers + val namesToMembers = members.associateBy { it.name } + + fun prop(name: String) = namesToMembers[name]!! as KProperty<*> + fun propValue(name: String) = prop(name).call(scriptInstance) + fun propType(name: String) = prop(name).returnType.classifier as KClass<*> + + assertEquals(1, propValue("a")) + assertEquals(Int::class, propType("b")) + assertEquals(3, propValue("c")) + assertEquals(Char::class, propType("d")) + assertNull(namesToMembers["_"]) + } + fun compile( script: SourceCode, cfgBody: ScriptCompilationConfiguration.Builder.() -> Unit