123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Style::RedundantSelf

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

Overview

Checks for redundant uses of self.

The usage of self is only needed when:

  • Sending a message to same object with zero arguments in presence of a method name clash with an argument or a local variable.

  • Calling an attribute writer to prevent a local variable assignment.

Note, with using explicit self you can only send messages with public or protected scope, you cannot send private messages this way.

Note we allow uses of self with operators because it would be awkward otherwise. Also allows the use of self.it without arguments in blocks, as in 0.times { self.it }, following Lint/ItWithoutArgumentsInBlock cop.

Examples:

# bad
def foo(bar)
  self.baz
end

# good
def foo(bar)
  self.bar  # Resolves name clash with the argument.
end

def foo
  bar = 1
  self.bar  # Resolves name clash with the local variable.
end

def foo
  %w[x y z].select do |bar|
    self.bar == bar  # Resolves name clash with argument of the block.
  end
end

Constant Summary

::RuboCop::Cop::Base - Inherited

EMPTY_OFFENSES, RESTRICT_ON_SEND

Class Attribute Summary

::RuboCop::Cop::AutoCorrector - Extended

::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 an 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::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_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, #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) ⇒ RedundantSelf

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 60

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

Class Method Details

.autocorrect_incompatible_with

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 56

def self.autocorrect_incompatible_with
  [ColonMethodCall, Layout::DotPosition]
end

Instance Method Details

#add_lhs_to_local_variables_scopes(rhs, lhs) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 196

def add_lhs_to_local_variables_scopes(rhs, lhs)
  if rhs&.send_type? && !rhs.arguments.empty?
    rhs.arguments.each { |argument| @local_variables_scopes[argument] << lhs }
  else
    @local_variables_scopes[rhs] << lhs
  end
end

#add_masgn_lhs_variables(rhs, lhs) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 204

def add_masgn_lhs_variables(rhs, lhs)
  lhs.children.each do |child|
    add_lhs_to_local_variables_scopes(rhs, child.to_a.first)
  end
end

#add_match_var_scopes(in_pattern_node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 210

def add_match_var_scopes(in_pattern_node)
  in_pattern_node.each_descendant(:match_var) do |match_var_node|
    @local_variables_scopes[in_pattern_node] << match_var_node.children.first
  end
end

#add_scope(node, local_variables = []) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 144

def add_scope(node, local_variables = [])
  node.each_descendant do |child_node|
    @local_variables_scopes[child_node] = local_variables
  end
end

#allow_self(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 190

def allow_self(node)
  return unless node.send_type? && node.self_receiver?

  @allowed_send_nodes << node
end

#allowed_send_node?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 150

def allowed_send_node?(node)
  @allowed_send_nodes.include?(node) ||
    @local_variables_scopes[node].include?(node.method_name) ||
    node.each_ancestor.any? do |ancestor|
      @local_variables_scopes[ancestor].include?(node.method_name)
    end ||
    KERNEL_METHODS.include?(node.method_name)
end

#it_method_in_block?(node) ⇒ Boolean (private)

Respects Lint/ItWithoutArgumentsInBlock cop and the following Ruby 3.3’s warning:

$ ruby -e '0.times { begin; it; end }' -e:1: warning: it calls without arguments will refer to the first block param in Ruby 3.4; use it() or self.it

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 165

def it_method_in_block?(node)
  return false unless node.method?(:it)
  return false unless (block_node = node.each_ancestor(:block).first)
  return false unless block_node.arguments.empty_and_without_delimiters?

  node.arguments.empty? && !node.block_literal?
end

#on_and_asgn(node)

Alias for #on_or_asgn.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 72

alias on_and_asgn on_or_asgn

#on_args(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 86

def on_args(node)
  node.children.each { |arg| on_argument(arg) }
end

#on_argument(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 181

def on_argument(node)
  if node.mlhs_type?
    on_args(node)
  else
    name, = *node
    @local_variables_scopes[node] << name
  end
end

#on_block(node) Also known as: #on_numblock

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 120

def on_block(node)
  add_scope(node, @local_variables_scopes[node])
end

#on_blockarg(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 90

def on_blockarg(node)
  on_argument(node)
end

#on_def(node) Also known as: #on_defs

Using self.x to distinguish from local variable x

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 81

def on_def(node)
  add_scope(node)
end

#on_defs(node)

Alias for #on_def.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 84

alias on_defs on_def

#on_if(node) Also known as: #on_while, #on_until

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 126

def on_if(node)
  # Allow conditional nodes to use `self` in the condition if that variable
  # name is used in an `lvasgn` or `masgn` within the `if`.
  node.child_nodes.each do |child_node|
    lhs, _rhs = *child_node

    if child_node.lvasgn_type?
      add_lhs_to_local_variables_scopes(node.condition, lhs)
    elsif child_node.masgn_type?
      add_masgn_lhs_variables(node.condition, lhs)
    end
  end
end

#on_in_pattern(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 104

def on_in_pattern(node)
  add_match_var_scopes(node)
end

#on_lvasgn(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 99

def on_lvasgn(node)
  lhs, rhs = *node
  add_lhs_to_local_variables_scopes(rhs, lhs)
end

#on_masgn(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 94

def on_masgn(node)
  lhs, rhs = *node
  add_masgn_lhs_variables(rhs, lhs)
end

#on_numblock(node)

Alias for #on_block.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 124

alias on_numblock on_block

#on_op_asgn(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 74

def on_op_asgn(node)
  lhs, _op, _rhs = *node
  allow_self(lhs)
end

#on_or_asgn(node) Also known as: #on_and_asgn

Assignment of self.x

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 68

def on_or_asgn(node)
  lhs, _rhs = *node
  allow_self(lhs)
end

#on_send(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 108

def on_send(node)
  return unless node.self_receiver? && regular_method_call?(node)
  return if node.parent&.mlhs_type?
  return if allowed_send_node?(node)
  return if it_method_in_block?(node)

  add_offense(node.receiver) do |corrector|
    corrector.remove(node.receiver)
    corrector.remove(node.loc.dot)
  end
end

#on_until(node)

Alias for #on_if.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 140

alias on_until on_if

#on_while(node)

Alias for #on_if.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 139

alias on_while on_if

#regular_method_call?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/redundant_self.rb', line 173

def regular_method_call?(node)
  !(node.operator_method? ||
    KEYWORDS.include?(node.method_name) ||
    node.camel_case_method? ||
    node.setter_method? ||
    node.implicit_call?)
end