VM: Fix issue with local variable values reported by the debugger.

I added a function to test if a variable is visible or not to the
debugger tests.

BUG=dartbug.com/22353
TEST=standalone/debugger/local_variables_test
R=hausner@google.com

Review URL: https://codereview.chromium.org//933253003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43850 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com 2015-02-18 18:48:00 +00:00
parent 6666c2502b
commit aefdc04fa8
5 changed files with 110 additions and 13 deletions

View file

@ -22,7 +22,7 @@ void DynamicAssertionHelper::Fail(const char* format, ...) {
va_list arguments;
va_start(arguments, format);
char buffer[2 * KB];
char buffer[4 * KB];
vsnprintf(buffer, sizeof(buffer), format, arguments);
va_end(arguments);
stream << buffer << std::endl;

View file

@ -6677,16 +6677,18 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
ASSERT(IsIdentifier());
const intptr_t ident_pos = TokenPos();
const String& ident = *CurrentLiteral();
LocalVariable* variable = new(Z) LocalVariable(
ident_pos, ident, type);
ConsumeToken(); // Variable identifier.
AstNode* initialization = NULL;
LocalVariable* variable = NULL;
if (CurrentToken() == Token::kASSIGN) {
// Variable initialization.
const intptr_t assign_pos = TokenPos();
ConsumeToken();
AstNode* expr = ParseAwaitableExpr(
is_const, kConsumeCascades, await_preamble);
const intptr_t expr_end_pos = TokenPos();
variable = new(Z) LocalVariable(
expr_end_pos, ident, type);
initialization = new(Z) StoreLocalNode(
assign_pos, variable, expr);
if (is_const) {
@ -6698,6 +6700,8 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
"missing initialization of 'final' or 'const' variable");
} else {
// Initialize variable with null.
variable = new(Z) LocalVariable(
ident_pos, ident, type);
AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z));
initialization = new(Z) StoreLocalNode(
ident_pos, variable, null_expr);
@ -6705,7 +6709,7 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
ASSERT(current_block_ != NULL);
const intptr_t previous_pos =
current_block_->scope->PreviousReferencePos(ident);
current_block_->scope->PreviousReferencePos(ident);
if (previous_pos >= 0) {
ASSERT(!script_.IsNull());
if (previous_pos > ident_pos) {

View file

@ -280,7 +280,7 @@ TEST_CASE(Parser_AllocateVariables_CapturedVar) {
" 0 ContextLevel level=1 scope=1 begin=2 end=37\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 2 ContextVar level=1 begin=7 end=37 name=value\n"
" 2 ContextVar level=1 begin=10 end=37 name=value\n"
" 3 StackVar scope=2 begin=12 end=37 name=f\n",
CaptureVarsAtLine(lib, "main", 4));
}
@ -321,7 +321,7 @@ TEST_CASE(Parser_AllocateVariables_NestedCapturedVar) {
" 0 ContextLevel level=1 scope=1 begin=8 end=38\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 2 ContextVar level=1 begin=13 end=38 name=value\n"
" 2 ContextVar level=1 begin=16 end=38 name=value\n"
" 3 StackVar scope=2 begin=18 end=38 name=c\n"
// Closure call saves current context.
@ -380,7 +380,7 @@ TEST_CASE(Parser_AllocateVariables_TwoChains) {
" 0 ContextLevel level=1 scope=1 begin=20 end=50\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 2 ContextVar level=1 begin=25 end=50 name=value2\n"
" 2 ContextVar level=1 begin=28 end=50 name=value2\n"
" 3 StackVar scope=2 begin=30 end=50 name=bb\n"
// Closure call saves current context.
@ -407,7 +407,7 @@ TEST_CASE(Parser_AllocateVariables_TwoChains) {
" 0 ContextLevel level=1 scope=1 begin=2 end=68\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 2 ContextVar level=1 begin=7 end=68 name=value1\n"
" 2 ContextVar level=1 begin=10 end=68 name=value1\n"
" 3 StackVar scope=2 begin=12 end=68 name=b\n",
CaptureVarsAtLine(lib, "a", 7));
}
@ -464,7 +464,7 @@ TEST_CASE(Parser_AllocateVariables_Issue7681) {
"doIt\n"
" 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 1 StackVar scope=2 begin=29 end=77 name=x\n",
" 1 StackVar scope=2 begin=35 end=77 name=x\n",
CaptureVarsAtLine(lib, "doIt", 12));
}
@ -505,9 +505,9 @@ TEST_CASE(Parser_AllocateVariables_CaptureLoopVar) {
"outer\n"
" 0 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 1 StackVar scope=3 begin=9 end=50 name=i\n"
" 1 StackVar scope=3 begin=12 end=50 name=i\n"
" 2 ContextLevel level=1 scope=4 begin=20 end=50\n"
" 3 ContextVar level=1 begin=23 end=50 name=value\n"
" 3 ContextVar level=1 begin=28 end=50 name=value\n"
" 4 StackVar scope=4 begin=30 end=50 name=inner\n",
CaptureVarsAtLine(lib, "outer", 5));
}
@ -548,7 +548,7 @@ TEST_CASE(Parser_AllocateVariables_MiddleChain) {
" name=:current_context_var\n"
" 2 StackVar scope=2 begin=46 end=68 name=c\n"
" 3 ContextLevel level=1 scope=3 begin=18 end=46\n"
" 4 ContextVar level=1 begin=19 end=46 name=i\n"
" 4 ContextVar level=1 begin=22 end=46 name=i\n"
" 5 StackVar scope=4 begin=32 end=46 name=d\n"
"_FunctionImpl.call\n"
@ -560,7 +560,7 @@ TEST_CASE(Parser_AllocateVariables_MiddleChain) {
" 0 ContextLevel level=1 scope=1 begin=1 end=76\n"
" 1 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 2 ContextVar level=1 begin=6 end=76 name=x\n"
" 2 ContextVar level=1 begin=9 end=76 name=x\n"
" 3 StackVar scope=2 begin=11 end=76 name=b\n",
CaptureVarsAtLine(lib, "a", 10));
}

