class RuboCop::Cop::Style::RedundantLineContinuation


(argument)
some_method <br># it is not redundant.
# also good - backslash with newline between the method name and its arguments,
- 3
+ 2 <br>1 <br># it is not redundant
# also good - backslash at the line following the newline begins with a + or -,
baz)
foo(bar, # <br># also good - backslash at the end of a comment is not redundant
’baz’)
foo(‘bar’ <br># also good - backslash in string concatenation is not redundant
baz)
foo(bar,
# good
baz)
foo(bar, <br># bad
bar}
{foo:
bar]
[foo,
# good
bar}
{foo: <br>bar]
[foo, <br># bad
.baz
&.bar
foo
bar
foo.
# good
.baz
&.bar <br>foo <br>bar
foo. <br># bad
@example
for string concatenation is not redundant and is not considered an offense.
However, a backslash at the end of a comment or
does not result in a syntax error.
This cop marks a line continuation as redundant if removing the backslash
Check for redundant line continuation.

def argument_is_method?(node)

def argument_is_method?(node)
  return false unless node.send_type?
  return false unless (first_argument = node.first_argument)
  method_call_with_arguments?(first_argument)
end

def argument_newline?(node)

rubocop:disable Metrics/AbcSize
def argument_newline?(node)
  node = node.to_a.last if node.assignment?
  return false if node.parenthesized_call?
  node = node.children.first if node.root? && node.begin_type?
  if argument_is_method?(node)
    argument_newline?(node.first_argument)
  else
    return false unless method_call_with_arguments?(node)
    node.loc.selector.line != node.first_argument.loc.line
  end
end

def code_ends_with_continuation?(last_line)

def code_ends_with_continuation?(last_line)
  return false if processed_source.line_with_comment?(processed_source.ast.last_line)
  last_line.end_with?(LINE_CONTINUATION)
end

def ends_with_uncommented_backslash?(range)

def ends_with_uncommented_backslash?(range)
  # A line continuation always needs to be the last character on the line, which
  # means that it is impossible to have a comment following a continuation.
  # Therefore, if the line contains a comment, it cannot end with a continuation.
  return false if processed_source.line_with_comment?(range.line)
  range.source_line.end_with?(LINE_CONTINUATION)
end

def find_node_for_line(last_line)

def find_node_for_line(last_line)
  processed_source.ast.each_node do |node|
    return node if same_line?(node, last_line)
  end
end

def inside_string_literal?(range, token)

def inside_string_literal?(range, token)
  ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
end

def inside_string_literal_or_method_with_argument?(range)

def inside_string_literal_or_method_with_argument?(range)
  line_range = range_by_whole_lines(range)
  processed_source.tokens.each_cons(2).any? do |token, next_token|
    next if token.line == next_token.line
    inside_string_literal?(range, token) ||
      method_with_argument?(line_range, token, next_token)
  end
end

def inspect_end_of_ruby_code_line_continuation

def inspect_end_of_ruby_code_line_continuation
  last_line = processed_source.lines[processed_source.ast.last_line - 1]
  return unless code_ends_with_continuation?(last_line)
  last_column = last_line.length
  line_continuation_range = range_between(last_column - 1, last_column)
  add_offense(line_continuation_range) do |corrector|
    corrector.remove_trailing(line_continuation_range, 1)
  end
end

def leading_dot_method_chain_with_blank_line?(range)

def leading_dot_method_chain_with_blank_line?(range)
  return false unless range.source_line.strip.start_with?('.', '&.')
  processed_source[range.line].strip.empty?
end

def method_call_with_arguments?(node)

def method_call_with_arguments?(node)
  node.call_type? && !node.arguments.empty?
end

def method_with_argument?(line_range, current_token, next_token)

argument
do_something \

A method call without parentheses such as the following cannot remove `\`:
def method_with_argument?(line_range, current_token, next_token)
  return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
  return false unless current_token.pos.overlaps?(line_range)
  ARGUMENT_TYPES.include?(next_token.type)
end

def on_new_investigation

def on_new_investigation
  return unless processed_source.ast
  each_match_range(processed_source.ast.source_range, LINE_CONTINUATION_PATTERN) do |range|
    next if require_line_continuation?(range)
    next unless redundant_line_continuation?(range)
    add_offense(range) do |corrector|
      corrector.remove_leading(range, 1)
    end
  end
  inspect_end_of_ruby_code_line_continuation
end

def redundant_line_continuation?(range)

def redundant_line_continuation?(range)
  return true unless (node = find_node_for_line(range.last_line))
  return false if argument_newline?(node)
  # Check if source is still valid without the continuation
  source = processed_source.raw_source.dup
  source[range.begin_pos, range.length] = "\n"
  parse(source).valid_syntax?
end

def require_line_continuation?(range)

def require_line_continuation?(range)
  !ends_with_uncommented_backslash?(range) ||
    string_concatenation?(range.source_line) ||
    start_with_arithmetic_operator?(range) ||
    inside_string_literal_or_method_with_argument?(range) ||
    leading_dot_method_chain_with_blank_line?(range)
end

def same_line?(node, line)

def same_line?(node, line)
  return false unless (source_range = node.source_range)
  if node.is_a?(AST::StrNode)
    if node.heredoc?
      (node.loc.heredoc_body.line..node.loc.heredoc_body.last_line).cover?(line)
    else
      (source_range.line..source_range.last_line).cover?(line)
    end
  else
    source_range.line == line
  end
end

def start_with_arithmetic_operator?(range)

def start_with_arithmetic_operator?(range)
  line_range = processed_source.buffer.line_range(range.line + 1)
  ARITHMETIC_OPERATOR_TOKENS.include?(processed_source.first_token_of(line_range).type)
end

def string_concatenation?(source_line)

def string_concatenation?(source_line)
  /["']\s*\\\z/.match?(source_line)
end