mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
Add local variable declaration token position to service protocol
- [x] Add three public fields to the "BoundVariable" service type: declarationTokenPos, visibleStartTokenPos, and visibleEndTokenPos. (naming suggestions welcome!) - [x] Extend LocalVarDescriptors to hold the declaration token position (it already had the scope visibility boundaries). - [x] Extend ContextScope to hold the declaration token position. - [x] Add a unit test which verifies this works for local variables, function parameters, and closure captured variables. Fixes https://github.com/dart-lang/sdk/issues/25569 BUG= R=rmacnak@google.com Review URL: https://codereview.chromium.org/2419013004 .
This commit is contained in:
parent
724ac40b8d
commit
8061bd5a8a
|
@ -3254,6 +3254,7 @@ class Script extends HeapObject implements M.Script {
|
|||
|
||||
Script._empty(ServiceObjectOwner owner) : super._empty(owner);
|
||||
|
||||
/// Retrieves line number [line] if it exists.
|
||||
ScriptLine getLine(int line) {
|
||||
assert(_loaded);
|
||||
assert(line >= 1);
|
||||
|
@ -3261,10 +3262,12 @@ class Script extends HeapObject implements M.Script {
|
|||
}
|
||||
|
||||
/// This function maps a token position to a line number.
|
||||
/// The VM considers the first line to be line 1.
|
||||
int tokenToLine(int tokenPos) => _tokenToLine[tokenPos];
|
||||
Map _tokenToLine = {};
|
||||
|
||||
/// This function maps a token position to a column number.
|
||||
/// The VM considers the first column to be column 1.
|
||||
int tokenToCol(int tokenPos) => _tokenToCol[tokenPos];
|
||||
Map _tokenToCol = {};
|
||||
|
||||
|
@ -3327,7 +3330,7 @@ class Script extends HeapObject implements M.Script {
|
|||
|
||||
static bool _isIdentifierChar(int c) {
|
||||
if (_isInitialIdentifierChar(c)) return true;
|
||||
return c >= 48 && c <= 75; // Digit
|
||||
return c >= 48 && c <= 57; // Digit
|
||||
}
|
||||
|
||||
void _update(Map map, bool mapIsRef) {
|
||||
|
@ -3408,6 +3411,28 @@ class Script extends HeapObject implements M.Script {
|
|||
}
|
||||
}
|
||||
|
||||
// Note, this may return source beyond the token length if [guessTokenLength]
|
||||
// fails.
|
||||
String getToken(int tokenPos) {
|
||||
final int line = tokenToLine(tokenPos);
|
||||
int column = tokenToCol(tokenPos);
|
||||
if ((line == null) || (column == null)) {
|
||||
return null;
|
||||
}
|
||||
// Line and column numbers start at 1 in the VM.
|
||||
column -= 1;
|
||||
String sourceLine = getLine(line).text;
|
||||
if (sourceLine == null) {
|
||||
return null;
|
||||
}
|
||||
final int length = guessTokenLength(line, column);
|
||||
if (length == null) {
|
||||
return sourceLine.substring(column);
|
||||
} else {
|
||||
return sourceLine.substring(column, column + length);
|
||||
}
|
||||
}
|
||||
|
||||
void _addBreakpoint(Breakpoint bpt) {
|
||||
var line;
|
||||
if (bpt.location.tokenPos != null) {
|
||||
|
@ -3610,13 +3635,20 @@ class LocalVarDescriptor implements M.LocalVarDescriptorsRef {
|
|||
final String id;
|
||||
final String name;
|
||||
final int index;
|
||||
final int declarationPos;
|
||||
final int beginPos;
|
||||
final int endPos;
|
||||
final int scopeId;
|
||||
final String kind;
|
||||
|
||||
LocalVarDescriptor(this.id, this.name, this.index, this.beginPos, this.endPos,
|
||||
this.scopeId, this.kind);
|
||||
LocalVarDescriptor(this.id,
|
||||
this.name,
|
||||
this.index,
|
||||
this.declarationPos,
|
||||
this.beginPos,
|
||||
this.endPos,
|
||||
this.scopeId,
|
||||
this.kind);
|
||||
}
|
||||
|
||||
class LocalVarDescriptors extends ServiceObject {
|
||||
|
@ -3638,12 +3670,13 @@ class LocalVarDescriptors extends ServiceObject {
|
|||
var id = descriptor['name'];
|
||||
var name = descriptor['name'];
|
||||
var index = descriptor['index'];
|
||||
var beginPos = descriptor['beginPos'];
|
||||
var endPos = descriptor['endPos'];
|
||||
var declarationPos = descriptor['declarationTokenPos'];
|
||||
var beginPos = descriptor['scopeStartTokenPos'];
|
||||
var endPos = descriptor['scopeEndTokenPos'];
|
||||
var scopeId = descriptor['scopeId'];
|
||||
var kind = descriptor['kind'].trim();
|
||||
descriptors.add(new LocalVarDescriptor(
|
||||
id, name, index, beginPos, endPos, scopeId, kind));
|
||||
id, name, index, declarationPos, beginPos, endPos, scopeId, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) 2016, 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.
|
||||
// VMOptions=--error_on_bad_type --error_on_bad_override --verbose_debug
|
||||
|
||||
import 'package:observatory/service_io.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'service_test_common.dart';
|
||||
import 'test_helper.dart';
|
||||
import 'dart:developer';
|
||||
|
||||
testParameters(int jjjj, int oooo, [int hhhh, int nnnn]) {
|
||||
debugger();
|
||||
}
|
||||
|
||||
testMain() {
|
||||
int xxx, yyyy, zzzzz;
|
||||
for (int i = 0; i < 1; i++) {
|
||||
var foo = () {
|
||||
};
|
||||
debugger();
|
||||
}
|
||||
var bar = () {
|
||||
print(xxx);
|
||||
print(yyyy);
|
||||
debugger();
|
||||
};
|
||||
bar();
|
||||
testParameters(0, 0);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedInFunction('testMain'),
|
||||
(Isolate isolate) async {
|
||||
var stack = await isolate.getStack();
|
||||
expect(stack.type, equals('Stack'));
|
||||
expect(stack['frames'].length, greaterThanOrEqualTo(1));
|
||||
// Grab the top frame.
|
||||
Frame frame = stack['frames'][0];
|
||||
// Grab the script.
|
||||
Script script = frame.location.script;
|
||||
await script.load();
|
||||
|
||||
// Ensure that the token at each declaration position is the name of the
|
||||
// variable.
|
||||
for (var variable in frame.variables) {
|
||||
final int declarationTokenPos = variable['declarationTokenPos'];
|
||||
final String name = variable['name'];
|
||||
final String token = script.getToken(declarationTokenPos);
|
||||
expect(name, token);
|
||||
}
|
||||
},
|
||||
resumeIsolate,
|
||||
hasStoppedAtBreakpoint,
|
||||
// We have stopped in the anonymous closure assigned to bar. Verify that
|
||||
// variables captured in the context have valid declaration positions.
|
||||
(Isolate isolate) async {
|
||||
var stack = await isolate.getStack();
|
||||
expect(stack.type, equals('Stack'));
|
||||
expect(stack['frames'].length, greaterThanOrEqualTo(1));
|
||||
// Grab the top frame.
|
||||
Frame frame = stack['frames'][0];
|
||||
// Grab the script.
|
||||
Script script = frame.location.script;
|
||||
await script.load();
|
||||
print(frame);
|
||||
expect(frame.variables.length, greaterThanOrEqualTo(1));
|
||||
for (var variable in frame.variables) {
|
||||
final int declarationTokenPos = variable['declarationTokenPos'];
|
||||
final String name = variable['name'];
|
||||
final String token = script.getToken(declarationTokenPos);
|
||||
expect(name, token);
|
||||
}
|
||||
},
|
||||
resumeIsolate,
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedInFunction('testParameters'),
|
||||
(Isolate isolate) async {
|
||||
var stack = await isolate.getStack();
|
||||
expect(stack.type, equals('Stack'));
|
||||
expect(stack['frames'].length, greaterThanOrEqualTo(1));
|
||||
// Grab the top frame.
|
||||
Frame frame = stack['frames'][0];
|
||||
// Grab the script.
|
||||
Script script = frame.location.script;
|
||||
await script.load();
|
||||
|
||||
// Ensure that the token at each declaration position is the name of the
|
||||
// variable.
|
||||
expect(frame.variables.length, greaterThanOrEqualTo(1));
|
||||
for (var variable in frame.variables) {
|
||||
final int declarationTokenPos = variable['declarationTokenPos'];
|
||||
final String name = variable['name'];
|
||||
final String token = script.getToken(declarationTokenPos);
|
||||
expect(name, token);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
|
|
@ -111,7 +111,8 @@ LocalVariable* LetNode::AddInitializer(AstNode* node) {
|
|||
OS::SNPrint(name, sizeof(name), ":lt%s_%" Pd "",
|
||||
token_pos().ToCString(), vars_.length());
|
||||
LocalVariable* temp_var =
|
||||
new LocalVariable(token_pos(),
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
token_pos(),
|
||||
String::ZoneHandle(zone, Symbols::New(thread, name)),
|
||||
Object::dynamic_type());
|
||||
vars_.Add(temp_var);
|
||||
|
|
|
@ -18,6 +18,7 @@ TEST_CASE(AstPrinter) {
|
|||
const TokenPosition kPos = TokenPosition::kNoSource;
|
||||
LocalVariable* v =
|
||||
new LocalVariable(kPos,
|
||||
kPos,
|
||||
String::ZoneHandle(Symbols::New(thread, "wurscht")),
|
||||
Type::ZoneHandle(Type::DynamicType()));
|
||||
v->set_index(5);
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace dart {
|
|||
|
||||
TEST_CASE(Ast) {
|
||||
LocalVariable* v = new LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
String::ZoneHandle(Symbols::New(thread, "v")),
|
||||
Type::ZoneHandle(Type::DynamicType()));
|
||||
|
@ -26,6 +27,7 @@ TEST_CASE(Ast) {
|
|||
EXPECT_EQ(1, v->index());
|
||||
|
||||
LocalVariable* p = new LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
String::ZoneHandle(Symbols::New(thread, "p")),
|
||||
Type::ZoneHandle(Type::DynamicType()));
|
||||
|
|
|
@ -77,7 +77,10 @@ LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
|
|||
if (await_tmp == NULL) {
|
||||
// We need a new temp variable; add it to the function's top scope.
|
||||
await_tmp = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource, symbol, Object::dynamic_type());
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
symbol,
|
||||
Object::dynamic_type());
|
||||
async_temp_scope_->AddVariable(await_tmp);
|
||||
// After adding it to the top scope, we can look it up from the preamble.
|
||||
// The following call includes an ASSERT check.
|
||||
|
|
|
@ -1728,7 +1728,7 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
|
|||
FLAG_precompiled_runtime ? 0 : frame->NumLocalVariables();
|
||||
TokenPosition unused = TokenPosition::kNoSource;
|
||||
for (intptr_t v = 0; v < num_vars; v++) {
|
||||
frame->VariableAt(v, &var_name, &unused, &unused, &var_value);
|
||||
frame->VariableAt(v, &var_name, &unused, &unused, &unused, &var_value);
|
||||
}
|
||||
}
|
||||
FLAG_stacktrace_every = saved_stacktrace_every;
|
||||
|
|
|
@ -50,7 +50,7 @@ static LocalVariable* NewTestLocalVariable(const char* name) {
|
|||
const String& variable_name = String::ZoneHandle(
|
||||
Symbols::New(Thread::Current(), name));
|
||||
const Type& variable_type = Type::ZoneHandle(Type::DynamicType());
|
||||
return new LocalVariable(kPos, variable_name, variable_type);
|
||||
return new LocalVariable(kPos, kPos, variable_name, variable_type);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -896,8 +896,9 @@ void ActivationFrame::PrintContextMismatchError(
|
|||
|
||||
void ActivationFrame::VariableAt(intptr_t i,
|
||||
String* name,
|
||||
TokenPosition* token_pos,
|
||||
TokenPosition* end_pos,
|
||||
TokenPosition* declaration_token_pos,
|
||||
TokenPosition* visible_start_token_pos,
|
||||
TokenPosition* visible_end_token_pos,
|
||||
Object* value) {
|
||||
GetDescIndices();
|
||||
ASSERT(i < desc_indices_.length());
|
||||
|
@ -908,10 +909,12 @@ void ActivationFrame::VariableAt(intptr_t i,
|
|||
|
||||
RawLocalVarDescriptors::VarInfo var_info;
|
||||
var_descriptors_.GetInfo(desc_index, &var_info);
|
||||
ASSERT(token_pos != NULL);
|
||||
*token_pos = var_info.begin_pos;
|
||||
ASSERT(end_pos != NULL);
|
||||
*end_pos = var_info.end_pos;
|
||||
ASSERT(declaration_token_pos != NULL);
|
||||
*declaration_token_pos = var_info.declaration_pos;
|
||||
ASSERT(visible_start_token_pos != NULL);
|
||||
*visible_start_token_pos = var_info.begin_pos;
|
||||
ASSERT(visible_end_token_pos != NULL);
|
||||
*visible_end_token_pos = var_info.end_pos;
|
||||
ASSERT(value != NULL);
|
||||
const int8_t kind = var_info.kind();
|
||||
if (kind == RawLocalVarDescriptors::kStackVar) {
|
||||
|
@ -966,7 +969,7 @@ RawArray* ActivationFrame::GetLocalVariables() {
|
|||
const Array& list = Array::Handle(Array::New(2 * num_variables));
|
||||
for (intptr_t i = 0; i < num_variables; i++) {
|
||||
TokenPosition ignore;
|
||||
VariableAt(i, &var_name, &ignore, &ignore, &value);
|
||||
VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value);
|
||||
list.SetAt(2 * i, var_name);
|
||||
list.SetAt((2 * i) + 1, value);
|
||||
}
|
||||
|
@ -981,7 +984,7 @@ RawObject* ActivationFrame::GetReceiver() {
|
|||
Instance& value = Instance::Handle();
|
||||
for (intptr_t i = 0; i < num_variables; i++) {
|
||||
TokenPosition ignore;
|
||||
VariableAt(i, &var_name, &ignore, &ignore, &value);
|
||||
VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value);
|
||||
if (var_name.Equals(Symbols::This())) {
|
||||
return value.raw();
|
||||
}
|
||||
|
@ -1011,7 +1014,7 @@ RawObject* ActivationFrame::Evaluate(const String& expr) {
|
|||
intptr_t num_variables = desc_indices_.length();
|
||||
for (intptr_t i = 0; i < num_variables; i++) {
|
||||
TokenPosition ignore;
|
||||
VariableAt(i, &name, &ignore, &ignore, &value);
|
||||
VariableAt(i, &name, &ignore, &ignore, &ignore, &value);
|
||||
if (!name.Equals(Symbols::This()) && !IsSyntheticVariableName(name)) {
|
||||
if (IsPrivateVariableName(name)) {
|
||||
name = String::ScrubName(name);
|
||||
|
@ -1087,20 +1090,27 @@ void ActivationFrame::PrintToJSONObject(JSONObject* jsobj,
|
|||
for (intptr_t v = 0; v < num_vars; v++) {
|
||||
String& var_name = String::Handle();
|
||||
Instance& var_value = Instance::Handle();
|
||||
TokenPosition token_pos;
|
||||
TokenPosition end_token_pos;
|
||||
VariableAt(v, &var_name, &token_pos, &end_token_pos, &var_value);
|
||||
TokenPosition declaration_token_pos;
|
||||
TokenPosition visible_start_token_pos;
|
||||
TokenPosition visible_end_token_pos;
|
||||
VariableAt(v,
|
||||
&var_name,
|
||||
&declaration_token_pos,
|
||||
&visible_start_token_pos,
|
||||
&visible_end_token_pos,
|
||||
&var_value);
|
||||
if (var_name.raw() != Symbols::AsyncOperation().raw()) {
|
||||
JSONObject jsvar(&jsvars);
|
||||
jsvar.AddProperty("type", "BoundVariable");
|
||||
var_name = String::ScrubName(var_name);
|
||||
jsvar.AddProperty("name", var_name.ToCString());
|
||||
jsvar.AddProperty("value", var_value, !full);
|
||||
// TODO(turnidge): Do we really want to provide this on every
|
||||
// stack dump? Should be associated with the function object, I
|
||||
// think, and not the stack frame.
|
||||
jsvar.AddProperty("_tokenPos", token_pos);
|
||||
jsvar.AddProperty("_endTokenPos", end_token_pos);
|
||||
// Where was the variable declared?
|
||||
jsvar.AddProperty("declarationTokenPos", declaration_token_pos);
|
||||
// When the variable becomes visible to the scope.
|
||||
jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos);
|
||||
// When the variable stops being visible to the scope.
|
||||
jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,8 +285,9 @@ class ActivationFrame : public ZoneAllocated {
|
|||
|
||||
void VariableAt(intptr_t i,
|
||||
String* name,
|
||||
TokenPosition* token_pos,
|
||||
TokenPosition* end_pos,
|
||||
TokenPosition* declaration_token_pos,
|
||||
TokenPosition* visible_start_token_pos,
|
||||
TokenPosition* visible_end_token_pos,
|
||||
Object* value);
|
||||
|
||||
RawArray* GetLocalVariables();
|
||||
|
|
|
@ -2294,6 +2294,7 @@ LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) {
|
|||
OS::SNPrint(name, 64, ":tmp_local%" Pd, index);
|
||||
LocalVariable* var =
|
||||
new(Z) LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
String::ZoneHandle(Z, Symbols::New(T, name)),
|
||||
*value->Type()->ToAbstractType());
|
||||
var->set_index(index);
|
||||
|
@ -4026,6 +4027,7 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
|
|||
// Create a temporary local describing the original position.
|
||||
const String& temp_name = Symbols::TempParam();
|
||||
LocalVariable* temp_local = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource, // Token index.
|
||||
TokenPosition::kNoSource, // Token index.
|
||||
temp_name,
|
||||
Object::dynamic_type()); // Type.
|
||||
|
|
|
@ -41,13 +41,19 @@ void ScopeBuilder::ExitScope() { scope_ = scope_->parent(); }
|
|||
|
||||
LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name) {
|
||||
return new (Z)
|
||||
LocalVariable(TokenPosition::kNoSource, name, Object::dynamic_type());
|
||||
LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
name,
|
||||
Object::dynamic_type());
|
||||
}
|
||||
|
||||
|
||||
LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name,
|
||||
const Type& type) {
|
||||
return new (Z) LocalVariable(TokenPosition::kNoSource, name, type);
|
||||
return new (Z) LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
name,
|
||||
type);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2503,7 +2509,10 @@ LocalVariable* FlowGraphBuilder::MakeTemporary() {
|
|||
intptr_t index = stack_->definition()->temp_index();
|
||||
OS::SNPrint(name, 64, ":temp%" Pd, index);
|
||||
LocalVariable* variable = new (Z) LocalVariable(
|
||||
TokenPosition::kNoSource, H.DartSymbol(name), Object::dynamic_type());
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
H.DartSymbol(name),
|
||||
Object::dynamic_type());
|
||||
// Set the index relative to the base of the expression stack including
|
||||
// outgoing arguments.
|
||||
variable->set_index(parsed_function_->first_stack_local_index() -
|
||||
|
@ -2764,7 +2773,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function,
|
|||
// create one directly.
|
||||
LocalVariable* parameter =
|
||||
new (Z) LocalVariable(TokenPosition::kNoSource,
|
||||
Symbols::TempParam(), Object::dynamic_type());
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::TempParam(),
|
||||
Object::dynamic_type());
|
||||
parameter->set_index(parameter_index);
|
||||
// Mark the stack variable so it will be ignored by the code for
|
||||
// try/catch.
|
||||
|
|
|
@ -14811,6 +14811,21 @@ void ContextScope::SetTokenIndexAt(intptr_t scope_index,
|
|||
}
|
||||
|
||||
|
||||
TokenPosition ContextScope::DeclarationTokenIndexAt(
|
||||
intptr_t scope_index) const {
|
||||
return TokenPosition(
|
||||
Smi::Value(VariableDescAddr(scope_index)->declaration_token_pos));
|
||||
}
|
||||
|
||||
|
||||
void ContextScope::SetDeclarationTokenIndexAt(
|
||||
intptr_t scope_index,
|
||||
TokenPosition declaration_token_pos) const {
|
||||
StoreSmi(&VariableDescAddr(scope_index)->declaration_token_pos,
|
||||
Smi::New(declaration_token_pos.value()));
|
||||
}
|
||||
|
||||
|
||||
RawString* ContextScope::NameAt(intptr_t scope_index) const {
|
||||
return VariableDescAddr(scope_index)->name;
|
||||
}
|
||||
|
|
|
@ -5151,6 +5151,10 @@ class ContextScope : public Object {
|
|||
TokenPosition TokenIndexAt(intptr_t scope_index) const;
|
||||
void SetTokenIndexAt(intptr_t scope_index, TokenPosition token_pos) const;
|
||||
|
||||
TokenPosition DeclarationTokenIndexAt(intptr_t scope_index) const;
|
||||
void SetDeclarationTokenIndexAt(intptr_t scope_index,
|
||||
TokenPosition declaration_token_pos) const;
|
||||
|
||||
RawString* NameAt(intptr_t scope_index) const;
|
||||
void SetNameAt(intptr_t scope_index, const String& name) const;
|
||||
|
||||
|
|
|
@ -736,8 +736,9 @@ void LocalVarDescriptors::PrintJSONImpl(JSONStream* stream,
|
|||
JSONObject var(&members);
|
||||
var.AddProperty("name", var_name.ToCString());
|
||||
var.AddProperty("index", static_cast<intptr_t>(info.index()));
|
||||
var.AddProperty("beginPos", info.begin_pos);
|
||||
var.AddProperty("endPos", info.end_pos);
|
||||
var.AddProperty("declarationTokenPos", info.declaration_pos);
|
||||
var.AddProperty("scopeStartTokenPos", info.begin_pos);
|
||||
var.AddProperty("scopeEndTokenPos", info.end_pos);
|
||||
var.AddProperty("scopeId", static_cast<intptr_t>(info.scope_id));
|
||||
var.AddProperty("kind", KindToCString(info.kind()));
|
||||
}
|
||||
|
|
|
@ -2535,17 +2535,26 @@ VM_TEST_CASE(ContextScope) {
|
|||
const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
|
||||
const String& a = String::ZoneHandle(Symbols::New(thread, "a"));
|
||||
LocalVariable* var_a =
|
||||
new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
a,
|
||||
dynamic_type);
|
||||
parent_scope->AddVariable(var_a);
|
||||
|
||||
const String& b = String::ZoneHandle(Symbols::New(thread, "b"));
|
||||
LocalVariable* var_b =
|
||||
new LocalVariable(TokenPosition::kNoSource, b, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
b,
|
||||
dynamic_type);
|
||||
local_scope->AddVariable(var_b);
|
||||
|
||||
const String& c = String::ZoneHandle(Symbols::New(thread, "c"));
|
||||
LocalVariable* var_c =
|
||||
new LocalVariable(TokenPosition::kNoSource, c, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
c,
|
||||
dynamic_type);
|
||||
parent_scope->AddVariable(var_c);
|
||||
|
||||
bool test_only = false; // Please, insert alias.
|
||||
|
|
|
@ -244,6 +244,7 @@ LocalVariable* ParsedFunction::EnsureExpressionTemp() {
|
|||
if (!has_expression_temp_var()) {
|
||||
LocalVariable* temp =
|
||||
new (Z) LocalVariable(function_.token_pos(),
|
||||
function_.token_pos(),
|
||||
Symbols::ExprTemp(),
|
||||
Object::dynamic_type());
|
||||
ASSERT(temp != NULL);
|
||||
|
@ -257,6 +258,7 @@ LocalVariable* ParsedFunction::EnsureExpressionTemp() {
|
|||
void ParsedFunction::EnsureFinallyReturnTemp(bool is_async) {
|
||||
if (!has_finally_return_temp_var()) {
|
||||
LocalVariable* temp = new(Z) LocalVariable(
|
||||
function_.token_pos(),
|
||||
function_.token_pos(),
|
||||
Symbols::FinallyRetVal(),
|
||||
Object::dynamic_type());
|
||||
|
@ -3137,6 +3139,7 @@ SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
|
|||
OpenFunctionBlock(func);
|
||||
|
||||
LocalVariable* receiver = new LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::This(),
|
||||
*ReceiverType(current_class()));
|
||||
|
@ -3185,6 +3188,7 @@ SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
|
|||
forwarding_args = new ArgumentListNode(ST(ctor_pos));
|
||||
for (int i = 1; i < func.NumParameters(); i++) {
|
||||
LocalVariable* param = new LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
String::ZoneHandle(Z, func.ParameterNameAt(i)),
|
||||
Object::dynamic_type());
|
||||
|
@ -7101,11 +7105,13 @@ void Parser::AddContinuationVariables() {
|
|||
// var :await_jump_var;
|
||||
// var :await_ctx_var;
|
||||
LocalVariable* await_jump_var = new (Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AwaitJumpVar(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(await_jump_var);
|
||||
LocalVariable* await_ctx_var = new (Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AwaitContextVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -7120,21 +7126,25 @@ void Parser::AddAsyncClosureVariables() {
|
|||
// var :async_catch_error_callback;
|
||||
// var :async_completer;
|
||||
LocalVariable* async_op_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncOperation(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(async_op_var);
|
||||
LocalVariable* async_then_callback_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncThenCallback(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(async_then_callback_var);
|
||||
LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncCatchErrorCallback(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(async_catch_error_callback_var);
|
||||
LocalVariable* async_completer = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncCompleter(),
|
||||
Object::dynamic_type());
|
||||
|
@ -7154,21 +7164,25 @@ void Parser::AddAsyncGeneratorVariables() {
|
|||
// These variables are used to store the async generator closure containing
|
||||
// the body of the async* function. They are used by the await operator.
|
||||
LocalVariable* controller_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::Controller(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(controller_var);
|
||||
LocalVariable* async_op_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncOperation(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(async_op_var);
|
||||
LocalVariable* async_then_callback_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncThenCallback(),
|
||||
Object::dynamic_type());
|
||||
current_block_->scope->AddVariable(async_then_callback_var);
|
||||
LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
Symbols::AsyncCatchErrorCallback(),
|
||||
Object::dynamic_type());
|
||||
|
@ -7658,7 +7672,10 @@ void Parser::AddFormalParamsToScope(const ParamList* params,
|
|||
ASSERT(!is_top_level_ || param_desc.type->IsResolved());
|
||||
const String* name = param_desc.name;
|
||||
LocalVariable* parameter = new(Z) LocalVariable(
|
||||
param_desc.name_pos, *name, *param_desc.type);
|
||||
param_desc.name_pos,
|
||||
param_desc.name_pos,
|
||||
*name,
|
||||
*param_desc.type);
|
||||
if (!scope->InsertParameterAt(i, parameter)) {
|
||||
ReportError(param_desc.name_pos,
|
||||
"name '%s' already exists in scope",
|
||||
|
@ -7770,7 +7787,10 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
|
|||
is_const, kConsumeCascades, await_preamble);
|
||||
const TokenPosition expr_end_pos = TokenPos();
|
||||
variable = new(Z) LocalVariable(
|
||||
expr_end_pos, ident, type);
|
||||
ident_pos,
|
||||
expr_end_pos,
|
||||
ident,
|
||||
type);
|
||||
initialization = new(Z) StoreLocalNode(
|
||||
assign_pos, variable, expr);
|
||||
if (is_const) {
|
||||
|
@ -7783,7 +7803,10 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
|
|||
} else {
|
||||
// Initialize variable with null.
|
||||
variable = new(Z) LocalVariable(
|
||||
assign_pos, ident, type);
|
||||
ident_pos,
|
||||
assign_pos,
|
||||
ident,
|
||||
type);
|
||||
AstNode* null_expr = new(Z) LiteralNode(ident_pos, Object::null_instance());
|
||||
initialization = new(Z) StoreLocalNode(
|
||||
ident_pos, variable, null_expr);
|
||||
|
@ -7920,6 +7943,7 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) {
|
|||
result_type = Type::DynamicType();
|
||||
|
||||
const TokenPosition function_pos = TokenPos();
|
||||
TokenPosition function_name_pos = TokenPosition::kNoSource;
|
||||
TokenPosition metadata_pos = TokenPosition::kNoSource;
|
||||
if (is_literal) {
|
||||
ASSERT(CurrentToken() == Token::kLPAREN || CurrentToken() == Token::kLT);
|
||||
|
@ -7934,7 +7958,7 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) {
|
|||
// referring to a not yet declared function type parameter.
|
||||
result_type = ParseType(ClassFinalizer::kDoNotResolve);
|
||||
}
|
||||
const TokenPosition name_pos = TokenPos();
|
||||
function_name_pos = TokenPos();
|
||||
variable_name = ExpectIdentifier("function name expected");
|
||||
function_name = variable_name;
|
||||
|
||||
|
@ -7947,7 +7971,7 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) {
|
|||
ASSERT(!script_.IsNull());
|
||||
intptr_t line_number;
|
||||
script_.GetTokenLocation(previous_pos, &line_number, NULL);
|
||||
ReportError(name_pos,
|
||||
ReportError(function_name_pos,
|
||||
"identifier '%s' previously used in line %" Pd "",
|
||||
function_name->ToCString(),
|
||||
line_number);
|
||||
|
@ -8026,7 +8050,8 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) {
|
|||
|
||||
// Add the function variable to the scope before parsing the function in
|
||||
// order to allow self reference from inside the function.
|
||||
function_variable = new(Z) LocalVariable(function_pos,
|
||||
function_variable = new(Z) LocalVariable(function_name_pos,
|
||||
function_pos,
|
||||
*variable_name,
|
||||
function_type);
|
||||
function_variable->set_is_final();
|
||||
|
@ -8838,7 +8863,7 @@ AstNode* Parser::ParseSwitchStatement(String* label_name) {
|
|||
expr_pos));
|
||||
temp_var_type.SetIsFinalized();
|
||||
LocalVariable* temp_variable = new(Z) LocalVariable(
|
||||
expr_pos, Symbols::SwitchExpr(), temp_var_type);
|
||||
expr_pos, expr_pos, Symbols::SwitchExpr(), temp_var_type);
|
||||
current_block_->scope->AddVariable(temp_variable);
|
||||
AstNode* save_switch_expr = new(Z) StoreLocalNode(
|
||||
expr_pos, temp_variable, switch_expr);
|
||||
|
@ -9128,7 +9153,7 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
|||
ctor_args);
|
||||
const AbstractType& iterator_type = Object::dynamic_type();
|
||||
LocalVariable* iterator_var = new(Z) LocalVariable(
|
||||
stream_expr_pos, Symbols::ForInIter(), iterator_type);
|
||||
stream_expr_pos, stream_expr_pos, Symbols::ForInIter(), iterator_type);
|
||||
current_block_->scope->AddVariable(iterator_var);
|
||||
AstNode* iterator_init =
|
||||
new(Z) StoreLocalNode(stream_expr_pos, iterator_var, ctor_call);
|
||||
|
@ -9213,6 +9238,7 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
|||
// loop block, so it gets put in the loop context level.
|
||||
LocalVariable* loop_var =
|
||||
new(Z) LocalVariable(loop_var_assignment_pos,
|
||||
loop_var_assignment_pos,
|
||||
*loop_var_name,
|
||||
loop_var_type);;
|
||||
if (loop_var_is_final) {
|
||||
|
@ -9388,6 +9414,7 @@ AstNode* Parser::ParseForInStatement(TokenPosition forin_pos,
|
|||
loop_var_type = ParseConstFinalVarOrType(
|
||||
I->type_checks() ? ClassFinalizer::kCanonicalize :
|
||||
ClassFinalizer::kIgnore);
|
||||
loop_var_pos = TokenPos();
|
||||
loop_var_name = ExpectIdentifier("variable name expected");
|
||||
}
|
||||
ExpectToken(Token::kIN);
|
||||
|
@ -9411,6 +9438,7 @@ AstNode* Parser::ParseForInStatement(TokenPosition forin_pos,
|
|||
// until the loop variable is assigned to.
|
||||
const AbstractType& iterator_type = Object::dynamic_type();
|
||||
LocalVariable* iterator_var = new(Z) LocalVariable(
|
||||
collection_pos,
|
||||
collection_pos, Symbols::ForInIter(), iterator_type);
|
||||
current_block_->scope->AddVariable(iterator_var);
|
||||
|
||||
|
@ -9448,7 +9476,8 @@ AstNode* Parser::ParseForInStatement(TokenPosition forin_pos,
|
|||
// The for loop variable is new for each iteration.
|
||||
// Create a variable and add it to the loop body scope.
|
||||
LocalVariable* loop_var =
|
||||
new(Z) LocalVariable(loop_var_assignment_pos,
|
||||
new(Z) LocalVariable(loop_var_pos,
|
||||
loop_var_assignment_pos,
|
||||
*loop_var_name,
|
||||
loop_var_type);;
|
||||
if (loop_var_is_final) {
|
||||
|
@ -9614,6 +9643,7 @@ void Parser::AddCatchParamsToScope(CatchParamDesc* exception_param,
|
|||
LocalScope* scope) {
|
||||
if (exception_param->name != NULL) {
|
||||
LocalVariable* var = new(Z) LocalVariable(
|
||||
exception_param->token_pos,
|
||||
exception_param->token_pos,
|
||||
*exception_param->name,
|
||||
*exception_param->type);
|
||||
|
@ -9624,6 +9654,7 @@ void Parser::AddCatchParamsToScope(CatchParamDesc* exception_param,
|
|||
}
|
||||
if (stack_trace_param->name != NULL) {
|
||||
LocalVariable* var = new(Z) LocalVariable(
|
||||
stack_trace_param->token_pos,
|
||||
stack_trace_param->token_pos,
|
||||
*stack_trace_param->name,
|
||||
*stack_trace_param->type);
|
||||
|
@ -10033,6 +10064,7 @@ void Parser::SetupSavedTryContext(LocalVariable* saved_try_context) {
|
|||
Symbols::AsyncSavedTryCtxVarPrefix().ToCString(),
|
||||
last_used_try_index_ - 1));
|
||||
LocalVariable* async_saved_try_ctx = new (Z) LocalVariable(
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
async_saved_try_ctx_name,
|
||||
Object::dynamic_type());
|
||||
|
@ -10074,6 +10106,7 @@ void Parser::SetupExceptionVariables(LocalScope* try_scope,
|
|||
*context_var = try_scope->LocalLookupVariable(Symbols::SavedTryContextVar());
|
||||
if (*context_var == NULL) {
|
||||
*context_var = new(Z) LocalVariable(
|
||||
TokenPos(),
|
||||
TokenPos(),
|
||||
Symbols::SavedTryContextVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -10082,6 +10115,7 @@ void Parser::SetupExceptionVariables(LocalScope* try_scope,
|
|||
*exception_var = try_scope->LocalLookupVariable(Symbols::ExceptionVar());
|
||||
if (*exception_var == NULL) {
|
||||
*exception_var = new(Z) LocalVariable(
|
||||
TokenPos(),
|
||||
TokenPos(),
|
||||
Symbols::ExceptionVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -10090,6 +10124,7 @@ void Parser::SetupExceptionVariables(LocalScope* try_scope,
|
|||
*stack_trace_var = try_scope->LocalLookupVariable(Symbols::StackTraceVar());
|
||||
if (*stack_trace_var == NULL) {
|
||||
*stack_trace_var = new(Z) LocalVariable(
|
||||
TokenPos(),
|
||||
TokenPos(),
|
||||
Symbols::StackTraceVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -10100,6 +10135,7 @@ void Parser::SetupExceptionVariables(LocalScope* try_scope,
|
|||
Symbols::SavedExceptionVar());
|
||||
if (*saved_exception_var == NULL) {
|
||||
*saved_exception_var = new(Z) LocalVariable(
|
||||
TokenPos(),
|
||||
TokenPos(),
|
||||
Symbols::SavedExceptionVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -10109,6 +10145,7 @@ void Parser::SetupExceptionVariables(LocalScope* try_scope,
|
|||
Symbols::SavedStackTraceVar());
|
||||
if (*saved_stack_trace_var == NULL) {
|
||||
*saved_stack_trace_var = new(Z) LocalVariable(
|
||||
TokenPos(),
|
||||
TokenPos(),
|
||||
Symbols::SavedStackTraceVar(),
|
||||
Object::dynamic_type());
|
||||
|
@ -11089,6 +11126,7 @@ LocalVariable* Parser::CreateTempConstVariable(TokenPosition token_pos,
|
|||
char name[64];
|
||||
OS::SNPrint(name, 64, ":%s%" Pd "", s, token_pos.value());
|
||||
LocalVariable* temp = new(Z) LocalVariable(
|
||||
token_pos,
|
||||
token_pos,
|
||||
String::ZoneHandle(Z, Symbols::New(T, name)),
|
||||
Object::dynamic_type());
|
||||
|
|
|
@ -114,6 +114,7 @@ class ParsedFunction : public ZoneAllocated {
|
|||
ASSERT(function.IsZoneHandle());
|
||||
// Every function has a local variable for the current context.
|
||||
LocalVariable* temp = new(zone()) LocalVariable(
|
||||
function.token_pos(),
|
||||
function.token_pos(),
|
||||
Symbols::CurrentContextVar(),
|
||||
Object::dynamic_type());
|
||||
|
|
|
@ -1355,6 +1355,7 @@ class RawLocalVarDescriptors : public RawObject {
|
|||
struct VarInfo {
|
||||
int32_t index_kind; // Bitfield for slot index on stack or in context,
|
||||
// and Entry kind of type VarInfoKind.
|
||||
TokenPosition declaration_pos; // Token position of declaration.
|
||||
TokenPosition begin_pos; // Token position of scope start.
|
||||
TokenPosition end_pos; // Token position of scope end.
|
||||
int16_t scope_id; // Scope to which the variable belongs.
|
||||
|
@ -1457,6 +1458,7 @@ class RawContextScope : public RawObject {
|
|||
// TODO(iposva): Switch to conventional enum offset based structure to avoid
|
||||
// alignment mishaps.
|
||||
struct VariableDesc {
|
||||
RawSmi* declaration_token_pos;
|
||||
RawSmi* token_pos;
|
||||
RawString* name;
|
||||
RawBool* is_final;
|
||||
|
|
|
@ -1485,6 +1485,7 @@ RawContextScope* ContextScope::ReadFrom(SnapshotReader* reader,
|
|||
|
||||
// Create a descriptor for 'this' variable.
|
||||
context_scope.SetTokenIndexAt(0, TokenPosition::kMinSource);
|
||||
context_scope.SetDeclarationTokenIndexAt(0, TokenPosition::kMinSource);
|
||||
context_scope.SetNameAt(0, Symbols::This());
|
||||
context_scope.SetIsFinalAt(0, true);
|
||||
context_scope.SetIsConstAt(0, false);
|
||||
|
|
|
@ -385,7 +385,10 @@ DEFINE_RAW_LEAF_RUNTIME_ENTRY(
|
|||
LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
|
||||
intptr_t index) const {
|
||||
LocalVariable* local = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource, name, Object::dynamic_type());
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
name,
|
||||
Object::dynamic_type());
|
||||
|
||||
intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index;
|
||||
local->set_index(param_frame_index);
|
||||
|
@ -396,7 +399,10 @@ LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
|
|||
|
||||
LocalVariable* IRRegExpMacroAssembler::Local(const String& name) {
|
||||
LocalVariable* local = new(Z) LocalVariable(
|
||||
TokenPosition::kNoSource, name, Object::dynamic_type());
|
||||
TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource,
|
||||
name,
|
||||
Object::dynamic_type());
|
||||
local->set_index(GetNextLocalIndex());
|
||||
|
||||
return local;
|
||||
|
|
|
@ -288,6 +288,7 @@ RawLocalVarDescriptors* LocalScope::GetVarDescriptors(const Function& func) {
|
|||
desc.name = &name;
|
||||
desc.info.set_kind(kind);
|
||||
desc.info.scope_id = context_scope.ContextLevelAt(i);
|
||||
desc.info.declaration_pos = context_scope.DeclarationTokenIndexAt(i);
|
||||
desc.info.begin_pos = begin_token_pos();
|
||||
desc.info.end_pos = end_token_pos();
|
||||
ASSERT(desc.info.begin_pos <= desc.info.end_pos);
|
||||
|
@ -336,6 +337,7 @@ void LocalScope::CollectLocalVariables(GrowableArray<VarDesc>* vars,
|
|||
desc.name = &var->name();
|
||||
desc.info.set_kind(RawLocalVarDescriptors::kSavedCurrentContext);
|
||||
desc.info.scope_id = 0;
|
||||
desc.info.declaration_pos = TokenPosition::kMinSource;
|
||||
desc.info.begin_pos = TokenPosition::kMinSource;
|
||||
desc.info.end_pos = TokenPosition::kMinSource;
|
||||
desc.info.set_index(var->index());
|
||||
|
@ -353,6 +355,7 @@ void LocalScope::CollectLocalVariables(GrowableArray<VarDesc>* vars,
|
|||
desc.info.set_kind(RawLocalVarDescriptors::kStackVar);
|
||||
desc.info.scope_id = *scope_id;
|
||||
}
|
||||
desc.info.declaration_pos = var->declaration_token_pos();
|
||||
desc.info.begin_pos = var->token_pos();
|
||||
desc.info.end_pos = var->owner()->end_token_pos();
|
||||
desc.info.set_index(var->index());
|
||||
|
@ -551,6 +554,8 @@ RawContextScope* LocalScope::PreserveOuterScope(int current_context_level)
|
|||
// Preserve the aliases of captured variables belonging to outer scopes.
|
||||
if (variable->owner()->function_level() != 1) {
|
||||
context_scope.SetTokenIndexAt(captured_idx, variable->token_pos());
|
||||
context_scope.SetDeclarationTokenIndexAt(
|
||||
captured_idx, variable->declaration_token_pos());
|
||||
context_scope.SetNameAt(captured_idx, variable->name());
|
||||
context_scope.SetIsFinalAt(captured_idx, variable->is_final());
|
||||
context_scope.SetIsConstAt(captured_idx, variable->IsConst());
|
||||
|
@ -582,13 +587,17 @@ LocalScope* LocalScope::RestoreOuterScope(const ContextScope& context_scope) {
|
|||
for (int i = 0; i < context_scope.num_variables(); i++) {
|
||||
LocalVariable* variable;
|
||||
if (context_scope.IsConstAt(i)) {
|
||||
variable = new LocalVariable(context_scope.TokenIndexAt(i),
|
||||
variable = new LocalVariable(
|
||||
context_scope.DeclarationTokenIndexAt(i),
|
||||
context_scope.TokenIndexAt(i),
|
||||
String::ZoneHandle(context_scope.NameAt(i)),
|
||||
Object::dynamic_type());
|
||||
variable->SetConstValue(
|
||||
Instance::ZoneHandle(context_scope.ConstValueAt(i)));
|
||||
} else {
|
||||
variable = new LocalVariable(context_scope.TokenIndexAt(i),
|
||||
variable = new LocalVariable(
|
||||
context_scope.DeclarationTokenIndexAt(i),
|
||||
context_scope.TokenIndexAt(i),
|
||||
String::ZoneHandle(context_scope.NameAt(i)),
|
||||
AbstractType::ZoneHandle(context_scope.TypeAt(i)));
|
||||
}
|
||||
|
@ -640,6 +649,7 @@ RawContextScope* LocalScope::CreateImplicitClosureScope(const Function& func) {
|
|||
|
||||
// Create a descriptor for 'this' variable.
|
||||
context_scope.SetTokenIndexAt(0, func.token_pos());
|
||||
context_scope.SetDeclarationTokenIndexAt(0, func.token_pos());
|
||||
context_scope.SetNameAt(0, Symbols::This());
|
||||
context_scope.SetIsFinalAt(0, true);
|
||||
context_scope.SetIsConstAt(0, false);
|
||||
|
|
|
@ -21,10 +21,12 @@ class LocalScope;
|
|||
|
||||
class LocalVariable : public ZoneAllocated {
|
||||
public:
|
||||
LocalVariable(TokenPosition token_pos,
|
||||
LocalVariable(TokenPosition declaration_pos,
|
||||
TokenPosition token_pos,
|
||||
const String& name,
|
||||
const AbstractType& type)
|
||||
: token_pos_(token_pos),
|
||||
: declaration_pos_(declaration_pos),
|
||||
token_pos_(token_pos),
|
||||
name_(name),
|
||||
owner_(NULL),
|
||||
type_(type),
|
||||
|
@ -41,6 +43,7 @@ class LocalVariable : public ZoneAllocated {
|
|||
}
|
||||
|
||||
TokenPosition token_pos() const { return token_pos_; }
|
||||
TokenPosition declaration_token_pos() const { return declaration_pos_; }
|
||||
const String& name() const { return name_; }
|
||||
LocalScope* owner() const { return owner_; }
|
||||
void set_owner(LocalScope* owner) {
|
||||
|
@ -117,6 +120,7 @@ class LocalVariable : public ZoneAllocated {
|
|||
private:
|
||||
static const int kUninitializedIndex = INT_MIN;
|
||||
|
||||
const TokenPosition declaration_pos_;
|
||||
const TokenPosition token_pos_;
|
||||
const String& name_;
|
||||
LocalScope* owner_; // Local scope declaring this variable.
|
||||
|
|
|
@ -14,15 +14,19 @@ TEST_CASE(LocalScope) {
|
|||
const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
|
||||
const String& a = String::ZoneHandle(Symbols::New(thread, "a"));
|
||||
LocalVariable* var_a =
|
||||
new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource, a, dynamic_type);
|
||||
LocalVariable* inner_var_a =
|
||||
new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource, a, dynamic_type);
|
||||
const String& b = String::ZoneHandle(Symbols::New(thread, "b"));
|
||||
LocalVariable* var_b =
|
||||
new LocalVariable(TokenPosition::kNoSource, b, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource, b, dynamic_type);
|
||||
const String& c = String::ZoneHandle(Symbols::New(thread, "c"));
|
||||
LocalVariable* var_c =
|
||||
new LocalVariable(TokenPosition::kNoSource, c, dynamic_type);
|
||||
new LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource, c, dynamic_type);
|
||||
const String& L = String::ZoneHandle(Symbols::New(thread, "L"));
|
||||
SourceLabel* label_L =
|
||||
new SourceLabel(TokenPosition::kNoSource, L, SourceLabel::kFor);
|
||||
|
|
|
@ -895,6 +895,15 @@ _BeingInitialized_ [Sentinel](#sentinel).
|
|||
class BoundVariable {
|
||||
string name;
|
||||
@Instance|Sentinel value;
|
||||
|
||||
// The token position where this variable was declared.
|
||||
int declarationTokenPos;
|
||||
|
||||
// The first token position where this variable is visible to the scope.
|
||||
int scopeStartTokenPos;
|
||||
|
||||
// The last token position where this variable is visible to the scope.
|
||||
int scopeEndTokenPos;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2528,4 +2537,6 @@ version | comments
|
|||
3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
|
||||
3.4 | Add the superType and mixin fields to Class. Added new pause event 'None'.
|
||||
3.5 | Add the error field to SourceReportRange. Clarify definition of token position. Add "Isolate must be paused" error code.
|
||||
3.6 (unreleased) | Add 'scopeStartTokenPos', 'scopeEndTokenPos', and 'declarationTokenPos' to BoundVariable.
|
||||
|
||||
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
|
||||
|
|
Loading…
Reference in a new issue