lib/brakeman/processors/alias_processor.rb in brakeman-5.0.4 vs lib/brakeman/processors/alias_processor.rb in brakeman-5.1.0
- old
+ new
@@ -206,10 +206,19 @@
return Sexp.new(:hash).line(exp.line)
elsif exp == RAILS_TEST or exp == RAILS_DEV
return Sexp.new(:false).line(exp.line)
end
+ # For the simplest case of `Foo.thing`
+ if node_type? target, :const and first_arg.nil?
+ if tracker and (klass = tracker.find_class(class_name(target.value)))
+ if return_value = klass.get_simple_method_return_value(:class, method)
+ return return_value.deep_clone(exp.line)
+ end
+ end
+ end
+
#See if it is possible to simplify some basic cases
#of addition/concatenation.
case method
when :+
if array? target and array? first_arg
@@ -218,17 +227,32 @@
exp = join_strings(target, first_arg, exp)
elsif number? first_arg
exp = math_op(:+, target, first_arg, exp)
end
when :-, :*, :/
- exp = math_op(method, target, first_arg, exp)
+ if method == :* and array? target
+ if string? first_arg
+ exp = process_array_join(target, first_arg)
+ end
+ else
+ exp = math_op(method, target, first_arg, exp)
+ end
when :[]
if array? target
exp = process_array_access(target, exp.args, exp)
elsif hash? target
exp = process_hash_access(target, first_arg, exp)
end
+ when :fetch
+ if array? target
+ # Not dealing with default value
+ # so just pass in first argument, but process_array_access expects
+ # an array of arguments.
+ exp = process_array_access(target, [first_arg], exp)
+ elsif hash? target
+ 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
return target
@@ -264,10 +288,16 @@
return target
else
target = find_push_target(target_var)
env[target] = exp unless target.nil? # Happens in TemplateAliasProcessor
end
+ when :push
+ if array? target
+ target << first_arg
+ env[target_var] = target
+ return target
+ end
when :first
if array? target and first_arg.nil? and sexp? target[1]
exp = target[1]
end
when :freeze
@@ -277,35 +307,51 @@
when :dup
unless target.nil?
exp = target
end
when :join
- if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
+ if array? target and (string? first_arg or first_arg.nil?)
exp = process_array_join(target, first_arg)
end
when :!
# Convert `!!a` to boolean
if call? target and target.method == :!
exp = s(:or, s(:true).line(exp.line), s(:false).line(exp.line)).line(exp.line)
end
+ when :values
+ # Hash literal
+ if node_type? target, :hash
+ exp = hash_values(target)
+ end
+ when :values_at
+ if node_type? target, :hash
+ exp = hash_values_at target, exp.args
+ end
end
exp
end
# Painful conversion of Array#join into string interpolation
def process_array_join array, join_str
+ # Empty array
+ if array.length == 1
+ return s(:str, '').line(array.line)
+ end
+
result = s().line(array.line)
join_value = if string? join_str
join_str.value
else
nil
end
- array[1..-2].each do |e|
- result << join_item(e, join_value)
+ if array.length > 2
+ array[1..-2].each do |e|
+ result << join_item(e, join_value)
+ end
end
result << join_item(array.last, nil)
# Combine the strings at the beginning because that's what RubyParser does
@@ -330,19 +376,27 @@
end
result.unshift combined_first
# Have to fix up strings that follow interpolation
- result.reduce(s(:dstr).line(array.line)) do |memo, e|
+ string = result.reduce(s(:dstr).line(array.line)) do |memo, e|
if string? e and node_type? memo.last, :evstr
e.value = "#{join_value}#{e.value}"
elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
memo << s(:str, join_value).line(e.line)
end
memo << e
end
+
+ # Convert (:dstr, "hello world")
+ # to (:str, "hello world")
+ if string.length == 2 and string.last.is_a? String
+ string[0] = :str
+ end
+
+ string
end
def join_item item, join_value
if item.is_a? String
"#{item}#{join_value}"
@@ -747,10 +801,22 @@
env[match] = get_rhs(exp)
exp
end
+ def hash_or_array_include_all_literals? exp
+ return unless call? exp and sexp? exp.target
+ target = exp.target
+
+ case target.node_type
+ when :hash
+ hash_include_all_literals? exp
+ else
+ array_include_all_literals? exp
+ end
+ end
+
# Check if exp is a call to Array#include? on an array literal
# that contains all literal values. For example:
#
# [1, 2, "a"].include? x
#
@@ -765,10 +831,20 @@
[:detect, :find].include? exp.method and
exp.first_arg.nil? and
(all_literals? exp.target or dir_glob? exp.target)
end
+ # Check if exp is a call to Hash#include? on a hash literal
+ # that contains all literal values. For example:
+ #
+ # {x: 1}.include? x
+ def hash_include_all_literals? exp
+ call? exp and
+ exp.method == :include? and
+ all_literals? exp.target, :hash
+ end
+
#Sets @inside_if = true
def process_if exp
if @ignore_ifs.nil?
@ignore_ifs = @tracker && @tracker.options[:ignore_ifs]
end
@@ -805,19 +881,19 @@
branch_scopes = []
exps.each_with_index do |branch, i|
scope do
@branch_env = env.current
branch_index = 2 + i # s(:if, condition, then_branch, else_branch)
- if i == 0 and array_include_all_literals? condition
+ if i == 0 and hash_or_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] = 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
+ elsif i == 1 and hash_or_array_include_all_literals? condition and early_return? branch
var = condition.first_arg
env.current[var] = safe_literal(var.line)
exp[branch_index] = process_if_branch branch
else
exp[branch_index] = process_if_branch branch
@@ -1011,11 +1087,11 @@
def get_call_value call
method_name = call.method
#Look for helper methods and see if we can get a return value
- if found_method = find_method(method_name, @current_class)
- helper = found_method[:method]
+ if found_method = tracker.find_method(method_name, @current_class)
+ helper = found_method.src
if sexp? helper
value = process_helper_method helper, call.args
value.line(call.line)
return value