From 4ed0c33d13ff0d2544aaf36e8e4f071b900d10cd Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 12 Oct 2020 00:26:39 +0900 Subject: Prohibit setter method names in all kinds of endless methods Also unwrap NODE_RIPPER to check the method name. --- parse.y | 19 ++++++++++++--- test/ripper/test_parser_events.rb | 50 ++++++++++++++++++++++++++++++++++----- test/ruby/test_syntax.rb | 7 +++++- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/parse.y b/parse.y index 1a6887e983..f8d05ad44a 100644 --- a/parse.y +++ b/parse.y @@ -961,6 +961,18 @@ restore_defun(struct parser_params *p, NODE *name) p->ctxt.in_def = c.ctxt.in_def; } +static void +endless_method_name(struct parser_params *p, NODE *defn, const YYLTYPE *loc) +{ +#ifdef RIPPER + defn = defn->nd_defn; +#endif + ID mid = defn->nd_mid; + if (is_attrset_id(mid)) { + yyerror1(loc, "setter method cannot be defined in an endless method definition"); + } +} + #ifndef RIPPER # define Qnone 0 # define Qnull 0 @@ -2477,9 +2489,7 @@ arg : lhs '=' arg_rhs } | defn_head f_paren_args '=' arg { - if (is_attrset_id($1->nd_mid)) { - yyerror1(&@1, "setter method cannot be defined in an endless method definition"); - } + endless_method_name(p, $1, &@1); token_info_drop(p, "def", @1.beg_pos); restore_defun(p, $1->nd_defn); /*%%%*/ @@ -2490,6 +2500,7 @@ arg : lhs '=' arg_rhs } | defn_head f_paren_args '=' arg modifier_rescue arg { + endless_method_name(p, $1, &@1); token_info_drop(p, "def", @1.beg_pos); restore_defun(p, $1->nd_defn); /*%%%*/ @@ -2501,6 +2512,7 @@ arg : lhs '=' arg_rhs } | defs_head f_paren_args '=' arg { + endless_method_name(p, $1, &@1); restore_defun(p, $1->nd_defn); /*%%%*/ $$ = set_defun_body(p, $1, $2, $4, &@$); @@ -2512,6 +2524,7 @@ arg : lhs '=' arg_rhs } | defs_head f_paren_args '=' arg modifier_rescue arg { + endless_method_name(p, $1, &@1); restore_defun(p, $1->nd_defn); /*%%%*/ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6); diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb index 13064c2bc8..4e1d233851 100644 --- a/test/ripper/test_parser_events.rb +++ b/test/ripper/test_parser_events.rb @@ -660,11 +660,30 @@ class TestRipper::ParserEvents < Test::Unit::TestCase } assert_equal true, thru_def assert_equal '[def(foo,[],bodystmt([void()]))]', parse('def foo ;end') + end - thru_def = false - tree = parse('def foo() = 42', :on_def) {thru_def = true} - assert_equal true, thru_def + def test_endless_def + events = %i[on_def on_parse_error] + thru = nil + hook = ->(name, *) {thru[name] = true} + + thru = {} + tree = parse('def foo() = 42', events, &hook) + assert_equal({on_def: true}, thru) assert_equal '[def(foo,[],42)]', tree + + thru = {} + tree = parse('def foo() = 42 rescue 0', events, &hook) + assert_equal({on_def: true}, thru) + assert_equal '[def(foo,[],rescue_mod(42,0))]', tree + + thru = {} + tree = parse('def foo=() = 42', events, &hook) + assert_equal({on_def: true, on_parse_error: true}, thru) + + thru = {} + tree = parse('def foo=() = 42 rescue 0', events, &hook) + assert_equal({on_def: true, on_parse_error: true}, thru) end def test_defined @@ -682,11 +701,30 @@ class TestRipper::ParserEvents < Test::Unit::TestCase thru_parse_error = false tree = parse('def foo&.bar; end', :on_parse_error) {thru_parse_error = true} assert_equal(true, thru_parse_error) + end - thru_defs = false - tree = parse('def foo.bar() = 42', :on_defs) {thru_defs = true} - assert_equal true, thru_defs + def test_endless_defs + events = %i[on_defs on_parse_error] + thru = nil + hook = ->(name, *) {thru[name] = true} + + thru = {} + tree = parse('def foo.bar() = 42', events, &hook) + assert_equal({on_defs: true}, thru) assert_equal '[defs(vcall(foo),.,bar,[],42)]', tree + + thru = {} + tree = parse('def foo.bar() = 42 rescue 0', events, &hook) + assert_equal({on_defs: true}, thru) + assert_equal '[defs(vcall(foo),.,bar,[],rescue_mod(42,0))]', tree + + thru = {} + tree = parse('def foo.bar=() = 42', events, &hook) + assert_equal({on_defs: true, on_parse_error: true}, thru) + + thru = {} + tree = parse('def foo.bar=() = 42 rescue 0', events, &hook) + assert_equal({on_defs: true, on_parse_error: true}, thru) end def test_do_block diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index fb982e8a1f..0542d4f90d 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -1429,7 +1429,12 @@ eom end assert_equal("class ok", k.rescued("ok")) assert_equal("instance ok", k.new.rescued("ok")) - assert_syntax_error('def foo=() = 42', /setter method cannot be defined in an endless method definition/) + + error = /setter method cannot be defined in an endless method definition/ + assert_syntax_error('def foo=() = 42', error) + assert_syntax_error('def obj.foo=() = 42', error) + assert_syntax_error('def foo=() = 42 rescue nil', error) + assert_syntax_error('def obj.foo=() = 42 rescue nil', error) end def test_methoddef_in_cond -- cgit v1.2.3