Skip to content

Commit 5661c19

Browse files
committed
Add support for statement-level Stepping
Introduce a debug preference to enable statement-level Stepping. This allows the debugger to skip intermediate bytecode instructions in multi-line statements and suspend only at the next executable source statement. This avoids unnecessary stops at intermediate load instructions during stepping. Fixes : #854
1 parent 0d00143 commit 5661c19

File tree

16 files changed

+387
-11
lines changed

16 files changed

+387
-11
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
public class StatementStep {
15+
16+
public static void main(String[] args) {
17+
String s = ";;";
18+
String s2 = ";;";
19+
String s3 = ";;";
20+
String s4 = ";;";
21+
String s5 = ";;";
22+
tet(
23+
1.0f,
24+
s2,
25+
s3,
26+
tet2(s4,s4),
27+
s5);
28+
s2 = s + s2;
29+
s2 = s + s2;
30+
}
31+
32+
public static String tet(float s, String s2,String s3,String s4,String s5) {
33+
return "sou";
34+
}
35+
public static String tet2(String s, String s2) {
36+
return "sous";
37+
}
38+
39+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
public class StatementStepArgumnt {
15+
16+
public static void method1(String firstName, String lastName)
17+
{
18+
System.out.println("Method1 " +
19+
" : first name: " + firstName +
20+
" : last name: " + lastName);
21+
}
22+
23+
public static void main(String[] args) {
24+
25+
String firstName = "John";
26+
String lastName = "Smith";
27+
28+
lastName = "Smith";
29+
30+
method1(firstName,
31+
lastName
32+
);
33+
34+
System.out.println("End call method1");
35+
36+
} /* main( args ) */
37+
38+
} /* TestApp */
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
public class StatementStepNested {
15+
16+
public static void main(String[] args) {
17+
String s1 = "A";
18+
String s2 = "B";
19+
String s3 = "C";
20+
String s4 = "D";
21+
22+
test(
23+
s1,
24+
helper1(
25+
s2,
26+
helper1(s3,
27+
helper1(s2,
28+
s3)
29+
)
30+
),
31+
s4
32+
);
33+
34+
System.out.println("Sou");
35+
}
36+
37+
static String helper1(String a, String b) {
38+
return a + b;
39+
}
40+
41+
static String helper2(String a) {
42+
return a;
43+
}
44+
45+
static void test(String a, String b, String c) {
46+
}
47+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.debug.test.stepping;
15+
16+
import org.eclipse.debug.core.model.ILineBreakpoint;
17+
import org.eclipse.jdt.debug.core.IJavaStackFrame;
18+
import org.eclipse.jdt.debug.core.IJavaThread;
19+
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
20+
import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;
21+
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
22+
import org.eclipse.jface.preference.IPreferenceStore;
23+
24+
public class StatementSteppingTests extends AbstractDebugTest {
25+
26+
private boolean fOriginalState;
27+
28+
public StatementSteppingTests(String name) {
29+
super(name);
30+
}
31+
32+
@Override
33+
protected void setUp() throws Exception {
34+
super.setUp();
35+
fOriginalState = getPrefStore().getBoolean(IJDIPreferencesConstants.PREF_STATEMENT_LEVEL_STEPPING);
36+
if (!fOriginalState) {
37+
getPrefStore().setValue(IJDIPreferencesConstants.PREF_STATEMENT_LEVEL_STEPPING, true);
38+
}
39+
}
40+
41+
/**
42+
* Tests a step over with lots of arguments
43+
*/
44+
public void testLotsOfMultilineArguments() throws Exception {
45+
46+
String typeName = "StatementStep";
47+
ILineBreakpoint bp = createLineBreakpoint(21, typeName);
48+
IJavaThread thread = null;
49+
try {
50+
thread = launchToLineBreakpoint(typeName, bp, true);
51+
IJavaStackFrame stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
52+
thread.stepOver();
53+
Thread.sleep(1000);
54+
assertEquals("Should be at line 26", 26, stackFrame.getLineNumber());
55+
56+
thread.stepInto();
57+
Thread.sleep(1000);
58+
stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
59+
assertEquals("Should be at line 36", 36, stackFrame.getLineNumber());
60+
61+
thread.stepReturn();
62+
Thread.sleep(1000);
63+
stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
64+
assertEquals("Should be at line 22", 22, stackFrame.getLineNumber());
65+
66+
thread.stepOver();
67+
Thread.sleep(1000);
68+
assertEquals("Should be at line 28", 28, stackFrame.getLineNumber());
69+
} finally {
70+
terminateAndRemove(thread);
71+
removeAllBreakpoints();
72+
}
73+
}
74+
75+
public void testStepOverWithSingleMultilineArgument() throws Exception {
76+
77+
String typeName = "StatementStepArgumnt";
78+
ILineBreakpoint bp = createLineBreakpoint(28, typeName);
79+
IJavaThread thread = null;
80+
try {
81+
thread = launchToLineBreakpoint(typeName, bp, true);
82+
IJavaStackFrame stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
83+
thread.stepOver();
84+
Thread.sleep(1000);
85+
assertEquals("Should be at line 30", 30, stackFrame.getLineNumber());
86+
87+
thread.stepOver();
88+
Thread.sleep(1000);
89+
assertEquals("Should be at line 34", 34, stackFrame.getLineNumber());
90+
91+
} finally {
92+
terminateAndRemove(thread);
93+
removeAllBreakpoints();
94+
}
95+
}
96+
97+
public void testStepOverWithNestedMultiLineArgs() throws Exception {
98+
99+
String typeName = "StatementStepNested";
100+
ILineBreakpoint bp = createLineBreakpoint(20, typeName);
101+
IJavaThread thread = null;
102+
try {
103+
thread = launchToLineBreakpoint(typeName, bp, true);
104+
IJavaStackFrame stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
105+
thread.stepOver();
106+
Thread.sleep(1000);
107+
assertEquals("Should be at line 27", 27, stackFrame.getLineNumber());
108+
109+
thread.stepInto();
110+
Thread.sleep(1000);
111+
stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
112+
assertEquals("Should be at line 38", 38, stackFrame.getLineNumber());
113+
114+
thread.stepReturn();
115+
Thread.sleep(1000);
116+
stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
117+
assertEquals("Should be at line 26", 26, stackFrame.getLineNumber());
118+
119+
thread.stepOver();
120+
Thread.sleep(1000);
121+
assertEquals("Should be at line 24", 24, stackFrame.getLineNumber());
122+
123+
thread.stepOver();
124+
Thread.sleep(1000);
125+
assertEquals("Should be at line 22", 22, stackFrame.getLineNumber());
126+
127+
thread.stepOver();
128+
Thread.sleep(1000);
129+
assertEquals("Should be at line 34", 34, stackFrame.getLineNumber());
130+
131+
} finally {
132+
terminateAndRemove(thread);
133+
removeAllBreakpoints();
134+
}
135+
}
136+
137+
/**
138+
* Returns the <code>JDIDebugUIPlugin</code> preference store
139+
*/
140+
protected IPreferenceStore getPrefStore() {
141+
return JDIDebugUIPlugin.getDefault().getPreferenceStore();
142+
}
143+
144+
@Override
145+
protected void tearDown() throws Exception {
146+
super.tearDown();
147+
if (fOriginalState != getPrefStore().getBoolean(IJDIPreferencesConstants.PREF_STATEMENT_LEVEL_STEPPING)) {
148+
getPrefStore().setValue(IJDIPreferencesConstants.PREF_STATEMENT_LEVEL_STEPPING, fOriginalState);
149+
}
150+
}
151+
}

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ public abstract class AbstractDebugTest extends TestCase implements IEvaluation
217217
"Bug534319earlyStart", "Bug534319lateStart", "Bug534319singleThread", "Bug534319startBetwen", "MethodCall", "Bug538303", "Bug540243",
218218
"OutSync", "OutSync2", "ConsoleOutputUmlaut", "ErrorRecurrence", "ModelPresentationTests", "Bug565982",
219219
"SuspendVMConditionalBreakpointsTestSnippet", "FileConditionSnippet2", "compare.CompareObjectsStringTest", "compare.CompareListObjects",
220-
"compare.CompareMapObjects", "compare.CompareSetObjects", "compare.CompareNormalObjects", "compare.CompareArrayObjects" };
220+
"compare.CompareMapObjects", "compare.CompareSetObjects", "compare.CompareNormalObjects", "compare.CompareArrayObjects",
221+
"StatementStep", "StatementStepArgumnt", "StatementStepNested" };
221222

