Skip to content

Commit eee7904

Browse files
committed
Fix breakpoints in classes with inner/anonymous classes
1 parent 6ceadac commit eee7904

6 files changed

Lines changed: 67 additions & 38 deletions

File tree

src/main/java/org/javacs/debug/JavaDebugServer.java

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ private Breakpoint enableBreakpoint(Source source, SourceBreakpoint b) {
159159
}
160160
// Check for breakpoint in loaded classes
161161
for (var type : loadedTypesMatching(source.path)) {
162-
return enableBreakpointImmediately(source, b, type);
162+
var ok = enableBreakpointImmediately(source, b, type);
163+
if (ok != null) {
164+
return ok;
165+
}
163166
}
164167
// If class hasn't been loaded, add breakpoint to pending list
165168
return enableBreakpointLater(source, b);
@@ -206,10 +209,7 @@ private Breakpoint enableDisabledBreakpoint(Source source, BreakpointRequest b)
206209

207210
private Breakpoint enableBreakpointImmediately(Source source, SourceBreakpoint b, ReferenceType type) {
208211
if (!tryEnableBreakpointImmediately(source, b, type)) {
209-
var failed = new Breakpoint();
210-
failed.verified = false;
211-
failed.message = source.name + ":" + b.line + " could not be found or had no code on it";
212-
return failed;
212+
return null;
213213
}
214214
var ok = new Breakpoint();
215215
ok.verified = true;
@@ -226,6 +226,9 @@ private boolean tryEnableBreakpointImmediately(Source source, SourceBreakpoint b
226226
LOG.info(String.format("No locations in %s for breakpoint %s:%d", type.name(), source.path, b.line));
227227
return false;
228228
}
229+
if (locations.isEmpty()) {
230+
return false;
231+
}
229232
for (var l : locations) {
230233
LOG.info(String.format("Create breakpoint %s:%d", source.path, l.lineNumber()));
231234
var req = vm.eventRequestManager().createBreakpointRequest(l);
@@ -384,48 +387,36 @@ private void enablePendingBreakpointsIn(ReferenceType type) {
384387
// Look for pending breakpoints that can be enabled
385388
var enabled = new ArrayList<Breakpoint>();
386389
for (var b : pendingBreakpoints) {
387-
if (b.source.path.endsWith(path)) {
388-
enablePendingBreakpoint(b, type);
390+
if (b.source.path.endsWith(path) && enablePendingBreakpoint(b, type)) {
389391
enabled.add(b);
390392
}
391393
}
392394
pendingBreakpoints.removeAll(enabled);
393395
}
394396

395-
private void enablePendingBreakpoint(Breakpoint b, ReferenceType type) {
397+
private boolean enablePendingBreakpoint(Breakpoint b, ReferenceType type) {
398+
List<Location> locations;
396399
try {
397-
var locations = type.locationsOfLine(b.line);
398-
for (var line : locations) {
399-
var req = vm.eventRequestManager().createBreakpointRequest(line);
400-
req.setSuspendPolicy(EventRequest.SUSPEND_ALL);
401-
req.enable();
402-
}
403-
if (locations.isEmpty()) {
404-
LOG.info("No locations at " + b.source.path + ":" + b.line);
405-
var failed = new BreakpointEventBody();
406-
failed.reason = "changed";
407-
failed.breakpoint = b;
408-
b.verified = false;
409-
b.message = b.source.name + ":" + b.line + " could not be found or had no code on it";
410-
client.breakpoint(failed);
411-
return;
412-
}
413-
LOG.info("Enable breakpoint at " + b.source.path + ":" + b.line);
414-
var ok = new BreakpointEventBody();
415-
ok.reason = "changed";
416-
ok.breakpoint = b;
417-
b.verified = true;
418-
b.message = null;
419-
client.breakpoint(ok);
400+
locations = type.locationsOfLine(b.line);
420401
} catch (AbsentInformationException __) {
421-
LOG.info("Absent information at " + b.source.path + ":" + b.line);
422-
var failed = new BreakpointEventBody();
423-
failed.reason = "changed";
424-
failed.breakpoint = b;
425-
b.verified = false;
426-
b.message = b.source.name + ":" + b.line + " could not be found or had no code on it";
427-
client.breakpoint(failed);
402+
return false;
403+
}
404+
if (locations.isEmpty()) {
405+
return false;
428406
}
407+
for (var line : locations) {
408+
var req = vm.eventRequestManager().createBreakpointRequest(line);
409+
req.setSuspendPolicy(EventRequest.SUSPEND_ALL);
410+
req.enable();
411+
}
412+
LOG.info("Enable breakpoint at " + b.source.path + ":" + b.line);
413+
var ok = new BreakpointEventBody();
414+
ok.reason = "changed";
415+
ok.breakpoint = b;
416+
b.verified = true;
417+
b.message = null;
418+
client.breakpoint(ok);
419+
return true;
429420
}
430421

431422
private String relativePath(ReferenceType type) {
777 Bytes
Binary file not shown.
657 Bytes
Binary file not shown.
678 Bytes
Binary file not shown.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
public class InnerClasses {
2+
public static void main(String[] args) {
3+
System.out.println("at main");
4+
new Inner().run();
5+
}
6+
7+
// An inner class:
8+
private static class Inner {
9+
public void run() {
10+
System.out.println("at Inner.run");
11+
// An anonymous class:
12+
new Runnable() {
13+
@Override
14+
public void run() {
15+
System.out.println("at Runnable.run");
16+
}
17+
}.run();
18+
}
19+
}
20+
}

src/test/java/org/javacs/JavaDebugServerTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,5 +361,23 @@ public void printCollections() throws IOException, InterruptedException {
361361
process.waitFor();
362362
}
363363

364+
@Test
365+
public void setBreakpointInnerClasses() throws IOException, InterruptedException {
366+
launchProcess("InnerClasses");
367+
// Attach to the process
368+
attach(5005);
369+
// Set breakpoints
370+
setBreakpoint("InnerClasses", 3); // at main
371+
setBreakpoint("InnerClasses", 10); // at Inner.run
372+
setBreakpoint("InnerClasses", 15); // at Runnable.run
373+
server.configurationDone();
374+
// Should stop 3 times
375+
for (int i = 0; i < 3; i++) {
376+
stoppedEvents.take();
377+
server.continue_(new ContinueArguments());
378+
}
379+
process.waitFor();
380+
}
381+
364382
private static final Logger LOG = Logger.getLogger("main");
365383
}

0 commit comments

Comments
 (0)