class RuboCop::Cop::Lint::EmptyConditionalBody

Checks for the presence of ‘if`, `elsif` and `unless` branches without a body.

NOTE: empty ‘else` branches are handled by `Style/EmptyElse`.

@safety

Autocorrection for this cop is not safe. The conditions for empty branches that
the autocorrection removes may have side effects, or the logic in subsequent
branches may change due to the removal of a previous condition.

@example

# bad
if condition
end

# bad
unless condition
end

# bad
if condition
  do_something
elsif other_condition
end

# good
if condition
  do_something
end

# good
unless condition
  do_something
end

# good
if condition
  do_something
elsif other_condition
  do_something_else
end

@example AllowComments: true (default)

# good
if condition
  do_something
elsif other_condition
  # noop
end

@example AllowComments: false

# bad
if condition
  do_something
elsif other_condition
  # noop
end

Constants

MSG

Public Instance Methods

on_if(node) click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 71
def on_if(node)
  return if node.body || same_line?(node.loc.begin, node.loc.end)
  return if cop_config['AllowComments'] && contains_comments?(node)

  range = offense_range(node)

  add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
    next if node.parent&.call_type?

    autocorrect(corrector, node)
  end
end

Private Instance Methods

all_branches_body_missing?(node) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 177
def all_branches_body_missing?(node)
  return false unless node.parent&.if_type?

  node.parent.branches.compact.empty?
end
autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 95
def autocorrect(corrector, node)
  remove_comments(corrector, node)
  remove_empty_branch(corrector, node)
  correct_other_branches(corrector, node)
end
branch_range(node) click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 163
def branch_range(node)
  if empty_if_branch?(node) && else_branch?(node)
    node.source_range.with(end_pos: node.loc.else.begin_pos)
  elsif node.loc.else
    node.source_range.with(end_pos: node.condition.source_range.end_pos)
  elsif all_branches_body_missing?(node)
    if_node = node.ancestors.detect(&:if?)
    node.source_range.join(if_node.loc.end.end)
  else
    node.source_range
  end
end
correct_other_branches(corrector, node) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 125
def correct_other_branches(corrector, node)
  return unless require_other_branches_correction?(node)

  if node.else_branch&.if_type? && !node.else_branch.modifier_form?
    # Replace an orphaned `elsif` with `if`
    corrector.replace(node.else_branch.loc.keyword, 'if')
  else
    # Flip orphaned `else`
    corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
  end
end
deletion_range(range) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 183
def deletion_range(range)
  # Collect a range between the start of the `if` node and the next relevant node,
  # including final new line.
  # Based on `RangeHelp#range_by_whole_lines` but allows the `if` to not start
  # on the first column.
  buffer = @processed_source.buffer

  last_line = buffer.source_line(range.last_line)
  end_offset = last_line.length - range.last_column + 1

  range.adjust(end_pos: end_offset).intersect(buffer.source_range)
end
else_branch?(node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 158
def else_branch?(node)
  node.else_branch && !node.else_branch.if_type?
end
empty_elsif_branch?(node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 152
def empty_elsif_branch?(node)
  return false unless (else_branch = node.else_branch)

  else_branch.if_type? && !else_branch.body
end
empty_if_branch?(node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 144
def empty_if_branch?(node)
  return false unless (parent = node.parent)
  return true unless parent.if_type?
  return true unless (if_branch = parent.if_branch)

  if_branch.if_type? && !if_branch.body
end
offense_range(node) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 87
def offense_range(node)
  if node.loc.else
    node.source_range.begin.join(node.loc.else.begin)
  else
    node.source_range
  end
end
remove_comments(corrector, node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 101
def remove_comments(corrector, node)
  comments_in_range(node).each do |comment|
    range = range_by_whole_lines(comment.source_range, include_final_newline: true)
    corrector.remove(range)
  end
end
remove_empty_branch(corrector, node) click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 109
def remove_empty_branch(corrector, node)
  range = if empty_if_branch?(node) && else_branch?(node)
            branch_range(node)
          elsif same_line?(node, else_kw_loc = node.loc.else)
            node.source_range.begin.join(else_kw_loc.begin)
          elsif node.parent&.loc.respond_to?(:end) &&
                same_line?(node, end_loc = node.parent.loc.end)
            node.source_range.begin.join(end_loc.begin)
          else
            deletion_range(branch_range(node))
          end

  corrector.remove(range)
end
require_other_branches_correction?(node) click to toggle source
# File lib/rubocop/cop/lint/empty_conditional_body.rb, line 137
def require_other_branches_correction?(node)
  return false unless node.if_type? && node.else?
  return false if !empty_if_branch?(node) && node.elsif?

  !empty_elsif_branch?(node)
end