123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Lint::DuplicateMethods

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ::RuboCop::Cop::Base, ::RuboCop::ExcludeLimit, NodePattern::Macros, RuboCop::AST::Sexp
Instance Chain:
Inherits: RuboCop::Cop::Base
Defined in: lib/rubocop/cop/lint/duplicate_methods.rb

Overview

Checks for duplicated instance (or singleton) method definitions.

Note
Aliasing a method to itself is allowed, as it indicates that the developer intends to suppress Ruby’s method redefinition warnings. See https://bugs.ruby-lang.org/issues/13574.

By default the cop can only detect duplicates within a single file. When AllCops/UseProjectIndex is enabled and the rubydex gem is installed, the cop additionally consults the project-wide index and reports methods whose duplicate definition lives in another file.

Note
The project index does not record whether a definition in another file is wrapped in a conditional, so a platform-specific redefinition in another file may still be reported. Aliasing the method to itself (see above) before redefining marks the redefinition as intentional and is respected across files.

Examples:

# bad
def foo
  1
end

def foo
  2
end

# bad
def foo
  1
end

alias foo bar

# good
def foo
  1
end

def bar
  2
end

# good
def foo
  1
end

alias bar foo

# good
alias foo foo
def foo
  1
end

# good
alias_method :foo, :foo
def foo
  1
end

# bad
class MyClass
  extend Forwardable

  # or with: {def_instance_delegator}, {def_delegators}, {def_instance_delegators}
  def_delegator :delegation_target, :delegated_method_name

  def delegated_method_name
  end
end

# good
class MyClass
  extend Forwardable

  def_delegator :delegation_target, :delegated_method_name

  def non_duplicated_delegated_method_name
  end
end

AllCops:ActiveSupportExtensionsEnabled: false (default)

# good
def foo
  1
end

delegate :foo, to: :bar

AllCops:ActiveSupportExtensionsEnabled: true

# bad
def foo
  1
end

delegate :foo, to: :bar

# good
def foo
  1
end

delegate :baz, to: :bar

# good - delegate with splat arguments is ignored
def foo
  1
end

delegate :foo, **options

# good - delegate inside a condition is ignored
def foo
  1
end

if cond
  delegate :foo, to: :bar
end

Constant Summary

::RuboCop::Cop::Base - Inherited

EMPTY_OFFENSES, RESTRICT_ON_SEND

::RuboCop::Cop::ProjectIndexHelp - Included

BUILTIN_DOCUMENT_URI, FILE_URI_PREFIX, WINDOWS_DRIVE_PREFIX

Class Attribute Summary

::RuboCop::Cop::Base - Inherited

.gem_requirements, .lint?,
.support_autocorrect?

Returns if class supports autocorrect.

.support_multiple_source?

Override if your cop should be called repeatedly for multiple investigations Between calls to #on_new_investigation and on_investigation_end, the result of processed_source will remain constant.

Class Method Summary

::RuboCop::Cop::Base - Inherited

.autocorrect_incompatible_with

List of cops that should not try to autocorrect at the same time as this cop.

.badge

Naming.

.callbacks_needed, .cop_name, .department,
.documentation_url

Returns a url to view this cops documentation online.

.exclude_from_registry

Call for abstract Cop classes.

.inherited,
.joining_forces

Override and return the Force class(es) you need to join.

.match?

Returns true if the cop name or the cop namespace matches any of the given names.

.new,
.requires_gem

Register a version requirement for the given gem name.

.restrict_on_send

::RuboCop::ExcludeLimit - Extended

exclude_limit

Sets up a configuration option to have an exclude limit tracked.

transform

Instance Attribute Summary

Instance Method Summary

::RuboCop::Cop::ProjectIndexHelp - Included

#external_dependency_checksum, #compute_project_index_signature,
#definitions_in_other_files

Returns the definitions among definitions that live in a file other than the one being inspected, ordered by path and line.

#indexed_singleton_member

A namespace without any singleton method has no singleton-class declaration of its own, so the lookup starts from the first ancestor that has one; its find_member covers the rest of the chain.

#indexed_singleton_of

