Skip to content
Merged
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
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2026 Simeon Andreev 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:
* Simeon Andreev - initial API and implementation
*******************************************************************************/
package selectiontests;

import java.util.Arrays;
import java.util.List;

/**
* The test resumes at lambda chain and at each resume expects selecting the next lambda expression.
*/
public class LambdaSelectionTest {

public static void main(String[] main) {
List<String> list = Arrays.asList("A");
list.stream()
.map(s -> s.toLowerCase()).filter(s -> s.equals("b")).forEach(System.out::println); // line 27, test breakpoint is set here
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ protected IEditorPart openEditor(String type) throws RuntimeException {
return callInUi(callable);
}

private static <T> T callInUi(Callable<T> callable) throws RuntimeException {
protected static <T> T callInUi(Callable<T> callable) throws RuntimeException {
if (Display.getCurrent() != null) {
try {
return callable.call();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*******************************************************************************
* Copyright (c) 2026 Simeon Andreev 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:
* Simeon Andreev - initial API and implementation
*******************************************************************************/

package org.eclipse.jdt.debug.tests.ui;

import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
import org.eclipse.jdt.debug.tests.TestUtil;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.test.OrderedTestSuite;
import org.eclipse.ui.texteditor.ITextEditor;

import junit.framework.Test;

public class DebugSelectionTests extends AbstractDebugUiTests {

public static Test suite() {
return new OrderedTestSuite(DebugSelectionTests.class);
}

private IJavaProject project;

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

@Override
protected IJavaProject getProjectContext() {
return project;
}

@Override
public void setUp() throws Exception {
super.setUp();
project = createProject("DebugSelectionTests", "testfiles/DebugSelectionTests/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false);
waitForBuild();
}

@Override
public void tearDown() throws Exception {
closeAllEditors();
project.getProject().delete(true, null);
super.tearDown();
}

/**
* Resume at lambda chain and at each resume expect selecting the next lambda expression.
*/
public void testLambdaEditorSelection() throws Exception {
IJavaThread thread = null;
try {
String typeName = "selectiontests.LambdaSelectionTest";
createLineBreakpoint(27, typeName);
ILaunchConfiguration config = createLaunchConfiguration(project, typeName);
thread = launchAndSuspend(config);
resume(thread);
waitForSelection("s -> s.toLowerCase()", 10_000L);
resume(thread);
waitForSelection("s -> s.equals(\"b\")", 10_000L);
} finally {
removeAllBreakpoints();
if (thread != null) {
terminateAndRemove(thread);
}
}
}

private static void waitForSelection(String expectedSelection, long timeout) throws InterruptedException {
long s = System.currentTimeMillis();
while (System.currentTimeMillis() - s < timeout) {
if (expectedSelection.equals(getActiveEditorSelectionText())) {
return;
}
TestUtil.runEventLoop();
Thread.sleep(50L);
}
assertEquals("Timed out while waiting for selection", expectedSelection, getActiveEditorSelectionText());
}

private static String getActiveEditorSelectionText() {
return callInUi(() -> {
ITextEditor editor = (ITextEditor) getActivePage().getActiveEditor();
if (editor != null) {
ITextSelection selection = (ITextSelection) editor.getSelectionProvider().getSelection();
if (selection != null) {
return selection.getText();
}
}
return "";
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.eclipse.debug.internal.ui.DefaultLabelProvider;
import org.eclipse.debug.internal.ui.views.variables.VariablesView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugEditorPresentation;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugModelPresentationExtension;
import org.eclipse.debug.ui.IDebugUIConstants;
Expand Down Expand Up @@ -111,6 +112,7 @@
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
Expand All @@ -125,7 +127,7 @@
* @see IDebugModelPresentation
*/
@SuppressWarnings("deprecation")
public class JDIModelPresentation extends LabelProvider implements IDebugModelPresentationExtension, IColorProvider {
public class JDIModelPresentation extends LabelProvider implements IDebugModelPresentationExtension, IColorProvider, IDebugEditorPresentation {

/**
* Qualified names presentation property (value <code>"DISPLAY_QUALIFIED_NAMES"</code>).
Expand Down Expand Up @@ -157,12 +159,15 @@ public class JDIModelPresentation extends LabelProvider implements IDebugModelPr
* */
private static final String BREAKPOINT_LABEL_SUFFIX = "JDT_BREAKPOINT_LABEL_SUFFIX"; //$NON-NLS-1$

private final JavaStackFrameEditorPresenter fJavaStackFrameEditorPresenter;

private JavaElementLabelProvider fJavaLabelProvider;

private StackFramePresentationProvider fStackFrameProvider;

public JDIModelPresentation() {
super();
fJavaStackFrameEditorPresenter = new JavaStackFrameEditorPresenter();
}

/* (non-Javadoc)
Expand Down Expand Up @@ -2281,4 +2286,14 @@ private void processInLineLambdaLabel(IJavaMethodBreakpoint methodBreakpoint, St
}
}
}

@Override
public boolean addAnnotations(IEditorPart editorPart, IStackFrame frame) {
return fJavaStackFrameEditorPresenter.addAnnotations(editorPart, frame);
}

@Override
public void removeAnnotations(IEditorPart editorPart, IThread thread) {
fJavaStackFrameEditorPresenter.removeAnnotations(editorPart, thread);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*******************************************************************************
* Copyright (c) 2026 IBM Corporation.
*
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui;

import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.ui.IDebugEditorPresentation;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;

/**
* Handles specialized selection of Java editors during debugging, such as selecting lambda expressions on a breakpoint hit.
*/
public class JavaStackFrameEditorPresenter implements IDebugEditorPresentation {

@Override
public boolean addAnnotations(IEditorPart editor, IStackFrame frame) {
try {
if (editor instanceof ITextEditor textEditor && frame instanceof JDIStackFrame jdiFrame
&& org.eclipse.jdt.internal.debug.core.model.LambdaUtils.isLambdaFrame(jdiFrame)) {
IEditorInput editorInput = editor.getEditorInput();
IDocumentProvider provider = textEditor.getDocumentProvider();
IDocument document = provider.getDocument(editorInput);
if (document != null && JavaUI.getEditorInputJavaElement(editorInput) != null) {
IRegion region = document.getLineInformation(jdiFrame.getLineNumber() - 1);
List<LambdaExpression> inLineLambdas = ToggleBreakpointAdapter.findLambdaExpressions(textEditor, region);
for (LambdaExpression exp : inLineLambdas) {
String key = getMethodBindingKey(exp);
if (key != null && key.contains(jdiFrame.getName())) {
textEditor.selectAndReveal(exp.getStartPosition(), exp.getLength());
return true;
}
}
}
}
} catch (CoreException | BadLocationException e) {
JDIDebugPlugin.log(e);
}
return false;
}

@Override
public void removeAnnotations(IEditorPart editorPart, IThread thread) {
// nothing to clean up
}

private static String getMethodBindingKey(LambdaExpression exp) {
String key = null;
IMethodBinding methodBinding = exp.resolveMethodBinding();
if (methodBinding != null) {
key = methodBinding.getKey();
}
return key;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@
package org.eclipse.jdt.internal.debug.ui.sourcelookup;

import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.sourcelookup.SourceLookupFacility;
import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.internal.debug.core.model.GroupedStackFrame;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTargetList;

Expand Down Expand Up @@ -54,14 +51,6 @@ public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
SourceLookupFacility.getDefault().displaySource(frame, page, forceSourceLookup);
};
}
try {
if (adaptableObject instanceof JDIStackFrame jdiFrame
&& org.eclipse.jdt.internal.debug.core.model.LambdaUtils.isLambdaFrame(jdiFrame)) {
return (T) new LambdaStackFrameSourceDisplayAdapter();
}
} catch (DebugException e) {
DebugUIPlugin.log(e);
}
}
return null;
}
Expand Down

This file was deleted.

Loading