Support local delegated properties in kotlinx-metadata-jvm

This commit is contained in:
Alexander Udalov
2018-06-13 19:17:02 +02:00
parent b00f765255
commit fec2c14ea5
12 changed files with 330 additions and 20 deletions
@@ -1,5 +1,9 @@
# kotlinx-metadata-jvm # kotlinx-metadata-jvm
## 0.0.3
- Support metadata of local delegated properties (see `JvmDeclarationContainerExtensionVisitor.visitLocalDelegatedProperty`)
## 0.0.2 ## 0.0.2
- Change group ID from `org.jetbrains.kotlin` to `org.jetbrains.kotlinx` - Change group ID from `org.jetbrains.kotlin` to `org.jetbrains.kotlinx`
@@ -6,11 +6,8 @@
package kotlinx.metadata.jvm.impl package kotlinx.metadata.jvm.impl
import kotlinx.metadata.* import kotlinx.metadata.*
import kotlinx.metadata.impl.ReadContext import kotlinx.metadata.impl.*
import kotlinx.metadata.impl.WriteContext
import kotlinx.metadata.impl.extensions.MetadataExtensions import kotlinx.metadata.impl.extensions.MetadataExtensions
import kotlinx.metadata.impl.readAnnotation
import kotlinx.metadata.impl.writeAnnotation
import kotlinx.metadata.jvm.* import kotlinx.metadata.jvm.*
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
@@ -25,6 +22,26 @@ internal class JvmMetadataExtensions : MetadataExtensions {
if (anonymousObjectOriginName != null) { if (anonymousObjectOriginName != null) {
ext.visitAnonymousObjectOriginName(c[anonymousObjectOriginName]) ext.visitAnonymousObjectOriginName(c[anonymousObjectOriginName])
} }
for (property in proto.getExtension(JvmProtoBuf.classLocalVariable)) {
ext.visitLocalDelegatedProperty(
property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
)?.let { property.accept(it, c) }
}
ext.visitEnd()
}
override fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext) {
val ext = v.visitExtensions(JvmPackageExtensionVisitor.TYPE) as? JvmPackageExtensionVisitor ?: return
for (property in proto.getExtension(JvmProtoBuf.packageLocalVariable)) {
ext.visitLocalDelegatedProperty(
property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
)?.let { property.accept(it, c) }
}
ext.visitEnd()
} }
override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) { override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) {
@@ -86,6 +103,25 @@ internal class JvmMetadataExtensions : MetadataExtensions {
override fun visitAnonymousObjectOriginName(internalName: String) { override fun visitAnonymousObjectOriginName(internalName: String) {
proto.setExtension(JvmProtoBuf.anonymousObjectOriginName, c[internalName]) proto.setExtension(JvmProtoBuf.anonymousObjectOriginName, c[internalName])
} }
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor = writeProperty(c, flags, name, getterFlags, setterFlags) {
proto.addExtension(JvmProtoBuf.classLocalVariable, it.build())
}
}
}
override fun writePackageExtensions(
type: KmExtensionType, proto: ProtoBuf.Package.Builder, c: WriteContext
): KmPackageExtensionVisitor? {
if (type != JvmPackageExtensionVisitor.TYPE) return null
return object : JvmPackageExtensionVisitor() {
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor = writeProperty(c, flags, name, getterFlags, setterFlags) {
proto.addExtension(JvmProtoBuf.packageLocalVariable, it.build())
}
} }
} }
@@ -9,11 +9,40 @@ import kotlinx.metadata.*
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
/** /**
* A visitor to visit JVM extensions for a function. * A visitor containing the common code to visit JVM extensions for Kotlin declaration containers, such as classes and package fragments.
*/
abstract class JvmDeclarationContainerExtensionVisitor @JvmOverloads constructor(
protected open val delegate: JvmDeclarationContainerExtensionVisitor? = null
) : KmDeclarationContainerExtensionVisitor {
/**
* Visits the metadata of a local delegated property used somewhere inside this container (but not in a nested declaration container).
* Note that for classes produced by the Kotlin compiler, such properties will have default accessors.
*
* The order of visited local delegated properties is important. The Kotlin compiler generates the corresponding property's index
* at the call site, so that reflection would be able to load the metadata of the property with that index at runtime.
* If an incorrect index is used, either the `KProperty<*>` object passed to delegate methods will point to the wrong property
* at runtime, or an exception will be thrown.
*
* @param flags property flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag and [Flag.Property] flags
* @param name the name of the property
* @param getterFlags property accessor flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flag.PropertyAccessor] flags
* @param setterFlags property accessor flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flag.PropertyAccessor] flags
*/
open fun visitLocalDelegatedProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? =
delegate?.visitLocalDelegatedProperty(flags, name, getterFlags, setterFlags)
}
/**
* A visitor to visit JVM extensions for a class.
*/ */
open class JvmClassExtensionVisitor @JvmOverloads constructor( open class JvmClassExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmClassExtensionVisitor? = null delegate: JvmClassExtensionVisitor? = null
) : KmClassExtensionVisitor { ) : KmClassExtensionVisitor, JvmDeclarationContainerExtensionVisitor(delegate) {
override val delegate: JvmClassExtensionVisitor?
get() = super.delegate as JvmClassExtensionVisitor?
/** /**
* Visits the JVM internal name of the original class this anonymous object is copied from. This method is called for * Visits the JVM internal name of the original class this anonymous object is copied from. This method is called for
* anonymous objects copied from bodies of inline functions to the use site by the Kotlin compiler. * anonymous objects copied from bodies of inline functions to the use site by the Kotlin compiler.
@@ -22,6 +51,13 @@ open class JvmClassExtensionVisitor @JvmOverloads constructor(
delegate?.visitAnonymousObjectOriginName(internalName) delegate?.visitAnonymousObjectOriginName(internalName)
} }
/**
* Visits the end of JVM extensions for the class.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object { companion object {
/** /**
* The type of this extension visitor. * The type of this extension visitor.
@@ -33,6 +69,33 @@ open class JvmClassExtensionVisitor @JvmOverloads constructor(
} }
} }
/**
* A visitor to visit JVM extensions for a package fragment.
*/
open class JvmPackageExtensionVisitor @JvmOverloads constructor(
delegate: JvmPackageExtensionVisitor? = null
) : KmPackageExtensionVisitor, JvmDeclarationContainerExtensionVisitor(delegate) {
override val delegate: JvmPackageExtensionVisitor?
get() = super.delegate as JvmPackageExtensionVisitor?
/**
* Visits the end of JVM extensions for the package fragment.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmPackageExtensionVisitor::class)
}
}
/** /**
* A visitor to visit JVM extensions for a function. * A visitor to visit JVM extensions for a function.
*/ */
@@ -35,10 +35,20 @@ data class KmExtensionType(val klass: KClass<out KmExtensionVisitor>)
*/ */
interface KmExtensionVisitor interface KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a declaration container, such as a class or a package fragment.
*/
interface KmDeclarationContainerExtensionVisitor : KmExtensionVisitor
/** /**
* A visitor to visit platform-specific extensions for a class. * A visitor to visit platform-specific extensions for a class.
*/ */
interface KmClassExtensionVisitor : KmExtensionVisitor interface KmClassExtensionVisitor : KmDeclarationContainerExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a package fragment.
*/
interface KmPackageExtensionVisitor : KmDeclarationContainerExtensionVisitor
/** /**
* A visitor to visit platform-specific extensions for a function. * A visitor to visit platform-specific extensions for a function.
@@ -14,6 +14,8 @@ import java.util.*
interface MetadataExtensions { interface MetadataExtensions {
fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, c: ReadContext) fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, c: ReadContext)
fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext)
fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext)
fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, c: ReadContext) fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, c: ReadContext)
@@ -26,6 +28,8 @@ interface MetadataExtensions {
fun writeClassExtensions(type: KmExtensionType, proto: ProtoBuf.Class.Builder, c: WriteContext): KmClassExtensionVisitor? fun writeClassExtensions(type: KmExtensionType, proto: ProtoBuf.Class.Builder, c: WriteContext): KmClassExtensionVisitor?
fun writePackageExtensions(type: KmExtensionType, proto: ProtoBuf.Package.Builder, c: WriteContext): KmPackageExtensionVisitor?
fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, c: WriteContext): KmFunctionExtensionVisitor? fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, c: WriteContext): KmFunctionExtensionVisitor?
fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, c: WriteContext): KmPropertyExtensionVisitor? fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, c: WriteContext): KmPropertyExtensionVisitor?
@@ -93,6 +93,10 @@ fun ProtoBuf.Package.accept(v: KmPackageVisitor, strings: NameResolver) {
v.visitDeclarations(functionList, propertyList, typeAliasList, c) v.visitDeclarations(functionList, propertyList, typeAliasList, c)
for (extension in c.extensions) {
extension.readPackageExtensions(v, this, c)
}
v.visitEnd() v.visitEnd()
} }
@@ -107,15 +111,8 @@ private fun KmDeclarationContainerVisitor.visitDeclarations(
} }
for (property in properties) { for (property in properties) {
val flags = property.flags
val defaultAccessorFlags = F.getAccessorFlags(
F.HAS_ANNOTATIONS.get(flags), F.VISIBILITY.get(flags), F.MODALITY.get(flags), false, false, false
)
visitProperty( visitProperty(
flags, property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
c[property.name],
if (property.hasGetterFlags()) property.getterFlags else defaultAccessorFlags,
if (property.hasSetterFlags()) property.setterFlags else defaultAccessorFlags
)?.let { property.accept(it, c) } )?.let { property.accept(it, c) }
} }
@@ -182,7 +179,7 @@ private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
v.visitEnd() v.visitEnd()
} }
private fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) { fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList) val c = outer.withTypeParameters(typeParameterList)
for (typeParameter in typeParameterList) { for (typeParameter in typeParameterList) {
@@ -425,3 +422,12 @@ private val ProtoBuf.Type.typeFlags: Flags
private val ProtoBuf.TypeParameter.typeParameterFlags: Flags private val ProtoBuf.TypeParameter.typeParameterFlags: Flags
get() = if (reified) 1 else 0 get() = if (reified) 1 else 0
fun ProtoBuf.Property.getPropertyGetterFlags(): Flags =
if (hasGetterFlags()) getterFlags else getDefaultPropertyAccessorFlags(flags)
fun ProtoBuf.Property.getPropertySetterFlags(): Flags =
if (hasSetterFlags()) setterFlags else getDefaultPropertyAccessorFlags(flags)
private fun getDefaultPropertyAccessorFlags(flags: Flags): Flags =
F.getAccessorFlags(F.HAS_ANNOTATIONS.get(flags), F.VISIBILITY.get(flags), F.MODALITY.get(flags), false, false, false)
@@ -190,7 +190,7 @@ private fun writeFunction(c: WriteContext, flags: Flags, name: String, output: (
} }
} }
private fun writeProperty( fun writeProperty(
c: WriteContext, flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags, output: (ProtoBuf.Property.Builder) -> Unit c: WriteContext, flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags, output: (ProtoBuf.Property.Builder) -> Unit
): KmPropertyVisitor = object : KmPropertyVisitor() { ): KmPropertyVisitor = object : KmPropertyVisitor() {
val t = ProtoBuf.Property.newBuilder() val t = ProtoBuf.Property.newBuilder()
@@ -480,6 +480,11 @@ open class PackageWriter(stringTable: StringTable) : KmPackageVisitor() {
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? = override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? =
writeTypeAlias(c, flags, name) { t.addTypeAlias(it) } writeTypeAlias(c, flags, name) { t.addTypeAlias(it) }
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? =
c.applySingleExtension(type) {
writePackageExtensions(type, t, c)
}
override fun visitEnd() { override fun visitEnd() {
c.versionRequirements.serialize()?.let { c.versionRequirements.serialize()?.let {
t.versionRequirementTable = it t.versionRequirementTable = it
@@ -6,7 +6,7 @@
package kotlinx.metadata package kotlinx.metadata
/** /**
* A visitor to visit Kotlin declarations, which are containers of other declarations: functions, properties and type aliases. * A visitor containing the common code to visit Kotlin declaration containers, such as classes and package fragments.
*/ */
abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected open val delegate: KmDeclarationContainerVisitor? = null) { abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected open val delegate: KmDeclarationContainerVisitor? = null) {
/** /**
@@ -39,6 +39,13 @@ abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected
*/ */
open fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? = open fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? =
delegate?.visitTypeAlias(flags, name) delegate?.visitTypeAlias(flags, name)
/**
* Visits the extensions of the given type on the container.
*
* @param type the type of extension visitor to be returned
*/
abstract fun visitExtensions(type: KmExtensionType): KmDeclarationContainerExtensionVisitor?
} }
/** /**
@@ -136,7 +143,7 @@ abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor
* *
* @param type the type of extension visitor to be returned * @param type the type of extension visitor to be returned
*/ */
open fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? = override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? =
delegate?.visitExtensions(type) delegate?.visitExtensions(type)
/** /**
@@ -156,6 +163,14 @@ abstract class KmPackageVisitor @JvmOverloads constructor(delegate: KmPackageVis
override val delegate: KmPackageVisitor? override val delegate: KmPackageVisitor?
get() = super.delegate as KmPackageVisitor? get() = super.delegate as KmPackageVisitor?
/**
* Visits the extensions of the given type on the package fragment.
*
* @param type the type of extension visitor to be returned
*/
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? =
delegate?.visitExtensions(type)
/** /**
* Visits the end of the package fragment. * Visits the end of the package fragment.
*/ */
@@ -509,6 +509,21 @@ private fun StringBuilder.appendFlags(flags: Flags, map: Map<Flag, String>) {
} }
} }
private fun StringBuilder.appendLocalDelegatedProperties(localDelegatedProperties: List<StringBuilder>) {
for ((i, sb) in localDelegatedProperties.withIndex()) {
appendln()
appendln(" // local delegated property #$i")
for (line in sb.lineSequence()) {
if (line.isBlank()) continue
// Comment all uncommented lines to not make it look like these properties are declared here
appendln(
if (line.startsWith(" ") && !line.startsWith(" //")) line.replaceFirst(" ", " // ")
else line
)
}
}
}
interface AbstractPrinter<in T : KotlinClassMetadata> { interface AbstractPrinter<in T : KotlinClassMetadata> {
fun print(klass: T): String fun print(klass: T): String
} }
@@ -594,9 +609,21 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? { override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? {
if (type != JvmClassExtensionVisitor.TYPE) return null if (type != JvmClassExtensionVisitor.TYPE) return null
return object : JvmClassExtensionVisitor() { return object : JvmClassExtensionVisitor() {
private val localDelegatedProperties = mutableListOf<StringBuilder>()
override fun visitAnonymousObjectOriginName(internalName: String) { override fun visitAnonymousObjectOriginName(internalName: String) {
anonymousObjectOriginName = internalName anonymousObjectOriginName = internalName
} }
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor? = visitProperty(
settings, StringBuilder().also { localDelegatedProperties.add(it) }, flags, name, getterFlags, setterFlags
)
override fun visitEnd() {
sb.appendLocalDelegatedProperties(localDelegatedProperties)
}
} }
} }
@@ -623,6 +650,23 @@ abstract class PackagePrinter(private val settings: KotlinpSettings) : KmPackage
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? = override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? =
visitTypeAlias(settings, sb, flags, name) visitTypeAlias(settings, sb, flags, name)
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? {
if (type != JvmPackageExtensionVisitor.TYPE) return null
return object : JvmPackageExtensionVisitor() {
private val localDelegatedProperties = mutableListOf<StringBuilder>()
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor? = visitProperty(
settings, StringBuilder().also { localDelegatedProperties.add(it) }, flags, name, getterFlags, setterFlags
)
override fun visitEnd() {
sb.appendLocalDelegatedProperties(localDelegatedProperties)
}
}
}
} }
class FileFacadePrinter(settings: KotlinpSettings) : PackagePrinter(settings), AbstractPrinter<KotlinClassMetadata.FileFacade> { class FileFacadePrinter(settings: KotlinpSettings) : PackagePrinter(settings), AbstractPrinter<KotlinClassMetadata.FileFacade> {
@@ -44,6 +44,11 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest {
runTest("libraries/tools/kotlinp/testData/LocalClass.kt"); runTest("libraries/tools/kotlinp/testData/LocalClass.kt");
} }
@TestMetadata("LocalDelegatedProperties.kt")
public void testLocalDelegatedProperties() throws Exception {
runTest("libraries/tools/kotlinp/testData/LocalDelegatedProperties.kt");
}
@TestMetadata("MultiFileClass.kt") @TestMetadata("MultiFileClass.kt")
public void testMultiFileClass() throws Exception { public void testMultiFileClass() throws Exception {
runTest("libraries/tools/kotlinp/testData/MultiFileClass.kt"); runTest("libraries/tools/kotlinp/testData/MultiFileClass.kt");
@@ -0,0 +1,30 @@
import kotlin.reflect.KProperty
class Delegate<T>(val value: T? = null) {
operator fun getValue(instance: Any?, property: KProperty<*>): T = value!!
}
val nonLocal by Delegate<String>()
val init0 = run {
val local1 by Delegate<Double>()
val local2 by Delegate<Any>()
}
val init1 = run {
val local3 by Delegate<CharSequence?>()
}
class Class {
init {
val local4 by Delegate<Array<String>>()
}
fun f() {
val local5 by Delegate<List<Unit>?>()
fun g() {
val local6 by Delegate<Int>()
}
}
}
@@ -0,0 +1,88 @@
// Class.class
// ------------------------------------------
public final class Class : kotlin/Any {
// signature: <init>()V
public /* primary */ constructor()
// signature: f()V
public final fun f(): kotlin/Unit
// local delegated property #0
// field: local4:Lkotlin/Array;
// local final /* delegated */ val local4: kotlin/Array<kotlin/String>
// local final get
// local delegated property #1
// field: local5:Ljava/util/List;
// local final /* delegated */ val local5: kotlin/collections/List<kotlin/Unit>?
// local final get
// local delegated property #2
// field: local6:I
// local final /* delegated */ val local6: kotlin/Int
// local final get
}
// Class$f$1.class
// ------------------------------------------
lambda {
// signature: invoke()V
local final fun g(): kotlin/Unit
}
// Delegate.class
// ------------------------------------------
public final class Delegate<T#0 /* T */> : kotlin/Any {
// signature: <init>(Ljava/lang/Object;)V
public /* primary */ constructor(value: T#0? /* = ... */)
// signature: getValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object;
public final operator fun getValue(instance: kotlin/Any?, property: kotlin/reflect/KProperty<*>): T#0
// field: value:Ljava/lang/Object;
// getter: getValue()Ljava/lang/Object;
public final val value: T#0?
public final get
}
// LocalDelegatedPropertiesKt.class
// ------------------------------------------
package {
// field: init0:Lkotlin/Unit;
// getter: getInit0()Lkotlin/Unit;
public final val init0: kotlin/Unit
public final get
// field: init1:Lkotlin/Unit;
// getter: getInit1()Lkotlin/Unit;
public final val init1: kotlin/Unit
public final get
// field: nonLocal$delegate:LDelegate;
// getter: getNonLocal()Ljava/lang/String;
public final /* delegated */ val nonLocal: kotlin/String
public final /* non-default */ get
// local delegated property #0
// field: local1:D
// local final /* delegated */ val local1: kotlin/Double
// local final get
// local delegated property #1
// field: local2:Ljava/lang/Object;
// local final /* delegated */ val local2: kotlin/Any
// local final get
// local delegated property #2
// field: local3:Ljava/lang/CharSequence;
// local final /* delegated */ val local3: kotlin/CharSequence?
// local final get
}
// META-INF/test-module.kotlin_module
// ------------------------------------------
module {
package <root> {
LocalDelegatedPropertiesKt
}
}