diff --git a/lib/ruby_parser/bm_sexp.rb b/lib/ruby_parser/bm_sexp.rb index 8694d77dc974d73ae501f079151350d8ebb608f6..bba287f6a5882ae5f9319129b151a8786ffbc2d7 100644 --- a/lib/ruby_parser/bm_sexp.rb +++ b/lib/ruby_parser/bm_sexp.rb @@ -147,8 +147,14 @@ class Sexp #s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1))) # ^- method def method - expect :call, :attrasgn - self[2] + expect :call, :attrasgn, :super, :zsuper + + case self.node_type + when :call, :attrasgn + self[2] + when :super, :zsuper + :super + end end #Sets the arglist in a method call. @@ -165,8 +171,18 @@ class Sexp # s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2))) # ^------------ arglist ------------^ def arglist - expect :call, :attrasgn - self[3] + expect :call, :attrasgn, :super, :zsuper + + case self.node_type + when :call, :attrasgn + self[3] + when :super, :zsuper + if self[1] + Sexp.new(:arglist).concat self[1..-1] + else + Sexp.new(:arglist) + end + end #For new ruby_parser #Sexp.new(:arglist, *self[3..-1]) @@ -177,7 +193,7 @@ class Sexp # s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2))) # ^--------args--------^ def args - expect :call, :attrasgn + expect :call, :attrasgn, :super, :zsuper #For new ruby_parser #if self[3] # self[3..-1] @@ -185,11 +201,20 @@ class Sexp # [] #end - #For old ruby_parser - if self[3] - self[3][1..-1] - else - [] + case self.node_type + when :call, :attrasgn + #For old ruby_parser + if self[3] + self[3][1..-1] + else + [] + end + when :super, :zsuper + if self[1] + self[1..-1] + else + [] + end end end @@ -345,7 +370,7 @@ class Sexp #Sets body def body= exp expect :defn, :defs, :methdef, :selfdef, :class, :module - + case self.node_type when :defn, :methdef, :class self[3] = exp @@ -392,7 +417,7 @@ end [:[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at, :delete_if, :drop, :drop_while, :fill, :flatten!, :replace, :insert, :keep_if, :map!, :pop, :push, :reject!, :replace, :reverse!, :rotate!, - :select!, :shift, :shuffle!, :slice!, :sort!, :sort_by!, :transpose, + :select!, :shift, :shuffle!, :slice!, :sort!, :sort_by!, :transpose, :uniq!, :unshift].each do |method| Sexp.class_eval <<-RUBY diff --git a/test/tests/test_brakeman.rb b/test/tests/test_brakeman.rb index 08462065e9f8aac5afa9416acc9f832e1260245f..00e1c4a00a905cf5a8c294c605accd1318e1c9e9 100644 --- a/test/tests/test_brakeman.rb +++ b/test/tests/test_brakeman.rb @@ -20,28 +20,6 @@ class UtilTests < Test::Unit::TestCase end end -class SexpTests < Test::Unit::TestCase - def setup - if RUBY_VERSION =~ /^1\.9/ - @ruby_parser = Ruby19Parser - else - @ruby_parser = RubyParser - end - end - - def parse src - @ruby_parser.new.parse src - end - - def test_sexp_call - call = parse "x()" - - assert_equal call.method, :x - assert_nil call.target - assert_equal call.args, Sexp.new() - end -end - class BaseCheckTests < Test::Unit::TestCase FakeTracker = Struct.new(:config) diff --git a/test/tests/test_sexp.rb b/test/tests/test_sexp.rb new file mode 100644 index 0000000000000000000000000000000000000000..2de7b9a530fbac93855fe887d97634686c0e3e2b --- /dev/null +++ b/test/tests/test_sexp.rb @@ -0,0 +1,246 @@ +require 'brakeman/processors/base_processor' + +class SexpTests < Test::Unit::TestCase + def setup + if RUBY_VERSION[/^1\.9/] + @ruby_parser = ::Ruby19Parser + else + @ruby_parser = ::RubyParser + end + end + + def parse string + Brakeman::BaseProcessor.new(nil).process @ruby_parser.new.parse string + end + + def test_method_call_with_no_args + exp = parse "x.y" + + assert_equal s(:call, nil, :x, s(:arglist)), exp.target + assert_equal :y, exp.method + assert_equal s(), exp.args + assert_equal s(:arglist), exp.arglist + assert_nil exp.first_arg + assert_nil exp.second_arg + end + + def test_method_call_with_args + exp = parse 'x.y(1, 2, 3)' + + assert_equal s(:call, nil, :x, s(:arglist)), exp.target + assert_equal :y, exp.method + assert_equal s(s(:lit, 1), s(:lit, 2), s(:lit, 3)), exp.args + assert_equal s(:arglist, s(:lit, 1), s(:lit, 2), s(:lit, 3)), exp.arglist + assert_equal s(:lit, 1), exp.first_arg + assert_equal s(:lit, 2), exp.second_arg + end + + def test_method_call_no_target + exp = parse 'x 1, 2, 3' + + assert_nil exp.target + assert_equal :x, exp.method + assert_equal s(s(:lit, 1), s(:lit, 2), s(:lit, 3)), exp.args + assert_equal s(:arglist, s(:lit, 1), s(:lit, 2), s(:lit, 3)), exp.arglist + assert_equal s(:lit, 1), exp.first_arg + assert_equal s(:lit, 2), exp.second_arg + end + + def test_method_call_set_target + exp = parse 'x.y' + exp.target = :z + + assert_equal :z, exp.target + end + + def test_method_call_set_args + exp = parse 'x.y' + exp.arglist = s(:arglist, s(:lit, 1), s(:lit, 2)) + + assert_equal s(:lit, 1), exp.first_arg + assert_equal s(:lit, 2), exp.second_arg + assert_equal s(:arglist, s(:lit, 1), s(:lit, 2)), exp.arglist + assert_equal s(s(:lit, 1), s(:lit, 2)), exp.args + end + + def test_method_call_with_block + exp = parse "x do |z|; blah z; end" + block = exp.block + call = exp.block_call + args = exp.block_args + + assert_equal s(:call, nil, :x, s(:arglist)), call + assert_equal s(:lasgn, :z), args + assert_equal s(:call, nil, :blah, s(:arglist, s(:lvar, :z))), block + end + + def test_or + exp = parse '1 or 2' + + assert_equal s(:lit, 1), exp.lhs + assert_equal s(:lit, 2), exp.rhs + end + + def test_and + exp = parse '1 and 2' + + assert_equal s(:lit, 1), exp.lhs + assert_equal s(:lit, 2), exp.rhs + end + + def test_if_expression + exp = parse <<-RUBY + if x + y + else + z + end + RUBY + + assert_equal s(:call, nil, :x, s(:arglist)), exp.condition + assert_equal s(:call, nil, :y, s(:arglist)), exp.then_clause + assert_equal s(:call, nil, :z, s(:arglist)), exp.else_clause + end + + def test_local_assignment + exp = parse 'x = 1' + + assert_equal :x, exp.lhs + assert_equal s(:lit, 1), exp.rhs + end + + def test_instance_assignment + exp = parse '@x = 1' + + assert_equal :@x, exp.lhs + assert_equal s(:lit, 1), exp.rhs + end + + def test_global_assignment + exp = parse '$x = 1' + + assert_equal :$x, exp.lhs + assert_equal s(:lit, 1), exp.rhs + end + + def test_constant_assignment + exp = parse 'X = 1' + + assert_equal :X, exp.lhs + assert_equal s(:lit, 1), exp.rhs + end + + def test_class_variable_assignment + exp = parse '@@x = 1' + + assert_equal :@@x, exp.lhs + assert_equal s(:lit, 1), exp.rhs + end + + def test_method_def_name + exp = parse <<-RUBY + def x(y) + z + y + end + RUBY + + assert_equal :x, exp.method_name + end + + def test_method_self_def_name + exp = parse <<-RUBY + def self.x(y) + z + y + end + RUBY + + assert_equal :x, exp.method_name + end + + def test_method_def_body + exp = parse <<-RUBY + def x(y) + z + y + end + RUBY + + assert_equal s(:scope, s(:rlist, s(:call, nil, :z, s(:arglist)), s(:lvar, :y))), exp.body + end + + def test_method_def_body_single_line + exp = parse <<-RUBY + def x(y) + y + end + RUBY + + assert_equal s(:scope, s(:rlist, s(:lvar, :y))), exp.body + end + + def test_class_body + exp = parse <<-RUBY + class X + def y + end + end + RUBY + + assert_equal s(:scope, s(:defn, :y, s(:args), s(:scope, s(:block, s(:nil))))), exp.body + end + + def test_module_body + exp = parse <<-RUBY + module X + def y + end + end + RUBY + + assert_equal s(:scope, s(:defn, :y, s(:args), s(:scope, s(:block, s(:nil))))), exp.body + end + + def test_class_name + exp = parse 'class X < Y; end' + + assert_equal :X, exp.class_name + end + + def test_parent_name + exp = parse 'class X < Y; end' + + assert_equal s(:const, :Y), exp.parent_name + end + + def test_module_name + exp = parse 'module X; end' + + assert_equal :X, exp.module_name + end + + def test_wrong_sexp_error + exp = parse 'true ? false : true' + + assert_raise WrongSexpError do + exp.method + end + end + + def test_zsuper_call + exp = parse 'super' + + assert_equal :super, exp.method + assert_equal s(:arglist), exp.arglist + assert_equal [], exp.args + end + + def test_super_call + exp = parse 'super 1' + + assert_equal :super, exp.method + assert_equal s(:arglist, s(:lit, 1)), exp.arglist + assert_equal s(s(:lit, 1)), exp.args + end +end