diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
index 44f55951c8..04c8d85fef 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
@@ -1775,33 +1775,35 @@ protected String getMethodBreakpointText(IJavaMethodBreakpoint methodBreakpoint)
appendSuspendPolicy(methodBreakpoint,label);
appendThreadFilter(methodBreakpoint, label);
-
- boolean entry = methodBreakpoint.isEntry();
- boolean exit = methodBreakpoint.isExit();
- if (entry && exit) {
- label.append(DebugUIMessages.JDIModelPresentation_entry_and_exit);
- } else if (entry) {
- label.append(DebugUIMessages.JDIModelPresentation_entry);
- } else if (exit) {
- label.append(DebugUIMessages.JDIModelPresentation_exit);
- }
- appendConditional(methodBreakpoint, label);
-
- if (member != null) {
- label.append(" - "); //$NON-NLS-1$
- label.append(getJavaLabelProvider().getText(member));
+ if (methodBreakpoint.isLambdaBreakpoint()) {
+ processInLineLambdaLabel(methodBreakpoint, label, member);
} else {
- String methodSig= methodBreakpoint.getMethodSignature();
- String methodName= methodBreakpoint.getMethodName();
- if (methodSig != null) {
- label.append(" - "); //$NON-NLS-1$
- label.append(Signature.toString(methodSig, methodName, null, false, false));
- } else if (methodName != null) {
+ boolean entry = methodBreakpoint.isEntry();
+ boolean exit = methodBreakpoint.isExit();
+ if (entry && exit) {
+ label.append(DebugUIMessages.JDIModelPresentation_entry_and_exit);
+ } else if (entry) {
+ label.append(DebugUIMessages.JDIModelPresentation_entry);
+ } else if (exit) {
+ label.append(DebugUIMessages.JDIModelPresentation_exit);
+ }
+ appendConditional(methodBreakpoint, label);
+
+ if (member != null) {
label.append(" - "); //$NON-NLS-1$
- label.append(methodName);
+ label.append(getJavaLabelProvider().getText(member));
+ } else {
+ String methodSig = methodBreakpoint.getMethodSignature();
+ String methodName = methodBreakpoint.getMethodName();
+ if (methodSig != null) {
+ label.append(" - "); //$NON-NLS-1$
+ label.append(Signature.toString(methodSig, methodName, null, false, false));
+ } else if (methodName != null) {
+ label.append(" - "); //$NON-NLS-1$
+ label.append(methodName);
+ }
}
}
-
return label.toString();
}
@@ -2199,4 +2201,29 @@ public Color getBackground(Object element) {
public synchronized boolean requiresUIThread(Object element) {
return !isInitialized();
}
+
+ /**
+ * Process custom label for inline lambda breakpoints
+ */
+ private void processInLineLambdaLabel(IJavaMethodBreakpoint methodBreakpoint, StringBuilder label, IMember member) throws CoreException {
+ appendConditional(methodBreakpoint, label);
+ if (methodBreakpoint.getLambdaName() != null) {
+ label.append(" - [ " + methodBreakpoint.getLambdaName() + " ]"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ if (member != null) {
+ label.append(" - "); //$NON-NLS-1$
+ label.append(getJavaLabelProvider().getText(member));
+ } else {
+ String methodSig = methodBreakpoint.getMethodSignature();
+ String methodName = methodBreakpoint.getMethodName();
+ if (methodSig != null) {
+ label.append(" - "); //$NON-NLS-1$
+ label.append(Signature.toString(methodSig, methodName, null, false, false));
+ } else if (methodName != null) {
+ label.append(" - "); //$NON-NLS-1$
+ label.append(methodName);
+ }
+ }
+ }
+ }
}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
index 61fe1daff8..348ad66674 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
@@ -176,6 +176,8 @@ public class ActionMessages extends NLS {
public static String Override_Dependencies_label1;
public static String Override_Dependencies_label2;
+ public static String LambdaSelectionDialog_title;
+
static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_NAME, ActionMessages.class);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
index d1ad471931..a5be1d1d78 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2022 IBM Corporation and others.
+# Copyright (c) 2000, 2025 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
@@ -154,4 +154,5 @@ Override_Dependencies_title=Override Dependencies
Override_Dependencies_button=&Override
Override_Dependencies_button1=&Override Dependencies...
Override_Dependencies_label1=Dependencies derived from the Java Build Path:
-Override_Dependencies_label2=Dependencies for launching:
\ No newline at end of file
+Override_Dependencies_label2=Dependencies for launching:
+LambdaSelectionDialog_title=Select lambda
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
index a6ce1cb07d..fa3f0bef8f 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
@@ -15,6 +15,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -65,7 +66,9 @@
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
@@ -78,11 +81,13 @@
import org.eclipse.jdt.debug.core.IJavaType;
import org.eclipse.jdt.debug.core.IJavaWatchpoint;
import org.eclipse.jdt.debug.core.JDIDebugModel;
+import org.eclipse.jdt.internal.core.LambdaMethod;
import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContext;
import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType;
import org.eclipse.jdt.internal.corext.template.java.JavaContextType;
import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
-import org.eclipse.jdt.internal.debug.core.breakpoints.FirstLambdaLocationLocator;
+import org.eclipse.jdt.internal.debug.core.breakpoints.LambdaCollector;
+import org.eclipse.jdt.internal.debug.core.breakpoints.LambdaLocationLocatorHelper;
import org.eclipse.jdt.internal.debug.core.breakpoints.ValidBreakpointLocationLocator;
import org.eclipse.jdt.internal.debug.ui.BreakpointUtils;
import org.eclipse.jdt.internal.debug.ui.DebugWorkingCopyManager;
@@ -111,18 +116,27 @@
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
+import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+import org.eclipse.ui.dialogs.FilteredList;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
@@ -136,7 +150,11 @@
public class ToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension2 {
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
-
+ private static final String TRUNCATION_SIGN = "... "; //$NON-NLS-1$
+ private static final String LAMBDA_SEPARATOR = " "; //$NON-NLS-1$
+ private static final int MAX_LAMBDA_LINE_LENGTH = 25;
+ private static final int MAX_TOTAL_LAMBDA_LINE_LENGTH = MAX_LAMBDA_LINE_LENGTH * 2;
+ private static final String ZERO_WIDTH_SPACE = "\u200B"; //$NON-NLS-1$
/**
* Constructor
@@ -269,7 +287,7 @@ protected IStatus run(IProgressMonitor monitor) {
job.schedule();
}
- public void toggleLambdaEntryMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final String lambdaMethodName, final String lambdaMethodSignature) {
+ static void toggleLambdaEntryMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final String lambdaMethodName, final String lambdaMethodSignature, final LambdaProperties lambdaProperties) {
Job job = new Job("Toggle Lambda Entry Method Breakpoints") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
@@ -277,7 +295,7 @@ protected IStatus run(IProgressMonitor monitor) {
return Status.CANCEL_STATUS;
}
try {
- return doToggleLambdaEntryMethodBreakpoints(part, finalSelection, lambdaMethodName, lambdaMethodSignature, monitor);
+ return doToggleLambdaEntryMethodBreakpoints(part, finalSelection, lambdaMethodName, lambdaMethodSignature, lambdaProperties, monitor);
} catch (CoreException e) {
return e.getStatus();
} finally {
@@ -290,7 +308,7 @@ protected IStatus run(IProgressMonitor monitor) {
job.schedule();
}
- static IStatus doToggleLambdaEntryMethodBreakpoints(IWorkbenchPart part, ISelection selection, String lambdaMethodName, String lambdaMethodSignature, IProgressMonitor monitor) throws CoreException {
+ static IStatus doToggleLambdaEntryMethodBreakpoints(IWorkbenchPart part, ISelection selection, String lambdaMethodName, String lambdaMethodSignature, LambdaProperties lambdaProperties, IProgressMonitor monitor) throws CoreException {
ITextEditor textEditor = getTextEditor(part);
if (textEditor == null || !(selection instanceof ITextSelection)) {
return Status.OK_STATUS;
@@ -316,7 +334,7 @@ static IStatus doToggleLambdaEntryMethodBreakpoints(IWorkbenchPart part, ISelect
}
if (method != null) {
- doToggleMethodBreakpoint(method, lambdaMethodName, lambdaMethodSignature, part, selection, monitor);
+ doToggleMethodBreakpoint(method, lambdaMethodName, lambdaMethodSignature, lambdaProperties, part, selection, monitor);
} else {
BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
}
@@ -354,7 +372,7 @@ static IStatus doToggleLambdaMethodBreakpoints(IWorkbenchPart part, ISelection s
}
if (method != null) {
- doToggleMethodBreakpoint(method, loc.getLambdaMethodName(), loc.getfLambdaMethodSignature(), part, selection, monitor);
+ doToggleMethodBreakpoint(method, loc.getLambdaMethodName(), loc.getfLambdaMethodSignature(), null, part, selection, monitor);
} else {
ValidBreakpointLocationLocator locNew = new ValidBreakpointLocationLocator(loc.getCompilationUnit(), textSelection.getStartLine()
+ 1, true, true);
@@ -392,11 +410,16 @@ static IStatus doToggleMethodBreakpoints(IWorkbenchPart part, ISelection finalSe
}
private static void doToggleMethodBreakpoint(IMethod member, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
- doToggleMethodBreakpoint(member, null, null, part, finalSelection, monitor);
+ doToggleMethodBreakpoint(member, null, null, null, part, finalSelection, monitor);
}
- private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethodName, String lambdaMethodSignature, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
- IJavaBreakpoint breakpoint = getMethodBreakpoint(member);
+ private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethodName, String lambdaMethodSignature, LambdaProperties lambdaProperties, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
+ int lambdaPosition = 0;
+ if (lambdaProperties != null) {
+ lambdaPosition = lambdaProperties.lambdaPosition();
+ }
+
+ IJavaBreakpoint breakpoint = getMethodBreakpoint(member, lambdaPosition);
if (breakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoint()) {
deleteTracepoint(breakpoint, part, monitor);
@@ -448,6 +471,13 @@ private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethod
}
BreakpointToggleUtils.setUnsetTracepoint(false);
}
+ if (lambdaProperties != null) {
+ methodBreakpoint.setLambdaBreakpoint(true);
+ methodBreakpoint.setInlineLambdaPosition(lambdaPosition);
+ if (lambdaProperties.isInline()) {
+ methodBreakpoint.setLambdaName(lambdaProperties.getLambdaName());
+ }
+ }
if (ValidBreakpointLocationLocator.LOCATION_METHOD_CLOSE) {
methodBreakpoint.setEntry(false);
methodBreakpoint.setExit(true);
@@ -1336,51 +1366,55 @@ protected static IMethod getMethodHandle(IEditorPart editorPart, String typeName
}
/**
- * Returns the IJavaBreakpoint from the specified IMember
- * @param element the element to get the breakpoint from
- * @return the current breakpoint from the element or null
- */
+ * Returns the IJavaBreakpoint from the specified IMember
+ *
+ * @param element
+ * the element to get the breakpoint from
+ * @param lambdaPosition
+ * the position of the lambda expression in the line (if any)
+ * @return the current breakpoint from the element or null
+ */
@SuppressWarnings("restriction")
- protected static IJavaBreakpoint getMethodBreakpoint(IMember element) {
+ protected static IJavaBreakpoint getMethodBreakpoint(IMember element, int lambdaPosition) {
+ if (!(element instanceof IMethod method)) {
+ return null;
+ }
IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager();
IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(JDIDebugModel.getPluginIdentifier());
- if (!(element instanceof IMethod)) {
- return null;
- }
- IMethod method = (IMethod) element;
for (IBreakpoint breakpoint : breakpoints) {
- if (!(breakpoint instanceof IJavaMethodBreakpoint)) {
+ if (!(breakpoint instanceof IJavaMethodBreakpoint methodBreakpoint)) {
continue;
}
- IJavaMethodBreakpoint methodBreakpoint = (IJavaMethodBreakpoint) breakpoint;
- IMember container = null;
+ IMember container;
try {
container = BreakpointUtils.getMember(methodBreakpoint);
- } catch (CoreException e) {
- JDIDebugUIPlugin.log(e);
- return null;
- }
- if (container == null) {
- try {
+ if (container == null) {
if (method.getDeclaringType().getFullyQualifiedName().equals(methodBreakpoint.getTypeName())
&& method.getElementName().equals(methodBreakpoint.getMethodName())
&& methodBreakpoint.getMethodSignature().equals(resolveMethodSignature(method))) {
return methodBreakpoint;
}
- } catch (CoreException e) {
- JDIDebugUIPlugin.log(e);
+ continue;
}
- } else {
- if (container instanceof IMethod) {
- if (method instanceof org.eclipse.jdt.internal.core.LambdaMethod) {
- return null;
+ if (!(container instanceof IMethod)) {
+ continue;
+ }
+ if (method instanceof LambdaMethod) {
+ ISourceRange sourceRange = element.getSourceRange();
+ if (sourceRange != null && methodBreakpoint.getInlineLambdaPosition() == lambdaPosition
+ && methodBreakpoint.getCharStart() == sourceRange.getOffset()) {
+ return methodBreakpoint;
}
- if (method.getDeclaringType().getFullyQualifiedName().equals(container.getDeclaringType().getFullyQualifiedName())) {
- if (method.isSimilar((IMethod) container)) {
- return methodBreakpoint;
- }
+ continue;
+ }
+ if (method.getDeclaringType().getFullyQualifiedName().equals(container.getDeclaringType().getFullyQualifiedName())) {
+ if (method.isSimilar((IMethod) container)) {
+ return methodBreakpoint;
}
}
+ } catch (CoreException e) {
+ JDIDebugUIPlugin.log(e);
+ continue;
}
}
return null;
@@ -1599,26 +1633,25 @@ private void toggleFieldOrMethodBreakpoints(IWorkbenchPart part, ISelection sele
}
// remove line breakpoint if present first
IJavaLineBreakpoint breakpoint = findExistingBreakpoint(editor, ts);
+
if (breakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoint()) {
deleteTracepoint(breakpoint, part, null);
BreakpointToggleUtils.setUnsetTracepoint(false);
-
} else if (BreakpointToggleUtils.isTriggerpoint()) {
-
deleteBreakpoint(breakpoint, part, null);
BreakpointToggleUtils.setTriggerpoint(false);
-
} else if (BreakpointToggleUtils.isHitpoint()) {
-
deleteBreakpoint(breakpoint, part, null);
BreakpointToggleUtils.setHitpoint(false);
- } else {
+ } else if ((breakpoint instanceof IJavaMethodBreakpoint javaMBp && !javaMBp.isLambdaBreakpoint())) {
+ deleteBreakpoint(breakpoint, part, null);
+ return;
+ } else if (!BreakpointToggleUtils.isToggleLambdaEntryBreakpoint()
+ && (breakpoint instanceof IJavaMethodBreakpoint javaMB && javaMB.isLambdaBreakpoint())) {
deleteBreakpoint(breakpoint, part, null);
- }
- if (!BreakpointToggleUtils.isToggleLambdaEntryBreakpoint()) {
return;
- } else if (breakpoint instanceof IJavaMethodBreakpoint) {
+ } else if (!BreakpointToggleUtils.isToggleLambdaEntryBreakpoint() && breakpoint instanceof IJavaMethodBreakpoint) {
return;
}
}
@@ -1653,33 +1686,68 @@ private void toggleFieldOrMethodBreakpoints(IWorkbenchPart part, ISelection sele
toggleWatchpoints(part, ts);
} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LINE) {
if (lambdaEntryBP) {
- IEditorInput editorInput = editor.getEditorInput();
- IDocumentProvider documentProvider = editor.getDocumentProvider();
- if (documentProvider == null) {
- BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
- throw new CoreException(Status.CANCEL_STATUS);
- }
- IDocument document = documentProvider.getDocument(editorInput);
- try {
- IRegion region = document.getLineInformation(ts.getStartLine());
- FirstLambdaLocationLocator firstLambda = new FirstLambdaLocationLocator(region.getOffset(), region.getOffset() + region.getLength());
- unit.accept(firstLambda);
- if (firstLambda.getNodeLength() == -1 || firstLambda.getNodeOffset() == -1) {
- BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
- return;
- }
- ITextSelection textSelection = new TextSelection(document, firstLambda.getNodeOffset(), firstLambda.getNodeLength());
- toggleLambdaEntryMethodBreakpoints(part, textSelection, firstLambda.getLambdaMethodName(), firstLambda.getfLambdaMethodSignature());
- } catch (BadLocationException e) {
- BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
- }
-
+ toggleLambdaBreakpoint(part, ts, editor);
} else {
toggleLineBreakpoints(part, ts, false, loc);
}
}
}
+ private static void toggleLambdaBreakpoint(IWorkbenchPart part, ITextSelection ts, ITextEditor editor) throws CoreException {
+ IDocumentProvider documentProvider = editor.getDocumentProvider();
+ if (documentProvider == null) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ IEditorInput editorInput = editor.getEditorInput();
+ IDocument document = documentProvider.getDocument(editorInput);
+ if (document == null) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ try {
+ IRegion region = document.getLineInformation(ts.getStartLine());
+ List lambdaExpresions = findLambdaExpressions(editor, region);
+ if (lambdaExpresions.isEmpty()) {
+ return;
+ }
+ int lambdaPosition;
+ if (lambdaExpresions.size() == 1) {
+ lambdaPosition = 0;
+ } else {
+ lambdaPosition = selectLambda(lambdaExpresions);
+ if (lambdaPosition == -1) {
+ return;
+ }
+ }
+ LambdaExpression selectedLambda = lambdaExpresions.get(lambdaPosition);
+ IMethodBinding methodBinding = selectedLambda.resolveMethodBinding();
+ if (methodBinding == null) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ return;
+ }
+ String lambdaMethodName = LambdaLocationLocatorHelper.toMethodName(methodBinding);
+ String lambdaMethodSignature = LambdaLocationLocatorHelper.toMethodSignature(methodBinding);
+ ITextSelection textSelection = new TextSelection(document, selectedLambda.getStartPosition(), selectedLambda.getLength());
+ boolean inline = lambdaExpresions.size() > 1;
+ LambdaProperties lambdaProperties = new LambdaProperties(lambdaExpresions.get(lambdaPosition).toString(), lambdaPosition, inline);
+ toggleLambdaEntryMethodBreakpoints(part, textSelection, lambdaMethodName, lambdaMethodSignature, lambdaProperties);
+ } catch (BadLocationException e) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ }
+ }
+
+ private static List findLambdaExpressions(ITextEditor editor, IRegion region) {
+ LambdaCollector lambdas = new LambdaCollector(region.getOffset(), region.getOffset() + region.getLength());
+ CompilationUnit unitForLambdas = parseCompilationUnit(editor);
+ if (unitForLambdas == null) {
+ JDIDebugUIPlugin.log("Failed to parse CU for: " + editor.getTitle(), new IllegalStateException()); //$NON-NLS-1$
+ return List.of();
+ }
+ unitForLambdas.accept(lambdas);
+ return lambdas.getLambdaExpressions();
+ }
+
/**
* Additional diagnosis info for bug 528321
*/
@@ -1894,4 +1962,161 @@ private static ICompilationUnit getCompilationUnit(ITextEditor editor) {
return JavaCore.createCompilationUnitFrom(file);
}
+ static int selectLambda(List lambdaExps) {
+ Map seen = new HashMap<>();
+ // Generate unique labels used also as keys for lambda expressions. Note that two identical
+ // lambda expressions in different locations should still have different names
+ // otherwise the selection dialog cannot distinguish them.
+ List lambdaNames = lambdaExps.stream().map(expr -> shortenLambdaExpression(expr.toString())).map(name -> {
+ int count = seen.getOrDefault(name, 0);
+ seen.put(name, count + 1);
+ if (count == 0) {
+ return name;
+ }
+ return name + ZERO_WIDTH_SPACE.repeat(count);
+ }).toList();
+ LambdaLabelProvider lambdaLabelProvider = new LambdaLabelProvider(lambdaExps, lambdaNames);
+ ElementListSelectionDialog dialog = new LambdaSelectionDialog(DebugUIPlugin.getShellForModalDialog(), lambdaLabelProvider, lambdaExps, lambdaNames);
+ dialog.setMultipleSelection(false);
+ dialog.setTitle(ActionMessages.LambdaSelectionDialog_title);
+ dialog.setElements(lambdaExps.toArray());
+ dialog.open();
+ if (dialog.getReturnCode() == Window.OK) {
+ Object result = dialog.getFirstResult();
+ return lambdaExps.indexOf(result);
+ }
+ return -1;
+ }
+
+ private static final class LambdaSelectionDialog extends ElementListSelectionDialog {
+ private final List lambdaExps;
+ private final List lambdaNames;
+
+ private LambdaSelectionDialog(Shell parent, ILabelProvider renderer, List lambdaExps, List lambdaNames) {
+ super(parent, renderer);
+ this.lambdaExps = lambdaExps;
+ this.lambdaNames = lambdaNames;
+ }
+
+ @Override
+ protected FilteredList createFilteredList(Composite parent) {
+ FilteredList filteredList = super.createFilteredList(parent);
+ // Disable default sorting to keep the original order
+ filteredList.setComparator(new LambdaPositionComparator(lambdaNames));
+ // Add selection listener to highlight selected lambda in the editor
+ filteredList.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ int index = filteredList.getSelectionIndex();
+ if (index < 0) {
+ return;
+ }
+ IWorkbenchPage page = JDIDebugUIPlugin.getActivePage();
+ if (page == null) {
+ return;
+ }
+ IEditorPart editorPart = page.getActiveEditor();
+ if (editorPart instanceof ITextEditor textEditor) {
+ LambdaExpression lambda = lambdaExps.get(index);
+ int start = lambda.getStartPosition();
+ int length = lambda.getLength();
+ textEditor.selectAndReveal(start, length);
+ }
+ }
+ });
+ return filteredList;
+ }
+
+ @Override
+ protected void setShellStyle(int newShellStyle) {
+ // overridden to allow interaction with the underlying editor while the dialog is open
+ super.setShellStyle(newShellStyle & ~SWT.APPLICATION_MODAL);
+ }
+ }
+
+ private static final record LambdaProperties(String lambdaName, int lambdaPosition, boolean isInline) {
+ public String getLambdaName() {
+ return shortenLambdaExpression(lambdaName);
+ }
+ }
+
+ private static final class LambdaPositionComparator implements Comparator