author | Jason Laster <jlaster@mozilla.com> |
Tue, 12 Mar 2019 21:07:43 +0000 | |
changeset 524600 | 6226618708d29c9bd5c4addb8dfe006ac40cab62 |
parent 524599 | 2f068b111006dfcd21caa9d10579a5569c8ea48c |
child 524601 | 356a982f5ba41e6f091023a4fd5aaf5c6532f929 |
push id | 2032 |
push user | ffxbld-merge |
push date | Mon, 13 May 2019 09:36:57 +0000 |
treeherder | mozilla-release@455c1065dcbe [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | loganfsmyth |
bugs | 1534332 |
milestone | 67.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js @@ -92,17 +92,27 @@ async function _setBreakpointPositions(s } } else { results = await client.getBreakpointPositions(generatedSource); } let positions = convertToList(results, generatedSource); positions = await mapLocations(positions, thunkArgs); positions = filterByUniqLocation(positions); - dispatch({ type: "ADD_BREAKPOINT_POSITIONS", sourceId, positions }); + + const source = getSource(getState(), sourceId); + // NOTE: it's possible that the source was removed during a navigate + if (!source) { + return; + } + dispatch({ + type: "ADD_BREAKPOINT_POSITIONS", + source: source, + positions + }); } export function setBreakpointPositions(sourceId: string) { return async (thunkArgs: ThunkArgs) => { const { getState } = thunkArgs; if (hasBreakpointPositions(getState(), sourceId)) { return getBreakpointPositionsForSource(getState(), sourceId); }
--- a/devtools/client/debugger/new/src/actions/breakpoints/index.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/index.js @@ -12,32 +12,32 @@ import { PROMISE } from "../utils/middleware/promise"; import { getBreakpoint, getBreakpointsList, getXHRBreakpoints, getSelectedSource, getBreakpointAtLocation, getConditionalPanelLocation, - getBreakpointsForSource + getBreakpointsForSource, + isEmptyLineInSource } from "../../selectors"; import { assertBreakpoint, createXHRBreakpoint, makeBreakpointLocation } from "../../utils/breakpoint"; import { addBreakpoint, addHiddenBreakpoint, enableBreakpoint } from "./addBreakpoint"; import remapLocations from "./remapLocations"; import { syncBreakpoint } from "./syncBreakpoint"; import { closeConditionalPanel } from "../ui"; -import { isEmptyLineInSource } from "../../reducers/ast"; // this will need to be changed so that addCLientBreakpoint is removed import type { ThunkArgs, Action } from "../types"; import type { Breakpoint, BreakpointOptions, Source,
--- a/devtools/client/debugger/new/src/actions/types/BreakpointAction.js +++ b/devtools/client/debugger/new/src/actions/types/BreakpointAction.js @@ -3,16 +3,17 @@ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ // @flow import type { Breakpoint, SourceLocation, XHRBreakpoint, + Source, BreakpointPositions } from "../../types"; import type { PromiseAction } from "../utils/middleware/promise"; export type BreakpointAction = | PromiseAction< {| @@ -90,10 +91,10 @@ export type BreakpointAction = |} | {| +type: "REMAP_BREAKPOINTS", +breakpoints: Breakpoint[] |} | {| type: "ADD_BREAKPOINT_POSITIONS", positions: BreakpointPositions, - sourceId: string + source: Source |};
--- a/devtools/client/debugger/new/src/reducers/ast.js +++ b/devtools/client/debugger/new/src/reducers/ast.js @@ -161,25 +161,16 @@ export function isSymbolsLoading(state: export function getOutOfScopeLocations(state: OuterState) { return state.ast.outOfScopeLocations; } export function getPreview(state: OuterState) { return state.ast.preview; } -export function isEmptyLineInSource( - state: OuterState, - line: number, - selectedSourceId: string -) { - const emptyLines = getEmptyLines(state, selectedSourceId); - return emptyLines && emptyLines.includes(line); -} - const emptySourceMetaData = {}; export function getSourceMetaData(state: OuterState, sourceId: string) { return state.ast.sourceMetaData[sourceId] || emptySourceMetaData; } export function hasSourceMetaData(state: OuterState, sourceId: string) { return state.ast.sourceMetaData[sourceId]; } @@ -188,17 +179,9 @@ export function getInScopeLines(state: O return state.ast.inScopeLines; } export function isLineInScope(state: OuterState, line: number) { const linesInScope = state.ast.inScopeLines; return linesInScope && linesInScope.includes(line); } -export function getEmptyLines(state: OuterState, sourceId: string) { - if (!sourceId) { - return null; - } - - return state.ast.emptyLines[sourceId]; -} - export default update;
--- a/devtools/client/debugger/new/src/reducers/breakpoints.js +++ b/devtools/client/debugger/new/src/reducers/breakpoints.js @@ -8,16 +8,17 @@ * Breakpoints reducer * @module reducers/breakpoints */ import { isGeneratedId, isOriginalId } from "devtools-source-map"; import { isEqual } from "lodash"; import { makeBreakpointId } from "../utils/breakpoint"; +import { findEmptyLines } from "../utils/empty-lines"; import type { XHRBreakpoint, Breakpoint, BreakpointId, SourceLocation, BreakpointPositions } from "../types"; @@ -26,27 +27,29 @@ import type { Action, DonePromiseAction export type BreakpointsMap = { [BreakpointId]: Breakpoint }; export type XHRBreakpointsList = $ReadOnlyArray<XHRBreakpoint>; export type BreakpointPositionsMap = { [string]: BreakpointPositions }; export type BreakpointsState = { breakpoints: BreakpointsMap, breakpointPositions: BreakpointPositionsMap, xhrBreakpoints: XHRBreakpointsList, - breakpointsDisabled: boolean + breakpointsDisabled: boolean, + emptyLines: { [string]: number[] } }; export function initialBreakpointsState( xhrBreakpoints?: XHRBreakpointsList = [] ): BreakpointsState { return { breakpoints: {}, xhrBreakpoints: xhrBreakpoints, breakpointPositions: {}, - breakpointsDisabled: false + breakpointsDisabled: false, + emptyLines: {} }; } function update( state: BreakpointsState = initialBreakpointsState(), action: Action ): BreakpointsState { switch (action.type) { @@ -106,22 +109,28 @@ function update( return updateXHRBreakpoint(state, action); } case "DISABLE_XHR_BREAKPOINT": { return updateXHRBreakpoint(state, action); } case "ADD_BREAKPOINT_POSITIONS": { - const { sourceId, positions } = action; + const { source, positions } = action; + const emptyLines = findEmptyLines(source, positions); + return { ...state, breakpointPositions: { ...state.breakpointPositions, - [sourceId]: positions + [source.id]: positions + }, + emptyLines: { + ...state.emptyLines, + [source.id]: emptyLines } }; } } return state; } @@ -378,9 +387,26 @@ export function getBreakpointPositionsFo return null; } return positions.filter(({ location, generatedLocation }) => { const loc = isOriginalId(sourceId) ? location : generatedLocation; return loc.line == line; }); } +export function isEmptyLineInSource( + state: OuterState, + line: number, + selectedSourceId: string +) { + const emptyLines = getEmptyLines(state, selectedSourceId); + return emptyLines && emptyLines.includes(line); +} + +export function getEmptyLines(state: OuterState, sourceId: string) { + if (!sourceId) { + return null; + } + + return state.breakpoints.emptyLines[sourceId]; +} + export default update;
new file mode 100644 --- /dev/null +++ b/devtools/client/debugger/new/src/utils/empty-lines.js @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import { xor, range } from "lodash"; +import { getSelectedLocation } from "./source-maps"; +import type { BreakpointPositions, Source } from "../types"; + +export function findEmptyLines( + source: Source, + breakpointPositions: BreakpointPositions +): number[] { + if (!breakpointPositions || source.isWasm) { + return []; + } + + const sourceText = source.text || ""; + const lineCount = sourceText.split("\n").length; + const sourceLines = range(1, lineCount + 1); + + const breakpointLines = breakpointPositions + .map(point => getSelectedLocation(point, source).line) + // NOTE: at the moment it is possible the location is an unmapped generated + // line which could be greater than the line count. + .filter(line => line <= lineCount); + + return xor(sourceLines, breakpointLines); +}
--- a/devtools/client/debugger/new/src/utils/moz.build +++ b/devtools/client/debugger/new/src/utils/moz.build @@ -16,16 +16,17 @@ CompiledModules( 'asyncStoreHelper.js', 'bootstrap.js', 'build-query.js', 'clipboard.js', 'connect.js', 'dbg.js', 'defer.js', 'DevToolsUtils.js', + 'empty-lines.js', 'expressions.js', 'fromJS.js', 'function.js', 'indentation.js', 'isMinified.js', 'location.js', 'log.js', 'makeRecord.js',
new file mode 100644 --- /dev/null +++ b/devtools/client/debugger/new/src/utils/tests/empty-lines.spec.js @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import { findEmptyLines } from "../empty-lines"; +import { makeSource } from "../test-head"; + +function ml(gLine) { + const generatedLocation = { line: gLine, column: 0, sourceId: "foo" }; + return { generatedLocation, location: generatedLocation }; +} + +describe("emptyLines", () => { + it("no positions", () => { + const source = makeSource("foo", { text: "\n" }); + const lines = findEmptyLines(source, []); + expect(lines).toEqual([1, 2]); + }); + + it("one position", () => { + const source = makeSource("foo", { text: "\n" }); + const lines = findEmptyLines(source, [ml(1)]); + expect(lines).toEqual([2]); + }); + + it("outside positions are not included", () => { + const source = makeSource("foo", { text: "\n" }); + const lines = findEmptyLines(source, [ml(10)]); + expect(lines).toEqual([1, 2]); + }); +});
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints.js @@ -30,16 +30,30 @@ function disableBreakpoints(dbg, count) } function enableBreakpoints(dbg, count) { const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT", count); toggleBreakpoints(dbg); return enabled; } +function every(array, predicate) { + return !array.some(item => !predicate(item)); +} + +function subset(subArray, superArray) { + return every(subArray, subItem => superArray.includes(subItem)); +} + +function assertEmptyLines(dbg, lines) { + const sourceId = dbg.selectors.getSelectedSourceId(dbg.store.getState()); + const emptyLines = dbg.selectors.getEmptyLines(dbg.store.getState(), sourceId); + ok(subset(lines, emptyLines), 'empty lines should match'); +} + // Test enabling and disabling a breakpoint using the check boxes add_task(async function() { const dbg = await initDebugger("doc-scripts.html", "simple2"); // Create two breakpoints await selectSource(dbg, "simple2"); await addBreakpoint(dbg, "simple2", 3); await addBreakpoint(dbg, "simple2", 5); @@ -60,16 +74,18 @@ add_task(async function() { // Test enabling and disabling a breakpoint using the context menu add_task(async function() { const dbg = await initDebugger("doc-scripts.html"); await selectSource(dbg, "simple2"); await addBreakpoint(dbg, "simple2", 3); await addBreakpoint(dbg, "simple2", 5); + assertEmptyLines(dbg, [1,2]); + rightClickElement(dbg, "breakpointItem", 3); const disableBreakpointDispatch = waitForDispatch(dbg, "DISABLE_BREAKPOINT"); selectContextMenuItem(dbg, selectors.breakpointContextMenu.disableSelf); await disableBreakpointDispatch; let bp1 = findBreakpoint(dbg, "simple2", 3); let bp2 = findBreakpoint(dbg, "simple2", 5); is(bp1.disabled, true, "first breakpoint is disabled");