1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Make eval(code, binding) use (eval) as __FILE__ and 1 as __LINE__

This removes the warning that was added in
3802fb92ff, and switches the behavior
so that the eval does not use the binding's __FILE__ and __LINE__
implicitly.

Fixes [Bug #4352]
This commit is contained in:
Jeremy Evans 2019-07-30 16:15:19 -07:00
parent 170f4dbb9b
commit 0eeed5bcc5
Notes: git 2020-01-04 13:13:49 +09:00
7 changed files with 103 additions and 67 deletions

24
parse.y
View file

@ -315,7 +315,6 @@ struct parser_params {
unsigned int do_loop: 1; unsigned int do_loop: 1;
unsigned int do_chomp: 1; unsigned int do_chomp: 1;
unsigned int do_split: 1; unsigned int do_split: 1;
unsigned int warn_location: 1;
NODE *eval_tree_begin; NODE *eval_tree_begin;
NODE *eval_tree; NODE *eval_tree;
@ -9917,19 +9916,6 @@ past_dvar_p(struct parser_params *p, ID id)
} }
# endif # endif
/* As Ripper#warn does not have arguments for the location, so the
* following messages cannot be separated */
#define WARN_LOCATION(type) do { \
if (p->warn_location) { \
int line; \
VALUE file = rb_source_location(&line); \
rb_warn3(type" in eval may not return location in binding;" \
" use Binding#source_location instead\n" \
"%"PRIsWARN":%d: warning: in `%"PRIsWARN"'", \
file, WARN_I(line), rb_id2str(rb_frame_this_func())); \
} \
} while (0)
static int static int
numparam_nested_p(struct parser_params *p) numparam_nested_p(struct parser_params *p)
{ {
@ -9963,7 +9949,6 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
case keyword_false: case keyword_false:
return NEW_FALSE(loc); return NEW_FALSE(loc);
case keyword__FILE__: case keyword__FILE__:
WARN_LOCATION("__FILE__");
{ {
VALUE file = p->ruby_sourcefile_string; VALUE file = p->ruby_sourcefile_string;
if (NIL_P(file)) if (NIL_P(file))
@ -9975,7 +9960,6 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
} }
return node; return node;
case keyword__LINE__: case keyword__LINE__:
WARN_LOCATION("__LINE__");
return NEW_LIT(INT2FIX(p->tokline), loc); return NEW_LIT(INT2FIX(p->tokline), loc);
case keyword__ENCODING__: case keyword__ENCODING__:
node = NEW_LIT(rb_enc_from_encoding(p->enc), loc); node = NEW_LIT(rb_enc_from_encoding(p->enc), loc);
@ -12248,14 +12232,6 @@ rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
p->do_split = split; p->do_split = split;
} }
void
rb_parser_warn_location(VALUE vparser, int warn)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->warn_location = warn;
}
static NODE * static NODE *
parser_append_options(struct parser_params *p, NODE *node) parser_append_options(struct parser_params *p, NODE *node)
{ {

View file

@ -23,6 +23,7 @@ describe "Binding#eval" do
bind2.local_variables.should == [] bind2.local_variables.should == []
end end
ruby_version_is ""..."2.8" do
it "inherits __LINE__ from the enclosing scope" do it "inherits __LINE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1) obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding bind = obj.get_binding
@ -47,6 +48,34 @@ describe "Binding#eval" do
bind, line = obj.get_binding_with_send_and_line bind, line = obj.get_binding_with_send_and_line
suppress_warning {bind.eval("__LINE__")}.should == line suppress_warning {bind.eval("__LINE__")}.should == line
end end
end
ruby_version_is "2.8" do
it "starts with line 1 if single argument is given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == 1
end
it "preserves __LINE__ across multiple calls to eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == 1
bind.eval("__LINE__").should == 1
end
it "increments __LINE__ on each line of a multiline eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("#foo\n__LINE__").should == 2
end
it "starts with line 1 if the Binding is created with #send" do
obj = BindingSpecs::Demo.new(1)
bind, line = obj.get_binding_with_send_and_line
bind.eval("__LINE__").should == 1
end
end
it "starts with a __LINE__ of 1 if a filename is passed" do it "starts with a __LINE__ of 1 if a filename is passed" do
bind = BindingSpecs::Demo.new(1).get_binding bind = BindingSpecs::Demo.new(1).get_binding
@ -60,11 +89,21 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89 bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end end
ruby_version_is ""..."2.8" do
it "inherits __FILE__ from the enclosing scope" do it "inherits __FILE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1) obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding bind = obj.get_binding
suppress_warning {bind.eval("__FILE__")}.should == obj.get_file_of_binding suppress_warning {bind.eval("__FILE__")}.should == obj.get_file_of_binding
end end
end
ruby_version_is "2.8" do
it "Uses (eval) as __FILE__ if single argument given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == '(eval)'
end
end
it "uses the __FILE__ that is passed in" do it "uses the __FILE__ that is passed in" do
bind = BindingSpecs::Demo.new(1).get_binding bind = BindingSpecs::Demo.new(1).get_binding

View file

@ -12,9 +12,19 @@ describe "Kernel#__dir__" do
end end
end end
ruby_version_is ""..."2.7" do
context "when used in eval with top level binding" do context "when used in eval with top level binding" do
it "returns the real name of the directory containing the currently-executing file" do it "returns the real name of the directory containing the currently-executing file" do
eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__)) eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
end end
end end
end
ruby_version_is "2.7" do
context "when used in eval with top level binding" do
it "returns nil" do
eval("__dir__", binding).should == nil
end
end
end
end end

