Skip to content

Commit f48a1bc

Browse files
Visualize the inline breakpoint locations
1 parent f9592bf commit f48a1bc

21 files changed

+608
-122
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,11 @@
3737
public class Breakpoint implements IBreakpoint {
3838
private VirtualMachine vm = null;
3939
private IEventHub eventHub = null;
40-
private String className = null;
41-
private int lineNumber = 0;
40+
private JavaBreakpointLocation sourceLocation = null;
4241
private int hitCount = 0;
4342
private String condition = null;
4443
private String logMessage = null;
4544
private HashMap<Object, Object> propertyMap = new HashMap<>();
46-
private String methodSignature = null;
4745

4846
private boolean async = false;
4947

@@ -56,21 +54,37 @@ public class Breakpoint implements IBreakpoint {
5654
}
5755

5856
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) {
57+
this(vm, eventHub, className, lineNumber, hitCount, condition, null);
58+
}
59+
60+
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) {
5961
this.vm = vm;
6062
this.eventHub = eventHub;
63+
String contextClass = className;
64+
String methodName = null;
65+
String methodSignature = null;
6166
if (className != null && className.contains("#")) {
62-
this.className = className.substring(0, className.indexOf("#"));
63-
this.methodSignature = className.substring(className.indexOf("#") + 1);
64-
} else {
65-
this.className = className;
67+
contextClass = className.substring(0, className.indexOf("#"));
68+
String[] methodInfo = className.substring(className.indexOf("#") + 1).split("#");
69+
methodName = methodInfo[0];
70+
methodSignature = methodInfo[1];
6671
}
67-
this.lineNumber = lineNumber;
72+
73+
this.sourceLocation = new JavaBreakpointLocation(lineNumber, -1);
74+
this.sourceLocation.setClassName(contextClass);
75+
this.sourceLocation.setMethodName(methodName);
76+
this.sourceLocation.setMethodSignature(methodSignature);
6877
this.hitCount = hitCount;
6978
this.condition = condition;
79+
this.logMessage = logMessage;
7080
}
7181

72-
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) {
73-
this(vm, eventHub, className, lineNumber, hitCount, condition);
82+
Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
83+
this.vm = vm;
84+
this.eventHub = eventHub;
85+
this.sourceLocation = sourceLocation;
86+
this.hitCount = hitCount;
87+
this.condition = condition;
7488
this.logMessage = logMessage;
7589
}
7690

@@ -104,14 +118,24 @@ public void close() throws Exception {
104118
}
105119

106120
// IBreakpoint
121+
@Override
122+
public JavaBreakpointLocation sourceLocation() {
123+
return this.sourceLocation;
124+
}
125+
107126
@Override
108127
public String className() {
109-
return className;
128+
return this.sourceLocation.className();
110129
}
111130

112131
@Override
113132
public int getLineNumber() {
114-
return lineNumber;
133+
return this.sourceLocation.lineNumber();
134+
}
135+
136+
@Override
137+
public int getColumnNumber() {
138+
return this.sourceLocation.columnNumber();
115139
}
116140

117141
@Override
@@ -120,20 +144,20 @@ public String getCondition() {
120144
}
121145

