class RuboCop::Cop::Lint::SafeNavigationChain

x&.foo || bar
x&.foo&.bar
# good

@example

x&.foo[bar]
x&.foo + bar
x&.foo.bar
# bad
@example
This cop checks for the problem outlined above.
safe navigation operator after a safe navigation operator.
navigation operator, it raises NoMethodError. We should use a
nil. If you chain an ordinary method call after a safe
The safe navigation operator returns nil if the receiver is

def add_safe_navigation_operator(offense_range:, send_node:)

Returns:
  • (String) -

Parameters:
  • send_node (RuboCop::AST::SendNode) --
  • offense_range (Parser::Source::Range) --
def add_safe_navigation_operator(offense_range:, send_node:)
  source =
    if brackets?(send_node)
      format(
        '%<method_name>s(%<arguments>s)%<method_chain>s',
        arguments: send_node.arguments.map(&:source).join(', '),
        method_name: send_node.method_name,
        method_chain: send_node.source_range.end.join(send_node.source_range.end).source
      )
    else
      offense_range.source
    end
  source.prepend('.') unless source.start_with?('.')
  source.prepend('&')
end

def autocorrect(corrector, offense_range:, send_node:)

Parameters:
  • send_node (RuboCop::AST::SendNode) --
  • offense_range (Parser::Source::Range) --
  • corrector (RuboCop::Cop::Corrector) --
def autocorrect(corrector, offense_range:, send_node:)
  corrector.replace(
    offense_range,
    add_safe_navigation_operator(
      offense_range: offense_range,
      send_node: send_node
    )
  )
end

def brackets?(send_node)

def brackets?(send_node)
  send_node.method?(:[]) || send_node.method?(:[]=)
end

def on_send(node)

def on_send(node)
  bad_method?(node) do |safe_nav, method|
    return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
    location =
      Parser::Source::Range.new(node.source_range.source_buffer,
                                safe_nav.source_range.end_pos,
                                node.source_range.end_pos)
    add_offense(location) do |corrector|
      autocorrect(corrector, offense_range: location, send_node: node)
    end
  end
end