class RuboCop::Cop::Style::RedundantSelf
end
end
self.bar == bar # Resolves name clash with argument of the block.
%w[x y z].select do |bar|
def foo
end
self.bar # Resolves name clash with the local variable.
bar = 1
def foo
end
self.bar # Resolves name clash with the argument.
def foo(bar)
# good
end
self.baz
def foo(bar)
# bad
@example
otherwise.
Note we allow uses of ‘self` with operators because it would be awkward
protected scope, you cannot send private messages this way.
Note, with using explicit self you can only send messages with public or
* Calling an attribute writer to prevent a local variable assignment.
variable.
presence of a method name clash with an argument or a local
* Sending a message to same object with zero arguments in
The usage of `self` is only needed when:
Checks for redundant uses of `self`.
def self.autocorrect_incompatible_with
def self.autocorrect_incompatible_with [ColonMethodCall, Layout::DotPosition] end
def add_lhs_to_local_variables_scopes(rhs, lhs)
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
def add_masgn_lhs_variables(rhs, lhs)
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
def add_match_var_scopes(in_pattern_node)
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
def add_scope(node, local_variables = [])
def add_scope(node, local_variables = []) node.each_descendant do |child_node| @local_variables_scopes[child_node] = local_variables end end
def allow_self(node)
def allow_self(node) return unless node.send_type? && node.self_receiver? @allowed_send_nodes << node end
def allowed_send_node?(node)
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
def initialize(config = nil, options = nil)
def initialize(config = nil, options = nil) super @allowed_send_nodes = [] @local_variables_scopes = Hash.new { |hash, key| hash[key] = [] }.compare_by_identity end
def on_args(node)
def on_args(node) node.children.each { |arg| on_argument(arg) } end
def on_argument(node)
def on_argument(node) if node.mlhs_type? on_args(node) else name, = *node @local_variables_scopes[node] << name end end
def on_block(node)
def on_block(node) add_scope(node, @local_variables_scopes[node]) end
def on_blockarg(node)
def on_blockarg(node) on_argument(node) end
def on_def(node)
def on_def(node) add_scope(node) end
def on_if(node)
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
def on_in_pattern(node)
def on_in_pattern(node) add_match_var_scopes(node) end
def on_lvasgn(node)
def on_lvasgn(node) lhs, rhs = *node add_lhs_to_local_variables_scopes(rhs, lhs) end
def on_masgn(node)
def on_masgn(node) lhs, rhs = *node add_masgn_lhs_variables(rhs, lhs) end
def on_op_asgn(node)
def on_op_asgn(node) lhs, _op, _rhs = *node allow_self(lhs) end
def on_or_asgn(node)
def on_or_asgn(node) lhs, _rhs = *node allow_self(lhs) end
def on_send(node)
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) add_offense(node.receiver) do |corrector| corrector.remove(node.receiver) corrector.remove(node.loc.dot) end end
def regular_method_call?(node)
def regular_method_call?(node) !(node.operator_method? || KEYWORDS.include?(node.method_name) || node.camel_case_method? || node.setter_method? || node.implicit_call?) end