lib/brakeman/processors/alias_processor.rb in brakeman-lib-4.3.0 vs lib/brakeman/processors/alias_processor.rb in brakeman-lib-4.3.1
- old
+ new
@@ -1,17 +1,19 @@
require 'brakeman/util'
require 'ruby_parser/bm_sexp_processor'
require 'brakeman/processors/lib/processor_helper'
require 'brakeman/processors/lib/safe_call_helper'
+require 'brakeman/processors/lib/call_conversion_helper'
#Returns an s-expression with aliases replaced with their value.
#This does not preserve semantics (due to side effects, etc.), but it makes
#processing easier when searching for various things.
class Brakeman::AliasProcessor < Brakeman::SexpProcessor
include Brakeman::ProcessorHelper
include Brakeman::SafeCallHelper
include Brakeman::Util
+ include Brakeman::CallConversionHelper
attr_reader :result, :tracker
#Returns a new AliasProcessor with an empty environment.
#
@@ -120,11 +122,11 @@
else
t = nil
end
if hash? t
- if v = hash_access(t, exp.first_arg)
+ if v = process_hash_access(t, exp.first_arg)
v.deep_clone(exp.line)
else
case t.node_type
when :params
exp.target = PARAMS_SEXP.deep_clone(exp.target.line)
@@ -200,53 +202,23 @@
#See if it is possible to simplify some basic cases
#of addition/concatenation.
case method
when :+
if array? target and array? first_arg
- joined = join_arrays target, first_arg
- joined.line(exp.line)
- exp = joined
+ exp = join_arrays(target, first_arg, exp)
elsif string? first_arg
- if string? target # "blah" + "blah"
- joined = join_strings target, first_arg
- joined.line(exp.line)
- exp = joined
- elsif call? target and target.method == :+ and string? target.first_arg
- joined = join_strings target.first_arg, first_arg
- joined.line(exp.line)
- target.first_arg = joined
- exp = target
- end
+ exp = join_strings(target, first_arg, exp)
elsif number? first_arg
- if number? target
- exp = Sexp.new(:lit, target.value + first_arg.value)
- elsif call? target and target.method == :+ and number? target.first_arg
- target.first_arg = Sexp.new(:lit, target.first_arg.value + first_arg.value)
- exp = target
- end
+ exp = math_op(:+, target, first_arg, exp)
end
- when :-
- if number? target and number? first_arg
- exp = Sexp.new(:lit, target.value - first_arg.value)
- end
- when :*
- if number? target and number? first_arg
- exp = Sexp.new(:lit, target.value * first_arg.value)
- end
- when :/
- if number? target and number? first_arg
- unless first_arg.value == 0 and not target.value.is_a? Float
- exp = Sexp.new(:lit, target.value / first_arg.value)
- end
- end
+ when :-, :*, :/
+ exp = math_op(method, target, first_arg, exp)
when :[]
if array? target
- temp_exp = process_array_access target, exp.args
- exp = temp_exp if temp_exp
+ exp = process_array_access(target, exp.args, exp)
elsif hash? target
- temp_exp = process_hash_access target, first_arg
- exp = temp_exp if temp_exp
+ exp = process_hash_access(target, first_arg, exp)
end
when :merge!, :update
if hash? target and hash? first_arg
target = process_hash_merge! target, first_arg
env[target_var] = target
@@ -285,12 +257,12 @@
when :first
if array? target and first_arg.nil? and sexp? target[1]
exp = target[1]
end
when :freeze
- if string? target
- exp = process exp.target
+ unless target.nil?
+ exp = target
end
when :join
if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
exp = process_array_join(target, first_arg)
end
@@ -362,32 +334,41 @@
def process_iter exp
@exp_context.push exp
exp[1] = process exp.block_call
if array_detect_all_literals? exp[1]
- return exp.block_call.target[1]
+ return safe_literal(exp.line)
end
@exp_context.pop
env.scope do
- exp.block_args.each do |e|
- #Force block arg(s) to be local
- if node_type? e, :lasgn
- env.current[Sexp.new(:lvar, e.lhs)] = Sexp.new(:lvar, e.lhs)
- elsif node_type? e, :kwarg
- env.current[Sexp.new(:lvar, e[1])] = e[2]
- elsif node_type? e, :masgn, :shadow
- e[1..-1].each do |var|
- local = Sexp.new(:lvar, var)
+ call = exp.block_call
+ block_args = exp.block_args
+
+ if call? call and [:each, :map].include? call.method and all_literals? call.target and block_args.length == 2 and block_args.last.is_a? Symbol
+ # Iterating over an array of all literal values
+ local = Sexp.new(:lvar, block_args.last)
+ env.current[local] = safe_literal(exp.line)
+ else
+ block_args.each do |e|
+ #Force block arg(s) to be local
+ if node_type? e, :lasgn
+ env.current[Sexp.new(:lvar, e.lhs)] = Sexp.new(:lvar, e.lhs)
+ elsif node_type? e, :kwarg
+ env.current[Sexp.new(:lvar, e[1])] = e[2]
+ elsif node_type? e, :masgn, :shadow
+ e[1..-1].each do |var|
+ local = Sexp.new(:lvar, var)
+ env.current[local] = local
+ end
+ elsif e.is_a? Symbol
+ local = Sexp.new(:lvar, e)
env.current[local] = local
+ else
+ raise "Unexpected value in block args: #{e.inspect}"
end
- elsif e.is_a? Symbol
- local = Sexp.new(:lvar, e)
- env.current[local] = local
- else
- raise "Unexpected value in block args: #{e.inspect}"
end
end
block = exp.block
@@ -713,22 +694,18 @@
# [1, 2, "a"].include? x
#
def array_include_all_literals? exp
call? exp and
exp.method == :include? and
- node_type? exp.target, :array and
- exp.target.length > 1 and
- exp.target.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
+ all_literals? exp.target
end
def array_detect_all_literals? exp
call? exp and
[:detect, :find].include? exp.method and
- node_type? exp.target, :array and
- exp.target.length > 1 and
exp.first_arg.nil? and
- exp.target.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
+ all_literals? exp.target
end
#Sets @inside_if = true
def process_if exp
if @ignore_ifs.nil?
@@ -765,16 +742,16 @@
if i == 0 and array_include_all_literals? condition
# If the condition is ["a", "b"].include? x
# set x to "a" inside the true branch
var = condition.first_arg
previous_value = env.current[var]
- env.current[var] = condition.target[1]
+ env.current[var] = safe_literal(var.line)
exp[branch_index] = process_if_branch branch
env.current[var] = previous_value
elsif i == 1 and array_include_all_literals? condition and early_return? branch
var = condition.first_arg
- env.current[var] = condition.target[1]
+ env.current[var] = safe_literal(var.line)
exp[branch_index] = process_if_branch branch
else
exp[branch_index] = process_if_branch branch
end
branch_scopes << env.current
@@ -907,48 +884,9 @@
def too_deep? exp
@or_depth_limit >= 0 and
node_type? exp, :or and
exp.or_depth and
exp.or_depth >= @or_depth_limit
- end
-
- #Process single integer access to an array.
- #
- #Returns the value inside the array, if possible.
- def process_array_access target, args
- if args.length == 1 and integer? args.first
- index = args.first.value
-
- #Have to do this because first element is :array and we have to skip it
- target[1..-1][index]
- else
- nil
- end
- end
-
- #Process hash access by returning the value associated
- #with the given argument.
- def process_hash_access target, index
- hash_access(target, index)
- end
-
- #Join two array literals into one.
- def join_arrays array1, array2
- result = Sexp.new(:array)
- result.concat array1[1..-1]
- result.concat array2[1..-1]
- end
-
- #Join two string literals into one.
- def join_strings string1, string2
- result = Sexp.new(:str)
- result.value = string1.value + string2.value
-
- if result.value.length > 50
- string1
- else
- result
- end
end
# Change x.send(:y, 1) to x.y(1)
def collapse_send_call exp, first_arg
# Handle try(&:id)