Bug 755346 - Global variables are not displayed in the debugger frontend; r=vporof,rcampbell

This commit is contained in:
Panos Astithas 2012-05-29 12:08:20 +03:00
Родитель 6d14db1293
Коммит d342aa7757
20 изменённых файлов: 756 добавлений и 274 удалений

Просмотреть файл

@ -418,9 +418,11 @@ StackFrames.prototype = {
_onFrames: function SF__onFrames() {
if (!this.activeThread.cachedFrames.length) {
DebuggerView.StackFrames.emptyText();
DebuggerView.Properties.emptyText();
return;
}
DebuggerView.StackFrames.empty();
DebuggerView.Properties.empty();
for each (let frame in this.activeThread.cachedFrames) {
this._addFrame(frame);
@ -451,8 +453,7 @@ StackFrames.prototype = {
_afterFramesCleared: function SF__afterFramesCleared() {
if (!this.activeThread.cachedFrames.length) {
DebuggerView.StackFrames.emptyText();
DebuggerView.Properties.localScope.empty();
DebuggerView.Properties.globalScope.empty();
DebuggerView.Properties.emptyText();
DebuggerController.dispatchEvent("Debugger:AfterFramesCleared");
}
},
@ -521,39 +522,76 @@ StackFrames.prototype = {
// Start recording any added variables or properties in any scope.
DebuggerView.Properties.createHierarchyStore();
// Display the local variables.
let localScope = DebuggerView.Properties.localScope;
localScope.empty();
// Add "this".
if (frame.this) {
let thisVar = localScope.addVar("this");
thisVar.setGrip({
type: frame.this.type,
class: frame.this.class
});
this._addExpander(thisVar, frame.this);
}
DebuggerView.Properties.empty();
if (frame.environment) {
// Add nodes for every argument.
let variables = frame.environment.bindings.arguments;
for each (let variable in variables) {
let name = Object.getOwnPropertyNames(variable)[0];
let paramVar = localScope.addVar(name);
let paramVal = variable[name].value;
paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal);
}
let env = frame.environment;
// Add nodes for every other variable in scope.
variables = frame.environment.bindings.variables;
for (let variable in variables) {
let paramVar = localScope.addVar(variable);
let paramVal = variables[variable].value;
paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal);
}
do {
// Construct the scope name.
let name = env.type.charAt(0).toUpperCase() + env.type.slice(1);
// Call the outermost scope Global.
if (!env.parent) {
name = L10N.getStr("globalScopeLabel");
}
let label = L10N.getFormatStr("scopeLabel", [name]);
switch (env.type) {
case "with":
case "object":
label += " [" + env.object.class + "]";
break;
case "function":
if (env.functionName) {
label += " [" + env.functionName + "]";
}
break;
default:
break;
}
let scope = DebuggerView.Properties.addScope(label);
// Add "this" to the innermost scope.
if (frame.this && env == frame.environment) {
let thisVar = scope.addVar("this");
thisVar.setGrip({
type: frame.this.type,
class: frame.this.class
});
this._addExpander(thisVar, frame.this);
// Expand the innermost scope by default.
scope.expand();
}
switch (env.type) {
case "with":
case "object":
let objClient = this.activeThread.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function SF_getProps(aResponse) {
this._addScopeVariables(aResponse.ownProperties, scope);
// Signal that variables have been fetched.
DebuggerController.dispatchEvent("Debugger:FetchedVariables");
}.bind(this));
break;
case "block":
case "function":
// Add nodes for every argument.
let variables = env.bindings.arguments;
for each (let variable in variables) {
let name = Object.getOwnPropertyNames(variable)[0];
let paramVar = scope.addVar(name);
let paramVal = variable[name].value;
paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal);
}
// Add nodes for every other variable in scope.
this._addScopeVariables(env.bindings.variables, scope);
break;
default:
Cu.reportError("Unknown Debugger.Environment type: " + env.type);
break;
}
} while (env = env.parent);
}
// Signal that variables have been fetched.
@ -567,6 +605,31 @@ StackFrames.prototype = {
DebuggerView.Properties.commitHierarchy();
},
/**
* Add nodes for every variable in scope.
*
* @param object aVariables
* The map of names to variables, as specified in the Remote
* Debugging Protocol.
* @param object aScope
* The scope where the nodes will be placed into.
*/
_addScopeVariables: function SF_addScopeVariables(aVariables, aScope) {
// Sort all of the variables before adding them, for better UX.
let variables = {};
for each (let prop in Object.keys(aVariables).sort()) {
variables[prop] = aVariables[prop];
}
// Add the sorted variables to the specified scope.
for (let variable in variables) {
let paramVar = aScope.addVar(variable);
let paramVal = variables[variable].value;
paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal);
}
},
/**
* Adds an 'onexpand' callback for a variable, lazily handling the addition of
* new properties.

Просмотреть файл

@ -760,12 +760,17 @@ StackFramesView.prototype = {
* Functions handling the properties view.
*/
function PropertiesView() {
this._addScope = this._addScope.bind(this);
this.addScope = this._addScope.bind(this);
this._addVar = this._addVar.bind(this);
this._addProperties = this._addProperties.bind(this);
}
PropertiesView.prototype = {
/**
* A monotonically-increasing counter, that guarantees the uniqueness of scope
* IDs.
*/
_idCount: 1,
/**
* Adds a scope to contain any inspected variables.
@ -786,8 +791,8 @@ PropertiesView.prototype = {
return null;
}
// Compute the id of the element if not specified.
aId = aId || (aName.toLowerCase().trim().replace(" ", "-") + "-scope");
// Generate a unique id for the element, if not specified.
aId = aId || aName.toLowerCase().trim().replace(" ", "-") + this._idCount++;
// Contains generic nodes and functionality.
let element = this._createPropertyElement(aName, aId, "scope", this._vars);
@ -806,6 +811,32 @@ PropertiesView.prototype = {
return element;
},
/**
* Removes all added scopes in the property container tree.
*/
empty: function DVP_empty() {
while (this._vars.firstChild) {
this._vars.removeChild(this._vars.firstChild);
}
},
/**
* Removes all elements from the variables container, and adds a child node
* with an empty text note attached.
*/
emptyText: function DVP_emptyText() {
// Make sure the container is empty first.
this.empty();
let item = document.createElement("label");
// The empty node should look grayed out to avoid confusion.
item.className = "list-item empty";
item.setAttribute("value", L10N.getStr("emptyVariablesText"));
this._vars.appendChild(item);
},
/**
* Adds a variable to a specified scope.
* If the optional id is not specified, the variable html node will have a
@ -1685,103 +1716,11 @@ PropertiesView.prototype = {
_currHierarchy: null,
_prevHierarchy: null,
/**
* Returns the global scope container.
*/
get globalScope() {
return this._globalScope;
},
/**
* Sets the display mode for the global scope container.
*
* @param boolean aFlag
* False to hide the container, true to show.
*/
set globalScope(aFlag) {
if (aFlag) {
this._globalScope.show();
} else {
this._globalScope.hide();
}
},
/**
* Returns the local scope container.
*/
get localScope() {
return this._localScope;
},
/**
* Sets the display mode for the local scope container.
*
* @param boolean aFlag
* False to hide the container, true to show.
*/
set localScope(aFlag) {
if (aFlag) {
this._localScope.show();
} else {
this._localScope.hide();
}
},
/**
* Returns the with block scope container.
*/
get withScope() {
return this._withScope;
},
/**
* Sets the display mode for the with block scope container.
*
* @param boolean aFlag
* False to hide the container, true to show.
*/
set withScope(aFlag) {
if (aFlag) {
this._withScope.show();
} else {
this._withScope.hide();
}
},
/**
* Returns the closure scope container.
*/
get closureScope() {
return this._closureScope;
},
/**
* Sets the display mode for the with block scope container.
*
* @param boolean aFlag
* False to hide the container, true to show.
*/
set closureScope(aFlag) {
if (aFlag) {
this._closureScope.show();
} else {
this._closureScope.hide();
}
},
/**
* The cached variable properties container.
*/
_vars: null,
/**
* Auto-created global, local, with block and closure scopes containing vars.
*/
_globalScope: null,
_localScope: null,
_withScope: null,
_closureScope: null,
/**
* Initialization function, called when the debugger is initialized.
*/
@ -1789,10 +1728,6 @@ PropertiesView.prototype = {
this.createHierarchyStore();
this._vars = document.getElementById("variables");
this._localScope = this._addScope(L10N.getStr("localScope")).expand();
this._withScope = this._addScope(L10N.getStr("withScope")).hide();
this._closureScope = this._addScope(L10N.getStr("closureScope")).hide();
this._globalScope = this._addScope(L10N.getStr("globalScope"));
},
/**
@ -1802,10 +1737,6 @@ PropertiesView.prototype = {
this._currHierarchy = null;
this._prevHierarchy = null;
this._vars = null;
this._globalScope = null;
this._localScope = null;
this._withScope = null;
this._closureScope = null;
}
};

Просмотреть файл

@ -30,6 +30,8 @@ _BROWSER_TEST_FILES = \
browser_dbg_propertyview-06.js \
browser_dbg_propertyview-07.js \
browser_dbg_propertyview-08.js \
browser_dbg_propertyview-09.js \
browser_dbg_propertyview-10.js \
browser_dbg_propertyview-edit.js \
browser_dbg_panesize.js \
browser_dbg_stack-01.js \
@ -66,6 +68,7 @@ _BROWSER_TEST_PAGES = \
test-editor-mode \
browser_dbg_displayName.html \
browser_dbg_iframes.html \
browser_dbg_with-frame.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

Просмотреть файл

@ -23,65 +23,14 @@ function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let globalScope = gDebugger.DebuggerView.Properties._globalScope;
let localScope = gDebugger.DebuggerView.Properties._localScope;
let withScope = gDebugger.DebuggerView.Properties._withScope;
let closureScope = gDebugger.DebuggerView.Properties._closureScope;
ok(globalScope,
"Should have a globalScope container for the variables property view.");
ok(localScope,
"Should have a localScope container for the variables property view.");
ok(withScope,
"Should have a withScope container for the variables property view.");
ok(closureScope,
"Should have a closureScope container for the variables property view.");
is(globalScope, gDebugger.DebuggerView.Properties.globalScope,
"The globalScope object should be equal to the corresponding getter.");
is(localScope, gDebugger.DebuggerView.Properties.localScope,
"The localScope object should be equal to the corresponding getter.");
is(withScope, gDebugger.DebuggerView.Properties.withScope,
"The withScope object should be equal to the corresponding getter.");
is(closureScope, gDebugger.DebuggerView.Properties.closureScope,
"The closureScope object should be equal to the corresponding getter.");
ok(!globalScope.expanded,
"The globalScope should be initially collapsed.");
ok(localScope.expanded,
"The localScope should be initially expanded.");
ok(!withScope.expanded,
"The withScope should be initially collapsed.");
ok(!withScope.visible,
"The withScope should be initially hidden.");
ok(!closureScope.expanded,
"The closureScope should be initially collapsed.");
ok(!closureScope.visible,
"The closureScope should be initially hidden.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
"Should have only 4 scopes created: global, local, with and scope.");
resumeAndFinish();
testScriptLabelShortening();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
function testScriptLabelShortening() {
gDebugger.DebuggerController.activeThread.resume(function() {
let vs = gDebugger.DebuggerView.Scripts;
let ss = gDebugger.DebuggerController.SourceScripts;

Просмотреть файл

@ -28,7 +28,7 @@ function testSimpleCall() {
ok(testScope,
"Should have created a scope.");
is(testScope.id, "test-scope",
is(testScope.id.substring(0, 4), "test",
"The newly created scope should have the default id set.");
is(testScope.querySelector(".name").getAttribute("value"), "test",
@ -37,8 +37,8 @@ function testSimpleCall() {
is(testScope.querySelector(".details").childNodes.length, 0,
"Any new scope should have a container with no child nodes.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 5,
"Should have 5 scopes created: global, local, with, closure and test.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 3,
"Should have 3 scopes created.");
ok(!testScope.expanded,

Просмотреть файл

@ -23,7 +23,7 @@ function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
let testScope = gDebugger.DebuggerView.Properties._addScope("test-scope");
let testVar = testScope.addVar("something");
let duplVar = testScope.addVar("something");
@ -33,9 +33,6 @@ function testSimpleCall() {
is(duplVar, null,
"Shouldn't be able to duplicate variables in the same scope.");
is(testVar.id, "test-scope->something-variable",
"The newly created scope should have the default id set.");
is(testVar.querySelector(".name").getAttribute("value"), "something",
"Any new variable should have the designated title.");
@ -188,7 +185,7 @@ function testSimpleCall() {
is(removeCallbackSender, testScope,
"The removeCallback wasn't called as it should.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 2,
"The scope should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {

Просмотреть файл

@ -23,8 +23,8 @@ function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
let localScope = gDebugger.DebuggerView.Properties.localScope;
let globalScope = gDebugger.DebuggerView.Properties.addScope("Global");
let localScope = gDebugger.DebuggerView.Properties.addScope("Local");
globalScope.empty();
localScope.empty();

Просмотреть файл

@ -37,7 +37,7 @@ function testFrameParameters()
var frames = gDebugger.DebuggerView.StackFrames._frames,
childNodes = frames.childNodes,
localScope = gDebugger.DebuggerView.Properties.localScope,
localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
localNodes = localScope.querySelector(".details").childNodes;
dump("Got our variables:\n");
@ -79,14 +79,14 @@ function testFrameParameters()
is(localNodes[7].querySelector(".value").getAttribute("value"), "1",
"Should have the right property value for 'a'.");
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'b'.");
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[9].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
"Should have the right property value for 'b'.");
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
resumeAndFinish();
}}, 0);

Просмотреть файл

@ -36,7 +36,7 @@ function testFrameParameters()
dump("After currentThread.dispatch!\n");
var frames = gDebugger.DebuggerView.StackFrames._frames,
localScope = gDebugger.DebuggerView.Properties.localScope,
localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
localNodes = localScope.querySelector(".details").childNodes;
dump("Got our variables:\n");
@ -59,7 +59,7 @@ function testFrameParameters()
// Expand the 'this', 'arguments' and 'c' tree nodes. This causes
// their properties to be retrieved and displayed.
localNodes[0].expand();
localNodes[9].expand();
localNodes[8].expand();
localNodes[10].expand();
// Poll every few milliseconds until the properties are retrieved.
@ -73,7 +73,7 @@ function testFrameParameters()
resumeAndFinish();
}
if (!localNodes[0].fetched ||
!localNodes[9].fetched ||
!localNodes[8].fetched ||
!localNodes[10].fetched) {
return;
}
@ -86,29 +86,29 @@ function testFrameParameters()
.getAttribute("value").search(/object/) != -1,
"__proto__ should be an object.");
is(localNodes[9].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
is(localNodes[9].querySelectorAll(".property > .title > .key")[1]
.getAttribute("value"), "a",
"Should have the right property name for 'a'.");
is(localNodes[9].querySelectorAll(".property > .title > .value")[1]
.getAttribute("value"), 1,
"Should have the right value for 'c.a'.");
is(localNodes[10].querySelector(".value").getAttribute("value"),
is(localNodes[8].querySelector(".value").getAttribute("value"),
"[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[10].querySelectorAll(".property > .title > .key")[7]
is(localNodes[8].querySelectorAll(".property > .title > .key")[7]
.getAttribute("value"), "length",
"Should have the right property name for 'length'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[7]
is(localNodes[8].querySelectorAll(".property > .title > .value")[7]
.getAttribute("value"), 5,
"Should have the right argument length.");
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
is(localNodes[10].querySelectorAll(".property > .title > .key")[1]
.getAttribute("value"), "a",
"Should have the right property name for 'a'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[1]
.getAttribute("value"), 1,
"Should have the right value for 'c.a'.");
resumeAndFinish();
}, 100);
}}, 0);

Просмотреть файл

@ -0,0 +1,94 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the property view populates the global scope pane.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
var gPane = null;
var gTab = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.contentWindow;
testFrameParameters();
});
}
function testFrameParameters()
{
let count = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
// We expect 2 Debugger:FetchedVariables events, one from the global object
// scope and the regular one.
if (++count <2) {
info("Number of received Debugger:FetchedVariables events: " + count);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._frames,
globalScope = gDebugger.DebuggerView.Properties._vars.lastChild,
globalNodes = globalScope.querySelector(".details").childNodes;
globalScope.expand();
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
"Should have three frames.");
is(globalNodes[0].querySelector(".name").getAttribute("value"), "Array",
"Should have the right property name for |Array|.");
is(globalNodes[0].querySelector(".value").getAttribute("value"), "[object Function]",
"Should have the right property value for |Array|.");
let len = globalNodes.length - 1;
is(globalNodes[len].querySelector(".name").getAttribute("value"), "window",
"Should have the right property name for |window|.");
is(globalNodes[len].querySelector(".value").getAttribute("value"), "[object Proxy]",
"Should have the right property value for |window|.");
resumeAndFinish();
}}, 0);
}, false);
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content.window);
}
function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._frames;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
}}, 0);
}, true);
gDebugger.DebuggerController.activeThread.resume();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

Просмотреть файл

@ -0,0 +1,105 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the property view is correctly populated in |with| frames.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
var gPane = null;
var gTab = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.contentWindow;
testWithFrame();
});
}
function testWithFrame()
{
let count = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
// We expect 4 Debugger:FetchedVariables events, one from the global object
// scope, two from the |with| scopes and the regular one.
if (++count <3) {
info("Number of received Debugger:FetchedVariables events: " + count);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._frames,
scopes = gDebugger.DebuggerView.Properties._vars,
globalScope = scopes.lastChild,
innerScope = scopes.firstChild,
globalNodes = globalScope.querySelector(".details").childNodes,
innerNodes = innerScope.querySelector(".details").childNodes;
globalScope.expand();
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
"Should have three frames.");
is(scopes.children.length, 5, "Should have 5 variable scopes.");
is(innerNodes[1].querySelector(".name").getAttribute("value"), "one",
"Should have the right property name for |one|.");
is(innerNodes[1].querySelector(".value").getAttribute("value"), "1",
"Should have the right property value for |one|.");
is(globalNodes[0].querySelector(".name").getAttribute("value"), "Array",
"Should have the right property name for |Array|.");
is(globalNodes[0].querySelector(".value").getAttribute("value"), "[object Function]",
"Should have the right property value for |Array|.");
let len = globalNodes.length - 1;
is(globalNodes[len].querySelector(".name").getAttribute("value"), "window",
"Should have the right property name for |window|.");
is(globalNodes[len].querySelector(".value").getAttribute("value"), "[object Proxy]",
"Should have the right property value for |window|.");
resumeAndFinish();
}}, 0);
}, false);
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content.window);
}
function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._frames;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
}}, 0);
}, true);
gDebugger.DebuggerController.activeThread.resume();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

Просмотреть файл

@ -29,7 +29,7 @@ function testFrameEval() {
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
var localScope = gDebugger.DebuggerView.Properties.localScope,
var localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
localNodes = localScope.querySelector(".details").childNodes,
varA = localNodes[7];
@ -68,11 +68,18 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
ok(aVar.querySelector(".element-input"),
"There should be an input element created.");
let count = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
// We expect 2 Debugger:FetchedVariables events, one from the global
// object scope and the regular one.
if (++count <2) {
info("Number of received Debugger:FetchedVariables events: " + count);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
// Get the variable reference anew, since the old ones were discarded when
// we resumed.
var localScope = gDebugger.DebuggerView.Properties.localScope,
var localScope = gDebugger.DebuggerView.Properties._vars.firstChild,
localNodes = localScope.querySelector(".details").childNodes,
varA = localNodes[7];

Просмотреть файл

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'/>
<title>Debugger Function Call Parameter Test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
window.addEventListener("load", function() {
function test(aNumber) {
var a, obj = { one: 1, two: 2 };
var r = aNumber;
with (Math) {
a = PI * r * r;
with (obj) {
var foo = two * PI;
debugger;
}
}
};
function load() {
test(10);
}
var button = document.querySelector("button");
button.addEventListener("click", load, false);
});
</script>
</head>
<body>
<button>Click me!</button>
</body>
</html>

Просмотреть файл

@ -42,22 +42,6 @@ pauseTooltip=Click to pause
# button when the debugger is in a paused state.
resumeTooltip=Click to resume
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
# pane as a header on the local scope container.
localScope=Local
# LOCALIZATION NOTE (globalScope): The label that is displayed in the variables
# pane as a header on the globel scope container.
globalScope=Global
# LOCALIZATION NOTE (withScope): The label that is displayed in the variables
# pane as a header on the container for identifiers in a with block.
withScope=With block
# LOCALIZATION NOTE (closureScope): The label that is displayed in the variables
# pane as a header on container for identifiers in a closure scope.
closureScope=Closure
# LOCALIZATION NOTE (emptyStackText): The text that is displayed in the stack
# frames list when there are no frames to display.
emptyStackText=No stacks to display.
@ -72,3 +56,17 @@ loadingText=Loading\u2026
# external resource file.
# %1$S=URL, %2$S=status code
loadingError=Error loading %1$S: %2$S
# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the
# variables pane when there are no variables to display.
emptyVariablesText=No variables to display.
# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables
# pane as a header for each variable scope (e.g. "Global scope, "With scope",
# etc.).
scopeLabel=%S scope
# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text
# is added to scopeLabel and displayed in the variables pane as a header for
# the global scope.
globalScopeLabel=Global

Просмотреть файл

@ -1078,6 +1078,10 @@ ObjectActor.prototype = {
message: "cannot access the environment of this function." };
}
// XXX: the following call of env.form() won't work until bug 747514 lands.
// We can't get to the frame that defined this function's environment,
// neither here, nor during ObjectActor's construction. Luckily, we don't
// use the 'scope' request in the debugger frontend.
return { name: this.obj.name || null,
scope: envActor.form(this.obj) };
},
@ -1197,14 +1201,7 @@ FrameActor.prototype = {
type: this.frame.type };
if (this.frame.type === "call") {
form.callee = this.threadActor.createValueGrip(this.frame.callee);
if (this.frame.callee.name) {
form.calleeName = this.frame.callee.name;
} else {
let desc = this.frame.callee.getOwnPropertyDescriptor("displayName");
if (desc && desc.value && typeof desc.value == "string") {
form.calleeName = desc.value;
}
}
form.calleeName = getFunctionName(this.frame.callee);
}
let envActor = this.threadActor
@ -1335,13 +1332,13 @@ EnvironmentActor.prototype = {
/**
* Returns an environment form for use in a protocol message. Note that the
* requirement of passing the frame or function as a parameter is only
* temporary, since when bug 747514 lands, the environment will have a callee
* property that will contain it.
* requirement of passing the frame as a parameter is only temporary, since
* when bug 747514 lands, the environment will have a callee property that
* will contain it.
*
* @param object aObject
* The stack frame or function object whose environment bindings are
* being generated.
* @param Debugger.Frame aObject
* The stack frame object whose environment bindings are being
* generated.
*/
form: function EA_form(aObject) {
// Debugger.Frame might be dead by the time we get here, which will cause
@ -1353,24 +1350,29 @@ EnvironmentActor.prototype = {
let parent;
if (this.obj.parent) {
let thread = this.threadActor;
parent = thread.createEnvironmentActor(this.obj.parent.environment,
parent = thread.createEnvironmentActor(this.obj.parent,
this.registeredPool);
}
// Deduce the frame that created the parent scope in order to pass it to
// parent.form(). TODO: this can be removed after bug 747514 is done.
let parentFrame = aObject;
if (this.obj.type == "declarative" && aObject.older) {
parentFrame = aObject.older;
}
let form = { actor: this.actorID,
parent: parent ? parent.form(this.obj.parent) : parent };
parent: parent ? parent.form(parentFrame) : parent };
if (aObject.type == "object") {
if (this.obj.parent) {
form.type = "with";
} else {
form.type = "object";
}
form.object = this.threadActor.createValueGrip(aObject.object);
} else {
if (aObject.class == "Function") {
if (this.obj.type == "with") {
form.type = "with";
form.object = this.threadActor.createValueGrip(this.obj.object);
} else if (this.obj.type == "object") {
form.type = "object";
form.object = this.threadActor.createValueGrip(this.obj.object);
} else { // this.obj.type == "declarative"
if (aObject.callee) {
form.type = "function";
form.function = this.threadActor.createValueGrip(aObject);
form.functionName = aObject.name;
form.function = this.threadActor.createValueGrip(aObject.callee);
form.functionName = getFunctionName(aObject.callee);
} else {
form.type = "block";
}
@ -1382,14 +1384,14 @@ EnvironmentActor.prototype = {
/**
* Return the identifier bindings object as required by the remote protocol
* specification. Note that the requirement of passing the frame or function
* as a parameter is only temporary, since when bug 747514 lands, the
* environment will have a callee property that will contain it.
* specification. Note that the requirement of passing the frame as a
* parameter is only temporary, since when bug 747514 lands, the environment
* will have a callee property that will contain it.
*
* @param object aObject [optional]
* The stack frame or function object whose environment bindings are
* being generated. When left unspecified, the bindings do not contain
* an 'arguments' property.
* @param Debugger.Frame aObject [optional]
* The stack frame whose environment bindings are being generated. When
* left unspecified, the bindings do not contain an 'arguments'
* property.
*/
_bindings: function EA_bindings(aObject) {
let bindings = { arguments: [], variables: {} };
@ -1514,3 +1516,22 @@ EnvironmentActor.prototype.requestTypes = {
"assign": EnvironmentActor.prototype.onAssign,
"bindings": EnvironmentActor.prototype.onBindings
};
/**
* Helper function to deduce the name of the provided function.
*
* @param Debugger.Object aFunction
* The function whose name will be returned.
*/
function getFunctionName(aFunction) {
let name;
if (aFunction.name) {
name = aFunction.name;
} else {
let desc = aFunction.getOwnPropertyDescriptor("displayName");
if (desc && desc.value && typeof desc.value == "string") {
name = desc.value;
}
}
return name;
}

Просмотреть файл

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a frame actor's parent bindings.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
let parentEnv = aPacket.frame.environment.parent;
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_neq(parentEnv, undefined);
do_check_eq(args.length, 0);
do_check_eq(vars.stopMe.value.type, "object");
do_check_eq(vars.stopMe.value.class, "Function");
do_check_true(!!vars.stopMe.value.actor);
parentEnv = parentEnv.parent;
do_check_neq(parentEnv, undefined);
let objClient = gThreadClient.pauseGrip(parentEnv.object);
objClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
do_check_true(!!aResponse.ownProperties.Object.value.actor);
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
gDebuggee.eval("(" + function() {
function stopMe(aNumber, aBool, aString, aNull, aUndefined, aObject) {
var a = 1;
var b = true;
var c = { a: "a" };
debugger;
};
stopMe(42, true, "nasu", null, undefined, { foo: "bar" });
} + ")()");
}

Просмотреть файл

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a |with| frame actor's bindings.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let parentEnv = env.parent;
do_check_neq(parentEnv, undefined);
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_eq(args.length, 1);
do_check_eq(args[0].aNumber.value, 10);
do_check_eq(vars.r.value, 10);
do_check_eq(vars.a.value, Math.PI * 100);
do_check_eq(vars.arguments.value.class, "Arguments");
do_check_true(!!vars.arguments.value.actor);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
gDebuggee.eval("(" + function() {
function stopMe(aNumber) {
var a;
var r = aNumber;
with (Math) {
a = PI * r * r;
debugger;
}
};
stopMe(10);
} + ")()");
}

Просмотреть файл

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check the environment bindongs of a |with| within a |with|.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.one.value, 1);
do_check_eq(aResponse.ownProperties.two.value, 2);
do_check_eq(aResponse.ownProperties.foo, undefined);
let parentEnv = env.parent;
do_check_neq(parentEnv, undefined);
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
parentClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
parentEnv = parentEnv.parent;
do_check_neq(parentEnv, undefined);
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_eq(args.length, 1);
do_check_eq(args[0].aNumber.value, 10);
do_check_eq(vars.r.value, 10);
do_check_eq(vars.a.value, Math.PI * 100);
do_check_eq(vars.arguments.value.class, "Arguments");
do_check_true(!!vars.arguments.value.actor);
do_check_eq(vars.foo.value, 2 * Math.PI);
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function() {
function stopMe(aNumber) {
var a, obj = { one: 1, two: 2 };
var r = aNumber;
with (Math) {
a = PI * r * r;
with (obj) {
var foo = two * PI;
debugger;
}
}
};
stopMe(10);
} + ")()");
}

Просмотреть файл

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check the environment bindings of a |with| in global scope.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
let parentEnv = env.parent;
do_check_neq(parentEnv, undefined);
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
parentClient.getPrototypeAndProperties(function(aResponse) {
do_check_eq(aResponse.ownProperties.a.value, Math.PI * 100);
do_check_eq(aResponse.ownProperties.r.value, 10);
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
do_check_true(!!aResponse.ownProperties.Object.value.actor);
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("var a, r = 10;\n" +
"with (Math) {\n" +
" a = PI * r * r;\n" +
" debugger;\n" +
"}");
}

Просмотреть файл

@ -54,3 +54,7 @@ tail =
[test_stepping-03.js]
[test_stepping-04.js]
[test_framebindings-01.js]
[test_framebindings-02.js]
[test_framebindings-03.js]
[test_framebindings-04.js]
[test_framebindings-05.js]