Add support for breakpoint-to-breakpoint dependencies#967
Conversation
|
This pull request changes some projects for the first time in this development cycle. An additional commit containing all the necessary changes was pushed to the top of this PR's branch. To obtain these changes (for example if you want to push more changes) either fetch from your fork or apply the git patch. Git patchFurther information are available in Common Build Issues - Missing version increments. |
Allow a breakpoint to suspend only after a configured dependency breakpoint has been hit. Dependency breakpoints can optionally continue execution on their first hit and enable dependent breakpoints afterwards.
0cf5aae to
c0cd7e0
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds “breakpoint-to-breakpoint” dependency support to Eclipse JDT Debug, allowing a breakpoint to suspend only after another breakpoint has been hit, with optional “continue on first hit” behavior for dependency breakpoints.
Changes:
- Extends the breakpoint core model/API to store dependency relationships and “hit” state used to gate suspension.
- Updates UI breakpoint property editor + model presentation labels to configure and display
[waiting]/[dependency]. - Adds a new automated test suite and test programs to validate dependency behavior (including chaining and condition/hitcount interactions).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java | Updates breakpoint suspend handling to record “hit” state and implement resume-on-first-hit for dependency breakpoints. |
| org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java | Adds dependency attributes/state and gating logic for waiting breakpoints. |
| org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java | Adds new public API for dependency configuration and “hit” tracking. |
| org.eclipse.jdt.debug/META-INF/MANIFEST.MF | Bumps bundle version to 3.27.0.qualifier. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/PropertyPageMessages.properties | Adds new UI strings for dependency selection/config. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/PropertyPageMessages.java | Exposes the new property page message keys. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java | Appends [waiting] / [dependency] labels to breakpoint presentation text. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties | Adds message keys for new breakpoint labels. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java | Declares new NLS message fields for the labels. |
| org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java | Adds “Wait Until” UI, dependency selection dialog, and dependency management actions. |
| org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/DependencyBreakpointsTests.java | New test suite covering dependency scenarios and chaining. |
| org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java | Registers the new dependency tests. |
| org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java | Adds new test program names to the test harness. |
| org.eclipse.jdt.debug.tests/testprograms/ExternalClassTst.java | New test program used by dependency tests. |
| org.eclipse.jdt.debug.tests/testprograms/DependencyTest.java | New test program used by dependency tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (breakpoint.isDependencyBreakpoint()) { | ||
| if (breakpoint.hasDependentBreakpoint()) { | ||
| IJavaBreakpoint dependented = breakpoint.getDependentBreakpoint(); | ||
| if (!dependented.hasBeenHit()) { | ||
| return false; | ||
| } | ||
| breakpoint.setHit(true); | ||
| } else { | ||
| breakpoint.setHit(true); | ||
| } | ||
| breakpoint.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD); | ||
| } |
| long markerId = Long.parseLong(value); | ||
| IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(); | ||
| for (IBreakpoint bp : breakpoints) { | ||
| if (bp.getMarker() != null && bp.getMarker().getId() == markerId) { | ||
| dependedBreakpoint = (IJavaBreakpoint) bp; | ||
| break; | ||
| } | ||
| } | ||
| } |
| if (!currentDependend.equals(waitingBp)) { | ||
| currentDependend.setDependencyBreakpoint(false); | ||
| setAttribute(DEPENDENT_BREAKPOINT, String.valueOf(waitingBp.getMarker().getId())); | ||
| dependedBreakpoint = waitingBp; | ||
| setDependancyEnabled(true); | ||
| } |
| private IJavaBreakpoint dependedBreakpoint; | ||
|
|
||
| public boolean hasHit = false; | ||
|
|
| public static Object JDIModelPresentation_waiting; | ||
|
|
||
| public static Object JDIModelPresentation_dependency; |
| /** | ||
| * Returns whether this breakpoint has been hit during the current debug session. | ||
| * | ||
| * @return whether this breakpoint has been hit | ||
| * @since 3.27 | ||
| */ | ||
| public boolean hasBeenHit(); | ||
|
|
||
| /** | ||
| * Sets whether this breakpoint has been hit during the current debug session. | ||
| * | ||
| * @param hasHit | ||
| * whether this breakpoint has been hit | ||
| * @since 3.27 | ||
| */ | ||
| public void setHit(boolean hasHit); |
| public boolean handleBreakpointEvent(Event event, JDIThread thread, | ||
| boolean suspendVote) { | ||
| expireHitCount(event); | ||
| disableTriggerPoint(event); | ||
| return !suspend(thread, suspendVote); // Resume if suspend fails | ||
| boolean shouldSuspend = suspend(thread, suspendVote); // Resume if suspend fails | ||
| boolean hasWaiting = handleWaitingBreakpoint(); | ||
| if (shouldSuspend && !hasWaiting) { | ||
| return true; | ||
| } | ||
| return !shouldSuspend; |
| @Override | ||
| public boolean hasDependentBreakpoint() throws CoreException { | ||
| if (dependedBreakpoint == null && ensureMarker().getAttribute(DEPENDENT_BREAKPOINT, null) == null) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } |
| if (breakpoint.hasDependentBreakpoint()) { | ||
| IJavaBreakpoint existingDependentBp = breakpoint.getDependentBreakpoint(); | ||
| existingDependentBp.setDependencyBreakpoint(false); | ||
| breakpoint.removeDependentBreakpoint(); | ||
| breakpoint.setDependancyEnabled(false); | ||
| dependentBreakpoint.setText(NLS.bind(PropertyPageMessages.WaitForBreakpointDefaultSelection)); | ||
| waitForBreakpoint.setSelection(false); | ||
| dependentBreakpoint.setEnabled(false); | ||
| } |
| import org.eclipse.jdt.debug.core.IJavaBreakpoint; | ||
| import org.eclipse.jdt.debug.ui.breakpoints.JavaBreakpointConditionEditor; | ||
| import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; | ||
| import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint; | ||
| import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; |
|
Thanks for triggering Co-Pilot, will go through the comments soon 👍 |
This PR introduces
breakpoint-to-breakpointdependency support. A breakpoint can now be configured to suspend execution only after another breakpoint has been hit, enabling more precise control over complex debugging workflows. Dependency breakpoints can also be configured to automatically continue execution on their first hit, allowing them to act as trigger points that activate dependent breakpoints without interrupting the debugging session.This capability reduces the need for complex conditional breakpoint expressions, minimizes manual breakpoint management, and introduces better flow-based debugging control. For example, when a frequently invoked method is reached many times during a debugging session, a dependent breakpoint can be configured to suspend execution only when that method is called as part of a specific execution flow that was activated by another breakpoint
eg. (Suspend A only when called from C)
Similar breakpoint dependency and chaining capabilities are available in other modern Java IDEs.
Workflow -
Click on the
wait until checkboxNow Select the dependent breakpoint. (Which will make user's current bp only hit after the selected bp is hit)
There's also option to
continue execution on first hitwhich is similar to Resume Triggers , and an option to remove existing dependent bp if addedOnce selected, the Breakpoint which is waiting for another bp to hit will have
[waiting]label and the dependent bp will have a label of[dependency]Also, "wait until" selection will show the name of the dependent bp as link (users can click this link to change the bp) or disable the dependancy condition by unchecking "wait until"
Work.mp4
What it does
How to test
Author checklist