Class: RuboCop::Cop::Lint::UnreachableLoop
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::RuboCop::Cop::Base ,
::RuboCop::ExcludeLimit ,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
Instance Chain:
self,
::RuboCop::Cop::AllowedPattern ,
::RuboCop::Cop::Base ,
::RuboCop::Cop::AutocorrectLogic ,
::RuboCop::Cop::IgnoredNode ,
::RuboCop::Util ,
RuboCop::AST::Sexp
|
|
Inherits: |
RuboCop::Cop::Base
|
Defined in: | lib/rubocop/cop/lint/unreachable_loop.rb |
Overview
Checks for loops that will have at most one iteration.
A loop that can never reach the second iteration is a possible error in the code.
In rare cases where only one iteration (or at most one iteration) is intended behavior,
the code should be refactored to use if
conditionals.
Note
|
Block methods that are used with Enumerable s are considered to be loops.
|
AllowedPatterns
can be used to match against the block receiver in order to allow
code that would otherwise be registered as an offense (eg. times
used not in an
Enumerable
context).
Constant Summary
-
CONTINUE_KEYWORDS =
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 90%i[next redo].freeze
-
MSG =
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 89'This loop will have at most one iteration.'
::RuboCop::Cop::Base
- Inherited
Class Attribute Summary
::RuboCop::Cop::Base
- Inherited
.gem_requirements, .lint?, | |
.support_autocorrect? | Returns if class supports autocorrect. |
.support_multiple_source? | Override if your cop should be called repeatedly for multiple investigations Between calls to |
Class Method Summary
::RuboCop::Cop::Base
- Inherited
.autocorrect_incompatible_with | List of cops that should not try to autocorrect at the same time as this cop. |
.badge | Naming. |
.callbacks_needed, .cop_name, .department, | |
.documentation_url | Returns a url to view this cops documentation online. |
.exclude_from_registry | Call for abstract Cop classes. |
.inherited, | |
.joining_forces | Override and return the Force class(es) you need to join. |
.match? | Returns true if the cop name or the cop namespace matches any of the given names. |
.new, | |
.requires_gem | Register a version requirement for the given gem name. |
.restrict_on_send |
::RuboCop::ExcludeLimit
- Extended
exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
transform |
Instance Attribute Summary
::RuboCop::Cop::AllowedPattern
- Included
::RuboCop::Cop::Base
- Inherited
::RuboCop::Cop::AutocorrectLogic
- Included
Instance Method Summary
- #on_block(node)
-
#on_for(node)
Alias for #on_while.
- #on_numblock(node)
-
#on_until(node)
Alias for #on_while.
-
#on_until_post(node)
Alias for #on_while.
- #on_while(node) (also: #on_until, #on_while_post, #on_until_post, #on_for)
-
#on_while_post(node)
Alias for #on_while.
- #break_command?(node) private
- #break_statement?(node) ⇒ Boolean private
- #check(node) private
- #check_case(node) private
- #check_if(node) private
- #conditional_continue_keyword?(break_statement) ⇒ Boolean private
- #loop_method?(node) ⇒ Boolean private
- #preceded_by_continue_statement?(break_statement) ⇒ Boolean private
- #statements(node) private
::RuboCop::Cop::AllowedPattern
- Included
#allowed_line?, #allowed_patterns, #cop_config_deprecated_methods_values, #cop_config_patterns_values, #matches_allowed_pattern? |
::RuboCop::Cop::Base
- Inherited
#add_global_offense | Adds an offense that has no particular location. |
#add_offense | Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense. |
#begin_investigation | Called before any investigation. |
#callbacks_needed, | |
#cop_config | Configuration Helpers. |
#cop_name, #excluded_file?, | |
#external_dependency_checksum | This method should be overridden when a cop’s behavior depends on state that lives outside of these locations: |
#inspect, | |
#message | Gets called if no message is specified when calling |
#name | Alias for Base#cop_name. |
#offenses, | |
#on_investigation_end | Called after all on_… |
#on_new_investigation | Called before all on_… |
#on_other_file | Called instead of all on_… |
#parse | There should be very limited reasons for a Cop to do it’s own parsing. |
#parser_engine, | |
#ready | Called between investigations. |
#relevant_file?, | |
#target_gem_version | Returns a gems locked versions (i.e. |
#target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
#callback_argument | Reserved for Cop::Cop. |
#complete_investigation | Called to complete an investigation. |
#correct, #current_corrector, | |
#current_offense_locations | Reserved for Commissioner: |
#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, | |
#reset_investigation | Actually private methods. |
#use_corrector |
::RuboCop::Cop::AutocorrectLogic
- Included
#disable_offense, #disable_offense_at_end_of_line, #disable_offense_before_and_after, #disable_offense_with_eol_or_surround_comment, #heredoc_range, #max_line_length, #multiline_ranges, #multiline_string?, | |
#range_by_lines | Expand the given range to include all of any lines it covers. |
#range_of_first_line, #range_overlaps_offense?, #string_continuation?, #surrounding_heredoc?, #surrounding_percent_array? |
::RuboCop::Cop::IgnoredNode
- Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Method Details
#break_command?(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 143
def_node_matcher :break_command?, <<~PATTERN { return break (send {nil? (const {nil? cbase} :Kernel)} {:raise :fail :throw :exit :exit! :abort} ...) } PATTERN
#break_statement?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 153
def break_statement?(node) return true if break_command?(node) case node.type when :begin, :kwbegin statements = *node break_statement = statements.find { |statement| break_statement?(statement) } break_statement && !preceded_by_continue_statement?(break_statement) when :if check_if(node) when :case, :case_match check_case(node) else false end end
#check(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 119
def check(node) statements = statements(node) break_statement = statements.find { |statement| break_statement?(statement) } return unless break_statement unless preceded_by_continue_statement?(break_statement) || conditional_continue_keyword?(break_statement) add_offense(node) end end
#check_case(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 176
def check_case(node) else_branch = node.else_branch return false unless else_branch return false unless break_statement?(else_branch) branches = if node.case_type? node.when_branches else node.in_pattern_branches end branches.all? { |branch| branch.body && break_statement?(branch.body) } end
#check_if(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 170
def check_if(node) if_branch = node.if_branch else_branch = node.else_branch if_branch && else_branch && break_statement?(if_branch) && break_statement?(else_branch) end
#conditional_continue_keyword?(break_statement) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 200
def conditional_continue_keyword?(break_statement) or_node = break_statement.each_descendant(:or).to_a.last or_node && CONTINUE_KEYWORDS.include?(or_node.rhs.type) end
#loop_method?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 110
def loop_method?(node) return false unless node.block_type? || node.numblock_type? send_node = node.send_node loopable = send_node.enumerable_method? || send_node.enumerator_method? || send_node.method?(:loop) loopable && !matches_allowed_pattern?(send_node.source) end
#on_block(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 100
def on_block(node) check(node) if loop_method?(node) end
#on_for(node)
Alias for #on_while.
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 98
alias on_for on_while
#on_numblock(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 104
def on_numblock(node) check(node) if loop_method?(node) end
#on_until(node)
Alias for #on_while.
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 95
alias on_until on_while
#on_until_post(node)
Alias for #on_while.
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 97
alias on_until_post on_while
#on_while(node) Also known as: #on_until, #on_while_post, #on_until_post, #on_for
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 92
def on_while(node) check(node) end
#on_while_post(node)
Alias for #on_while.
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 96
alias on_while_post on_while
#preceded_by_continue_statement?(break_statement) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 190
def preceded_by_continue_statement?(break_statement) break_statement.left_siblings.any? do |sibling| # Numblocks have the arguments count as a number in the AST. next if sibling.is_a?(Integer) next if sibling.loop_keyword? || loop_method?(sibling) sibling.each_descendant(*CONTINUE_KEYWORDS).any? end end
#statements(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/unreachable_loop.rb', line 130
def statements(node) body = node.body if body.nil? [] elsif body.begin_type? body.children else [body] end end