View file

@ -338,6 +338,43 @@ MatchLocals(Map localValues) {
}
// Used to check if local variables are visible.
class AssertLocalsNotVisibleMatcher extends Command {
List<String> locals;
int frame_index;
AssertLocalsNotVisibleMatcher(this.locals, this.frame_index) {
template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
}
void matchResponse(Debugger debugger) {
super.matchResponse(debugger);
List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
assert(frames != null);
String functionName = frames[frame_index]['functionName'];
List localsList = frames[frame_index]['locals'];
Map reportedLocals = {};
localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
for (String key in locals) {
if (reportedLocals[key] != null) {
debugger.error("Error in $functionName(): local variable $key not "
"expected in scope (reported value "
"${reportedLocals[key]['text']})");
return;
}
}
print("Matched locals $locals");
}
}
AssertLocalsNotVisible(List<String> locals, [int frame_index = 0]) {
return new AssertLocalsNotVisibleMatcher(locals, frame_index);
}
class EventMatcher {
String eventName;
Map params;

View file

@ -0,0 +1,56 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This test forks a second vm process that runs this dart script as
// a debug target.
// Run this test with option --wire to see the json messages sent
// between the processes.
// Run this test with option --verbose to see the stdout and stderr output
// of the debug target process.
import "debug_lib.dart";
foo() {
var y; // Breakpoint
return 123;
}
test() {
if (true) {
var temp = 777;
}
if (true) {
var a = foo(); // Breakpoint
if (true) {
var s = 456;
print(s);
}
}
}
main(List<String> arguments) {
if (RunScript(testScript, arguments)) return;
print("Hello from debuggee");
test();
print("Hello again");
}
// Expected debugger events and commands.
var testScript = [
MatchFrame(0, "main"), // Top frame in trace is function "main".
Step(),
MatchFrame(0, "main"), // Should still be in "main".
SetBreakpoint(15), // Set breakpoint in function foo.
SetBreakpoint(24), // Set breakpoint in function test.
Resume(),
MatchFrames(["test", "main"]),
AssertLocalsNotVisible(["a"]), // Here, a is not in scope yet.
Resume(),
MatchFrames(["foo", "test", "main"]),
AssertLocalsNotVisible(["a"], 1), // In the caller, a is not in scope.
Step(),
MatchLocals({"y": "null"}), // Expect y initialized to null.
Resume(),
];