lib/brakeman/processors/alias_processor.rb in brakeman-1.9.4 vs lib/brakeman/processors/alias_processor.rb in brakeman-1.9.5
- old
+ new
@@ -17,11 +17,11 @@
#
# AliasProcessor.new.process_safely src
def initialize tracker = nil
super()
@env = SexpProcessor::Environment.new
- @inside_if = []
+ @inside_if = false
@ignore_ifs = nil
@exp_context = []
@current_module = nil
@tracker = tracker #set in subclass as necessary
@helper_method_cache = {}
@@ -165,10 +165,45 @@
end
exp
end
+ def process_call_with_block exp
+ exp[1] = process exp.block_call
+
+ 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)] = e.rhs
+ elsif node_type? e, :masgn
+ 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
+ end
+
+ block = exp.block
+
+ if block? block
+ process_all! block
+ else
+ exp[3] = process block
+ end
+ end
+
+ exp
+ end
+
+ alias process_iter process_call_with_block
+
#Process a new scope.
def process_scope exp
env.scope do
process exp.block
end
@@ -230,23 +265,24 @@
#Global assignment
# $x = 1
def process_gasgn exp
match = Sexp.new(:gvar, exp.lhs)
value = exp.rhs = process(exp.rhs)
+ value.line = exp.line
- set_value match, value, exp.line
+ set_value match, value
exp
end
#Class variable assignment
# @@x = 1
def process_cvdecl exp
match = Sexp.new(:cvar, exp.lhs)
value = exp.rhs = process(exp.rhs)
- set_value match, value, exp.line
+ set_value match, value
exp
end
#'Attribute' assignment
@@ -263,21 +299,21 @@
if method == :[]=
index = exp.first_arg = process(index_arg)
value = exp.second_arg = process(value_arg)
match = Sexp.new(:call, target, :[], index)
- set_value match, value, exp.line
+ set_value match, value
if hash? target
env[tar_variable] = hash_insert target.deep_clone, index, value
end
elsif method.to_s[-1,1] == "="
value = exp.first_arg = process(index_arg)
#This is what we'll replace with the value
match = Sexp.new(:call, target, method.to_s[0..-2].to_sym)
- set_value match, value, exp.line
+ set_value match, value
else
raise "Unrecognized assignment: #{exp}"
end
exp
end
@@ -375,38 +411,73 @@
@ignore_ifs = @tracker && @tracker.options[:ignore_ifs]
end
condition = process exp.condition
+ #Check if a branch is obviously going to be taken
if true? condition
no_branch = true
- exps = [exp.then_clause]
+ exps = [exp.then_clause, nil]
elsif false? condition
no_branch = true
- exps = [exp.else_clause]
+ exps = [nil, exp.else_clause]
else
no_branch = false
exps = [exp.then_clause, exp.else_clause]
end
- exps.each do |e|
- @inside_if << [] unless no_branch or @ignore_ifs
+ if @ignore_ifs or no_branch
+ exps.each_with_index do |branch, i|
+ exp[2 + i] = process_if_branch branch
+ end
+ else
+ was_inside = @inside_if
+ @inside_if = true
- if sexp? e
- if e.node_type == :block
- process_default e #avoid creating new scope
- else
- process e
+ branch_scopes = []
+ exps.each_with_index do |branch, i|
+ scope do
+ branch_index = 2 + i # s(:if, condition, then_branch, else_branch)
+ exp[branch_index] = process_if_branch branch
+ branch_scopes << env.current
end
end
- @inside_if.pop unless no_branch or @ignore_ifs
+ @inside_if = was_inside
+
+ branch_scopes.each do |s|
+ merge_if_branch s
+ end
end
exp
end
+ def process_if_branch exp
+ if sexp? exp
+ if block? exp
+ process_default exp
+ else
+ process exp
+ end
+ end
+ end
+
+ def merge_if_branch branch_env
+ branch_env.each do |k, v|
+ current_val = env[k]
+
+ if current_val
+ unless same_value? current_val, v
+ env[k] = Sexp.new(:or, current_val, v).line(k.line || -2)
+ end
+ else
+ env[k] = v
+ end
+ end
+ 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
@@ -599,16 +670,10 @@
def find_method *args
nil
end
- #Return true if this value should be "branched" - i.e. converted into an or
- #expression with two or more values
- def branch_value? exp
- not (@inside_if.empty? or @inside_if.last.include? exp)
- end
-
#Return true if lhs == rhs or lhs is an or expression and
#rhs is one of its values
def same_value? lhs, rhs
if lhs == rhs
true
@@ -617,35 +682,44 @@
else
false
end
end
+ def value_from_if exp
+ if block? exp.else_clause or block? exp.then_clause
+ #If either clause is more than a single expression, just use entire
+ #if expression for now
+ exp
+ elsif exp.else_clause.nil?
+ exp.then_clause
+ elsif exp.then_clause.nil?
+ exp.else_clause
+ else
+ condition = exp.condition
+
+ if true? condition
+ exp.then_clause
+ elsif false? condition
+ exp.else_clause
+ else
+ Sexp.new(:or, exp.then_clause, exp.else_clause).line(exp.line)
+ end
+ end
+ end
+
#Set variable to given value.
#Creates "branched" versions of values when appropriate.
#Avoids creating multiple branched versions inside same
#if branch.
- def set_value var, value, line = nil
- unless @ignore_ifs
- current_val = env[var]
- current_if = @inside_if.last
+ def set_value var, value
+ if node_type? value, :if
+ value = value_from_if(value)
+ end
- if branch_value? var and current_val = env[var]
- unless same_value? current_val, value
- env[var] = Sexp.new(:or, current_val, value).line(line || var.line || -2)
- current_if << var
- end
- elsif current_if and current_if.include?(var) and node_type?(current_val, :or)
- #Replace last value instead of creating another or
- current_val.rhs = value
- else
- env[var] = value
-
- if current_if
- current_if << var
- end
- end
- else
+ if @ignore_ifs or not @inside_if
env[var] = value
+ else
+ env.current[var] = value
end
end
#If possible, distribute operation over both sides of an or.
#For example,