122146
@Override
123-
public boolean equals(Object obj) {
124-
if (!(obj instanceof Breakpoint)) {
125-
return super.equals(obj);
126-
}
127-
128-
Breakpoint breakpoint = (Breakpoint) obj;
129-
return Objects.equals(this.className(), breakpoint.className())
130-
&& this.getLineNumber() == breakpoint.getLineNumber()
131-
&& Objects.equals(this.methodSignature, breakpoint.methodSignature);
147+
public int hashCode() {
148+
return Objects.hash(sourceLocation);
132149
}
133150

134151
@Override
135-
public int hashCode() {
136-
return Objects.hash(this.className, this.lineNumber, this.methodSignature);
152+
public boolean equals(Object obj) {
153+
if (this == obj) {
154+
return true;
155+
}
156+
if (!(obj instanceof Breakpoint)) {
157+
return false;
158+
}
159+
Breakpoint other = (Breakpoint) obj;
160+
return Objects.equals(sourceLocation, other.sourceLocation);
137161
}
138162

139163
@Override
@@ -149,6 +173,7 @@ public void setHitCount(int hitCount) {
149173
.filter(request -> request instanceof BreakpointRequest)
150174
.subscribe(request -> {
151175
request.addCountFilter(hitCount);
176+
request.disable();
152177
request.enable();
153178
});
154179
}
@@ -183,13 +208,13 @@ public CompletableFuture<IBreakpoint> install() {
183208
// It's possible that different class loaders create new class with the same name.
184209
// Here to listen to future class prepare events to handle such case.
185210
ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest();
186-
classPrepareRequest.addClassFilter(className);
211+
classPrepareRequest.addClassFilter(className());
187212
classPrepareRequest.enable();
188213
requests.add(classPrepareRequest);
189214

190215
// Local types also needs to be handled
191216
ClassPrepareRequest localClassPrepareRequest = vm.eventRequestManager().createClassPrepareRequest();
192-
localClassPrepareRequest.addClassFilter(className + "$*");
217+
localClassPrepareRequest.addClassFilter(className() + "$*");
193218
localClassPrepareRequest.enable();
194219
requests.add(localClassPrepareRequest);
195220

@@ -202,7 +227,7 @@ public CompletableFuture<IBreakpoint> install() {
202227
.subscribe(debugEvent -> {
203228
ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event;
204229
List<BreakpointRequest> newRequests = AsyncJdwpUtils.await(
205-
createBreakpointRequests(event.referenceType(), lineNumber, hitCount, false)
230+
createBreakpointRequests(event.referenceType(), getLineNumber(), hitCount, false)
206231
);
207232
requests.addAll(newRequests);
208233
if (!newRequests.isEmpty() && !future.isDone()) {
@@ -213,8 +238,8 @@ public CompletableFuture<IBreakpoint> install() {
213238
subscriptions.add(subscription);
214239

215240
Runnable resolveRequestsFromExistingClasses = () -> {
216-
List<ReferenceType> refTypes = vm.classesByName(className);
217-
createBreakpointRequests(refTypes, lineNumber, hitCount, true)
241+
List<ReferenceType> refTypes = vm.classesByName(className());
242+
createBreakpointRequests(refTypes, getLineNumber(), hitCount, true)
218243
.whenComplete((newRequests, ex) -> {
219244
if (ex != null) {
220245
return;
@@ -281,14 +306,13 @@ private CompletableFuture<List<Location>> collectLocations(ReferenceType refType
281306
});
282307
}
283308

284-
private CompletableFuture<List<Location>> collectLocations(List<ReferenceType> refTypes, String nameAndSignature) {
285-
String[] segments = nameAndSignature.split("#");
309+
private CompletableFuture<List<Location>> collectLocations(List<ReferenceType> refTypes, String methodName, String methodSiguature) {
286310
List<CompletableFuture<Location>> futures = new ArrayList<>();
287311
for (ReferenceType refType : refTypes) {
288312
if (async()) {
289-
futures.add(AsyncJdwpUtils.supplyAsync(() -> findMethodLocaiton(refType, segments[0], segments[1])));
313+
futures.add(AsyncJdwpUtils.supplyAsync(() -> findMethodLocaiton(refType, methodName, methodSiguature)));
290314
} else {
291-
futures.add(CompletableFuture.completedFuture(findMethodLocaiton(refType, segments[0], segments[1])));
315+
futures.add(CompletableFuture.completedFuture(findMethodLocaiton(refType, methodName, methodSiguature)));
292316
}
293317
}
294318

@@ -329,10 +353,22 @@ private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(Refe
329353
private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(List<ReferenceType> refTypes, int lineNumber,
330354
int hitCount, boolean includeNestedTypes) {
331355
CompletableFuture<List<Location>> locationsFuture;
332-
if (this.methodSignature != null) {
333-
locationsFuture = collectLocations(refTypes, this.methodSignature);
356+
if (this.sourceLocation.methodName() != null) {
357+
locationsFuture = collectLocations(refTypes, this.sourceLocation.methodName(), this.sourceLocation.methodSignature());
334358
} else {
335-
locationsFuture = collectLocations(refTypes, lineNumber, includeNestedTypes);
359+
locationsFuture = collectLocations(refTypes, lineNumber, includeNestedTypes).thenApply((locations) -> {
360+
if (locations.isEmpty()) {
361+
return locations;
362+
}
363+
364+
/**
365+
* For a line breakpoint, we default to breaking at the first location
366+
* of the line. If you want to break at other locations on the same line,
367+
* you can add an inline breakpoint based on the locations returned by
368+
* the BreakpointLocation request.
369+
*/
370+
return Arrays.asList(locations.get(0));
371+
});
336372
}
337373

338374
return locationsFuture.thenCompose((locations) -> {
@@ -389,11 +425,11 @@ private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(List
389425
}
390426

391427
private Object computeRequestType() {
392-
if (this.methodSignature == null) {
428+
if (this.sourceLocation.methodName() == null) {
393429
return IBreakpoint.REQUEST_TYPE_LINE;
394430
}
395431

396-
if (this.methodSignature.startsWith("lambda$")) {
432+
if (this.sourceLocation.methodName().startsWith("lambda$")) {
397433
return IBreakpoint.REQUEST_TYPE_LAMBDA;
398434
} else {
399435
return IBreakpoint.REQUEST_TYPE_METHOD;

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ public void terminate() {
8181
}
8282
}
8383

84+
@Override
85+
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
86+
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
87+
}
88+
8489
@Override
8590
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) {
8691
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018 Microsoft Corporation and others.
2+
* Copyright (c) 2018-2022 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -48,6 +48,12 @@ public class EvaluatableBreakpoint extends Breakpoint implements IEvaluatableBre
4848
this.eventHub = eventHub;
4949
}
5050

51+
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount,
52+
String condition, String logMessage) {
53+
super(vm, eventHub, sourceLocation, hitCount, condition, logMessage);
54+
this.eventHub = eventHub;
55+
}
56+
5157
@Override
5258
public boolean containsEvaluatableExpression() {
5359
return containsConditionalExpression() || containsLogpointExpression();

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017 Microsoft Corporation and others.
2+
* Copyright (c) 2017-2022 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -23,10 +23,14 @@ public interface IBreakpoint extends IDebugResource {
2323

2424
int REQUEST_TYPE_LAMBDA = 2;
2525

26+
JavaBreakpointLocation sourceLocation();
27+
2628
String className();
2729

2830
int getLineNumber();
2931

32+
int getColumnNumber();
33+
3034
int getHitCount();
3135

3236
void setHitCount(int hitCount);

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017 Microsoft Corporation and others.
2+
* Copyright (c) 2017-2022 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -30,6 +30,8 @@ public interface IDebugSession {
3030
// breakpoints
3131
IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage);
3232

33+
IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage);
34+
3335
IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount);
3436

3537
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught);

0 commit comments

Comments
 (0)