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
This commit is contained in:
Nikolay Krasko
2016-06-16 17:52:00 +03:00
committed by Nikolay Krasko
parent 0bc5007147
commit 4087e650aa
5 changed files with 58 additions and 7 deletions
@@ -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
@@ -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
}
@@ -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
@@ -0,0 +1,13 @@
package delegatedPropertyInOtherFile
import delegatedPropertyInOtherFileOther.*
fun main(a: Array<String>) {
val t = WithDelegate()
//Breakpoint!
t.a
}
// EXPRESSION: t.a
// RESULT: 12: I
@@ -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");