Local variable shouldn't be visible in debugger before initialization
This commit is contained in:
@@ -1539,20 +1539,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
if (statement instanceof JetMultiDeclaration) {
|
||||
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
|
||||
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
generateLocalVariableDeclaration(entry, blockEnd, leaveTasks);
|
||||
}
|
||||
}
|
||||
|
||||
if (statement instanceof JetVariableDeclaration) {
|
||||
generateLocalVariableDeclaration((JetVariableDeclaration) statement, blockEnd, leaveTasks);
|
||||
}
|
||||
|
||||
if (statement instanceof JetNamedFunction) {
|
||||
generateLocalFunctionDeclaration((JetNamedFunction) statement, leaveTasks);
|
||||
}
|
||||
putDescriptorIntoFrameMap(statement);
|
||||
|
||||
boolean isExpression = !iterator.hasNext() && !isStatement;
|
||||
if (isExpression && labelBeforeLastExpression != null) {
|
||||
@@ -1567,6 +1554,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
else {
|
||||
result.put(Type.VOID_TYPE, v);
|
||||
}
|
||||
|
||||
removeDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
|
||||
}
|
||||
|
||||
return new StackValueWithLeaveTask(answer, new ExtensionFunction0<StackValueWithLeaveTask, Unit>() {
|
||||
@@ -1583,34 +1572,97 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
});
|
||||
}
|
||||
|
||||
private void generateLocalVariableDeclaration(
|
||||
@NotNull JetVariableDeclaration variableDeclaration,
|
||||
final @NotNull Label blockEnd,
|
||||
@NotNull
|
||||
private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) {
|
||||
Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
|
||||
return sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
|
||||
}
|
||||
|
||||
private static boolean isSharedVarType(@NotNull Type type) {
|
||||
return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
|
||||
}
|
||||
|
||||
|
||||
private void putDescriptorIntoFrameMap(@NotNull JetElement statement) {
|
||||
if (statement instanceof JetMultiDeclaration) {
|
||||
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
|
||||
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
putLocalVariableIntoFrameMap(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (statement instanceof JetVariableDeclaration) {
|
||||
putLocalVariableIntoFrameMap((JetVariableDeclaration) statement);
|
||||
}
|
||||
|
||||
if (statement instanceof JetNamedFunction) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
|
||||
myFrameMap.enter(descriptor, OBJECT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private void putLocalVariableIntoFrameMap(@NotNull JetVariableDeclaration statement) {
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
|
||||
assert variableDescriptor != null;
|
||||
|
||||
Type type = getVariableType(variableDescriptor);
|
||||
int index = myFrameMap.enter(variableDescriptor, type);
|
||||
|
||||
if (isSharedVarType(type)) {
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
v.invokespecial(type.getInternalName(), "<init>", "()V", false);
|
||||
v.store(index, OBJECT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeDescriptorFromFrameMap(
|
||||
@NotNull JetElement statement,
|
||||
@NotNull Label blockEnd,
|
||||
@NotNull List<Function<StackValue, Void>> leaveTasks
|
||||
) {
|
||||
final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
|
||||
if (statement instanceof JetMultiDeclaration) {
|
||||
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
|
||||
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
removeLocalVariableFromFrameMap(entry, blockEnd, leaveTasks);
|
||||
}
|
||||
}
|
||||
|
||||
if (statement instanceof JetVariableDeclaration) {
|
||||
removeLocalVariableFromFrameMap((JetVariableDeclaration) statement, blockEnd, leaveTasks);
|
||||
}
|
||||
|
||||
if (statement instanceof JetNamedFunction) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
|
||||
leaveTasks.add(new Function<StackValue, Void>() {
|
||||
@Override
|
||||
public Void fun(StackValue value) {
|
||||
myFrameMap.leave(descriptor);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLocalVariableFromFrameMap(
|
||||
@NotNull JetVariableDeclaration statement,
|
||||
final Label blockEnd,
|
||||
@NotNull List<Function<StackValue, Void>> leaveTasks
|
||||
) {
|
||||
final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
|
||||
assert variableDescriptor != null;
|
||||
|
||||
final Type type = getVariableType(variableDescriptor);
|
||||
|
||||
final Label scopeStart = new Label();
|
||||
v.mark(scopeStart);
|
||||
|
||||
final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
|
||||
final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
|
||||
int index = myFrameMap.enter(variableDescriptor, type);
|
||||
|
||||
if (sharedVarType != null) {
|
||||
v.anew(sharedVarType);
|
||||
v.dup();
|
||||
v.invokespecial(sharedVarType.getInternalName(), "<init>", "()V", false);
|
||||
v.store(index, OBJECT_TYPE);
|
||||
}
|
||||
|
||||
leaveTasks.add(new Function<StackValue, Void>() {
|
||||
@Override
|
||||
public Void fun(StackValue answer) {
|
||||
int index = myFrameMap.leave(variableDescriptor);
|
||||
|
||||
if (sharedVarType != null) {
|
||||
if (isSharedVarType(type)) {
|
||||
v.aconst(null);
|
||||
v.store(index, OBJECT_TYPE);
|
||||
}
|
||||
@@ -1620,22 +1672,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
});
|
||||
}
|
||||
|
||||
private void generateLocalFunctionDeclaration(
|
||||
@NotNull JetNamedFunction namedFunction,
|
||||
@NotNull List<Function<StackValue, Void>> leaveTasks
|
||||
) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, namedFunction);
|
||||
myFrameMap.enter(descriptor, OBJECT_TYPE);
|
||||
|
||||
leaveTasks.add(new Function<StackValue, Void>() {
|
||||
@Override
|
||||
public Void fun(StackValue value) {
|
||||
myFrameMap.leave(descriptor);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isShouldMarkLineNumbers() {
|
||||
return shouldMarkLineNumbers;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1235,7 @@ public abstract class StackValue {
|
||||
if (primitiveType == null) throw new UnsupportedOperationException();
|
||||
|
||||
String typeName = primitiveType.getTypeName().getIdentifier();
|
||||
return Type.getObjectType("kotlin/jvm/internal/Ref$" + typeName + "Ref");
|
||||
return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -154,6 +154,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
int from = insnList.indexOf(localVariableNode.start) + 1;
|
||||
int to = insnList.indexOf(localVariableNode.end) - 1;
|
||||
|
||||
Frame<BasicValue> frameForFromInstr = frames[from];
|
||||
if (frameForFromInstr != null) {
|
||||
BasicValue localVarValue = frameForFromInstr.getLocal(localVariableNode.index);
|
||||
if (localVarValue != null) {
|
||||
values.add(localVarValue);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = from; i <= to; i++) {
|
||||
if (i < 0 || i >= insnList.size()) continue;
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ public class AsmTypes {
|
||||
|
||||
public static final String REFLECTION_INTERNAL_PACKAGE = reflectInternal("InternalPackage").getInternalName();
|
||||
|
||||
public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef");
|
||||
public static final String REF_TYPE_PREFIX = "kotlin/jvm/internal/Ref$";
|
||||
public static final Type OBJECT_REF_TYPE = Type.getObjectType(REF_TYPE_PREFIX + "ObjectRef");
|
||||
|
||||
@NotNull
|
||||
private static Type reflectInternal(@NotNull String className) {
|
||||
|
||||
@@ -23,7 +23,6 @@ fun foo(f: () -> Unit) {
|
||||
// RESULT: Cannot find local variable: name = val1
|
||||
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
|
||||
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
|
||||
local = a: int = 0 (sp = frameLambdaNotUsed.kt, 7)
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
LineBreakpoint created at frameLocalVariable.kt:6
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! frameLocalVariable.FrameLocalVariablePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
frameLocalVariable.kt:6
|
||||
package frameLocalVariable
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val val1 = 1
|
||||
//Breakpoint!
|
||||
val val2 = 1
|
||||
}
|
||||
|
||||
// PRINT_FRAME
|
||||
frame = main():6, FrameLocalVariablePackage$@packagePartHASH {frameLocalVariable}
|
||||
static = static = frameLocalVariable.FrameLocalVariablePackage$@packagePartHASH
|
||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameLocalVariable.kt, 3)
|
||||
local = val1: int = 1 (sp = frameLocalVariable.kt, 4)
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package frameLocalVariable
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val val1 = 1
|
||||
//Breakpoint!
|
||||
val val2 = 1
|
||||
}
|
||||
|
||||
// PRINT_FRAME
|
||||
+6
@@ -294,6 +294,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("frameLocalVariable.kt")
|
||||
public void testFrameLocalVariable() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLocalVariable.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("frameObject.kt")
|
||||
public void testFrameObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameObject.kt");
|
||||
|
||||
Reference in New Issue
Block a user