Skip to content

Commit 952b171

Browse files
committed
Allow stepping through disassembly
1 parent a4aa8d5 commit 952b171

6 files changed

Lines changed: 362 additions & 25 deletions

File tree

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*******************************************************************************/
1616
package org.eclipse.jdt.debug.tests;
1717

18+
import junit.framework.JUnit4TestAdapter;
19+
import junit.framework.Test;
20+
import junit.framework.TestSuite;
1821
import org.eclipse.core.runtime.Platform;
1922
import org.eclipse.jdt.debug.test.stepping.ForceReturnTests;
2023
import org.eclipse.jdt.debug.test.stepping.StatementSteppingTests;
@@ -135,6 +138,7 @@
135138
import org.eclipse.jdt.debug.tests.refactoring.RenamePublicTypeUnitTests;
136139
import org.eclipse.jdt.debug.tests.sourcelookup.ArchiveSourceLookupTests;
137140
import org.eclipse.jdt.debug.tests.sourcelookup.Bug565462Tests;
141+
import org.eclipse.jdt.debug.tests.sourcelookup.ClassFileEditorHighlightingTest;
138142
import org.eclipse.jdt.debug.tests.sourcelookup.DefaultSourceContainerTests;
139143
import org.eclipse.jdt.debug.tests.sourcelookup.DirectorySourceContainerTests;
140144
import org.eclipse.jdt.debug.tests.sourcelookup.DirectorySourceLookupTests;
@@ -148,6 +152,7 @@
148152
import org.eclipse.jdt.debug.tests.sourcelookup.TypeResolutionTests;
149153
import org.eclipse.jdt.debug.tests.state.RefreshStateTests;
150154
import org.eclipse.jdt.debug.tests.ui.DebugHoverTests;
155+
import org.eclipse.jdt.debug.tests.ui.DebugSelectionTests;
151156
import org.eclipse.jdt.debug.tests.ui.DebugViewTests;
152157
import org.eclipse.jdt.debug.tests.ui.DetailPaneManagerTests;
153158
import org.eclipse.jdt.debug.tests.ui.HotCodeReplaceErrorDialogTest;
@@ -166,10 +171,6 @@
166171
import org.eclipse.jdt.debug.tests.variables.TestLogicalStructures;
167172
import org.eclipse.jdt.debug.tests.variables.TestLogicalStructuresJava9;
168173