The declaration of `declaration’s singleton class, or nil when no singleton method is defined on it anywhere in the project.

#inherited_index_member?

Whether an ancestor of scope other than scope itself defines member_name.

#lexical_nesting_of

The lexical nesting the node’s constants resolve through, outermost first.

#prior_definition_in_other_file, #project_index_signature,
#resolve_constant_in_index

Resolves a constant node the way Ruby does: the first segment through the lexical nesting and every following segment inside the previous one.

#same_file?

::RuboCop::Cop::Base - Inherited

#add_global_offense

Adds an offense that has no particular location.

#add_offense

Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense.

#begin_investigation

Called before any investigation.

#callbacks_needed,
#cop_config

Configuration Helpers.

#cop_name, #excluded_file?,
#external_dependency_checksum

This method should be overridden when a cop’s behavior depends on state that lives outside of these locations:

#inspect,
#message

Gets called if no message is specified when calling add_offense or add_global_offense Cops are discouraged to override this; instead pass your message directly.

#name

Alias for Base#cop_name.

#offenses,
#on_investigation_end

Called after all on_…​

#on_new_investigation

Called before all on_…​

#on_other_file

Called instead of all on_…​

#parse

There should be very limited reasons for a Cop to do it’s own parsing.

#parser_engine,
#ready

Called between investigations.

#relevant_file?,
#target_gem_version

Returns a gems locked versions (i.e.

#target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction,
#callback_argument

Reserved for Cop::Cop.

#complete_investigation

Called to complete an investigation.

#correct, #current_corrector,
#current_offense_locations

Reserved for Commissioner:

#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #matches_absolute_include_pattern?, #range_for_original, #range_from_node_or_range,
#reset_investigation

Actually private methods.

#use_corrector

::RuboCop::Cop::AutocorrectLogic - Included

::RuboCop::Cop::IgnoredNode - Included

Constructor Details

.new(config = nil, options = nil) ⇒ DuplicateMethods

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 146

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

Instance Method Details

#alias_method?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 198

def_node_matcher :alias_method?, <<~PATTERN
  (send nil? :alias_method (sym $_name) (sym $_original_name))
PATTERN

#anon_block_identity(anon_block) (private)

Internal identity for an anonymous block, used as a scope key. Includes the source range’s begin position to distinguish blocks that share the same line (e.g. two Class.new calls separated by ;). The user-facing offense message still uses #source_location, which shows only path:line.

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 589

def anon_block_identity(anon_block)
  range = anon_block.source_range
  "#{smart_path(range.source_buffer.name)}:#{range.line}:#{range.begin_pos}"
end

#anon_block_scope_id(anon_block) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 358

def anon_block_scope_id(anon_block)
  parent = anon_block.parent
  return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def)

  if (receiver = scope_receiver(parent, anon_block))
    "#{receiver.source}.#{parent.method_name}"
  elsif !parent.begin_type? || parent.parent&.any_block_type?
    anon_block_identity(anon_block)
  end
end

#anonymous_class_block(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 349

def anonymous_class_block(node)
  first_block = node.each_ancestor(:block).first
  return unless class_or_module_new_block?(first_block)
  return if first_block.parent&.type?(:lvasgn)
  return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? }

  first_block
end

#check_const_receiver(node, name, const_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 275

def check_const_receiver(node, name, const_name)
  qualified = lookup_constant(node, const_name)
  return unless qualified

  found_method(node, "#{qualified}.#{name}")
end

#check_cross_file_duplicate(node, method_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 516

def check_cross_file_duplicate(node, method_name)
  return unless project_index
  return if @self_aliased.include?(method_name)
  return if node.each_ancestor(:any_def).any?
  return unless (prior = cross_file_prior_definition(method_name))

  message = format(MSG, method: method_name,
                        defined: index_source_location(prior),
                        current: source_location(node))
  add_offense(location(node), message: message)
end

#check_self_receiver(node, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 282

def check_self_receiver(node, name)
  enclosing = node.parent_module_name
  if enclosing
    found_method(node, "#{enclosing}.#{name}")
  elsif (anon_block = anonymous_class_block(node))
    scope = qualified_name(anon_block.parent_module_name, nil, 'Object')
    found_method(node, "#{scope}.#{name}", scope_id: anon_block_scope_id(anon_block))
  end
end

#class_new_block?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 239

def_node_matcher :class_new_block?, <<~PATTERN
  (block
    (send (const _ :Class) :new ...)
    ...)
PATTERN

#class_or_module_new_block?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 232

def_node_matcher :class_or_module_new_block?, <<~PATTERN
  (block
    (send (const _ {:Class :Module}) :new ...)
    ...)
PATTERN

#cross_file_prior_definition(method_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 528

def cross_file_prior_definition(method_name)
  return unless (match = INDEXABLE_METHOD_NAME.match(method_name))

  definitions = definitions_in_other_files(
    indexed_definitions(match[:owner], match[:separator], match[:name])
  )
  return if definitions.empty? || cross_file_self_alias_trick?(definitions)

  first_indexed_definition(definitions)
end

#cross_file_self_alias_trick?(definitions) ⇒ Boolean (private)

An alias of the method alongside one of its definitions in another file may be the self-alias trick marking an intentional redefinition there, so no offense is registered. A genuine alias duplicate is still reported when the alias itself is inspected.

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 566

def cross_file_self_alias_trick?(definitions)
  aliases, others = definitions.partition do |definition|
    definition.is_a?(Rubydex::MethodAliasDefinition)
  end
  alias_paths = aliases.map { |definition| definition.location.to_file_path }

  others.any? { |definition| alias_paths.include?(definition.location.to_file_path) }
end

#delegate_method?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 203

def_node_matcher :delegate_method?, <<~PATTERN
  (send nil? :delegate
    ({sym str} $_)+
    (hash <(pair (sym :to) {sym str}) ...>)
  )
PATTERN

#delegate_prefix(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 311

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

#delegator?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 211

def_node_matcher :delegator?, <<~PATTERN
  (send nil? {:def_delegator :def_instance_delegator}
    {
      {sym str} ({sym str} $_) |
      {sym str} {sym str} ({sym str} $_)
    }
  )
PATTERN

#delegators?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 221

def_node_matcher :delegators?, <<~PATTERN
  (send nil? {:def_delegators :def_instance_delegators}
    {sym str}
    ({sym str} $_)+
  )
PATTERN

#first_indexed_definition(definitions) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 575

def first_indexed_definition(definitions)
  definitions.find { |definition| !definition.is_a?(Rubydex::MethodAliasDefinition) }
end

#found_attr(node, args, readable: false, writable: false) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 468

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

#found_instance_method(node, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 327

def found_instance_method(node, name)
  if (scope = node.parent_module_name)
    found_method(node, "#{humanize_scope(scope)}#{name}")
  elsif (anon_block = anonymous_class_block(node))
    base = qualified_name(anon_block.parent_module_name, nil, 'Object')
    scope = node.each_ancestor(:sclass).any? ? "#<Class:#{base}>" : base
    found_method(
      node, "#{humanize_scope(scope)}#{name}", scope_id: anon_block_scope_id(anon_block)
    )
  else
    found_sclass_method(node, name)
  end
end

#found_method(node, method_name, scope_id: nil) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 398

def found_method(node, method_name, scope_id: nil)
  key = method_key(node, method_name)
  key = "#{key}@#{scope_id}" if scope_id
  scope = node.each_ancestor(:rescue, :ensure).first&.type

  if @definitions.key?(key)
    found_redefinition(node, method_name, key, scope)
  else
    @definitions[key] = node
    check_cross_file_duplicate(node, method_name) if scope_id.nil? && scope.nil?
  end
end

#found_redefinition(node, method_name, key, scope) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 411

def found_redefinition(node, method_name, key, scope)
  if scope && !@scopes[scope].include?(key)
    @definitions[key] = node
    @scopes[scope] << key
  elsif intentional_cross_file_redefinition?(node, method_name, key)
    @definitions[key] = node
  else
    add_offense(location(node), message: message_for_dup(node, method_name, key))
  end
end

#found_sclass_method(node, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 388

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

#hash_value(node, key) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 323

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

#humanize_scope(scope) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 341

def humanize_scope(scope)
  scope = scope.sub(
    /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
    '\k<name>.'
  )
  scope.end_with?('.') ? scope : "#{scope}#"
end

#index_source_location(definition) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 579

def index_source_location(definition)
  location = definition.location
  "#{smart_path(location.to_file_path)}:#{location.to_display.start_line}"
end

#indexed_declaration_definitions(namespace, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 553

def indexed_declaration_definitions(namespace, name)
  project_index["#{namespace}##{name}()"]&.definitions.to_a
end

#indexed_definitions(owner, separator, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 539

def indexed_definitions(owner, separator, name)
  namespace = separator == '.' ? "#{owner}::<#{owner.split('::').last}>" : owner

  if name.match?(/\A\w+=\z/)
    # Rubydex indexes `attr_writer :foo` under `foo` rather than `foo=`, so
    # writer definitions come from both the `foo=` and the `foo` declarations.
    indexed_declaration_definitions(namespace, name) +
      indexed_declaration_definitions(namespace, name.delete_suffix('='))
      .select { |definition| writer_attr_definition?(definition) }
  else
    indexed_declaration_definitions(namespace, name).grep_v(Rubydex::AttrWriterDefinition)
  end
end

#inside_condition?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 292

def inside_condition?(node)
  node.ancestors.any?(&:if_type?)
end

#intentional_cross_file_redefinition?(node, method_name, key) ⇒ Boolean (private)

The self-alias trick (alias foo foo or alias_method :foo, :foo right before a def) suppresses Ruby’s method redefinition warning, signaling an intentional redefinition of a method defined in another file.

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 425

def intentional_cross_file_redefinition?(node, method_name, key)
  @self_aliased.include?(method_name) &&
    @definitions[key].source_range.source_buffer.name !=
      node.source_range.source_buffer.name
end

#location(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 446

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

#lookup_constant(node, const_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 478

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, key) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 296

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

#method_alias?(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 180

def_node_matcher :method_alias?, <<~PATTERN
  (alias (sym $_name) (sym $_original_name))
PATTERN

#method_key(node, method_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 438

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

#named_receiver(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 383

def named_receiver(node)
  receiver = node.receiver
  receiver unless class_or_module_new_block?(receiver)
end

#on_alias(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 184

def on_alias(node)
  name, original_name = method_alias?(node)
  return unless name && original_name

  if name == original_name
    track_self_alias(node, name)
    return
  end
  return if node.ancestors.any?(&:if_type?)

  found_instance_method(node, name)
end

#on_attr(node, attr_name, args) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 454

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

#on_def(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 160

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

#on_defs(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 168

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

#on_delegate(node, method_names) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 301

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

#on_new_investigation

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 153

def on_new_investigation
  # The self-alias trick declares an intentional redefinition only within
  # the file that uses it, so the tracked names do not carry over.
  @self_aliased = Set.new
  super
end

#on_send(node)

Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 245

def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
  name, original_name = alias_method?(node)

  if name && original_name
    if name == original_name
      track_self_alias(node, name)
      return
    end
    return if inside_condition?(node)

    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 inside_condition?(node)

    on_delegate(node, names)
  elsif (name = delegator?(node))
    return if inside_condition?(node)

    found_instance_method(node, name)
  elsif (names = delegators?(node))
    return if inside_condition?(node)

    names.each { |name| found_instance_method(node, name) }
  end
end

#qualified_name(enclosing, namespace, mod_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 496

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

#scope_receiver(parent, anon_block) (private)

When a Class.new block is passed as an argument to a named-receiver method call (e.g. T.cast(Class.new(Base) do …​ end, …​)), the receiver-based scope id (e.g. "T.cast") is the same for every call, causing false positives for methods defined in distinct anonymous classes. Return nil so the block falls through to the unique source-location-based scope id. Module.new blocks are excluded because they may be intentionally mixed into the same target via prepend/include/extend.

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 377

def scope_receiver(parent, anon_block)
  return if class_new_block?(anon_block) && parent.call_type?

  named_receiver(parent)
end

#source_location(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 510

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

#sym_name(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 229

def_node_matcher :sym_name, '(sym $_name)'

#track_self_alias(node, name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 431

def track_self_alias(node, name)
  scope = node.parent_module_name
  return unless scope

  @self_aliased << "#{humanize_scope(scope)}#{name}"
end

#writer_attr_definition?(definition) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 557

def writer_attr_definition?(definition)
  definition.is_a?(Rubydex::AttrWriterDefinition) ||
    definition.is_a?(Rubydex::AttrAccessorDefinition)
end