222223
/**
223224
* the default timeout

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2025 IBM Corporation and others.
2+
* Copyright (c) 2000, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -17,6 +17,7 @@
1717

1818
import org.eclipse.core.runtime.Platform;
1919
import org.eclipse.jdt.debug.test.stepping.ForceReturnTests;
20+
import org.eclipse.jdt.debug.test.stepping.StatementStepOverTests;
2021
import org.eclipse.jdt.debug.test.stepping.StepFilterTests;
2122
import org.eclipse.jdt.debug.test.stepping.StepIntoSelectionTests;
2223
import org.eclipse.jdt.debug.test.stepping.StepIntoSelectionWithGenerics;
@@ -251,6 +252,7 @@ public AutomatedSuite() {
251252
if (JavaProjectHelper.isJava6Compatible()) {
252253
addTest(new TestSuite(ForceReturnTests.class));
253254
}
255+
addTest(new TestSuite(StatementStepOverTests.class));
254256

255257
//Classpath tests
256258
addTest(new TestSuite(JavaLibraryPathTests.class));

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2024 IBM Corporation and others.
2+
* Copyright (c) 2000, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -77,6 +77,8 @@ public class DebugUIMessages extends NLS {
7777
public static String JavaDebugPreferencePage_ShowStepResult_local;
7878
public static String JavaDebugPreferencePage_ShowStepResult_remote;
7979
public static String JavaDebugPreferencePage_ShowStepTimeout_ms_1;
80+
81+
public static String JavaDebugPreferencePage_StatementLevelStepping;
8082
public static String JavaDebugPreferencePage_Communication_1;
8183
public static String JavaDebugPreferencePage_Debugger__timeout__2;
8284
public static String JavaDebugPreferencePage__Launch_timeout__ms___1;

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ JavaDebugPreferencePage_ShowStepResult_1=Show method result after a step operati
3737
JavaDebugPreferencePage_ShowStepResult_local=Enable for local launc&h types
3838
JavaDebugPreferencePage_ShowStepResult_remote=Enable for remote connections (may be e&ven slower)
3939
JavaDebugPreferencePage_ShowStepTimeout_ms_1=Don't show &if step operation takes longer than (ms):
40+
JavaDebugPreferencePage_StatementLevelStepping=Skip intermediate instructions while stepping
4041
JavaDebugPreferencePage_Communication_1=Communication
4142
JavaDebugPreferencePage_Debugger__timeout__2=Debugger &timeout (ms):
4243
JavaDebugPreferencePage__Launch_timeout__ms___1=&Launch timeout (ms):

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/IJDIPreferencesConstants.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2011 IBM Corporation and others.
2+
* Copyright (c) 2000, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -269,4 +269,9 @@ public interface IJDIPreferencesConstants {
269269
*/
270270
public static final String PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT= IJavaDebugUIConstants.PLUGIN_ID + ".prompt_delete_conditional_breakpoint"; //$NON-NLS-1$
271271

272+
/**
273+
* Boolean preference controlling whether debugger should suspend only for statement-level instructions.
274+
*/
275+
public static final String PREF_STATEMENT_LEVEL_STEPPING = IJavaDebugUIConstants.PLUGIN_ID + ".statement_only_stepping"; //$NON-NLS-1$
276+
272277
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2004, 2024 IBM Corporation and others.
2+
* Copyright (c) 2004, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -38,6 +38,7 @@ public void initializeDefaultPreferences() {
3838
store.setDefault(IJDIPreferencesConstants.PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT, true);
3939
store.setDefault(IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS, true);
4040
store.setDefault(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, true);
41+
store.setDefault(IJDIPreferencesConstants.PREF_STATEMENT_LEVEL_STEPPING, false);
4142

4243
store.setDefault(IJDIPreferencesConstants.PREF_SHOW_QUALIFIED_NAMES, false);
4344

0 commit comments

Comments
 (0)