From 8ca9e792e928314d14376b284f066d71b0261232 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Thu, 5 Nov 2020 16:29:02 +0300 Subject: [PATCH] [KLIB] Make sure that referenced local anonymous class is deserialzied. In case if such class is used an type argument for field type make sure that field initializer is being read. Check type recursively. - fix KT-41143 - update test --- .../serialization/IrFileDeserializer.kt | 20 ++++++++++--------- .../codegen/box/ir/anonymousClassLeak.kt | 18 ++++++++++++++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt index ceb119d085a..c7fd5035352 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt @@ -1170,8 +1170,10 @@ abstract class IrFileDeserializer( * * For more information see `anonymousClassLeak.kt` test and issue KT-40216 */ - private fun IrType.checkObjectLeak(isPrivate: Boolean): Boolean { - return isPrivate && this is IrSimpleType && classifier.let { !it.isPublicApi && it !is IrTypeParameterSymbol } + private fun IrType.checkObjectLeak(): Boolean { + return if (this is IrSimpleType) { + classifier.let { !it.isPublicApi && it !is IrTypeParameterSymbol } || arguments.any { it.typeOrNull?.checkObjectLeak() == true } + } else false } private fun T.withBodyGuard(block: T.() -> Unit) { @@ -1180,7 +1182,7 @@ abstract class IrFileDeserializer( fun checkInlineBody(): Boolean = deserializeInlineFunctions && this is IrSimpleFunction && isInline try { - deserializeBodies = oldBodiesPolicy || checkInlineBody() || returnType.checkObjectLeak(!symbol.isPublicApi) + deserializeBodies = oldBodiesPolicy || checkInlineBody() || returnType.checkObjectLeak() block() } finally { deserializeBodies = oldBodiesPolicy @@ -1188,11 +1190,11 @@ abstract class IrFileDeserializer( } - private fun IrField.withInitializerGuard(isPrivateProperty: Boolean, f: IrField.() -> Unit) { + private fun IrField.withInitializerGuard(f: IrField.() -> Unit) { val oldBodiesPolicy = deserializeBodies try { - deserializeBodies = oldBodiesPolicy || type.checkObjectLeak(isPrivateProperty) + deserializeBodies = oldBodiesPolicy || type.checkObjectLeak() f() } finally { deserializeBodies = oldBodiesPolicy @@ -1319,7 +1321,7 @@ abstract class IrFileDeserializer( - private fun deserializeIrField(proto: ProtoField, isPrivateProperty: Boolean): IrField = + private fun deserializeIrField(proto: ProtoField): IrField = withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode -> val nameType = BinaryNameAndType.decode(proto.nameType) val type = deserializeIrType(nameType.typeIndex) @@ -1337,7 +1339,7 @@ abstract class IrFileDeserializer( ) }.usingParent { if (proto.hasInitializer()) { - withInitializerGuard(isPrivateProperty) { + withInitializerGuard { initializer = irFactory.createExpressionBody(deserializeExpressionBody(proto.initializer)) } } @@ -1396,7 +1398,7 @@ abstract class IrFileDeserializer( } } if (proto.hasBackingField()) { - backingField = deserializeIrField(proto.backingField, !symbol.isPublicApi).also { + backingField = deserializeIrField(proto.backingField).also { // A property symbol and its field symbol share the same descriptor. // Unfortunately symbol deserialization doesn't know anything about that. // So we can end up with two wrapped property descriptors for property and its field. @@ -1444,7 +1446,7 @@ abstract class IrFileDeserializer( val declaration: IrDeclaration = when (proto.declaratorCase!!) { IR_ANONYMOUS_INIT -> deserializeIrAnonymousInit(proto.irAnonymousInit) IR_CONSTRUCTOR -> deserializeIrConstructor(proto.irConstructor) - IR_FIELD -> deserializeIrField(proto.irField, false) + IR_FIELD -> deserializeIrField(proto.irField) IR_CLASS -> deserializeIrClass(proto.irClass) IR_FUNCTION -> deserializeIrFunction(proto.irFunction) IR_PROPERTY -> deserializeIrProperty(proto.irProperty) diff --git a/compiler/testData/codegen/box/ir/anonymousClassLeak.kt b/compiler/testData/codegen/box/ir/anonymousClassLeak.kt index 48910947ecb..d698de9419e 100644 --- a/compiler/testData/codegen/box/ir/anonymousClassLeak.kt +++ b/compiler/testData/codegen/box/ir/anonymousClassLeak.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME // MODULE: lib // FILE: lib.kt @@ -51,6 +52,16 @@ object FunTest { fun bbb() = qqq().biq().also { it.caz() } } +object DelegateTest { + var result = "" + + val f by lazy { + object { }.also { result += "OK" } + } + + fun bbb() = f +} + // MODULE: lib2(lib) // FILE: lib2.kt fun test1(): String { @@ -62,11 +73,16 @@ fun test2(): String { return FunTest.result } +fun test3(): String { + DelegateTest.bbb() + return DelegateTest.result +} + // MODULE: main(lib2) // FILE: main.kt fun box(): String { if (test1() != "!abcd") return "FAIL 1: ${test1()}" if (test2() != "zyxw") return "FAIL 2: ${test2()}" - return "OK" + return test3() } \ No newline at end of file