module Brakeman::Util

def all_literals? exp, expected_type = :array

def all_literals? exp, expected_type = :array
  node_type? exp, expected_type and
    exp.length > 1 and
    exp.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
end

def array? exp

Check if _exp_ represents an array: s(:array, [...])
def array? exp
  exp.is_a? Sexp and exp.node_type == :array
end

def block? exp

Check if _exp_ represents a block of code
def block? exp
  exp.is_a? Sexp and (exp.node_type == :block or
                      exp.node_type == :rlist)
end

def call? exp

Check if _exp_ represents a method call: s(:call, ...)
def call? exp
  exp.is_a? Sexp and
    (exp.node_type == :call or exp.node_type == :safe_call)
end

def camelize lower_case_and_underscored_word

Taken from ActiveSupport.

Convert a string from "something_like_this" to "SomethingLikeThis"
def camelize lower_case_and_underscored_word
  lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
end

def class_name exp

If class name cannot be determined, returns _exp_.
Returns a class name as a Symbol.
def class_name exp
  case exp
  when Sexp
    case exp.node_type
    when :const, :colon3
      exp.value
    when :lvar
      exp.value.to_sym
    when :colon2
      "#{class_name(exp.lhs)}::#{exp.rhs}".to_sym
    when :self
      @current_class || @current_module || nil
    else
      exp
    end
  when Symbol
    exp
  when nil
    nil
  else
    exp
  end
end

def constant? exp

def constant? exp
  node_type? exp, :const, :colon2, :colon3
end

def contains_class? exp

Useful for checking if a module is just a module or if it is a namespace.

Returns true if the given _exp_ contains a :class node.
def contains_class? exp
  todo = [exp]
  until todo.empty?
    current = todo.shift
    if node_type? current, :class
      return true
    elsif sexp? current
      todo = current.sexp_body.concat todo
    end
  end
  false
end

def cookies? exp

def cookies? exp
  recurse_check?(exp) { |child| child.node_type == :cookies or ALL_COOKIES.include? child }
end

def dir_glob? exp

Dir.glob(...).whatever
def dir_glob? exp
  exp = exp.block_call if node_type? exp, :iter
  return unless call? exp
  (exp.target == DIR_CONST and exp.method == :glob) or dir_glob? exp.target
end

def false? exp

Check if _exp_ represents a :false or :nil node
def false? exp
  exp.is_a? Sexp and (exp.node_type == :false or
                      exp.node_type == :nil)
end

def hash? exp

This also includes pseudo hashes params, session, and cookies.
Check if _exp_ represents a hash: s(:hash, {...})
def hash? exp
  exp.is_a? Sexp and (exp.node_type == :hash or
                      exp.node_type == :params or
                      exp.node_type == :session or
                      exp.node_type == :cookies)
end

def hash_access hash, key

If _key_ is a Symbol, it will be converted to a Sexp(:lit, key).

Get value from hash using key.
def hash_access hash, key
  if key.is_a? Symbol
    key = Sexp.new(:lit, key)
  end
  if index = hash.find_index(key) and index > 0
    return hash[index + 1]
  end
  nil
end

def hash_insert hash, key, value

Insert value into Hash Sexp
def hash_insert hash, key, value
  index = 1
  hash_iterate hash.dup do |k,v|
    if k == key
      hash[index + 1] = value
      return hash
    end
    index += 2
  end
  hash << key << value
  hash
end

def hash_iterate hash

names #["bob"]
end
end
names << value[1]
if symbol? key and key[1] == :name
hash_iterate(h) do |key, value|
names = []
h = Sexp.new(:hash, (:lit, :name), (:str, "bob"), (:lit, :name), (:str, "jane"))

For example:

and yields the key and value pairs to the given block.
(:hash, (:lit, :key), (:str, "value"))
Takes an Sexp like
def hash_iterate hash
  hash = remove_kwsplat(hash)
  1.step(hash.length - 1, 2) do |i|
    yield hash[i], hash[i + 1]
  end
end

def hash_values hash

def hash_values hash
  values = hash.each_sexp.each_slice(2).map do |_, value|
    value
  end
  Sexp.new(:array).concat(values).line(hash.line)
end

def integer? exp

Check if _exp_ represents an Integer: s(:lit, ...)
def integer? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer
end

def kwsplat? exp

def kwsplat? exp
  exp.is_a? Sexp and
    exp.node_type == :hash and
    exp[1].is_a? Sexp and
    exp[1].node_type == :kwsplat
end

def literal? exp

def literal? exp
  exp.is_a? Sexp and LITERALS.include? exp.node_type
