class RuboCop::Cop::Lint::UnreachableLoop

exactly(2).times { raise StandardError }
# good
@example IgnoredPatterns: [/(exactly|at_least|at_most)(d+).times/] (default)
2.times { raise ArgumentError }
# bad
end
raise NotFoundError
end
end
return item
if something?(item)
items.each do |item|
def find_something(items)
# good
end
end
end
raise NotFoundError
else
return item
if something?(item)
items.each do |item|
def find_something(items)
# bad
end
true
end while(item)
end
return false
else
item = item.next
if verify(item)
begin
item = head
def verify_list(head)
# good
end
end while(item)
end
return false
else
return true
if verify(item)
begin
item = head
def verify_list(head)
# bad
end
node = node.parent
do_something(node)
while node
# good
end
break
node = node.parent
do_something(node)
while node
# bad
@example
`Enumerable` context).
code that would otherwise be registered as an offense (eg. ‘times` used not in an
`IgnoredPatterns` can be used to match against the block receiver in order to allow
NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
the code should be refactored to use `if` conditionals.
In rare cases where only one iteration (or at most one iteration) is intended behavior,
A loop that can never reach the second iteration is a possible error in the code.
This cop checks for loops that will have at most one iteration.

def break_statement?(node)

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
    check_case(node)
  else
    false
  end
end

def check(node)

def check(node)
  statements = statements(node)
  break_statement = statements.find { |statement| break_statement?(statement) }
  return unless break_statement
  add_offense(node) unless preceded_by_continue_statement?(break_statement)
end

def check_case(node)

def check_case(node)
  else_branch = node.else_branch
  return false unless else_branch
  return false unless break_statement?(else_branch)
  node.when_branches.all? do |branch|
    branch.body && break_statement?(branch.body)
  end
end

def check_if(node)

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

def loop_method?(node)

def loop_method?(node)
  return false unless node.block_type?
  send_node = node.send_node
  return false if matches_ignored_pattern?(send_node.source)
  send_node.enumerable_method? || send_node.enumerator_method? || send_node.method?(:loop)
end

def on_block(node)

def on_block(node)
  check(node) if loop_method?(node)
end

def on_while(node)

def on_while(node)
  check(node)
end

def preceded_by_continue_statement?(break_statement)

def preceded_by_continue_statement?(break_statement)
  break_statement.left_siblings.any? do |sibling|
    next if sibling.loop_keyword? || loop_method?(sibling)
    sibling.each_descendant(:next, :redo).any?
  end
end

def statements(node)

def statements(node)
  body = node.body
  if body.nil?
    []
  elsif body.begin_type?
    body.children
  else
    [body]
  end
end