Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2228,6 +2228,20 @@ protected IJavaMethodBreakpoint createMethodBreakpoint(IJavaProject project, Str
protected IJavaMethodBreakpoint createMethodBreakpoint(String packageName, String cuName, String typeName, String methodName, String methodSignature, boolean entry, boolean exit) throws Exception {
IType type = getType(packageName, cuName, typeName);
assertNotNull("did not find type to install breakpoint in", type); //$NON-NLS-1$
return createMethodBreakpoint(type, methodName, methodSignature, entry, exit);
}

/**
* Creates a method breakpoint in a specified type.
*
* @param type the type in which the method breakpoint is set
* @param methodName method or <code>null</code> for all methods
* @param methodSignature JLS method signature or <code>null</code> for all methods with the given name
* @param entry whether to break on entry
* @param exit whether to break on exit
* @return method breakpoint
*/
protected IJavaMethodBreakpoint createMethodBreakpoint(IType type, String methodName, String methodSignature, boolean entry, boolean exit) throws Exception {
IMethod method= null;
if (methodSignature != null && methodName != null) {
if (type != null ) {
Expand All @@ -2240,7 +2254,6 @@ protected IJavaMethodBreakpoint createMethodBreakpoint(String packageName, Strin
return bp;
}


/**
* Creates a MethodBreakPoint on the method specified at the given path.
* Syntax:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
import org.eclipse.jdt.debug.tests.refactoring.RenamePublicTypeUnitTests;
import org.eclipse.jdt.debug.tests.sourcelookup.ArchiveSourceLookupTests;
import org.eclipse.jdt.debug.tests.sourcelookup.Bug565462Tests;
import org.eclipse.jdt.debug.tests.sourcelookup.ClassFileEditorHighlightingTest;
import org.eclipse.jdt.debug.tests.sourcelookup.DefaultSourceContainerTests;
import org.eclipse.jdt.debug.tests.sourcelookup.DirectorySourceContainerTests;
import org.eclipse.jdt.debug.tests.sourcelookup.DirectorySourceLookupTests;
Expand All @@ -148,6 +149,7 @@
import org.eclipse.jdt.debug.tests.sourcelookup.TypeResolutionTests;
import org.eclipse.jdt.debug.tests.state.RefreshStateTests;
import org.eclipse.jdt.debug.tests.ui.DebugHoverTests;
import org.eclipse.jdt.debug.tests.ui.DebugSelectionTests;
import org.eclipse.jdt.debug.tests.ui.DebugViewTests;
import org.eclipse.jdt.debug.tests.ui.DetailPaneManagerTests;
import org.eclipse.jdt.debug.tests.ui.HotCodeReplaceErrorDialogTest;
Expand Down Expand Up @@ -229,6 +231,8 @@ public AutomatedSuite() {
addTest(new TestSuite(TypeResolutionTests.class));
addTest(new TestSuite(JarSourceLookupTests.class));
addTest(new TestSuite(Bug565462Tests.class));
addTest(new TestSuite(DebugSelectionTests.class));
addTest(new TestSuite(ClassFileEditorHighlightingTest.class));

// Variable tests
addTest(new TestSuite(InstanceVariableTests.class));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
/*******************************************************************************
* Copyright (c) 2026, Daniel Schmid and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Daniel Schmid - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.debug.tests.sourcelookup;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
import org.eclipse.jdt.debug.tests.TestUtil;
import org.eclipse.jdt.debug.tests.ui.AbstractDebugUiTests;
import org.eclipse.jdt.internal.ui.javaeditor.ClassFileEditor;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable;
import org.eclipse.jdt.ui.jarpackager.JarPackageData;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextContent;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.junit.Assume;

public class ClassFileEditorHighlightingTest extends AbstractDebugUiTests {

private static final long TIMEOUT = 10_000L;

private static final String CLASS_NAME = "NoSources";
private static final String CLASS_CONTENTS = """
public class NoSources {
private static int i = 0;
public static void main(String[] args) {
i++;
System.out.println(i);
}
}
""";

public ClassFileEditorHighlightingTest(String name) {
super(name);
}

@Override
protected boolean enableUIEventLoopProcessingInWaiter() {
return true;
}

@Override
public void tearDown() throws Exception {
try {
closeAllEditors();
} finally {
super.tearDown();
}
}

public void testDisplaySourceWithClassFileEditorHighlightsLine() throws Exception {
IJavaProject project = createProjectWithNoSources(CLASS_NAME, CLASS_CONTENTS, true);
IJavaThread thread = null;
try {
ILaunchConfiguration config = createLaunchConfiguration(project, CLASS_NAME);
createLineBreakpoint(project.findType(CLASS_NAME), 4);
thread = launchToBreakpoint(config);

stepOver((IJavaStackFrame) thread.getTopStackFrame());
expectHighlightedText(" 8 getstatic java.lang.System.out : java.io.PrintStream [13]", TIMEOUT);

stepOver((IJavaStackFrame) thread.getTopStackFrame());
expectHighlightedText(" 17 return", TIMEOUT);
} finally {
terminateAndRemove(thread);
removeAllBreakpoints();
project.getProject().delete(true, null);
}
}

public void testConstructorInPackage() throws Exception {
IJavaProject project = createProjectWithNoSources("ClassOne", """
public class ClassOne {

public static void main(String[] args) {
ClassOne co = new ClassOne();
co.method1();
}

public void method1() {
method2();
}

public void method2() {
method3();
}

public void method3() {
System.out.println("ClassOne, method3");
}
}
""");
createMethodBreakpoint(project.findType("ClassOne"), "<init>", "()V", true, false);
IJavaThread thread = null;
try {
ILaunchConfiguration config = createLaunchConfiguration(project, "ClassOne");
thread = launchToBreakpoint(config);
expectHighlightedText(" 0 aload_0 [this]", TIMEOUT);
} finally {
terminateAndRemove(thread);
removeAllBreakpoints();
project.getProject().delete(true, null);
}
}

public void testDisplaySourceWithClassFileEditorHighlightsLineInConstructor() throws Exception {
IJavaProject project = createProjectWithNoSources("MethodCall", """
public class MethodCall {

private int i;
private int sum = 0;

public static void main(String[] args) {
MethodCall mc = new MethodCall();
mc.go();
}

public void go() {
calculateSum();
}

protected void calculateSum() {
sum += i;
}
}
""");
createMethodBreakpoint(project.findType("MethodCall"), "<init>", "()V", true, false);
IJavaThread thread = null;
try {
ILaunchConfiguration config = createLaunchConfiguration(project, "MethodCall");
thread = launchToBreakpoint(config);
expectHighlightedText(" 0 aload_0 [this]", TIMEOUT);
} finally {
terminateAndRemove(thread);
removeAllBreakpoints();
project.getProject().delete(true, null);
}
}

public void testClassFileWithoutDebuggingInformation() throws Exception {
IJavaProject project = createProjectWithNoSources(CLASS_NAME, CLASS_CONTENTS);
IJavaThread thread = null;
try {
ILaunchConfiguration config = createLaunchConfiguration(project, CLASS_NAME);
ILaunchConfigurationWorkingCopy workingCopy = config.getWorkingCopy();
workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, true);
config = workingCopy.doSave();
thread = launchToBreakpoint(config);

String[] expectedHighlights = """
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
""".split(System.lineSeparator());

for (int i = 0; i < expectedHighlights.length; i++) {
expectHighlightedText(expectedHighlights[i], TIMEOUT);

if (i < expectedHighlights.length - 1) {
stepOver((IJavaStackFrame) thread.getTopStackFrame());
}
}
} finally {
terminateAndRemove(thread);
removeAllBreakpoints();
project.getProject().delete(true, null);
}
}

private IJavaProject createProjectWithNoSources(String className, String contents) throws Exception {
return createProjectWithNoSources(className, contents, false);
}

private IJavaProject createProjectWithNoSources(String className, String contents, boolean generateLineInfo) throws Exception {
IJavaProject javaProject = JavaProjectHelper.createJavaProject("ClassFileEditorHighlightingTest", JavaProjectHelper.BIN_DIR);
IProject project = javaProject.getProject();
project.getFolder(LAUNCHCONFIGURATIONS).create(true, true, null);

IFile classFile = project.getFile(className + ".class");

String debug = generateLineInfo ? "lines" : "none";
compileWithJavac(className, contents, List.of("-g:" + debug, "-d", project.getLocation().toString(), "--release", "8"));
classFile.refreshLocal(IResource.DEPTH_ONE, null);

IFile lib = project.getFile("lib.jar");
jarClassFile(lib, classFile);

JavaProjectHelper.addLibrary(javaProject, lib.getFullPath());
waitForBuild();
return javaProject;
}

private static void jarClassFile(IFile jar, IFile classFile) {
JarPackageData data = new JarPackageData();
data.setJarLocation(jar.getLocation());
data.setBuildIfNeeded(true);
data.setOverwrite(true);
data.setElements(new Object[] { classFile });
data.setExportClassFiles(true);

IStatus status = callInUi(() -> {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IJarExportRunnable op = data.createJarExportRunnable(window.getShell());
window.run(false, false, op);
return op.getStatus();
});
if (status.getSeverity() == IStatus.ERROR) {
fail("Creating jar failed: " + status.getMessage());
}
}

private static void expectHighlightedText(String expectedHighlightedText, long timeout) throws InterruptedException {
long s = System.currentTimeMillis();
while (System.currentTimeMillis() - s < timeout) {
List<String> highlighted = callInUi(ClassFileEditorHighlightingTest::getClassEditorHighlightedText);
if (Arrays.asList(expectedHighlightedText).equals(highlighted)) {
break;
}
TestUtil.runEventLoop();
Thread.sleep(50L);
}
List<String> highlighted = callInUi(ClassFileEditorHighlightingTest::getClassEditorHighlightedText);
assertEquals("Timed out while waiting on highlighting", Arrays.asList(expectedHighlightedText), highlighted);
}

private static List<String> getClassEditorHighlightedText() {
List<String> highlighted = new ArrayList<>();
StyledText noSourceTextWidget = null;
ClassFileEditor editor = (ClassFileEditor) getActivePage().getActiveEditor();
if (editor != null) {
noSourceTextWidget = editor.getNoSourceTextWidget();
}
if (noSourceTextWidget != null) {
StyleRange[] styleRanges = noSourceTextWidget.getStyleRanges();
StyledTextContent content = noSourceTextWidget.getContent();
for (int i = 0; i < styleRanges.length; ++i) {
String highlightedText = content.getTextRange(styleRanges[0].start, styleRanges[0].length);
highlighted.add(highlightedText);
}
}
return highlighted;
}

private static void compileWithJavac(String className, String source, List<String> compilerOptions) {
JavaFileObject fileObject = new SourceJavaFileObject(className, source);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Assume.assumeNotNull(compiler);

StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, Locale.ROOT, StandardCharsets.UTF_8);
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
CompilationTask task = compiler.getTask(null, fileManager, collector, compilerOptions, null, List.of(fileObject));
Boolean result = task.call();
assertTrue(String.valueOf(collector.getDiagnostics()), result);
}

private static class SourceJavaFileObject extends SimpleJavaFileObject {

private final String code;

protected SourceJavaFileObject(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return code;
}
}
}
Loading
Loading