class RuboCop::Cop::Style::AndOr

end
if foo && bar
# good
foo.save && return
# good
end
if foo and bar
# bad
foo.save and return
# bad
@example EnforcedStyle: always
end
if foo && bar
# good
foo.save and return
# good
foo.save && return
# good
end
if foo and bar
# bad
@example EnforcedStyle: conditionals (default)
and that might change the behavior.
between logical operators (‘&&` and `||`) and semantic operators (`and` and `or`),
Autocorrection is unsafe because there is a different operator precedence
@safety
all contexts.
`||` instead. It can be configured to check only in conditions or in
Checks for uses of `and` and `or`, and suggests using `&&` and

def correct_not(node, receiver, corrector)

however, 'not x' also parses as (send x :!)
recurse down a level and add parens to 'obj.method arg'
'x and !obj.method arg' can be autocorrected if we
! is a special case:
def correct_not(node, receiver, corrector)
  if node.prefix_bang?
    return unless receiver.send_type?
    correct_send(receiver, corrector)
  elsif node.prefix_not?
    correct_other(node, corrector)
  else
    raise 'unrecognized unary negation operator'
  end
end

def correct_other(node, corrector)

def correct_other(node, corrector)
  return if node.parenthesized_call?
  corrector.wrap(node, '(', ')')
end

def correct_send(node, corrector)

def correct_send(node, corrector)
  return correct_not(node, node.receiver, corrector) if node.method?(:!)
  return correct_setter(node, corrector) if node.setter_method?
  return correct_other(node, corrector) if node.comparison_method?
  return unless correctable_send?(node)
  whitespace_before_arg_range = whitespace_before_arg(node)
  corrector.remove(whitespace_before_arg_range)
  corrector.insert_before(whitespace_before_arg_range, '(')
  corrector.insert_after(node.last_argument, ')')
end

def correct_setter(node, corrector)

def correct_setter(node, corrector)
  corrector.insert_before(node.receiver, '(')
  corrector.insert_after(node.last_argument, ')')
end

def correctable_send?(node)

def correctable_send?(node)
  !node.parenthesized? && node.arguments? && !node.method?(:[])
end

def keep_operator_precedence(corrector, node)

def keep_operator_precedence(corrector, node)
  if node.or_type? && node.parent&.and_type?
    corrector.wrap(node, '(', ')')
  elsif node.and_type? && node.rhs.or_type?
    corrector.wrap(node.rhs, '(', ')')
  end
end

def message(node)

def message(node)
  format(MSG, prefer: node.alternate_operator, current: node.operator)
end

def on_and(node)

def on_and(node)
  process_logical_operator(node) if style == :always
end

def on_conditionals(node)

def on_conditionals(node)
  node.condition.each_node(*AST::Node::OPERATOR_KEYWORDS) do |operator|
    process_logical_operator(operator)
  end
end

def on_if(node)

def on_if(node)
  on_conditionals(node) if style == :conditionals
end

def process_logical_operator(node)

def process_logical_operator(node)
  return if node.logical_operator?
  message = message(node)
  add_offense(node.loc.operator, message: message) do |corrector|
    node.each_child_node do |expr|
      if expr.send_type?
        correct_send(expr, corrector)
      elsif expr.return_type? || expr.assignment?
        correct_other(expr, corrector)
      end
    end
    corrector.replace(node.loc.operator, node.alternate_operator)
    keep_operator_precedence(corrector, node)
  end
end

def whitespace_before_arg(node)

def whitespace_before_arg(node)
  begin_paren = node.loc.selector.end_pos
  end_paren = begin_paren
  # Increment position of parenthesis, unless message is a predicate
  # method followed by a non-whitespace char (e.g. is_a?String).
  end_paren += 1 unless /\?\S/.match?(node.source)
  range_between(begin_paren, end_paren)
end