class RuboCop::Cop::Lint::DuplicateMethods


end
delegate :foo, to: :bar
if cond
end
1
def foo
# good - delegate inside a condition is ignored
delegate :foo, **options
end
1
def foo
# good - delegate with splat arguments is ignored
delegate :baz, to: :bar
end
1
def foo
# good
delegate :foo, to: :bar
end
1
def foo
# bad
@example AllCops:ActiveSupportExtensionsEnabled: true
delegate :foo, to: :bar
end
1
def foo
# good
@example AllCops:ActiveSupportExtensionsEnabled: false (default)
end
1
def foo
alias_method :foo, :foo
# good
end
1
def foo
alias foo foo
# good
alias bar foo
end
1
def foo
# good
end
2
def bar
end
1
def foo
# good
alias foo bar
end
1
def foo
# bad
end
2
def foo
end
1
def foo
# bad
@example
See bugs.ruby-lang.org/issues/13574.
the developer intends to suppress Ruby’s method redefinition warnings.
NOTE: Aliasing a method to itself is allowed, as it indicates that
definitions.
Checks for duplicated instance (or singleton) method

def check_const_receiver(node, name, const_name)

def check_const_receiver(node, name, const_name)
  qualified = lookup_constant(node, const_name)
  return unless qualified
  found_method(node, "#{qualified}.#{name}")
end

def check_self_receiver(node, name)

def check_self_receiver(node, name)
  enclosing = node.parent_module_name
  return unless enclosing
  found_method(node, "#{enclosing}.#{name}")
end

def delegate_prefix(node)

def delegate_prefix(node)
  kwargs_node = node.last_argument
  return unless (prefix = hash_value(kwargs_node, :prefix))
  if prefix.true_type?
    hash_value(kwargs_node, :to).value
  elsif prefix.type?(:sym, :str)
    prefix.value
  end
end

def found_attr(node, args, readable: false, writable: false)

def found_attr(node, args, readable: false, writable: false)
  args.each do |arg|
    name = sym_name(arg)
    next unless name
    found_instance_method(node, name) if readable
    found_instance_method(node, "#{name}=") if writable
  end
end

def found_instance_method(node, name)

def found_instance_method(node, name)
  return found_sclass_method(node, name) unless (scope = node.parent_module_name)
  # Humanize the scope
  scope = scope.sub(
    /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
    '\k<name>.'
  )
  scope << '#' unless scope.end_with?('.')
  found_method(node, "#{scope}#{name}")
end

def found_method(node, method_name)

def found_method(node, method_name)
  key = method_key(node, method_name)
  scope = node.each_ancestor(:rescue, :ensure).first&.type
  if @definitions.key?(key)
    if scope && !@scopes[scope].include?(key)
      @definitions[key] = node
      @scopes[scope] << key
      return
    end
    message = message_for_dup(node, method_name, key)
    add_offense(location(node), message: message)
  else
    @definitions[key] = node
  end
end

def found_sclass_method(node, name)

def found_sclass_method(node, name)
  singleton_ancestor = node.each_ancestor.find(&:sclass_type?)
  return unless singleton_ancestor
  singleton_receiver_node = singleton_ancestor.children[0]
  return unless singleton_receiver_node.send_type?
  found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
end

def hash_value(node, key)

def hash_value(node, key)
  node.pairs.find { |pair| pair.key.value == key }&.value
end

def initialize(config = nil, options = nil)

def initialize(config = nil, options = nil)
  super
  @definitions = {}
  @scopes = Hash.new { |hash, key| hash[key] = [] }
end

def location(node)

def location(node)
  if node.any_def_type?
    node.loc.keyword.join(node.loc.name)
  else
    node.source_range
  end
end

def lookup_constant(node, const_name)

def lookup_constant(node, const_name)
  # this method is quite imperfect and can be fooled
  # to do much better, we would need to do global analysis of the whole
  # codebase
  node.each_ancestor(:class, :module, :casgn) do |ancestor|
    namespace, mod_name = *ancestor.defined_module
    loop do
      if mod_name == const_name
        return qualified_name(ancestor.parent_module_name, namespace, mod_name)
      end
      break if namespace.nil?
      namespace, mod_name = *namespace
    end
  end
end

def message_for_dup(node, method_name, key)

def message_for_dup(node, method_name, key)
  format(MSG, method: method_name, defined: source_location(@definitions[key]),
              current: source_location(node))
end

def method_key(node, method_name)

def method_key(node, method_name)
  if (ancestor_def = node.each_ancestor(:any_def).first)
    "#{ancestor_def.method_name}.#{method_name}"
  else
    method_name
  end
end

def on_alias(node)

def on_alias(node)
  name, original_name = method_alias?(node)
  return unless name && original_name
  return if name == original_name
  return if node.ancestors.any?(&:if_type?)
  found_instance_method(node, name)
end

def on_attr(node, attr_name, args)

def on_attr(node, attr_name, args)
  case attr_name
  when :attr
    writable = args.size == 2 && args.last.true_type?
    found_attr(node, [args.first], readable: true, writable: writable)
  when :attr_reader
    found_attr(node, args, readable: true)
  when :attr_writer
    found_attr(node, args, writable: true)
  when :attr_accessor
    found_attr(node, args, readable: true, writable: true)
  end
end

def on_def(node)

def on_def(node)
  # if a method definition is inside an if, it is very likely
  # that a different definition is used depending on platform, etc.
  return if node.each_ancestor.any?(&:if_type?)
  found_instance_method(node, node.method_name)
end

def on_defs(node)

def on_defs(node)
  return if node.each_ancestor.any?(&:if_type?)
  if node.receiver.const_type?
    _, const_name = *node.receiver
    check_const_receiver(node, node.method_name, const_name)
  elsif node.receiver.self_type?
    check_self_receiver(node, node.method_name)
  end
end

def on_delegate(node, method_names)

def on_delegate(node, method_names)
  name_prefix = delegate_prefix(node)
  method_names.each do |name|
    name = "#{name_prefix}_#{name}" if name_prefix
    found_instance_method(node, name)
  end
end

def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  name, original_name = alias_method?(node)
  if name && original_name
    return if name == original_name
    return if node.ancestors.any?(&:if_type?)
    found_instance_method(node, name)
  elsif (attr = node.attribute_accessor?)
    on_attr(node, *attr)
  elsif active_support_extensions_enabled? && (names = delegate_method?(node))
    return if node.ancestors.any?(&:if_type?)
    on_delegate(node, names)
  end
end

def qualified_name(enclosing, namespace, mod_name)

def qualified_name(enclosing, namespace, mod_name)
  if enclosing != 'Object'
    if namespace
      "#{enclosing}::#{namespace.const_name}::#{mod_name}"
    else
      "#{enclosing}::#{mod_name}"
    end
  elsif namespace
    "#{namespace.const_name}::#{mod_name}"
  else
    mod_name
  end
end

def source_location(node)

def source_location(node)
  range = node.source_range
  path = smart_path(range.source_buffer.name)
  "#{path}:#{range.line}"
end