Class: RuboCop::Cop::Lint::OutOfRangeRegexpRef

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/lint/out_of_range_regexp_ref.rb

Overview

Looks for references of Regexp captures that are out of range and thus always returns nil.

Examples:


/(foo)bar/ =~ 'foobar'

# bad - always returns nil

puts $2 # => nil

# good

puts $1 # => foo

Cop Safety Information:

  • This cop is unsafe because it is naive in how it determines what references are available based on the last encountered regexp, but it cannot handle some cases, such as conditional regexp matches, which leads to false positives, such as:

    foo ? /(c)(b)/ =~ str : /(b)/ =~ str
    do_something if $2
    # $2 is defined for the first condition but not the second, however
    # the cop will mark this as an offense.

    This might be a good indication of code that should be refactored, however.

Constant Summary collapse

MSG =
'$%<backref>s is out of range (%<count>s regexp capture %<group>s detected).'
REGEXP_RECEIVER_METHODS =
%i[=~ === match].to_set.freeze
REGEXP_ARGUMENT_METHODS =
%i[=~ match grep gsub gsub! sub sub! [] slice slice! index rindex
scan partition rpartition start_with? end_with?].to_set.freeze
REGEXP_CAPTURE_METHODS =
(REGEXP_RECEIVER_METHODS + REGEXP_ARGUMENT_METHODS).freeze
RESTRICT_ON_SEND =
REGEXP_CAPTURE_METHODS

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_other_file, #parse, #ready, #relevant_file?, support_autocorrect?, support_multiple_source?, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#after_send(node) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 55

def after_send(node)
  @valid_ref = nil

  if regexp_first_argument?(node)
    check_regexp(node.first_argument)
  elsif regexp_receiver?(node)
    check_regexp(node.receiver)
  end
end

#on_in_pattern(node) ⇒ Object



71
72
73
74
75
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 71

def on_in_pattern(node)
  regexp_patterns = regexp_patterns(node)

  @valid_ref = regexp_patterns.filter_map { |pattern| check_regexp(pattern) }.max
end

#on_match_with_lvasgn(node) ⇒ Object



51
52
53
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 51

def on_match_with_lvasgn(node)
  check_regexp(node.children.first)
end

#on_new_investigationObject



47
48
49
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 47

def on_new_investigation
  @valid_ref = 0
end

#on_nth_ref(node) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 77

def on_nth_ref(node)
  backref, = *node
  return if @valid_ref.nil? || backref <= @valid_ref

  message = format(
    MSG,
    backref: backref,
    count: @valid_ref.zero? ? 'no' : @valid_ref,
    group: @valid_ref == 1 ? 'group' : 'groups'
  )

  add_offense(node, message: message)
end

#on_when(node) ⇒ Object



65
66
67
68
69
# File 'lib/rubocop/cop/lint/out_of_range_regexp_ref.rb', line 65

def on_when(node)
  regexp_conditions = node.conditions.select(&:regexp_type?)

  @valid_ref = regexp_conditions.filter_map { |condition| check_regexp(condition) }.max
end