| // 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; |
| }); |
| } |
| |
| } |