class RuboCop::Cop::Style::EvalWithLocation

RUBY
end
def do_something
C.class_eval <<-RUBY, __FILE__, __LINE__ + 1
# good
RUBY
end
def do_something
eval <<-RUBY, binding, __FILE__, __LINE__ + 1
# good
RUBY
end
def do_something
C.class_eval <<-RUBY
# bad
RUBY
end
def do_something
eval <<-RUBY
# bad
@example
backtraces. This cop recommends to pass the metadata to ‘eval` method.
metadata, that are filename and line number. The metadata is used by
This cop checks `eval` method usage. `eval` can receive source location

def add_offense_for_different_line(node, line_node, line_diff)

def add_offense_for_different_line(node, line_node, line_diff)
  sign = line_diff.positive? ? :+ : :-
  return if line_with_offset?(line_node, sign, line_diff.abs)
  add_offense(
    node,
    location: line_node.loc.expression,
    message: message_incorrect_line(line_node, sign, line_diff.abs)
  )
end

def add_offense_for_same_line(node, line_node)

def add_offense_for_same_line(node, line_node)
  return if special_line_keyword?(line_node)
  add_offense(
    node,
    location: line_node.loc.expression,
    message: message_incorrect_line(line_node, nil, 0)
  )
end

def message_incorrect_line(actual, sign, line_diff)

def message_incorrect_line(actual, sign, line_diff)
  expected =
    if line_diff.zero?
      '__LINE__'
    else
      "__LINE__ #{sign} #{line_diff}"
    end
  format(MSG_INCORRECT_LINE, actual: actual.source, expected: expected)
end

def on_send(node)

def on_send(node)
  eval_without_location?(node) do |code|
    if with_lineno?(node)
      on_with_lineno(node, code)
    else
      add_offense(node)
    end
  end
end

def on_with_lineno(node, code)

def on_with_lineno(node, code)
  line_node = node.arguments.last
  lineno_range = line_node.loc.expression
  line_diff = string_first_line(code) - lineno_range.first_line
  if line_diff.zero?
    add_offense_for_same_line(node, line_node)
  else
    add_offense_for_different_line(node, line_node, line_diff)
  end
end

def special_file_keyword?(node)

def special_file_keyword?(node)
  node.str_type? &&
    node.source == '__FILE__'
end

def special_line_keyword?(node)

def special_line_keyword?(node)
  node.int_type? &&
    node.source == '__LINE__'
end

def string_first_line(str_node)

def string_first_line(str_node)
  if str_node.heredoc?
    str_node.loc.heredoc_body.first_line
  else
    str_node.loc.expression.first_line
  end
end

def with_lineno?(node)

rubocop:disable Style/ConditionalAssignment
FIXME: It's a Style/ConditionalAssignment's false positive.
def with_lineno?(node)
  if node.method_name == :eval
    node.arguments.size == 4
  else
    node.arguments.size == 3
  end
end