diff --git a/devtools/server/actors/breakpoint.js b/devtools/server/actors/breakpoint.js index f299bd51d285..a0742421aa6d 100644 --- a/devtools/server/actors/breakpoint.js +++ b/devtools/server/actors/breakpoint.js @@ -191,8 +191,7 @@ BreakpointActor.prototype = { if ( this.threadActor.sources.isBlackBoxed(sourceActor.url, line, column) || - this.threadActor.skipBreakpoints || - frame.onStep + this.threadActor.skipBreakpoints ) { return undefined; } diff --git a/devtools/server/actors/common.js b/devtools/server/actors/common.js index 865a2379f2c9..f4fad306d258 100644 --- a/devtools/server/actors/common.js +++ b/devtools/server/actors/common.js @@ -145,6 +145,10 @@ SourceLocation.prototype = { return this._lastColumn; }, + get sourceUrl() { + return this.sourceActor.url; + }, + equals: function(other) { return ( this.sourceActor.url == other.sourceActor.url && diff --git a/devtools/server/actors/thread.js b/devtools/server/actors/thread.js index d42e64d63f20..41dedb35b954 100644 --- a/devtools/server/actors/thread.js +++ b/devtools/server/actors/thread.js @@ -929,7 +929,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, { // Continue if: // 1. the location is not a valid breakpoint position // 2. the source is not blackboxed - // 3. has not moved + // 3. we have not moved since the last pause if ( !meta.isBreakpoint || this.sources.isFrameBlackBoxed(frame) || @@ -944,6 +944,11 @@ const ThreadActor = ActorClassWithSpec(threadSpec, { return frame !== startFrame || meta.isStepStart; }, + atBreakpointLocation(frame) { + const location = this.sources.getFrameLocation(frame); + return !!this.breakpointActorMap.get(location); + }, + createCompletionGrip: function(packet, completion) { if (!completion) { return packet; @@ -1760,16 +1765,17 @@ const ThreadActor = ActorClassWithSpec(threadSpec, { */ onDebuggerStatement: function(frame) { const location = this.sources.getFrameLocation(frame); - const url = location.sourceActor.url; // Don't pause if - // 1. the debugger is in the same position + // 1. we have not moved since the last pause // 2. breakpoints are disabled // 3. the source is blackboxed + // 4. there is a breakpoint at the same location if ( !this.hasMoved(frame, "debuggerStatement") || this.skipBreakpoints || - this.sources.isBlackBoxed(url) + this.sources.isBlackBoxed(location.sourceUrl) || + this.atBreakpointLocation(frame) ) { return undefined; } diff --git a/devtools/server/actors/utils/breakpoint-actor-map.js b/devtools/server/actors/utils/breakpoint-actor-map.js index a0ad07517680..bcf25459a979 100644 --- a/devtools/server/actors/utils/breakpoint-actor-map.js +++ b/devtools/server/actors/utils/breakpoint-actor-map.js @@ -53,6 +53,11 @@ BreakpointActorMap.prototype = { return this._actors[key]; }, + get(location) { + const key = this._locationKey(location); + return this._actors[key]; + }, + /** * Delete the BreakpointActor from the given location in this * BreakpointActorMap. diff --git a/devtools/server/tests/unit/test_breakpoint-13.js b/devtools/server/tests/unit/test_breakpoint-13.js index 36ebbbdd57f2..710703449175 100644 --- a/devtools/server/tests/unit/test_breakpoint-13.js +++ b/devtools/server/tests/unit/test_breakpoint-13.js @@ -17,7 +17,10 @@ add_task( ); const source = await getSourceById(threadFront, packet.frame.where.actor); - await threadFront.setBreakpoint({ sourceUrl: source.url, line: 3 }, {}); + await threadFront.setBreakpoint( + { sourceUrl: source.url, line: 3, column: 6 }, + {} + ); info("Check that the stepping worked."); const packet1 = await stepIn(threadFront); diff --git a/devtools/server/tests/unit/test_breakpoint-24.js b/devtools/server/tests/unit/test_breakpoint-24.js index fb4758ae9d01..d302fb053944 100644 --- a/devtools/server/tests/unit/test_breakpoint-24.js +++ b/devtools/server/tests/unit/test_breakpoint-24.js @@ -110,7 +110,7 @@ async function testBreakpoints({ threadFront, targetFront }) { ); threadFront.setBreakpoint( - { sourceUrl: "http://example.com/testBreakpoints.js", line: 3 }, + { sourceUrl: "http://example.com/testBreakpoints.js", line: 3, column: 6 }, {} ); diff --git a/devtools/server/tests/unit/test_breakpoint-26.js b/devtools/server/tests/unit/test_breakpoint-26.js new file mode 100644 index 000000000000..28e4362fa851 --- /dev/null +++ b/devtools/server/tests/unit/test_breakpoint-26.js @@ -0,0 +1,67 @@ +/* eslint-disable max-nested-callbacks */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Bug 925269 - Verify that debugger statements are skipped + * if there is a falsey conditional breakpoint at the same location. + */ +add_task( + threadFrontTest(async props => { + await testBreakpointsAndDebuggerStatements(props); + }) +); + +async function testBreakpointsAndDebuggerStatements({ + threadFront, + targetFront, +}) { + const consoleFront = await targetFront.getFront("console"); + consoleFront.evaluateJSAsync( + `function foo(stop) { + debugger; + debugger; + debugger; + } + foo(); + //# sourceURL=http://example.com/testBreakpointsAndDebuggerStatements.js` + ); + + threadFront.setBreakpoint( + { + sourceUrl: "http://example.com/testBreakpointsAndDebuggerStatements.js", + line: 3, + column: 6, + }, + { condition: "false" } + ); + + await performActions(threadFront, [ + [ + "paused at first debugger statement", + { line: 2, type: "debuggerStatement" }, + "resume", + ], + [ + "pause at the third debugger statement", + { line: 4, type: "debuggerStatement" }, + "resume", + ], + ]); +} + +async function performActions(threadFront, actions) { + for (const action of actions) { + await performAction(threadFront, action); + } +} + +async function performAction(threadFront, [description, result, action]) { + info(description); + const packet = await waitForEvent(threadFront, "paused"); + Assert.equal(packet.frame.where.line, result.line); + Assert.equal(packet.why.type, result.type); + await threadFront[action](); +} diff --git a/devtools/server/tests/unit/xpcshell.ini b/devtools/server/tests/unit/xpcshell.ini index 031ca4aa9c11..9310dd314d96 100644 --- a/devtools/server/tests/unit/xpcshell.ini +++ b/devtools/server/tests/unit/xpcshell.ini @@ -136,6 +136,7 @@ skip-if = true # breakpoint sliding is not supported bug 1525685 [test_breakpoint-23.js] [test_breakpoint-24.js] [test_breakpoint-25.js] +[test_breakpoint-26.js] [test_conditional_breakpoint-01.js] [test_conditional_breakpoint-02.js] [test_conditional_breakpoint-03.js]