Skip to content

Commit 495f8bb

Browse files
Disable on hit for Breakpoints (#682)
Disable on Hit feature is now supported for all breakpoints except trigger points Fixes: #680
1 parent ad975c4 commit 495f8bb

File tree

8 files changed

+137
-0
lines changed

8 files changed

+137
-0
lines changed

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.eclipse.jdt.debug.tests.breakpoints.ConditionalBreakpointsWithFileClass;
3030
import org.eclipse.jdt.debug.tests.breakpoints.ConditionalBreakpointsWithGenerics;
3131
import org.eclipse.jdt.debug.tests.breakpoints.DeferredBreakpointTests;
32+
import org.eclipse.jdt.debug.tests.breakpoints.DisableOnHitTest;
3233
import org.eclipse.jdt.debug.tests.breakpoints.ExceptionBreakpointTests;
3334
import org.eclipse.jdt.debug.tests.breakpoints.HitCountBreakpointsTests;
3435
import org.eclipse.jdt.debug.tests.breakpoints.ImportBreakpointsTest;
@@ -399,6 +400,7 @@ public AutomatedSuite() {
399400
addTest(new TestSuite(JavaThreadEventHandlerTests.class));
400401
addTest(new TestSuite(ConditionalBreakpointsWithFileClass.class));
401402
addTest(new TestSuite(CompareObjectsTest.class));
403+
addTest(new TestSuite(DisableOnHitTest.class));
402404

403405
if (JavaProjectHelper.isJava8Compatible()) {
404406
addTest(new TestSuite(TestToggleBreakpointsTarget8.class));
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.debug.tests.breakpoints;
15+
16+
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
17+
import org.eclipse.jdt.debug.core.IJavaThread;
18+
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
19+
20+
/**
21+
* Tests for disable on hit breakpoints.
22+
*/
23+
24+
public class DisableOnHitTest extends AbstractDebugTest {
25+
26+
/**
27+
* Constructor
28+
*
29+
* @param name
30+
* the name of the test
31+
*/
32+
public DisableOnHitTest(String name) {
33+
super(name);
34+
}
35+
36+
public void testBreakpointHitWith() throws Exception {
37+
String typeName = "TriggerPoint_01";
38+
IJavaLineBreakpoint bp1 = createLineBreakpoint(19, typeName);
39+
IJavaLineBreakpoint bp2 = createLineBreakpoint(20, typeName);
40+
bp1.setDisableOnHit(true);
41+
IJavaThread thread = null;
42+
try {
43+
thread = launchToBreakpoint(typeName);
44+
thread.resume();
45+
boolean isBp1Disabled = bp1.isEnabled();
46+
assertFalse("Breakpoint should be disabled after hit", isBp1Disabled);
47+
bp1.delete();
48+
bp2.delete();
49+
} finally {
50+
terminateAndRemove(thread);
51+
removeAllBreakpoints();
52+
}
53+
}
54+
55+
public void testBreakpointHitWithout() throws Exception {
56+
String typeName = "TriggerPoint_01";
57+
IJavaLineBreakpoint bp1 = createLineBreakpoint(19, typeName);
58+
IJavaLineBreakpoint bp2 = createLineBreakpoint(20, typeName);
59+
IJavaThread thread = null;
60+
try {
61+
thread = launchToBreakpoint(typeName);
62+
thread.resume();
63+
boolean isBp1Disabled = bp1.isEnabled();
64+
assertTrue("Breakpoint should be not be disabled after hit", isBp1Disabled);
65+
bp1.delete();
66+
bp2.delete();
67+
} finally {
68+
terminateAndRemove(thread);
69+
removeAllBreakpoints();
70+
}
71+
}
72+
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.debug.internal.ui.SWTFactory;
2121
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
2222
import org.eclipse.jdt.debug.ui.breakpoints.JavaBreakpointConditionEditor;
23+
import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint;
2324
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
2425
import org.eclipse.jdt.internal.debug.ui.propertypages.PropertyPageMessages;
2526
import org.eclipse.jface.util.Util;
@@ -48,6 +49,7 @@ public class StandardJavaBreakpointEditor extends AbstractJavaBreakpointEditor {
4849
private Button fResumeOnHit;
4950
private Button fSuspendVM;
5051
protected Button fTriggerPointButton;
52+
protected Button fDisableOnHit;
5153

5254
private final JavaBreakpointConditionEditor javaBpConditionEditor;
5355

@@ -158,6 +160,8 @@ public void widgetSelected(SelectionEvent e) {
158160
}
159161

160162
protected Control createStandardControls(Composite parent) {
163+
Composite comp = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, 0, 0, 0);
164+
fDisableOnHit = SWTFactory.createCheckButton(comp, PropertyPageMessages.BreakpointDisableOnHit, null, false, 2);
161165
Composite composite = SWTFactory.createComposite(parent, parent.getFont(), 4, 1, 0, 0, 0);
162166
fHitCountButton = SWTFactory.createCheckButton(composite, processMnemonics(PropertyPageMessages.JavaBreakpointPage_4), null, false, 1);
163167
fHitCountButton.setLayoutData(new GridData());
@@ -202,6 +206,15 @@ public void widgetSelected(SelectionEvent e) {
202206
setDirty(PROP_SUSPEND_POLICY);
203207
}
204208
});
209+
fDisableOnHit.addSelectionListener(new SelectionAdapter() {
210+
@Override
211+
public void widgetSelected(SelectionEvent event) {
212+
boolean enabled = fDisableOnHit.getSelection();
213+
if (fBreakpoint instanceof JavaBreakpoint javaBp) {
214+
javaBp.setDisableOnHit(enabled);
215+
}
216+
}
217+
});
205218
composite.addDisposeListener(new DisposeListener() {
206219
@Override
207220
public void widgetDisposed(DisposeEvent e) {
@@ -249,6 +262,7 @@ protected void setBreakpoint(IJavaBreakpoint breakpoint) throws CoreException {
249262
String text = Util.ZERO_LENGTH_STRING;
250263
boolean suspendThread = true;
251264
boolean resumeOnHit = false;
265+
boolean isDisableOnHit = false;
252266
if (breakpoint != null) {
253267
enabled = true;
254268
int hitCount = breakpoint.getHitCount();
@@ -258,6 +272,7 @@ protected void setBreakpoint(IJavaBreakpoint breakpoint) throws CoreException {
258272
}
259273
suspendThread= breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_THREAD;
260274
resumeOnHit = breakpoint.getSuspendPolicy() == IJavaBreakpoint.RESUME_ON_HIT && isTriggerPoint();
275+
isDisableOnHit = breakpoint.isDisableOnHit();
261276
}
262277
fHitCountButton.setEnabled(enabled);
263278
fHitCountButton.setSelection(enabled && hasHitCount);
@@ -271,6 +286,8 @@ protected void setBreakpoint(IJavaBreakpoint breakpoint) throws CoreException {
271286
fSuspendVM.setSelection(!suspendThread && !resumeOnHit);
272287
fTriggerPointButton.setEnabled(enabled);
273288
fTriggerPointButton.setSelection(isTriggerPoint());
289+
fDisableOnHit.setEnabled(!isTriggerPoint() && enabled);
290+
fDisableOnHit.setSelection(isDisableOnHit);
274291
setDirty(false);
275292
}
276293

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/PropertyPageMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,6 @@ public class PropertyPageMessages extends NLS {
121121
public static String BreakpointResumeOnHit;
122122
public static String BreakpointResumeConditionalTrue;
123123
public static String BreakpointResumeConditionalValue;
124+
public static String BreakpointDisableOnHit;
124125

125126
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/PropertyPageMessages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@ VMCapabilitiesPropertyPage_31=This page displays optional debug capabilities tha
9494
BreakpointResumeOnHit=Continue execution on hit
9595
BreakpointResumeConditionalTrue=Resume when 'true'
9696
BreakpointResumeConditionalValue=Resume when value changes
97+
BreakpointDisableOnHit=Disable on hit

org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,19 @@ public IJavaThread getThreadFilter(IJavaDebugTarget target)
275275
public boolean removeBreakpointListener(String identifier)
276276
throws CoreException;
277277

278+
/**
279+
* Returns whether the breakpoint should disable on hit or not.
280+
*
281+
* @return whether the breakpoint should disable on hit or not.
282+
* @since 3.23
283+
*/
284+
public boolean isDisableOnHit();
285+
286+
/**
287+
* Sets whether the breakpoint should disable on hit or not
288+
*
289+
* @since 3.23
290+
*/
291+
public void setDisableOnHit(boolean disable);
292+
278293
}

org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/BreakpointListenerManager.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ public void breakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, DebugE
151151
public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
152152
IJavaBreakpointListener delegate = getDelegate();
153153
if (delegate != null) {
154+
try {
155+
if (breakpoint.isDisableOnHit()) {
156+
breakpoint.setEnabled(false);
157+
}
158+
} catch (CoreException e) {
159+
JDIDebugPlugin.log(e);
160+
}
154161
return delegate.breakpointHit(thread, breakpoint);
155162
}
156163
return IJavaBreakpointListener.DONT_CARE;

org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ public abstract class JavaBreakpoint extends Breakpoint implements IJavaBreakpoi
177177
protected static final String[] fgExpiredEnabledAttributes = new String[] {
178178
EXPIRED, ENABLED };
179179

180+
private boolean disableOnHit;
181+
180182
public JavaBreakpoint() {
181183
fRequestsByTarget = new HashMap<>(1);
182184
fFilteredThreadsByTarget = new HashMap<>(1);
@@ -1493,4 +1495,24 @@ private String[] readBreakpointListeners() throws CoreException {
14931495
}
14941496
return value.split(","); //$NON-NLS-1$
14951497
}
1498+
1499+
/*
1500+
* (non-Javadoc)
1501+
*
1502+
* @see org.eclipse.jdt.debug.core.IJavaBreakpoint#isDisableOnHit()
1503+
*/
1504+
@Override
1505+
public boolean isDisableOnHit() {
1506+
return disableOnHit;
1507+
}
1508+
1509+
/*
1510+
* (non-Javadoc)
1511+
*
1512+
* @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setDisableOnHit()
1513+
*/
1514+
@Override
1515+
public void setDisableOnHit(boolean disable) {
1516+
disableOnHit = disable;
1517+
}
14961518
}

0 commit comments

Comments
 (0)