Bug 486264 - [1.8] Entry breakpoint for lambda expression
Change-Id: I958f033a470598bf0da911c016cbbe8f191fbe47
Signed-off-by: Gayan Perera <gayanper@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/151461
Tested-by: Sarika Sinha <sarika.sinha@in.ibm.com>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.jdt.debug.ui/plugin.properties b/org.eclipse.jdt.debug.ui/plugin.properties
index 613c24c..cdb3237 100644
--- a/org.eclipse.jdt.debug.ui/plugin.properties
+++ b/org.eclipse.jdt.debug.ui/plugin.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2021 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@
vmCapabilitiesPageName=VM Capabilities
AddBreakpoint.label=Toggle &Breakpoint
AddTracepoint.label=Toggle &Tracepoint
+AddLambdaEntryBreakpoint.label=Toggle &Lambda Entry Breakpoint
addTypeStepFilterAction.label=&Filter Type
addTypeStepFilterAction.tooltip=Filter the selected type(s)
@@ -236,7 +237,11 @@
ToggleTracepointAction.label=Toggle Tra&cepoint
ToggleTracepointCommand.label=Toggle Tracepoint
-ToggleTracepointCommand.description=Creates or removes a tracepoint
+ToggleTracepointCommand.description=Creates or removes a tracepoint
+
+ToggleLambdaEntryBreakpointAction.label=Toggle Lambda Entry Breakpoint
+ToggleLambdaEntryBreakpointCommand.label=Toggle &Lambda Entry Breakpoint
+ToggleLambdaEntryBreakpointCommand.description=Creates or removes a lambda entry breakpoint
AddBookmark.label=Add Boo&kmark...
AddBookmark.tooltip=Add Bookmark...
diff --git a/org.eclipse.jdt.debug.ui/plugin.xml b/org.eclipse.jdt.debug.ui/plugin.xml
index d6ae998..6b6594a 100644
--- a/org.eclipse.jdt.debug.ui/plugin.xml
+++ b/org.eclipse.jdt.debug.ui/plugin.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<!--
- Copyright (c) 2005, 2021 IBM Corporation and others.
+ Copyright (c) 2005, 2022 IBM Corporation and others.
This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
@@ -160,6 +160,16 @@
id="org.eclipse.jdt.debug.ui.actions.ToggleTracepoint">
</action>
<action
+ definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+ label="%ToggleLambdaEntryBreakpointAction.label"
+ icon="icons/full/obj16/brkp_obj.png"
+ disabledIcon="icons/full/obj16/brkpd_obj.png"
+ helpContextId="toggle_tracepoint_action_context"
+ class="org.eclipse.jdt.internal.debug.ui.actions.RetargetToggleLambdaEntryBreakpointAction"
+ menubarPath="org.eclipse.ui.run/lineBreakpointBeforeGroup"
+ id="org.eclipse.jdt.debug.ui.actions.ToggleLambdaEntryBreakpoint">
+ </action>
+ <action
definitionId="org.eclipse.jdt.debug.ui.commands.AddClassPrepareBreakpoint"
label="%classPrepareAction.label"
icon="$nl$/icons/full/obj16/class_obj.png"
@@ -1006,6 +1016,15 @@
menubarPath="debug">
</action>
<action
+ class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleLambdaEntryBreakpointActionDelegate"
+ helpContextId="manage_breakpoint_action_context"
+ icon="icons/full/obj16/brkp_obj.png"
+ id="org.eclipse.jdt.debug.ui.actions.RulerToggleLambdaEntryBreakpointAction"
+ definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+ label="%AddLambdaEntryBreakpoint.label"
+ menubarPath="debug">
+ </action>
+ <action
label="%EnableBreakpoint.label"
helpContextId="enable_disable_breakpoint_action_context"
class="org.eclipse.debug.ui.actions.RulerEnableDisableBreakpointActionDelegate"
@@ -1050,6 +1069,15 @@
menubarPath="debug">
</action>
<action
+ class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleLambdaEntryBreakpointActionDelegate"
+ helpContextId="manage_breakpoint_action_context"
+ icon="icons/full/obj16/brkp_obj.png"
+ id="org.eclipse.jdt.debug.ui.actions.RulerToggleLambdaEntryBreakpointAction"
+ definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+ label="%AddLambdaEntryBreakpoint.label"
+ menubarPath="debug">
+ </action>
+ <action
label="%EnableBreakpoint.label"
helpContextId="enable_disable_breakpoint_action_context"
class="org.eclipse.debug.ui.actions.RulerEnableDisableBreakpointActionDelegate"
@@ -2688,6 +2716,12 @@
id="org.eclipse.jdt.debug.ui.commands.ToggleTracepoint">
</command>
<command
+ name="%ToggleLambdaEntryBreakpointCommand.label"
+ description="%ToggleLambdaEntryBreakpointCommand.description"
+ categoryId="org.eclipse.debug.ui.category.run"
+ id="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint">
+ </command>
+ <command
name="%ActionDefinition.addException.name"
description="%ActionDefinition.addException.description"
categoryId="org.eclipse.debug.ui.category.run"
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
index 53a7b46..1bf6647 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2015 IBM Corporation and others.
+ * Copyright (c) 2006, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,7 @@
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
import org.eclipse.jdt.debug.core.IJavaPatternBreakpoint;
import org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint;
import org.eclipse.jdt.debug.core.IJavaWatchpoint;
@@ -67,6 +68,7 @@
*
* @since 3.3
*/
+@SuppressWarnings("deprecation")
public class BreakpointMarkerUpdater implements IMarkerUpdater {
public BreakpointMarkerUpdater() {}
@@ -113,7 +115,22 @@
return false;
}
try {
- ValidBreakpointLocationLocator loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset())+1, true, true);
+ ValidBreakpointLocationLocator loc;
+ if (breakpoint instanceof IJavaMethodBreakpoint && ((IJavaMethodBreakpoint) breakpoint).isEntry()) {
+ IMarker m = breakpoint.getMarker();
+ if (m != null) {
+ int charStart = m.getAttribute(IMarker.CHAR_START, -1);
+ int charEnd = m.getAttribute(IMarker.CHAR_END, -1);
+ int length = charEnd - charStart + 1;
+ loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset())
+ + 1, true, true, position.getOffset(), length);
+
+ } else {
+ loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset()) + 1, true, true);
+ }
+ } else {
+ loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset()) + 1, true, true);
+ }
unit.accept(loc);
if(loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_NOT_FOUND) {
return false;
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 351f3c9..61fe1da 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2021 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -168,6 +168,8 @@
public static String TracepointToggleAction_Unavailable;
+ public static String LambdaEntryBreakpointToggleAction_Unavailable;
+
public static String Override_Dependencies_title;
public static String Override_Dependencies_button;
public static String Override_Dependencies_button1;
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 425b5f7..d1ad471 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, 2021 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
@@ -149,6 +149,7 @@
EditClasspathEntryAction_0=Ed&it...
ProjectSelectionDialog_0=Choose &project(s) to add:
TracepointToggleAction_Unavailable=The operation is unavailable on the current selection.
+LambdaEntryBreakpointToggleAction_Unavailable=The operation is unavailable on the current selection.
Override_Dependencies_title=Override Dependencies
Override_Dependencies_button=&Override
Override_Dependencies_button1=&Override Dependencies...
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
index eeb3d97..903d26e 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016, 2017 IBM Corporation and others.
+ * Copyright (c) 2016, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,7 @@
public class BreakpointToggleUtils {
private static boolean isTracepoint = false;
+ private static boolean isLambdaEntryBreakpoint = false;
public static void setUnsetTracepoints(boolean tracePoint) {
@@ -35,6 +36,14 @@
return isTracepoint;
}
+ public static void setUnsetLambdaEntryBreakpoint(boolean lambdaEntryBreakpoint) {
+ isLambdaEntryBreakpoint = lambdaEntryBreakpoint;
+ }
+
+ public static boolean isToggleLambdaEntryBreakpoint() {
+ return isLambdaEntryBreakpoint;
+ }
+
/**
* Convenience method for printing messages to the status line
*
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java
new file mode 100644
index 0000000..e24b19a
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 20227 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.internal.ui.actions.breakpoints.RetargetToggleBreakpointAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Global retargettable toggle Line Entry action.
+ *
+ * @since 3.12
+ *
+ */
+public class RetargetToggleLambdaEntryBreakpointAction extends RetargetToggleBreakpointAction {
+
+ @Override
+ protected void performAction(Object target, ISelection selection, IWorkbenchPart part) throws CoreException {
+ BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(true);
+ super.performAction(target, selection, part);
+ }
+
+ @Override
+ protected boolean canPerformAction(Object target, ISelection selection, IWorkbenchPart part) {
+ return super.canPerformAction(target, selection, part);
+ }
+
+ @Override
+ protected String getOperationUnavailableMessage() {
+ return ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java
new file mode 100644
index 0000000..df131df
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public class RulerToggleLambdaEntryBreakpointActionDelegate extends AbstractRulerActionDelegate implements IActionDelegate2 {
+
+ private IEditorPart currentEditor;
+ private IAction dummyAction;
+
+ @Override
+ protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
+ dummyAction = new Action() {
+ // empty implementation to make compiler happy
+ };
+ return dummyAction;
+ }
+
+ @Override
+ public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
+ currentEditor = targetEditor;
+ }
+
+ @Override
+ public void init(IAction action) {
+ }
+
+ @Override
+ public void dispose() {
+ currentEditor = null;
+ dummyAction = null;
+ super.dispose();
+ }
+
+ @Override
+ public void runWithEvent(IAction action, Event event) {
+ if (!(currentEditor instanceof ITextEditor)) {
+ return;
+ }
+ IVerticalRulerInfo rulerInfo = currentEditor.getAdapter(IVerticalRulerInfo.class);
+ if (rulerInfo == null) {
+ return;
+ }
+ int lineOfLastMouseButtonActivity = rulerInfo.getLineOfLastMouseButtonActivity();
+ if (lineOfLastMouseButtonActivity < 0) {
+ return;
+ }
+ IDocument document = getDocument((ITextEditor) currentEditor);
+ if (document == null) {
+ return;
+ }
+ ToggleBreakpointAdapter toggle = new ToggleBreakpointAdapter();
+ try {
+ ITextSelection selection = getTextSelection(currentEditor, document, lineOfLastMouseButtonActivity);
+ if (toggle.canToggleLineBreakpoints(currentEditor, selection)) {
+ BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(true);
+ toggle.toggleBreakpoints(currentEditor, selection);
+ }
+ } catch (BadLocationException | CoreException e) {
+ DebugUIPlugin.log(e);
+ }
+ }
+
+ private static IDocument getDocument(ITextEditor editor) {
+ IDocumentProvider provider = editor.getDocumentProvider();
+ if (provider != null) {
+ return provider.getDocument(editor.getEditorInput());
+ }
+ IDocument doc = editor.getAdapter(IDocument.class);
+ if (doc != null) {
+ return doc;
+ }
+ return null;
+ }
+
+ private static ITextSelection getTextSelection(IEditorPart editor, IDocument document, int line) throws BadLocationException {
+ IRegion region = document.getLineInformation(line);
+ ITextSelection textSelection = new TextSelection(document, region.getOffset(), 0);
+ ISelectionProvider provider = editor.getSite().getSelectionProvider();
+ if (provider != null) {
+ ISelection selection = provider.getSelection();
+ if (selection instanceof ITextSelection && ((ITextSelection) selection).getStartLine() <= line
+ && ((ITextSelection) selection).getEndLine() >= line) {
+ textSelection = (ITextSelection) selection;
+ }
+ }
+ return textSelection;
+ }
+}
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 8b131a6..4e34313 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
@@ -19,6 +19,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.resources.IFile;
@@ -81,6 +82,7 @@
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.ValidBreakpointLocationLocator;
import org.eclipse.jdt.internal.debug.ui.BreakpointUtils;
import org.eclipse.jdt.internal.debug.ui.DebugWorkingCopyManager;
@@ -101,6 +103,7 @@
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IVerticalRulerInfo;
@@ -245,6 +248,123 @@
job.schedule();
}
+ public void toggleLambdaMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final ValidBreakpointLocationLocator loc) {
+ Job job = new Job("Toggle Lambda Method Breakpoints") { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ try {
+ return doToggleLambdaMethodBreakpoints(part, finalSelection, loc, monitor);
+ } catch (CoreException e) {
+ return e.getStatus();
+ } finally {
+ BreakpointToggleUtils.setUnsetTracepoints(false);
+ }
+ }
+ };
+ job.setPriority(Job.INTERACTIVE);
+ job.setSystem(true);
+ job.schedule();
+ }
+
+ public void toggleLambdaEntryMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final String lambdaMethodName) {
+ Job job = new Job("Toggle Lambda Entry Method Breakpoints") { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ try {
+ return doToggleLambdaEntryMethodBreakpoints(part, finalSelection, lambdaMethodName, monitor);
+ } catch (CoreException e) {
+ return e.getStatus();
+ } finally {
+ BreakpointToggleUtils.setUnsetTracepoints(false);
+ }
+ }
+ };
+ job.setPriority(Job.INTERACTIVE);
+ job.setSystem(true);
+ job.schedule();
+ }
+
+ static IStatus doToggleLambdaEntryMethodBreakpoints(IWorkbenchPart part, ISelection selection, String lambdaMethodName, IProgressMonitor monitor) throws CoreException {
+ ITextEditor textEditor = getTextEditor(part);
+ if (textEditor == null || !(selection instanceof ITextSelection)) {
+ return Status.OK_STATUS;
+ }
+ ITextSelection textSelection = (ITextSelection) selection;
+ IEditorInput editorInput = textEditor.getEditorInput();
+ ITypeRoot root = getTypeRoot(editorInput);
+ if (root instanceof ICompilationUnit) {
+ ICompilationUnit unit = (ICompilationUnit) root;
+ synchronized (unit) {
+ unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
+ }
+ IJavaElement[] elements = unit.codeSelect(textSelection.getOffset(), textSelection.getLength());
+ if (elements == null || elements.length == 0) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ return Status.OK_STATUS;
+ }
+ IMethod method = null;
+ if (elements[0] instanceof IMethod) {
+ method = (IMethod) elements[0];
+ } else if (elements[0].getParent() instanceof IMethod) {
+ method = (IMethod) elements[0].getParent();
+ }
+
+ if (method != null) {
+ doToggleMethodBreakpoint(method, lambdaMethodName, part, selection, monitor);
+ } else {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+
+ static IStatus doToggleLambdaMethodBreakpoints(IWorkbenchPart part, ISelection selection, ValidBreakpointLocationLocator loc, IProgressMonitor monitor) throws CoreException {
+ ITextEditor textEditor = getTextEditor(part);
+ if (textEditor == null || !(selection instanceof ITextSelection)) {
+ return Status.OK_STATUS;
+ }
+ ITextSelection textSelection = (ITextSelection) selection;
+ IEditorInput editorInput = textEditor.getEditorInput();
+ ITypeRoot root = getTypeRoot(editorInput);
+ if (root instanceof ICompilationUnit) {
+ ICompilationUnit unit = (ICompilationUnit) root;
+ synchronized (unit) {
+ unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
+ }
+ IJavaElement[] elements = unit.codeSelect(textSelection.getOffset(), textSelection.getLength());
+ if (elements == null || elements.length == 0) {
+ ValidBreakpointLocationLocator locNew = new ValidBreakpointLocationLocator(loc.getCompilationUnit(), textSelection.getStartLine()
+ + 1, true, true);
+ locNew.getCompilationUnit().accept(locNew);
+ toggleLineBreakpoints(part, selection, false, locNew);
+ return Status.OK_STATUS;
+ }
+ IMethod method = null;
+ if (elements[0] instanceof IMethod) {
+ method = (IMethod) elements[0];
+ } else if (elements[0].getParent() instanceof IMethod) {
+ method = (IMethod) elements[0].getParent();
+ }
+
+ if (method != null) {
+ doToggleMethodBreakpoint(method, loc.getLambdaMethodName(), part, selection, monitor);
+ } else {
+ ValidBreakpointLocationLocator locNew = new ValidBreakpointLocationLocator(loc.getCompilationUnit(), textSelection.getStartLine()
+ + 1, true, true);
+ locNew.getCompilationUnit().accept(locNew);
+ toggleLineBreakpoints(part, selection, false, locNew);
+ }
+
+ }
+ return Status.OK_STATUS;
+ }
static IStatus doToggleMethodBreakpoints(IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
BreakpointToggleUtils.report(null, part);
ISelection selection = finalSelection;
@@ -272,6 +392,10 @@
}
private static void doToggleMethodBreakpoint(IMethod member, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
+ doToggleMethodBreakpoint(member, null, part, finalSelection, monitor);
+ }
+
+ private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethodName, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
IJavaBreakpoint breakpoint = getMethodBreakpoint(member);
if (breakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
@@ -293,7 +417,7 @@
BreakpointUtils.addJavaBreakpointAttributes(attributes, member);
IType type = member.getDeclaringType();
String signature = member.getSignature();
- String mname = member.getElementName();
+ String mname = Optional.ofNullable(lambdaMethodName).orElse(member.getElementName());
if (member.isConstructor()) {
mname = "<init>"; //$NON-NLS-1$
if (type.isEnum()) {
@@ -1432,9 +1556,21 @@
JDIDebugUIPlugin.log("Failed to parse CU for: " + editor.getTitle(), new IllegalStateException()); //$NON-NLS-1$
return;
}
- ValidBreakpointLocationLocator loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true);
+ ValidBreakpointLocationLocator loc = null;
+ boolean lambdaEntryBP = false;
+ if (BreakpointToggleUtils.isToggleLambdaEntryBreakpoint()) {
+ loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine()
+ + 1, true, true, ts.getOffset(), ts.getLength());
+ lambdaEntryBP = true;
+ BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(false);
+ } else {
+ loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true);
+ }
unit.accept(loc);
- if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_METHOD) {
+
+ if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LAMBDA_METHOD) {
+ toggleLambdaMethodBreakpoints(part, ts, loc);
+ } else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_METHOD) {
toggleMethodBreakpoints(part, ts);
} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_FIELD) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
@@ -1444,7 +1580,31 @@
}
toggleWatchpoints(part, ts);
} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LINE) {
- toggleLineBreakpoints(part, ts, false, loc);
+ 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());
+ } catch (BadLocationException e) {
+ BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+ }
+
+ } else {
+ toggleLineBreakpoints(part, ts, false, loc);
+ }
}
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java
new file mode 100644
index 0000000..9f743a2
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.core.breakpoints;
+
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+
+public class FirstLambdaLocationLocator extends ASTVisitor {
+ private int fNodeLength = -1;
+ private int fNodeOffset = -1;
+ private int fLineOffset = -1;
+ private int fLineEndPosition = -1;
+ private String fLambdaMethodName;
+ private boolean fLocationFound = false;
+
+ public FirstLambdaLocationLocator(int lineOffset, int lineEndPosition) {
+ fLineOffset = lineOffset;
+ fLineEndPosition = lineEndPosition;
+ }
+
+ /**
+ * Return of the name of the lambda method where the valid location is.
+ */
+ public String getLambdaMethodName() {
+ return fLambdaMethodName;
+ }
+
+ public int getNodeLength() {
+ return fNodeLength;
+ }
+
+ public int getNodeOffset() {
+ return fNodeOffset;
+ }
+
+ @Override
+ public boolean visit(LambdaExpression node) {
+ if (fLocationFound) {
+ return false;
+ }
+ if (node.getStartPosition() < fLineOffset || node.getStartPosition() > fLineEndPosition) {
+ return false;
+ }
+ fNodeLength = node.getLength();
+ fNodeOffset = node.getStartPosition();
+ IMethodBinding methodBinding = node.resolveMethodBinding();
+ if (methodBinding != null) {
+ fLambdaMethodName = toMethodName(methodBinding);
+ fLocationFound = true;
+ }
+ return false;
+ }
+
+ private String toMethodName(IMethodBinding methodBinding) {
+ String key = methodBinding.getKey();
+ return key.substring(key.indexOf('.') + 1, key.indexOf('('));
+ }
+
+}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
index 42f014c..206894a 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -30,6 +30,7 @@
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
import org.eclipse.jdt.internal.debug.core.model.JDIThread;
+import org.eclipse.jdt.internal.debug.core.model.LambdaUtils;
import org.eclipse.jdt.internal.debug.core.model.MethodResult;
import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
@@ -464,7 +465,7 @@
}
}
- if (getMethodName() != null) {
+ if (getMethodName() != null && !LambdaUtils.isLambdaMethod(method)) {
if (!method.name().equals(getMethodName())) {
return true;
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
index 76cdc9a..91d3864 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2019 IBM Corporation and others.
+ * Copyright (c) 2003, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -54,6 +54,7 @@
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ForStatement;
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.IVariableBinding;
import org.eclipse.jdt.core.dom.IfStatement;
@@ -63,6 +64,7 @@
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.LabeledStatement;
+import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.core.dom.LineComment;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberRef;
@@ -125,6 +127,8 @@
public static final int LOCATION_LINE = 1;
public static final int LOCATION_METHOD = 2;
public static final int LOCATION_FIELD = 3;
+ public static final int LOCATION_LAMBDA_METHOD = 4;
+
private CompilationUnit fCompilationUnit;
private int fLineNumber;
@@ -134,10 +138,15 @@
private int fLocationType;
private boolean fLocationFound;
+ private boolean fLambdaVisited;
+ private String fLambdaMethodName;
private String fTypeName;
private int fLineLocation;
private int fMemberOffset;
+ private int fNodeLength;
private List<String> fLabels;
+ private int fInputOffset;
+ private int fInputLength;
/**
* @param compilationUnit
@@ -156,6 +165,30 @@
fBindingsResolved = bindingsResolved;
fBestMatch = bestMatch;
fLocationFound = false;
+ fInputOffset = -1;
+ fInputLength = -1;
+ }
+
+ /**
+ * @param compilationUnit
+ * the JDOM CompilationUnit of the source code.
+ * @param lineNumber
+ * the line number in the source code where to put the breakpoint.
+ * @param bestMatch
+ * if <code>true</code> look for the best match, otherwise look only for a valid line
+ * @param offset
+ * selection offset on which breakpoints should be toggled
+ * @param end
+ * selection end on which breakpoints should be toggled
+ */
+ public ValidBreakpointLocationLocator(CompilationUnit compilationUnit, int lineNumber, boolean bindingsResolved, boolean bestMatch, int offset, int end) {
+ fCompilationUnit = compilationUnit;
+ fLineNumber = lineNumber;
+ fBindingsResolved = bindingsResolved;
+ fBestMatch = bestMatch;
+ fLocationFound = false;
+ fInputOffset = offset;
+ fInputLength = end;
}
/**
@@ -189,6 +222,12 @@
}
/**
+ * Return of the name of the lambda method where the valid location is.
+ */
+ public String getLambdaMethodName() {
+ return fLambdaMethodName;
+ }
+ /**
* Return the line number of the computed valid location
*/
public int getLineLocation() {
@@ -206,6 +245,13 @@
return fMemberOffset;
}
+ public int getNodeLength() {
+ return fNodeLength;
+ }
+
+ public CompilationUnit getCompilationUnit() {
+ return fCompilationUnit;
+ }
/**
* Compute the name of the type which contains this node. <br>
* <br>
@@ -281,13 +327,17 @@
* lines.
*/
private boolean visit(ASTNode node, boolean isCode) {
+ int startPosition = node.getStartPosition();
+ int startLine = lineNumber(startPosition);
+ int endLine = lineNumber(startPosition + node.getLength() - 1);
+
// if we already found a correct location
- // no need to check the element inside.
- if (fLocationFound) {
+ // no need to check the element inside if the line number doesn't match.
+ // if line numbers match we still need to visit the whole expression in this line
+ // to make sure we have any lambda's we were looking for which we didn't visited yet.
+ if (fLambdaVisited || (fLocationFound && fLineNumber != startLine)) {
return false;
}
- int startPosition = node.getStartPosition();
- int endLine = lineNumber(startPosition + node.getLength() - 1);
// if the position is not in this part of the code
// no need to check the element inside.
if (endLine < fLineNumber) {
@@ -298,7 +348,6 @@
// breakpoint is requested on this line or on a previous line, this is a
// valid
// location
- int startLine = lineNumber(startPosition);
if (isCode && (fLineNumber <= startLine)) {
fLineLocation = startLine;
fLocationFound = true;
@@ -595,6 +644,15 @@
*/
@Override
public boolean visit(ClassInstanceCreation node) {
+ if (visit(node, false)) {
+ List<? extends ASTNode> arguments = node.arguments();
+ for (ASTNode astNode : arguments) {
+ if (astNode instanceof LambdaExpression) {
+ astNode.accept(this);
+ return false;
+ }
+ }
+ }
return visit(node, true);
}
@@ -708,7 +766,16 @@
*/
@Override
public boolean visit(ExpressionStatement node) {
- return visit(node, false);
+ if (fLocationFound && fLambdaVisited) {
+ return false;
+ }
+ if (visit(node, false)) {
+ if (node.getExpression() instanceof MethodInvocation) {
+ node.getExpression().accept(this);
+ return false;
+ }
+ }
+ return visit(node, true);
}
/**
@@ -948,6 +1015,56 @@
fLabels.remove(fLabels.size() - 1);
}
+ @Override
+ public boolean visit(LambdaExpression node) {
+ fMemberOffset = node.getStartPosition();
+ fNodeLength = node.getLength();
+ if (fInputOffset != -1 && fInputLength > 0 && fInputOffset >= fMemberOffset && fInputOffset + fInputLength <= fMemberOffset + fNodeLength) {
+ IMethodBinding methodBinding = node.resolveMethodBinding();
+ if (methodBinding != null) {
+ fLambdaVisited = true;
+ fLocationType = LOCATION_LAMBDA_METHOD;
+ fLambdaMethodName = toMethodName(methodBinding);
+ fLocationFound = true;
+ return false;
+ }
+ } else if (fLocationType != LOCATION_LAMBDA_METHOD) {
+ fLocationType = LOCATION_LINE;
+ fTypeName = computeTypeName(node);
+ int startLine = lineNumber(fMemberOffset);
+ if (fLineNumber <= startLine) {
+ if (fInputOffset != -1) {
+ fLineLocation = lineNumber(fInputOffset);
+ } else {
+ fLineLocation = startLine;
+ }
+ } else {
+ // visit the body
+ ASTNode body = node.getBody();
+ if (body instanceof Block) { // body is null for abstract methods
+ fLocationFound = false;
+ Block block1 = (Block) body;
+ if (visit(block1)) {
+ for (Object object : block1.statements()) {
+ if (object instanceof ASTNode) {
+ ASTNode node1 = (ASTNode) object;
+ node1.accept(this);
+ }
+
+ }
+ }
+ }
+ }
+ return false;
+ }
+ return visit(node, true);
+ }
+
+ private String toMethodName(IMethodBinding methodBinding) {
+ String key = methodBinding.getKey();
+ return key.substring(key.indexOf('.') + 1, key.indexOf('('));
+ }
+
/*
* (non-Javadoc)
*
@@ -1028,6 +1145,27 @@
*/
@Override
public boolean visit(MethodInvocation node) {
+ if (fLocationFound && fLambdaVisited) {
+ return false;
+ }
+ if (visit(node, false)) {
+ // first run through arguments to avoid pre-mature line breakpoint identification
+ List<? extends ASTNode> arguments = node.arguments();
+ for (ASTNode astNode : arguments) {
+ // arguments needs to be accepted to handle stream operation where the lambda debug point
+ // is expected on a lambda expression which is a parameter on a nested method invocation like
+ // strings.stream().collect(Collectors.toMap(s -> s.substring(0), s -> s))
+ astNode.accept(this);
+ if (astNode instanceof LambdaExpression && fLambdaVisited) {
+ return false;
+ }
+ }
+
+ Expression expression = node.getExpression();
+ if (expression instanceof ClassInstanceCreation || expression instanceof MethodInvocation) {
+ expression.accept(this);
+ }
+ }
return visit(node, true);
}
@@ -1403,6 +1541,9 @@
fLocationFound = true;
fLocationType = LOCATION_LINE;
fTypeName = computeTypeName(node);
+ if (initializer instanceof MethodInvocation || initializer instanceof LambdaExpression) {
+ initializer.accept(this);
+ }
return false;
}
initializer.accept(this);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
index 272b486..aee1c97 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 IBM Corporation and others.
+ * Copyright (c) 2018, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0