From 4087e650aa804ce13bafab4073ca59fb32838005 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 16 Jun 2016 17:52:00 +0300 Subject: [PATCH] Wrong delegation to delegation property in debugger when property defined in another module (KT-12678) Different bytecode can be generated for delegated property and for non-delegated one. Backend inspects DELEGATED_PROPERTY_CALL to understand the property type, and expects that this information had been already recorded into context. Frontend writes DELEGATED_PROPERTY_CALL into context during body resolve or type inference if type is not present. Either way in debugger context it may happen that the DELEGATED_PROPERTY_CALL won't be written into context. #KT-12678 --- .../kotlin/codegen/JvmCodegenUtil.java | 27 ++++++++++++++----- .../delegatedPropertyInOtherFile2.kt | 11 ++++++++ .../outs/delegatedPropertyInOtherFile.out | 8 ++++++ .../delegatedPropertyInOtherFile.kt | 13 +++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 6 +++++ 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 idea/testData/debugger/customLibraryForTinyApp/delegatedPropertyInOtherFile/delegatedPropertyInOtherFile2.kt create mode 100644 idea/testData/debugger/tinyApp/outs/delegatedPropertyInOtherFile.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/delegatedPropertyInOtherFile.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 06a3b4bcdb0..12c64717eae 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -181,13 +181,26 @@ public class JvmCodegenUtil { return false; } - if (!isDebuggerContext(context)) { - // Unless we are evaluating expression in debugger context, only properties of the same class can be directly accessed - if (!isCallInsideSameClassAsDeclared(property, context)) return false; - } - else { - // In debugger we want to access through accessors if they are present. If property overrides something accessors must be present. - if (!property.getOverriddenDescriptors().isEmpty()) return false; + if (!isCallInsideSameClassAsDeclared(property, context)) { + if (!isDebuggerContext(context)) { + // Unless we are evaluating expression in debugger context, only properties of the same class can be directly accessed + return false; + } + else { + // In debugger we want to access through accessors if they are generated + + // Non default accessors must always be generated + for (PropertyAccessorDescriptor accessorDescriptor : property.getAccessors()) { + if (!accessorDescriptor.isDefault()) { + if (forGetter == accessorDescriptor instanceof PropertyGetterDescriptor) { + return false; + } + } + } + + // If property overrides something, accessors must be generated too + if (!property.getOverriddenDescriptors().isEmpty()) return false; + } } // Delegated and extension properties have no backing fields diff --git a/idea/testData/debugger/customLibraryForTinyApp/delegatedPropertyInOtherFile/delegatedPropertyInOtherFile2.kt b/idea/testData/debugger/customLibraryForTinyApp/delegatedPropertyInOtherFile/delegatedPropertyInOtherFile2.kt new file mode 100644 index 00000000000..86850df9a07 --- /dev/null +++ b/idea/testData/debugger/customLibraryForTinyApp/delegatedPropertyInOtherFile/delegatedPropertyInOtherFile2.kt @@ -0,0 +1,11 @@ +package delegatedPropertyInOtherFileOther + +import kotlin.reflect.KProperty + +class WithDelegate { + val a: Int by Id(12) +} + +class Id(val v: Int) { + operator fun getValue(o: Any, property: KProperty<*>): Int = v +} diff --git a/idea/testData/debugger/tinyApp/outs/delegatedPropertyInOtherFile.out b/idea/testData/debugger/tinyApp/outs/delegatedPropertyInOtherFile.out new file mode 100644 index 00000000000..d0e2494e02c --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/delegatedPropertyInOtherFile.out @@ -0,0 +1,8 @@ +LineBreakpoint created at delegatedPropertyInOtherFile.kt:9 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! delegatedPropertyInOtherFile.DelegatedPropertyInOtherFileKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +delegatedPropertyInOtherFile.kt:9 +Compile bytecode for t.a +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/delegatedPropertyInOtherFile.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/delegatedPropertyInOtherFile.kt new file mode 100644 index 00000000000..e623ca99a63 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/delegatedPropertyInOtherFile.kt @@ -0,0 +1,13 @@ +package delegatedPropertyInOtherFile + +import delegatedPropertyInOtherFileOther.* + +fun main(a: Array) { + val t = WithDelegate() + + //Breakpoint! + t.a +} + +// EXPRESSION: t.a +// RESULT: 12: I diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 57253a9a2eb..a5dbc7ef9c8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -103,6 +103,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doSingleBreakpointTest(fileName); } + @TestMetadata("delegatedPropertyInOtherFile.kt") + public void testDelegatedPropertyInOtherFile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/delegatedPropertyInOtherFile.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("dependentOnFile.kt") public void testDependentOnFile() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/dependentOnFile.kt");