зеркало из https://github.com/github/ruby.git
Make RubyVM::AbstractSyntaxTree.of raise for backtrace location in eval
This check is needed to fix a bug of error_highlight when NameError
occurred in eval'ed code.
https://github.com/ruby/error_highlight/pull/16
The same check for proc/method has been already introduced since
64ac984129
.
This commit is contained in:
Родитель
7e0e6f9074
Коммит
acac2b8128
14
ast.c
14
ast.c
|
@ -196,14 +196,15 @@ static VALUE
|
|||
ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script_lines)
|
||||
{
|
||||
VALUE path, node, lines = Qnil;
|
||||
const rb_iseq_t *iseq;
|
||||
int node_id;
|
||||
|
||||
if (rb_frame_info_p(body)) {
|
||||
rb_frame_info_get(body, &path, &lines, &node_id);
|
||||
if (NIL_P(path) && NIL_P(lines)) return Qnil;
|
||||
iseq = rb_get_iseq_from_frame_info(body);
|
||||
node_id = rb_get_node_id_from_frame_info(body);
|
||||
}
|
||||
else {
|
||||
const rb_iseq_t *iseq = NULL;
|
||||
iseq = NULL;
|
||||
|
||||
if (rb_obj_is_proc(body)) {
|
||||
iseq = vm_proc_iseq(body);
|
||||
|
@ -213,6 +214,11 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script
|
|||
else {
|
||||
iseq = rb_method_iseq(body);
|
||||
}
|
||||
if (iseq) {
|
||||
node_id = iseq->body->location.node_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iseq) {
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -221,8 +227,6 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script
|
|||
}
|
||||
path = rb_iseq_path(iseq);
|
||||
lines = iseq->body->variable.script_lines;
|
||||
node_id = iseq->body->location.node_id;
|
||||
}
|
||||
|
||||
if (!NIL_P(lines) || !NIL_P(lines = script_lines(path))) {
|
||||
node = rb_ast_parse_array(lines, keep_script_lines);
|
||||
|
|
|
@ -111,7 +111,8 @@ VALUE rb_backtrace_to_str_ary(VALUE obj);
|
|||
VALUE rb_backtrace_to_location_ary(VALUE obj);
|
||||
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
||||
int rb_frame_info_p(VALUE obj);
|
||||
void rb_frame_info_get(VALUE obj, VALUE *path, VALUE *script_lines, int *node_id);
|
||||
int rb_get_node_id_from_frame_info(VALUE obj);
|
||||
const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj);
|
||||
|
||||
MJIT_SYMBOL_EXPORT_BEGIN
|
||||
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
|
||||
|
|
|
@ -29,7 +29,7 @@ module ErrorHighlight
|
|||
|
||||
spot = ErrorHighlight.spot(node, **opts)
|
||||
|
||||
rescue SystemCallError, SyntaxError
|
||||
rescue SystemCallError, SyntaxError, ArgumentError
|
||||
end
|
||||
|
||||
if spot
|
||||
|
|
|
@ -185,7 +185,7 @@ class TestAst < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_of
|
||||
def test_of_proc_and_method
|
||||
proc = Proc.new { 1 + 2 }
|
||||
method = self.method(__method__)
|
||||
|
||||
|
@ -194,7 +194,6 @@ class TestAst < Test::Unit::TestCase
|
|||
|
||||
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_proc)
|
||||
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_method)
|
||||
assert_raise(TypeError) { RubyVM::AbstractSyntaxTree.of("1 + 2") }
|
||||
|
||||
Tempfile.create(%w"test_of .rb") do |tmp|
|
||||
tmp.print "#{<<-"begin;"}\n#{<<-'end;'}"
|
||||
|
@ -211,7 +210,22 @@ class TestAst < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_of_eval
|
||||
def sample_backtrace_location
|
||||
[caller_locations(0).first, __LINE__]
|
||||
end
|
||||
|
||||
def test_of_backtrace_location
|
||||
backtrace_location, lineno = sample_backtrace_location
|
||||
node = RubyVM::AbstractSyntaxTree.of(backtrace_location)
|
||||
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node)
|
||||
assert_equal(lineno, node.first_lineno)
|
||||
end
|
||||
|
||||
def test_of_error
|
||||
assert_raise(TypeError) { RubyVM::AbstractSyntaxTree.of("1 + 2") }
|
||||
end
|
||||
|
||||
def test_of_proc_and_method_under_eval
|
||||
method = self.method(eval("def example_method_#{$$}; end"))
|
||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) }
|
||||
|
||||
|
@ -229,6 +243,21 @@ class TestAst < Test::Unit::TestCase
|
|||
|
||||
method = eval("Class.new{def example_method; end}.instance_method(:example_method)")
|
||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) }
|
||||
|
||||
method = eval("Class.new{def example_method; end}.instance_method(:example_method)")
|
||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) }
|
||||
end
|
||||
|
||||
def test_of_backtrace_location_under_eval
|
||||
m = Module.new do
|
||||
eval(<<-END, nil, __FILE__, __LINE__)
|
||||
def self.sample_backtrace_location
|
||||
[caller_locations(0).first, __LINE__]
|
||||
end
|
||||
END
|
||||
end
|
||||
backtrace_location, lineno = m.sample_backtrace_location
|
||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(backtrace_location) }
|
||||
end
|
||||
|
||||
def test_of_c_method
|
||||
|
|
|
@ -333,20 +333,25 @@ location_node_id(rb_backtrace_location_t *loc)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
rb_frame_info_get(VALUE obj, VALUE *path, VALUE *script_lines, int *node_id)
|
||||
int
|
||||
rb_get_node_id_from_frame_info(VALUE obj)
|
||||
{
|
||||
#ifdef USE_ISEQ_NODE_ID
|
||||
rb_backtrace_location_t *loc = location_ptr(obj);
|
||||
const rb_iseq_t *iseq = location_iseq(loc);
|
||||
*path = iseq ? rb_iseq_path(iseq) : Qnil;
|
||||
*script_lines = iseq ? iseq->body->variable.script_lines : Qnil;
|
||||
*node_id = location_node_id(loc);
|
||||
return location_node_id(loc);
|
||||
#else
|
||||
*path = Qnil;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
const rb_iseq_t *
|
||||
rb_get_iseq_from_frame_info(VALUE obj)
|
||||
{
|
||||
rb_backtrace_location_t *loc = location_ptr(obj);
|
||||
const rb_iseq_t *iseq = location_iseq(loc);
|
||||
return iseq;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
location_realpath(rb_backtrace_location_t *loc)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче