class RuboCop::Cop::Lint::OutOfRangeRegexpRef
Looks for references of ‘Regexp` captures that are out of range and thus always returns nil.
@safety
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: [source,ruby] ---- 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.
@example
/(foo)bar/ =~ 'foobar' # bad - always returns nil puts $2 # => nil # good puts $1 # => foo
Constants
- MSG
- REGEXP_ARGUMENT_METHODS
- REGEXP_CAPTURE_METHODS
- REGEXP_RECEIVER_METHODS
- RESTRICT_ON_SEND
Public Instance Methods
Source
# 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
Also aliased as: after_csend
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 72 def on_in_pattern(node) regexp_patterns = regexp_patterns(node) @valid_ref = regexp_patterns.filter_map { |pattern| check_regexp(pattern) }.max end
Source
# 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
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 47 def on_new_investigation @valid_ref = 0 end
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 78 def on_nth_ref(node) backref = node.children.first 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
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 66 def on_when(node) regexp_conditions = node.conditions.select(&:regexp_type?) @valid_ref = regexp_conditions.filter_map { |condition| check_regexp(condition) }.max end
Private Instance Methods
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 103 def check_regexp(node) return if node.interpolation? named_capture = node.each_capture(named: true).count @valid_ref = if named_capture.positive? named_capture else node.each_capture(named: false).count end end
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 123 def nth_ref_receiver?(send_node) send_node.receiver&.nth_ref_type? end
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 114 def regexp_first_argument?(send_node) send_node.first_argument&.regexp_type? \ && REGEXP_ARGUMENT_METHODS.include?(send_node.method_name) end
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 94 def regexp_patterns(in_node) pattern = in_node.pattern if pattern.regexp_type? [pattern] else pattern.each_descendant(:regexp).to_a end end
Source
# File lib/rubocop/cop/lint/out_of_range_regexp_ref.rb, line 119 def regexp_receiver?(send_node) send_node.receiver&.regexp_type? end