169-
import junit.framework.JUnit4TestAdapter;
170-
import junit.framework.Test;
171-
import junit.framework.TestSuite;
172-
173174
/**
174175
* Tests for integration and nightly builds.
175176
*/
@@ -229,6 +230,8 @@ public AutomatedSuite() {
229230
addTest(new TestSuite(TypeResolutionTests.class));
230231
addTest(new TestSuite(JarSourceLookupTests.class));
231232
addTest(new TestSuite(Bug565462Tests.class));
233+
addTest(new TestSuite(DebugSelectionTests.class));
234+
addTest(new UIThreadTestSuite(ClassFileEditorHighlightingTest.class));
232235

233236
// Variable tests
234237
addTest(new TestSuite(InstanceVariableTests.class));

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
import java.util.Enumeration;
1818

19+
import junit.framework.Test;
20+
import junit.framework.TestResult;
21+
import junit.framework.TestSuite;
1922
import org.eclipse.jdt.debug.tests.eval.ArrayAllocationTests;
2023
import org.eclipse.jdt.debug.tests.eval.ArrayAssignmentTests;
2124
import org.eclipse.jdt.debug.tests.eval.ArrayValueTests;
@@ -105,10 +108,6 @@
105108
import org.eclipse.jdt.debug.tests.eval.XfixOperatorsTests;
106109
import org.eclipse.swt.widgets.Display;
107110

108-
import junit.framework.Test;
109-
import junit.framework.TestResult;
110-
import junit.framework.TestSuite;
111-
112111
/**
113112
* Test all areas of the UI.
114113
*/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026, Daniel Schmid and others.
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+
* Daniel Schmid - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.debug.tests;
15+
16+
import junit.framework.TestResult;
17+
import junit.framework.TestSuite;
18+
import org.eclipse.debug.internal.ui.DebugUIPlugin;
19+
20+
/**
21+
* Allows running tests in the UI thread.
22+
*/
23+
public class UIThreadTestSuite extends TestSuite {
24+
25+
public UIThreadTestSuite(Class<?> clazz) {
26+
super(clazz);
27+
}
28+
@Override
29+
public void run(TestResult result) {
30+
DebugUIPlugin.getStandardDisplay().syncExec(() -> super.run(result));
31+
}
32+
}
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026, Daniel Schmid and others.
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+
* Daniel Schmid - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.debug.tests.sourcelookup;
15+
16+
import java.io.File;
17+
import java.io.IOException;
18+
import java.net.URI;
19+
import java.nio.charset.StandardCharsets;
20+
import java.util.List;
21+
import java.util.Locale;
22+
23+
import javax.tools.DiagnosticCollector;
24+
import javax.tools.JavaCompiler;
25+
import javax.tools.JavaCompiler.CompilationTask;
26+
import javax.tools.JavaFileObject;
27+
import javax.tools.SimpleJavaFileObject;
28+
import javax.tools.StandardJavaFileManager;
29+
import javax.tools.ToolProvider;
30+
31+
import org.eclipse.core.resources.IFile;
32+
import org.eclipse.core.resources.IResource;
33+
import org.eclipse.core.resources.ResourcesPlugin;
34+
import org.eclipse.debug.core.DebugException;
35+
import org.eclipse.debug.core.ILaunchConfiguration;
36+
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
37+
import org.eclipse.debug.core.model.IStackFrame;
38+
import org.eclipse.jdt.core.IClassFile;
39+
import org.eclipse.jdt.core.IJavaProject;
40+
import org.eclipse.jdt.debug.core.IJavaStackFrame;
41+
import org.eclipse.jdt.debug.core.IJavaThread;
42+
import org.eclipse.jdt.debug.tests.TestUtil;
43+
import org.eclipse.jdt.debug.tests.ui.AbstractDebugUiTests;
44+
import org.eclipse.jdt.internal.ui.javaeditor.ClassFileEditor;
45+
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
46+
import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
47+
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
48+
import org.eclipse.swt.custom.StyleRange;
49+
import org.eclipse.swt.custom.StyledText;
50+
import org.junit.Assume;
51+
52+
public class ClassFileEditorHighlightingTest extends AbstractDebugUiTests {
53+
54+
private static final String CLASS_NAME = "OneToTen";
55+
private static final long TIMEOUT = 10_000;
56+
57+
public ClassFileEditorHighlightingTest(String name) {
58+
super(name);
59+
}
60+
61+
public void testDisplaySourceWithClassFileEditorHighlightsLine() throws Exception {
62+
IJavaProject javaProject = getProjectContext();
63+
createLineBreakpoint(21, CLASS_NAME);
64+
65+
IJavaThread thread = null;
66+
try {
67+
thread = launchToBreakpoint(CLASS_NAME);
68+
69+
ClassFileEditor editor = (ClassFileEditor) EditorUtility.openInEditor(javaProject.getProject().getFile("bin/" + CLASS_NAME + ".class"));
70+
IClassFileEditorInput editorInput = (IClassFileEditorInput) editor.getEditorInput();
71+
IClassFile classFile = editorInput.getClassFile();
72+
thread.getTopStackFrame().getLaunch().setSourceLocator(stackFrame -> classFile);
73+
74+
openCurrentFrameAndExpectHighlightedText(thread, editor, " 0 getstatic java.lang.System.out : java.io.PrintStream [16]");
75+
76+
stepOver((IJavaStackFrame) thread.getTopStackFrame());
77+
openCurrentFrameAndExpectHighlightedText(thread, editor, " 8 getstatic java.lang.System.out : java.io.PrintStream [16]");
78+
79+
thread.resume();
80+
81+
} finally {
82+
terminateAndRemove(thread);
83+
removeAllBreakpoints();
84+
}
85+
}
86+
87+
public void testConstructorInPackage() throws Exception {
88+
IJavaProject javaProject = getProjectContext();
89+
createMethodBreakpoint("org.eclipse.debug.tests.targets", "ClassOne.java", "ClassOne", "<init>", "()V", true, false);
90+
91+
IJavaThread thread = null;
92+
try {
93+
thread = launchToBreakpoint("org.eclipse.debug.tests.targets.CallStack");
94+
95+
ClassFileEditor editor = (ClassFileEditor) EditorUtility.openInEditor(
96+
javaProject.getProject().getFile("bin/org/eclipse/debug/tests/targets/ClassOne.class")
97+
);
98+
IClassFileEditorInput editorInput = (IClassFileEditorInput) editor.getEditorInput();
99+
IClassFile classFile = editorInput.getClassFile();
100+
thread.getTopStackFrame().getLaunch().setSourceLocator(stackFrame -> classFile);
101+
102+
openCurrentFrameAndExpectHighlightedText(thread, editor, " 0 aload_0 [this]");
103+
104+
thread.resume();
105+
106+
} finally {
107+
terminateAndRemove(thread);
108+
removeAllBreakpoints();
109+
}
110+
}
111+
112+
public void testDisplaySourceWithClassFileEditorHighlightsLineInConstructor() throws Exception {
113+
IJavaProject javaProject = getProjectContext();
114+
createMethodBreakpoint("", "MethodCall.java", "MethodCall", "<init>", "()V", true, false);
115+
116+
IJavaThread thread = null;
117+
try {
118+
thread = launchToBreakpoint("MethodCall");
119+
120+
ClassFileEditor editor = (ClassFileEditor) EditorUtility.openInEditor(javaProject.getProject().getFile("bin/MethodCall.class"));
121+
IClassFileEditorInput editorInput = (IClassFileEditorInput) editor.getEditorInput();
122+
IClassFile classFile = editorInput.getClassFile();
123+
thread.getTopStackFrame().getLaunch().setSourceLocator(stackFrame -> classFile);
124+
125+
openCurrentFrameAndExpectHighlightedText(thread, editor, " 0 aload_0 [this]");
126+
127+
thread.resume();
128+
} finally {
129+
terminateAndRemove(thread);
130+
removeAllBreakpoints();
131+
}
132+
}
133+
134+
public void testClassFileWithoutDebuggingInformation() throws Exception {
135+
IJavaProject javaProject = getProjectContext();
136+
URI uri = ResourcesPlugin.getWorkspace().getRoot().getFile(javaProject.getOutputLocation()).getLocationURI();
137+
138+
compileWithJavac("NoSources.java", """
139+
class NoSources {
140+
private static int i;
141+
public static void main(String[] args) {
142+
i++;
143+
System.out.println(i);
144+
}
145+
}
146+
""", List.of("-g:none", "-d", new File(uri).getAbsolutePath(), "--release", "8"));
147+
String mainTypeName = "NoSources";
148+
ILaunchConfiguration config = createLaunchConfiguration(javaProject, mainTypeName);
149+
ILaunchConfigurationWorkingCopy workingCopy = config.getWorkingCopy();
150+
workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, true);
151+
config = workingCopy.doSave();
152+
153+
IJavaThread thread = null;
154+
try {
155+
thread = launchToBreakpoint(config);
156+
157+
javaProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
158+
IFile classResource = javaProject.getProject().getFile("bin/" + mainTypeName + ".class");
159+
ClassFileEditor editor = (ClassFileEditor) EditorUtility.openInEditor(classResource, true);
160+
161+
IClassFileEditorInput editorInput = (IClassFileEditorInput) editor.getEditorInput();
162+
IClassFile classFile = editorInput.getClassFile();
163+
thread.getTopStackFrame().getLaunch().setSourceLocator(stackFrame -> classFile);
164+
165+
List<String> expectedHighlights = List.of(/* @formatter:off */
166+
" 0 getstatic NoSources.i : int [7]", " 3 iconst_1", " 4 iadd", " 5 putstatic NoSources.i : int [7]", " 8 getstatic java.lang.System.out : java.io.PrintStream [13]", " 11 getstatic NoSources.i : int [7]", " 14 invokevirtual java.io.PrintStream.println(int) : void [19]", " 17 return"/*
167+
* @formatter
168+
* :
169+
* on
170+
*/
171+
);
172+
for (int i = 0; i < expectedHighlights.size(); i++) {
173+
openCurrentFrameAndExpectHighlightedText(thread, editor, expectedHighlights.get(i));
174+
175+
if (i < expectedHighlights.size() - 1) {
176+
stepOver((IJavaStackFrame) thread.getTopStackFrame());
177+
}
178+
}
179+
thread.resume();
180+
} finally {
181+
terminateAndRemove(thread);
182+
removeAllBreakpoints();
183+
}
184+
}
185+
186+
private void openCurrentFrameAndExpectHighlightedText(IJavaThread thread, ClassFileEditor editor, String expectedHighlightedText) throws DebugException, InterruptedException {
187+
StyledText noSourceTextWidget = editor.getNoSourceTextWidget();
188+
IStackFrame topStackFrame = thread.getTopStackFrame();
189+
assertNotNull(topStackFrame);
190+
// sourceDisplay.displaySource(topStackFrame, PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), true);
191+
192+
long s = System.currentTimeMillis();
193+
while (System.currentTimeMillis() - s < TIMEOUT) {
194+
if (noSourceTextWidget.getStyleRanges().length != 0) {
195+
return;
196+
}
197+
TestUtil.runEventLoop();
198+
Thread.sleep(50L);
199+
}
200+
201+
StyleRange[] styleRanges = noSourceTextWidget.getStyleRanges();
202+
assertEquals(1, styleRanges.length);
203+
String highlightedText = noSourceTextWidget.getContent().getTextRange(styleRanges[0].start, styleRanges[0].length);
204+
assertEquals(expectedHighlightedText, highlightedText);
205+
}
206+
207+
private void compileWithJavac(String className, String source, List<String> compilerOptions) {
208+
JavaFileObject fileObject = new SourceJavaFileObject(className, source);
209+
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
210+
Assume.assumeNotNull(compiler);
211+
212+
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, Locale.ROOT, StandardCharsets.UTF_8);
213+
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
214+
CompilationTask task = compiler.getTask(null, fileManager, collector, compilerOptions, null, List.of(fileObject));
215+
Boolean result = task.call();
216+
assertTrue(String.valueOf(collector.getDiagnostics()), result);
217+
}
218+
219+
private static class SourceJavaFileObject extends SimpleJavaFileObject {
220+
221+
private final String code;
222+
223+
protected SourceJavaFileObject(String name, String code) {
224+
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
225+
this.code = code;
226+
}
227+
228+
@Override
229+
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
230+
return code;
231+
}
232+
}
233+
}

0 commit comments

Comments
 (0)