end

def make_call target, method, *args

def make_call target, method, *args
  call = Sexp.new(:call, target, method)
  if args.empty? or args.first.empty?
    #nothing to do
  elsif node_type? args.first, :arglist
    call.concat args.first.sexp_body
  elsif args.first.node_type.is_a? Sexp #just a list of args
    call.concat args.first
  else
    call.concat args
  end
  call
end

def node_type? exp, *types

Check if _exp_ is a Sexp and the node type matches one of the given types.
def node_type? exp, *types
  exp.is_a? Sexp and types.include? exp.node_type
end

def number? exp

Check if _exp_ represents a number: s(:lit, ...)
def number? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Numeric
end

def params? exp

Check if _exp_ is a params hash
def params? exp
  recurse_check?(exp) { |child| child.node_type == :params or ALL_PARAMETERS.include? child }
end

def pluralize word

stupid simple, used to delegate to ActiveSupport
def pluralize word
  if word.end_with? 's'
    word + 'es'
  else
    word + 's'
  end
end

def rails_version

def rails_version
  @tracker.config.rails_version
end

def recurse_check? exp, &check

def recurse_check? exp, &check
  if exp.is_a? Sexp
    return true if yield(exp)
    if call? exp
      if recurse_check? exp[1], &check
        return true
      elsif exp[2] == :[]
        return recurse_check? exp[1], &check
      end
    end
  end
  false
end

def regexp? exp

Check if _exp_ represents a Regexp: s(:lit, /.../)
def regexp? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Regexp
end

def remove_kwsplat exp

def remove_kwsplat exp
  if exp.any? { |e| node_type? e, :kwsplat }
    exp.reject { |e| node_type? e, :kwsplat }
  else
    exp
  end
end

def request_headers? exp

Only return true when accessing request headers via request.env[...]
def request_headers? exp
  return unless sexp? exp
  if exp[1] == REQUEST_ENV
    if exp.method == :[]
      if string? exp.first_arg
        # Only care about HTTP headers, which are prefixed by 'HTTP_'
        exp.first_arg.value.start_with?('HTTP_'.freeze)
      else
        true # request.env[something]
      end
    else
      false # request.env.something
    end
  else
    false
  end
end

def request_value? exp

Check if exp is params, cookies, or request_headers
def request_value? exp
  params? exp or
  cookies? exp or
  request_headers? exp
end

def result? exp

Check if _exp_ represents a result: s(:result, ...)
def result? exp
  exp.is_a? Sexp and exp.node_type == :result
end

def safe_literal line = nil

def safe_literal line = nil
  s(:lit, :BRAKEMAN_SAFE_LITERAL).line(line || 0)
end

def safe_literal? exp

def safe_literal? exp
  exp == SAFE_LITERAL
end

def safe_literal_target? exp

def safe_literal_target? exp
  if call? exp
    safe_literal_target? exp.target
  else
    safe_literal? exp
  end
end

def set_env_defaults

so they can be replaced by their respective Sexps.
Adds params, session, and cookies to environment
def set_env_defaults
  @env[PARAMETERS] = PARAMS_SEXP
  @env[SESSION] = SESSION_SEXP
  @env[COOKIES] = COOKIES_SEXP
end

def sexp? exp

Check if _exp_ is a Sexp.
def sexp? exp
  exp.is_a? Sexp
end

def simple_literal? exp

def simple_literal? exp
  exp.is_a? Sexp and SIMPLE_LITERALS.include? exp.node_type
end

def string? exp

Check if _exp_ represents a String: s(:str, "...")
def string? exp
  exp.is_a? Sexp and exp.node_type == :str
end

def string_interp? exp

def string_interp? exp
  exp.is_a? Sexp and exp.node_type == :dstr
end

def symbol? exp

Check if _exp_ represents a Symbol: s(:lit, :...)
def symbol? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Symbol
end

def template_path_to_name path

views/test/something.html.erb -> test/something

Convert path/filename to view name
def template_path_to_name path
  names = path.relative.split('/')
  names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '')
  if names.include? 'views'
    names[(names.index('views') + 1)..-1]
  else
    names
  end.join('/').to_sym
end

def true? exp

Check if _exp_ represents a :true, :lit, or :string node
def true? exp
  exp.is_a? Sexp and (exp.node_type == :true or
                      exp.node_type == :lit or
                      exp.node_type == :string)
end

def underscore camel_cased_word

Taken from ActiveSupport.

Convert a string from "Something::LikeThis" to "something/like_this"
def underscore camel_cased_word
  camel_cased_word.to_s.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    downcase
end