Class: RuboCop::Cop::InternalAffairs::UseRestrictOnSend

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb

Overview

Flags if ‘RESTRICT_ON_SEND` constant not defined and method name is checked programmatically in `on_send` methods.

Examples:

# bad
def on_send(node)
  return unless method_name(node) == :foo
  return unless node.children[1] == :foo
  return unless METHOD_NAMES.include?(method_name(node))

  name = node.children[1]
  return unless name == :foo
  name2 = method_name(node)
  return unless name == :foo

  # more code
end

# good
RESTRICT_ON_SEND = %i[foo].freeze

def on_send(node)
  # more code
end

# ignored - not `on_send`
def on_def(node)
  return unless method_name(node) == :foo
end

# ignored - `else` branch
def on_send(node)
  if method_name(node) == :foo
    add_offense(node)
  else
    something_else
  end
end

Constant Summary collapse

MSG =
'Define constant `RESTRICT_ON_SEND` to speed up calls to `on_send`. ' \
'The following line is then no longer necessary:'

Instance Method Summary collapse

Instance Method Details

#method_name_assignment(node, send_param) ⇒ Object



65
66
67
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 65

def_node_search :method_name_assignment, <<~PATTERN
  (lvasgn $_ #method_name_plain(%1))
PATTERN

#method_name_call(node, send_param, local_assignments) ⇒ Object



57
58
59
60
61
62
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 57

def_node_matcher :method_name_call, <<~PATTERN
  {
    #method_name_plain(%1)  # direct method_name/children[1] call on the on_send param
    (lvar %2)               # local variable previously assigned from such a call
  }
PATTERN

#method_name_check(node, send_param, local_assignments) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 70

def_node_search :method_name_check, <<~PATTERN
  (if
    ${
      (send #method_name_call(%1, %2) {:== :!=} _) # method_name(on_send_param) == foo
      (send _ :include? #method_name_call(%1, %2)) # a.include?(method_name(on_send_param))
    }
    {!nil? nil? | nil? !nil?}                      # has either `if` or `else` branch - not both
  )
PATTERN

#method_name_plain(node, send_param) ⇒ Object



49
50
51
52
53
54
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 49

def_node_matcher :method_name_plain, <<~PATTERN
  {
    (send _ :method_name (lvar %1) ...)           # method_name(on_send_param)
    (send (send (lvar %1) :children) :[] (int 1)) # on_send_param.children[1]
  }
PATTERN

#on_casgn(node) ⇒ Object



94
95
96
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 94

def on_casgn(node)
  @restrict_on_send_set = true if node.name == :RESTRICT_ON_SEND
end

#on_def(node) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rubocop/cop/internal_affairs/use_restrict_on_send.rb', line 80

def on_def(node)
  return unless node.method?(:on_send)
  return if @restrict_on_send_set

  send_param = node.first_argument&.name
  return unless send_param

  local_assignments = method_name_assignment(node, send_param).to_set

  method_name_check(node, send_param, local_assignments) do |call_node|
    add_offense(call_node)
  end
end