mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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:
parent
7e0e6f9074
commit
acac2b8128
5 changed files with 62 additions and 23 deletions
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)
|
ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script_lines)
|
||||||
{
|
{
|
||||||
VALUE path, node, lines = Qnil;
|
VALUE path, node, lines = Qnil;
|
||||||
|
const rb_iseq_t *iseq;
|
||||||
int node_id;
|
int node_id;
|
||||||
|
|
||||||
if (rb_frame_info_p(body)) {
|
if (rb_frame_info_p(body)) {
|
||||||
rb_frame_info_get(body, &path, &lines, &node_id);
|
iseq = rb_get_iseq_from_frame_info(body);
|
||||||
if (NIL_P(path) && NIL_P(lines)) return Qnil;
|
node_id = rb_get_node_id_from_frame_info(body);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const rb_iseq_t *iseq = NULL;
|
iseq = NULL;
|
||||||
|
|
||||||
if (rb_obj_is_proc(body)) {
|
if (rb_obj_is_proc(body)) {
|
||||||
iseq = vm_proc_iseq(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 {
|
else {
|
||||||
iseq = rb_method_iseq(body);
|
iseq = rb_method_iseq(body);
|
||||||
}
|
}
|
||||||
|
if (iseq) {
|
||||||
|
node_id = iseq->body->location.node_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iseq) {
|
if (!iseq) {
|
||||||
return Qnil;
|
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);
|
path = rb_iseq_path(iseq);
|
||||||
lines = iseq->body->variable.script_lines;
|
lines = iseq->body->variable.script_lines;
|
||||||
node_id = iseq->body->location.node_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NIL_P(lines) || !NIL_P(lines = script_lines(path))) {
|
if (!NIL_P(lines) || !NIL_P(lines = script_lines(path))) {
|
||||||
node = rb_ast_parse_array(lines, keep_script_lines);
|
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);
|
VALUE rb_backtrace_to_location_ary(VALUE obj);
|
||||||
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
||||||
int rb_frame_info_p(VALUE obj);
|
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
|
MJIT_SYMBOL_EXPORT_BEGIN
|
||||||
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
|
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
|
||||||
|
|
|
@ -29,7 +29,7 @@ module ErrorHighlight
|
||||||
|
|
||||||
spot = ErrorHighlight.spot(node, **opts)
|
spot = ErrorHighlight.spot(node, **opts)
|
||||||
|
|
||||||
rescue SystemCallError, SyntaxError
|
rescue SystemCallError, SyntaxError, ArgumentError
|
||||||
end
|
end
|
||||||
|
|
||||||
if spot
|
if spot
|
||||||
|
|
|
@ -185,7 +185,7 @@ class TestAst < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_of
|
def test_of_proc_and_method
|
||||||
proc = Proc.new { 1 + 2 }
|
proc = Proc.new { 1 + 2 }
|
||||||
method = self.method(__method__)
|
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_proc)
|
||||||
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_method)
|
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_method)
|
||||||
assert_raise(TypeError) { RubyVM::AbstractSyntaxTree.of("1 + 2") }
|
|
||||||
|
|
||||||
Tempfile.create(%w"test_of .rb") do |tmp|
|
Tempfile.create(%w"test_of .rb") do |tmp|
|
||||||
tmp.print "#{<<-"begin;"}\n#{<<-'end;'}"
|
tmp.print "#{<<-"begin;"}\n#{<<-'end;'}"
|
||||||
|
@ -211,7 +210,22 @@ class TestAst < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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"))
|
method = self.method(eval("def example_method_#{$$}; end"))
|
||||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) }
|
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)")
|
method = eval("Class.new{def example_method; end}.instance_method(:example_method)")
|
||||||
assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(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
|
end
|
||||||
|
|
||||||
def test_of_c_method
|
def test_of_c_method
|
||||||
|
|
|
@ -333,20 +333,25 @@ location_node_id(rb_backtrace_location_t *loc)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
int
|
||||||
rb_frame_info_get(VALUE obj, VALUE *path, VALUE *script_lines, int *node_id)
|
rb_get_node_id_from_frame_info(VALUE obj)
|
||||||
{
|
{
|
||||||
#ifdef USE_ISEQ_NODE_ID
|
#ifdef USE_ISEQ_NODE_ID
|
||||||
rb_backtrace_location_t *loc = location_ptr(obj);
|
rb_backtrace_location_t *loc = location_ptr(obj);
|
||||||
const rb_iseq_t *iseq = location_iseq(loc);
|
return location_node_id(loc);
|
||||||
*path = iseq ? rb_iseq_path(iseq) : Qnil;
|
|
||||||
*script_lines = iseq ? iseq->body->variable.script_lines : Qnil;
|
|
||||||
*node_id = location_node_id(loc);
|
|
||||||
#else
|
#else
|
||||||
*path = Qnil;
|
return -1;
|
||||||
#endif
|
#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
|
static VALUE
|
||||||
location_realpath(rb_backtrace_location_t *loc)
|
location_realpath(rb_backtrace_location_t *loc)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue