class RubbyCop::Cop::Lint::DuplicateMethods

This cop checks for duplicated instance (or singleton) method definitions.

@example

# bad

def duplicated
  1
end

def duplicated
  2
end

@example

# good

def duplicated
  1
end

def other_duplicated
  2
end

Constants

MSG

Public Class Methods

new(config = nil, options = nil) click to toggle source
Calls superclass method RubbyCop::Cop::Cop::new
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 35
def initialize(config = nil, options = nil)
  super
  @definitions = {}
end

Public Instance Methods

on_def(node) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 40
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.ancestors.any?(&:if_type?)
  return if possible_dsl?(node)

  return unless (scope = node.parent_module_name)
  found_instance_method(node, scope)
end
on_defs(node) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 50
def on_defs(node)
  return if node.ancestors.any?(&:if_type?)
  return if possible_dsl?(node)

  receiver, name, = *node
  if receiver.const_type?
    _, const_name = *receiver
    check_const_receiver(node, name, const_name)
  elsif receiver.self_type?
    check_self_receiver(node, name)
  end
end

Private Instance Methods

check_const_receiver(node, name, const_name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 65
def check_const_receiver(node, name, const_name)
  qualified = lookup_constant(node, const_name)
  return unless qualified

  found_method(node, "#{qualified}.#{name}")
end
check_self_receiver(node, name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 72
def check_self_receiver(node, name)
  enclosing = node.parent_module_name
  return unless enclosing

  found_method(node, "#{enclosing}.#{name}")
end
found_instance_method(node, scope) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 84
def found_instance_method(node, scope)
  name, = *node
  if scope =~ /\A#<Class:(.*)>\Z/
    found_method(node, "#{Regexp.last_match(1)}.#{name}")
  else
    found_method(node, "#{scope}##{name}")
  end
end
found_method(node, method_name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 93
def found_method(node, method_name)
  if @definitions.key?(method_name)
    add_offense(node, :keyword, message_for_dup(node, method_name))
  else
    @definitions[method_name] = source_location(node)
  end
end
lookup_constant(node, const_name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 101
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
message_for_dup(node, method_name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 79
def message_for_dup(node, method_name)
  format(MSG, method_name, @definitions[method_name],
         source_location(node))
end
possible_dsl?(node) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 134
def possible_dsl?(node)
  # DSL methods may evaluate a block in the context of a newly created
  # class or module
  # Assume that if a method definition is inside any block call which
  # we can't identify, it could be a DSL
  node.each_ancestor(:block).any? do |ancestor|
    ancestor.method_name != :class_eval && !ancestor.class_constructor?
  end
end
qualified_name(enclosing, namespace, mod_name) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 120
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
source_location(node) click to toggle source
# File lib/rubbycop/cop/lint/duplicate_methods.rb, line 144
def source_location(node)
  range = node.location.expression
  "#{range.source_buffer.name}:#{range.line}"
end