Project

General

Profile

Bug #4352 ยป eval-binding-file-line-4352.patch

jeremyevans0 (Jeremy Evans), 07/31/2019 06:39 PM

View differences:

parse.y
274 274
    unsigned int do_loop: 1;
275 275
    unsigned int do_chomp: 1;
276 276
    unsigned int do_split: 1;
277
    unsigned int warn_location: 1;
278 277

  
279 278
    NODE *eval_tree_begin;
280 279
    NODE *eval_tree;
......
9739 9738
}
9740 9739
# endif
9741 9740

  
9742
#define WARN_LOCATION(type) do { \
9743
    if (p->warn_location) { \
9744
	rb_warning0(type" in eval may not return location in binding;" \
9745
		    " use Binding#source_location instead"); \
9746
    } \
9747
} while (0)
9748

  
9749 9741
static NODE*
9750 9742
gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
9751 9743
{
......
9761 9753
      case keyword_false:
9762 9754
	return NEW_FALSE(loc);
9763 9755
      case keyword__FILE__:
9764
	WARN_LOCATION("__FILE__");
9765 9756
	{
9766 9757
	    VALUE file = p->ruby_sourcefile_string;
9767 9758
	    if (NIL_P(file))
......
9772 9763
	}
9773 9764
	return node;
9774 9765
      case keyword__LINE__:
9775
	WARN_LOCATION("__LINE__");
9776 9766
	return NEW_LIT(INT2FIX(p->tokline), loc);
9777 9767
      case keyword__ENCODING__:
9778 9768
	return NEW_LIT(add_mark_object(p, rb_enc_from_encoding(p->enc)), loc);
......
11977 11967
    p->do_split = split;
11978 11968
}
11979 11969

  
11980
void
11981
rb_parser_warn_location(VALUE vparser, int warn)
11982
{
11983
    struct parser_params *p;
11984
    TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
11985
    p->warn_location = warn;
11986
}
11987

  
11988 11970
static NODE *
11989 11971
parser_append_options(struct parser_params *p, NODE *node)
11990 11972
{
spec/ruby/core/binding/eval_spec.rb
23 23
    bind2.local_variables.should == []
24 24
  end
25 25

  
26
  it "inherits __LINE__ from the enclosing scope" do
27
    obj = BindingSpecs::Demo.new(1)
28
    bind = obj.get_binding
29
    bind.eval("__LINE__").should == obj.get_line_of_binding
30
  end
26
  ruby_version_is ""..."2.7" do
27
    it "inherits __LINE__ from the enclosing scope" do
28
      obj = BindingSpecs::Demo.new(1)
29
      bind = obj.get_binding
30
      bind.eval("__LINE__").should == obj.get_line_of_binding
31
    end
31 32

  
32
  it "preserves __LINE__ across multiple calls to eval" do
33
    obj = BindingSpecs::Demo.new(1)
34
    bind = obj.get_binding
35
    bind.eval("__LINE__").should == obj.get_line_of_binding
36
    bind.eval("__LINE__").should == obj.get_line_of_binding
37
  end
33
    it "preserves __LINE__ across multiple calls to eval" do
34
      obj = BindingSpecs::Demo.new(1)
35
      bind = obj.get_binding
36
      bind.eval("__LINE__").should == obj.get_line_of_binding
37
      bind.eval("__LINE__").should == obj.get_line_of_binding
38
    end
38 39

  
39
  it "increments __LINE__ on each line of a multiline eval" do
40
    obj = BindingSpecs::Demo.new(1)
41
    bind = obj.get_binding
42
    bind.eval("#foo\n__LINE__").should == obj.get_line_of_binding + 1
40
    it "increments __LINE__ on each line of a multiline eval" do
41
      obj = BindingSpecs::Demo.new(1)
42
      bind = obj.get_binding
43
      bind.eval("#foo\n__LINE__").should == obj.get_line_of_binding + 1
44
    end
45

  
46
    it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
47
      obj = BindingSpecs::Demo.new(1)
48
      bind, line = obj.get_binding_with_send_and_line
49
      bind.eval("__LINE__").should == line
50
    end
43 51
  end
44 52

  
45
  it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
46
    obj = BindingSpecs::Demo.new(1)
47
    bind, line = obj.get_binding_with_send_and_line
48
    bind.eval("__LINE__").should == line
53
  ruby_version_is "2.7" do
54
    it "starts with line 1 if single argument is given" do
55
      obj = BindingSpecs::Demo.new(1)
56
      bind = obj.get_binding
57
      bind.eval("__LINE__").should == 1
58
    end
59

  
60
    it "preserves __LINE__ across multiple calls to eval" do
61
      obj = BindingSpecs::Demo.new(1)
62
      bind = obj.get_binding
63
      bind.eval("__LINE__").should == 1
64
      bind.eval("__LINE__").should == 1
65
    end
66

  
67
    it "increments __LINE__ on each line of a multiline eval" do
68
      obj = BindingSpecs::Demo.new(1)
69
      bind = obj.get_binding
70
      bind.eval("#foo\n__LINE__").should == 2
71
    end
72

  
73
    it "starts with line 1 if the Binding is created with #send" do
74
      obj = BindingSpecs::Demo.new(1)
75
      bind, line = obj.get_binding_with_send_and_line
76
      bind.eval("__LINE__").should == 1
77
    end
49 78
  end
50 79

  
51 80
  it "starts with a __LINE__ of 1 if a filename is passed" do
......
60 89
    bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
61 90
  end
62 91

  
63
  it "inherits __FILE__ from the enclosing scope" do
64
    obj = BindingSpecs::Demo.new(1)
65
    bind = obj.get_binding
66
    bind.eval("__FILE__").should == obj.get_file_of_binding
92
  ruby_version_is ""..."2.7" do
93
    it "inherits __FILE__ from the enclosing scope" do
94
      obj = BindingSpecs::Demo.new(1)
95
      bind = obj.get_binding
96
      bind.eval("__FILE__").should == obj.get_file_of_binding
97
    end
98
  end
99

  
100
  ruby_version_is "2.7" do
101
    it "Uses (eval) as __FILE__ if single argument given" do
102
      obj = BindingSpecs::Demo.new(1)
103
      bind = obj.get_binding
104
      bind.eval("__FILE__").should == '(eval)'
105
    end
67 106
  end
68 107

  
69 108
  it "uses the __FILE__ that is passed in" do
spec/ruby/core/kernel/__dir___spec.rb
12 12
    end
13 13
  end
14 14

  
15
  context "when used in eval with top level binding" do
16
    it "returns the real name of the directory containing the currently-executing file" do
17
      eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
15
  ruby_version_is ""..."2.7" do
16
    context "when used in eval with top level binding" do
17
      it "returns the real name of the directory containing the currently-executing file" do
18
        eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
19
      end
20
    end
21
  end
22

  
23
  ruby_version_is "2.7" do
24
    context "when used in eval with top level binding" do
25
      it "returns nil" do
26
        eval("__dir__", binding).should == nil
27
      end
18 28
    end
19 29
  end
20 30
end
spec/ruby/core/kernel/eval_spec.rb
159 159
    end
160 160
  end
161 161

  
162
  it "uses the filename of the binding if none is provided" do
163
    eval("__FILE__").should == "(eval)"
164
    eval("__FILE__", binding).should == __FILE__
165
    eval("__FILE__", binding, "success").should == "success"
166
    eval("eval '__FILE__', binding").should == "(eval)"
167
    eval("eval '__FILE__', binding", binding).should == __FILE__
168
    eval("eval '__FILE__', binding", binding, 'success').should == 'success'
162
  ruby_version_is ""..."2.7" do
163
    it "uses the filename of the binding if none is provided" do
164
      eval("__FILE__").should == "(eval)"
165
      eval("__FILE__", binding).should == __FILE__
166
      eval("__FILE__", binding, "success").should == "success"
167
      eval("eval '__FILE__', binding").should == "(eval)"
168
      eval("eval '__FILE__', binding", binding).should == __FILE__
169
      eval("eval '__FILE__', binding", binding, 'success').should == 'success'
170
      eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
171
    end
172
  end
173

  
174
  ruby_version_is "2.7" do
175
    it "uses (eval) filename if none is provided" do
176
      eval("__FILE__").should == "(eval)"
177
      eval("__FILE__", binding).should == "(eval)"
178
      eval("__FILE__", binding, "success").should == "success"
179
      eval("eval '__FILE__', binding").should == "(eval)"
180
      eval("eval '__FILE__', binding", binding).should == "(eval)"
181
      eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
182
      eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
183
    end
169 184
  end
170 185

  
171 186
  # Found via Rubinius bug github:#149
test/ruby/test_eval.rb
470 470
  end
471 471

  
472 472
  def test_eval_location_binding
473
    assert_warning(/__FILE__ in eval/) do
474
      assert_equal(__FILE__, eval("__FILE__", binding))
475
    end
473
    assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", nil))
474
    assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", binding))
475
    assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", nil, 'foo'))
476
    assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", binding, 'foo'))
477
    assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", nil, 'foo', 2))
478
    assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", binding, 'foo', 2))
476 479
  end
477 480

  
478 481
  def test_fstring_instance_eval
test/ruby/test_method.rb
722 722
    assert_instance_of String, __dir__
723 723
    assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
724 724
    bug8436 = '[ruby-core:55123] [Bug #8436]'
725
    assert_equal(__dir__, eval("__dir__", binding), bug8436)
725
    assert_equal(__dir__, eval("__dir__", binding, *binding.source_location), bug8436)
726 726
    bug8662 = '[ruby-core:56099] [Bug #8662]'
727 727
    assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
728 728
    assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)
vm_eval.c
1286 1286
    if (fname != Qundef) {
1287 1287
	realpath = fname;
1288 1288
    }
1289
    else if (bind) {
1290
	fname = pathobj_path(bind->pathobj);
1291
	realpath = pathobj_realpath(bind->pathobj);
1292
	line = bind->first_lineno;
1293
	rb_parser_warn_location(parser, TRUE);
1294
    }
1295 1289
    else {
1296 1290
	fname = rb_usascii_str_new_cstr("(eval)");
1297 1291
    }
1298
-