[scripting] Make properties from destructing declarations available with reflection

This commit is contained in:
Ilya Muradyan
2021-10-05 16:40:59 +03:00
committed by teamcityserver
parent 1c16f2f8c9
commit 58831eacca
5 changed files with 65 additions and 1 deletions
@@ -212,6 +212,15 @@ protected constructor(
}.toList() }.toList()
} }
protected open fun collectDescriptorsFromDestructingDeclaration(
result: MutableSet<DeclarationDescriptor>,
declaration: KtDestructuringDeclaration,
nameFilter: (Name) -> Boolean,
location: LookupLocation,
) {
// MultiDeclarations are not supported on global level by default
}
protected fun computeDescriptorsFromDeclaredElements( protected fun computeDescriptorsFromDeclaredElements(
kindFilter: DescriptorKindFilter, kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean, nameFilter: (Name) -> Boolean,
@@ -258,7 +267,7 @@ protected constructor(
} }
} }
is KtDestructuringDeclaration -> { is KtDestructuringDeclaration -> {
// MultiDeclarations are not supported on global level collectDescriptorsFromDestructingDeclaration(result, declaration, nameFilter, location)
} }
else -> throw IllegalArgumentException("Unsupported declaration kind: " + declaration) else -> throw IllegalArgumentException("Unsupported declaration kind: " + declaration)
} }
@@ -2,7 +2,14 @@ package
public final class DestructuringDeclarationsScript : kotlin.script.templates.standard.ScriptTemplateWithArgs { public final class DestructuringDeclarationsScript : kotlin.script.templates.standard.ScriptTemplateWithArgs {
public constructor DestructuringDeclarationsScript(/*0*/ args: kotlin.Array<kotlin.String>) public constructor DestructuringDeclarationsScript(/*0*/ args: kotlin.Array<kotlin.String>)
public final val a1: kotlin.Int
public final val a2: kotlin.String
public final override /*1*/ /*fake_override*/ val args: kotlin.Array<kotlin.String> public final override /*1*/ /*fake_override*/ val args: kotlin.Array<kotlin.String>
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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@@ -2,7 +2,10 @@ package
public final class ResolveInitializerOfDestructuringDeclarationOnce : kotlin.script.templates.standard.ScriptTemplateWithArgs { public final class ResolveInitializerOfDestructuringDeclarationOnce : kotlin.script.templates.standard.ScriptTemplateWithArgs {
public constructor ResolveInitializerOfDestructuringDeclarationOnce(/*0*/ args: kotlin.Array<kotlin.String>) public constructor ResolveInitializerOfDestructuringDeclarationOnce(/*0*/ args: kotlin.Array<kotlin.String>)
public final val a: kotlin.Unit
public final override /*1*/ /*fake_override*/ val args: kotlin.Array<kotlin.String> public final override /*1*/ /*fake_override*/ val args: kotlin.Array<kotlin.String>
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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@@ -6,8 +6,11 @@
package org.jetbrains.kotlin.scripting.resolve package org.jetbrains.kotlin.scripting.resolve
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
@@ -53,6 +56,20 @@ class LazyScriptClassMemberScope(
override fun createPropertiesFromPrimaryConstructorParameters(name: Name, result: MutableSet<PropertyDescriptor>) { override fun createPropertiesFromPrimaryConstructorParameters(name: Name, result: MutableSet<PropertyDescriptor>) {
} }
override fun collectDescriptorsFromDestructingDeclaration(
result: MutableSet<DeclarationDescriptor>,
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 { companion object {
const val IMPLICIT_RECEIVER_PARAM_NAME_PREFIX = "\$\$implicitReceiver" const val IMPLICIT_RECEIVER_PARAM_NAME_PREFIX = "\$\$implicitReceiver"
const val IMPORTED_SCRIPT_PARAM_NAME_PREFIX = "\$\$importedScript" const val IMPORTED_SCRIPT_PARAM_NAME_PREFIX = "\$\$importedScript"
@@ -9,6 +9,9 @@ import junit.framework.TestCase
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerIsolated import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerIsolated
import kotlin.reflect.KClass 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.api.*
import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
@@ -46,6 +49,31 @@ class ScriptCompilerTest : TestCase() {
assertEquals("Clazz", nestedClasses[0].simpleName) 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( fun compile(
script: SourceCode, script: SourceCode,
cfgBody: ScriptCompilationConfiguration.Builder.() -> Unit cfgBody: ScriptCompilationConfiguration.Builder.() -> Unit