blob: a0a9c3f044e1f54a20a07bb97db7ad82de1cddd7 [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
import java.util.Arrays;
import java.util.List;
import org.apache.harmony.jpda.tests.framework.jdwp.Frame.Variable;
import org.apache.harmony.jpda.tests.framework.jdwp.Location;
/**
* A specialization for Kotlin-based tests which provides extra commands.
*/
public abstract class KotlinDebugTestBase extends DebugTestBase {
protected final JUnit3Wrapper.Command kotlinStepOver() {
return testBaseBeforeStep -> {
final JUnit3Wrapper.DebuggeeState debuggeeStateBeforeStep = testBaseBeforeStep
.getDebuggeeState();
final int frameDepthBeforeStep = debuggeeStateBeforeStep.getFrameDepth();
final Location locationBeforeStep = debuggeeStateBeforeStep.getLocation();
final List<Variable> kotlinLvsBeforeStep = getVisibleKotlinInlineVariables(
debuggeeStateBeforeStep);
// This is the command that will be executed after the initial (normal) step over. If we
// reach an inlined location, this command will step until reaching a non-inlined location.
JUnit3Wrapper.Command commandAfterStep = testBaseAfterStep -> {
// Get the new debuggee state (previous one is stale).
JUnit3Wrapper.DebuggeeState debuggeeStateAfterStep = testBaseBeforeStep.getDebuggeeState();
// Are we in the same frame ?
final int frameDepthAfterStep = debuggeeStateAfterStep.getFrameDepth();
final Location locationAfterStep = debuggeeStateAfterStep.getLocation();
if (frameDepthBeforeStep == frameDepthAfterStep
&& locationBeforeStep.classID == locationAfterStep.classID
&& locationBeforeStep.methodID == locationAfterStep.methodID) {
// We remain in the same method. Do we step into an inlined section ?
List<Variable> kotlinLvsAfterStep = getVisibleKotlinInlineVariables(
debuggeeStateAfterStep);
if (kotlinLvsBeforeStep.isEmpty() && !kotlinLvsAfterStep.isEmpty()) {
assert kotlinLvsAfterStep.size() == 1;
// We're located in an inlined section. Instead of doing a classic step out, we must
// jump out of the inlined section.
Variable inlinedSectionLv = kotlinLvsAfterStep.get(0);
testBaseAfterStep.enqueueCommandFirst(stepUntilOutOfInlineScope(inlinedSectionLv));
}
}
};
// Step over then check whether we need to continue stepping.
testBaseBeforeStep.enqueueCommandsFirst(Arrays.asList(stepOver(), commandAfterStep));
};
}
protected final JUnit3Wrapper.Command kotlinStepOut() {
return wrapper -> {
final List<Variable> kotlinLvsBeforeStep = getVisibleKotlinInlineVariables(
wrapper.getDebuggeeState());
JUnit3Wrapper.Command nextCommand;
if (!kotlinLvsBeforeStep.isEmpty()) {
// We are in an inline section. We need to step until being out of inline scope.
assert kotlinLvsBeforeStep.size() == 1;
final Variable inlinedSectionLv = kotlinLvsBeforeStep.get(0);
nextCommand = stepUntilOutOfInlineScope(inlinedSectionLv);
} else {
nextCommand = stepOut();
}
wrapper.enqueueCommandFirst(nextCommand);
};
}
private JUnit3Wrapper.Command stepUntilOutOfInlineScope(Variable inlineScopeLv) {
return stepUntil(StepKind.OVER, StepLevel.LINE, debuggeeState -> {
boolean inInlineScope = JUnit3Wrapper
.inScope(debuggeeState.getLocation().index, inlineScopeLv);
return !inInlineScope;
});
}
}