class RuboCop::Cop::Lint::UselessRuby2Keywords


define_method(:foo) { |arg| }
# good
ruby2_keywords :foo
define_method(:foo) { |arg| }
# bad (ruby2_keywords with dynamic method)
def foo; end
# good
ruby2_keywords :foo
def foo; end
# bad (ruby2_keywords given a symbol)
def foo(*args, **kwargs); end
# good
ruby2_keywords def foo(*args, **kwargs); end
# bad (splat argument with double splat)
def foo(*args, i:, j:); end
# good
ruby2_keywords def foo(*args, i:, j:); end
# bad (splat argument with keyword arguments)
def foo(i:, j:); end
# good
ruby2_keywords def foo(i:, j:); end
# bad (keyword arguments)
def foo(**args); end
# good
ruby2_keywords def foo(**args); end
# bad (double splatted argument)
def foo(arg); end
# good
ruby2_keywords def foo(arg); end
# bad (positional argument)
def foo; end
# good
ruby2_keywords def foo; end
# bad (no arguments)
ruby2_keywords def foo(*args); end
# good (splat argument without keyword arguments)
@example
a keyword splat (‘**kwargs`).
(`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
`ruby2_keywords` should only be called on methods that accept an argument splat
Looks for `ruby2_keywords` calls for methods that do not need it.

def allowed_arguments(arguments)

`ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
def allowed_arguments(arguments)
  return false if arguments.empty?
  arguments.each_child_node(:restarg).any? &&
    arguments.each_child_node(:kwarg, :kwoptarg, :kwrestarg).none?
end

def find_method_definition(node, method_name)

def find_method_definition(node, method_name)
  node.each_ancestor.lazy.map do |ancestor|
    ancestor.each_child_node(:def, :block, :numblock).find do |child|
      method_definition(child, method_name)
    end
  end.find(&:itself)
end

def inspect_def(node, def_node)

def inspect_def(node, def_node)
  return if allowed_arguments(def_node.arguments)
  add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
end

def inspect_sym(node, sym_node)

def inspect_sym(node, sym_node)
  return unless node.parent
  method_name = sym_node.value
  definition = find_method_definition(node, method_name)
  return unless definition
  return if allowed_arguments(definition.arguments)
  add_offense(node, message: format(MSG, method_name: method_name))
end

def on_send(node)

def on_send(node)
  return unless (first_argument = node.first_argument)
  if first_argument.def_type?
    inspect_def(node, first_argument)
  elsif node.first_argument.sym_type?
    inspect_sym(node, first_argument)
  end
end