View file

@ -159,6 +159,7 @@ describe "Kernel#eval" do
end end
end end
ruby_version_is ""..."2.8" do
it "uses the filename of the binding if none is provided" do it "uses the filename of the binding if none is provided" do
eval("__FILE__").should == "(eval)" eval("__FILE__").should == "(eval)"
suppress_warning {eval("__FILE__", binding)}.should == __FILE__ suppress_warning {eval("__FILE__", binding)}.should == __FILE__
@ -167,6 +168,19 @@ describe "Kernel#eval" do
suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__ suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success' suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
end end
end
ruby_version_is "2.8" do
it "uses (eval) filename if none is provided" do
eval("__FILE__").should == "(eval)"
eval("__FILE__", binding).should == "(eval)"
eval("__FILE__", binding, "success").should == "success"
eval("eval '__FILE__', binding").should == "(eval)"
eval("eval '__FILE__', binding", binding).should == "(eval)"
eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
end
end
# Found via Rubinius bug github:#149 # Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do it "does not alter the value of __FILE__ in the binding" do

View file

@ -470,9 +470,12 @@ class TestEval < Test::Unit::TestCase
end end
def test_eval_location_binding def test_eval_location_binding
assert_warning(/__FILE__ in eval/) do assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", nil))
assert_equal(__FILE__, eval("__FILE__", binding)) assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", binding))
end assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", nil, 'foo'))
assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", binding, 'foo'))
assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", nil, 'foo', 2))
assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", binding, 'foo', 2))
end end
def test_fstring_instance_eval def test_fstring_instance_eval

View file

@ -790,7 +790,7 @@ class TestMethod < Test::Unit::TestCase
assert_instance_of String, __dir__ assert_instance_of String, __dir__
assert_equal(File.dirname(File.realpath(__FILE__)), __dir__) assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
bug8436 = '[ruby-core:55123] [Bug #8436]' bug8436 = '[ruby-core:55123] [Bug #8436]'
assert_equal(__dir__, eval("__dir__", binding), bug8436) assert_equal(__dir__, eval("__dir__", binding, *binding.source_location), bug8436)
bug8662 = '[ruby-core:56099] [Bug #8662]' bug8662 = '[ruby-core:56099] [Bug #8662]'
assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662) assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662) assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)

View file

@ -1497,12 +1497,6 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
if (!NIL_P(fname)) fname = rb_fstring(fname); if (!NIL_P(fname)) fname = rb_fstring(fname);
realpath = fname; realpath = fname;
} }
else if (bind) {
fname = pathobj_path(bind->pathobj);
realpath = pathobj_realpath(bind->pathobj);
line = bind->first_lineno;
rb_parser_warn_location(parser, TRUE);
}
else { else {
fname = rb_fstring_lit("(eval)"); fname = rb_fstring_lit("(eval)");
} }