module RuboCop::Cop::AutocorrectLogic

This module encapsulates the logic for autocorrect behavior for a cop.

Public Instance Methods

autocorrect?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 7
def autocorrect?
  autocorrect_requested? && correctable? && autocorrect_enabled?
end
autocorrect_enabled?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 31
def autocorrect_enabled?
  # allow turning off autocorrect on a cop by cop basis
  return true unless cop_config

  # `false` is the same as `disabled` for backward compatibility.
  return false if ['disabled', false].include?(cop_config['AutoCorrect'])

  # When LSP is enabled, it is considered as editing source code,
  # and autocorrection with `AutoCorrect: contextual` will not be performed.
  return false if contextual_autocorrect? && LSP.enabled?

  # :safe_autocorrect is a derived option based on several command-line
  # arguments - see RuboCop::Options#add_autocorrection_options
  return safe_autocorrect? if @options.fetch(:safe_autocorrect, false)

  true
end
autocorrect_requested?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 15
def autocorrect_requested?
  @options.fetch(:autocorrect, false)
end
autocorrect_with_disable_uncorrectable?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 11
def autocorrect_with_disable_uncorrectable?
  autocorrect_requested? && disable_uncorrectable? && autocorrect_enabled?
end
correctable?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 19
def correctable?
  self.class.support_autocorrect? || disable_uncorrectable?
end
disable_uncorrectable?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 23
def disable_uncorrectable?
  @options[:disable_uncorrectable] == true
end
safe_autocorrect?() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 27
def safe_autocorrect?
  cop_config.fetch('Safe', true) && cop_config.fetch('SafeAutoCorrect', true)
end

Private Instance Methods

disable_offense(offense_range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 51
def disable_offense(offense_range)
  range = surrounding_heredoc(offense_range) ||
          surrounding_percent_array(offense_range) ||
          string_continuation(offense_range)

  if range
    disable_offense_before_and_after(range_by_lines(range))
  else
    disable_offense_with_eol_or_surround_comment(offense_range)
  end
end
disable_offense_at_end_of_line(range, eol_comment) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 138
def disable_offense_at_end_of_line(range, eol_comment)
  Corrector.new(range).insert_after(range, eol_comment)
end
disable_offense_before_and_after(range_by_lines) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 142
def disable_offense_before_and_after(range_by_lines)
  range_with_newline = range_by_lines.resize(range_by_lines.size + 1)
  leading_whitespace = range_by_lines.source_line[/^\s*/]

  Corrector.new(range_by_lines).wrap(
    range_with_newline,
    "#{leading_whitespace}# rubocop:todo #{cop_name}\n",
    "#{leading_whitespace}# rubocop:enable #{cop_name}\n"
  )
end
disable_offense_with_eol_or_surround_comment(range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 63
def disable_offense_with_eol_or_surround_comment(range)
  eol_comment = " # rubocop:todo #{cop_name}"
  needed_line_length = (range.source_line + eol_comment).length

  if needed_line_length <= max_line_length
    disable_offense_at_end_of_line(range_of_first_line(range), eol_comment)
  else
    disable_offense_before_and_after(range_by_lines(range))
  end
end
max_line_length() click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 134
def max_line_length
  config.for_cop('Layout/LineLength')['Max'] || 120
end
range_by_lines(range) click to toggle source

Expand the given range to include all of any lines it covers. Does not include newline at end of the last line.

# File lib/rubocop/cop/autocorrect_logic.rb, line 124
def range_by_lines(range)
  begin_of_first_line = range.begin_pos - range.column

  last_line = range.source_buffer.source_line(range.last_line)
  last_line_offset = last_line.length - range.last_column
  end_of_last_line = range.end_pos + last_line_offset

  Parser::Source::Range.new(range.source_buffer, begin_of_first_line, end_of_last_line)
end
range_of_first_line(range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 115
def range_of_first_line(range)
  begin_of_first_line = range.begin_pos - range.column
  end_of_first_line = begin_of_first_line + range.source_line.length

  Parser::Source::Range.new(range.source_buffer, begin_of_first_line, end_of_first_line)
end
range_overlaps_offense?(offense_range, range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 107
def range_overlaps_offense?(offense_range, range)
  offense_range.begin_pos > range.begin_pos && range.overlaps?(offense_range)
end
string_continuation(offense_range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 97
def string_continuation(offense_range)
  return nil if offense_range.empty?

  string_continuation_nodes = processed_source.ast.each_descendant.filter_map do |node|
    range_by_lines(node.source_range) if string_continuation?(node)
  end

  string_continuation_nodes.find { |range| range_overlaps_offense?(offense_range, range) }
end
string_continuation?(node) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 111
def string_continuation?(node)
  (node.str_type? || node.dstr_type? || node.xstr_type?) && node.source.match?(/\\\s*$/)
end
surrounding_heredoc(offense_range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 74
def surrounding_heredoc(offense_range)
  # The empty offense range is an edge case that can be reached from the Lint/Syntax cop.
  return nil if offense_range.empty?

  heredoc_nodes = processed_source.ast.each_descendant.select do |node|
    node.respond_to?(:heredoc?) && node.heredoc?
  end
  heredoc_nodes.map { |node| node.source_range.join(node.loc.heredoc_end) }
               .find { |range| range.contains?(offense_range) }
end
surrounding_percent_array(offense_range) click to toggle source
# File lib/rubocop/cop/autocorrect_logic.rb, line 85
def surrounding_percent_array(offense_range)
  return nil if offense_range.empty?

  percent_array = processed_source.ast.each_descendant.select do |node|
    node.array_type? && node.percent_literal?
  end

  percent_array.map(&:source_range).find do |range|
    range_overlaps_offense?(offense_range, range)
  end
end