Skip to content

Commit

Permalink
Add new Lint/UselessNumericOperation cop
Browse files Browse the repository at this point in the history
Makes progress on rubocop#11191.

Certain numeric operations have no impact, being:
Adding or subtracting 0, multiplying or dividing by 1 or raising to the power of 1.

These are probably mistakes or leftover from debugging, so flag and optionally remove them.
  • Loading branch information
Zopolis4 committed Aug 27, 2024
1 parent 985c322 commit b05a51c
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/new_lint_useless_numeric_operation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#13074](https://github.com/rubocop/rubocop/issues/13074): Add new `Lint/UselessNumericOperation` cop to check for inconsequential numeric operations. ([@zopolis4][])
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,11 @@ Lint/UselessMethodDefinition:
VersionChanged: '1.61'
Safe: false

Lint/UselessNumericOperation:
Description: 'Checks for useless numeric operations.'
Enabled: pending
VersionAdded: '<<next>>'

Lint/UselessRescue:
Description: 'Checks for useless `rescue`s.'
Enabled: pending
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@
require_relative 'rubocop/cop/lint/useless_assignment'
require_relative 'rubocop/cop/lint/useless_else_without_rescue'
require_relative 'rubocop/cop/lint/useless_method_definition'
require_relative 'rubocop/cop/lint/useless_numeric_operation'
require_relative 'rubocop/cop/lint/useless_rescue'
require_relative 'rubocop/cop/lint/useless_ruby2_keywords'
require_relative 'rubocop/cop/lint/useless_setter_call'
Expand Down
77 changes: 77 additions & 0 deletions lib/rubocop/cop/lint/useless_numeric_operation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# Certain numeric operations have no impact, being:
# Adding or subtracting 0, multiplying or dividing by 1 or raising to the power of 1.
# These are probably leftover from debugging, or are mistakes.
#
# @example
#
# # bad
# x + 0
# x - 0
# x * 1
# x / 1
# x ** 1
#
# # good
# x
#
# # bad
# x += 0
# x -= 0
# x *= 1
# x /= 1
# x **= 1
#
# # good
# x = x
#
class UselessNumericOperation < Base
extend AutoCorrector
MSG = 'Do not apply inconsequential numeric operations to variables.'
RESTRICT_ON_SEND = %i[+ - * / **].freeze

# @!method useless_operation?(node)
def_node_matcher :useless_operation?, '(send (send nil? $_) $_ (int $_))'

# @!method useless_abbreviated_assignment?(node)
def_node_matcher :useless_abbreviated_assignment?, '(op-asgn (lvasgn $_) $_ (int $_))'

def on_send(node)
return unless useless_operation?(node)

variable, operation, number = useless_operation?(node)
return unless useless?(operation, number)

add_offense(node) do |corrector|
corrector.replace(node, variable)
end
end

def on_op_asgn(node)
return unless useless_abbreviated_assignment?(node)

variable, operation, number = useless_abbreviated_assignment?(node)
return unless useless?(operation, number)

add_offense(node) do |corrector|
corrector.replace(node, "#{variable} = #{variable}")
end
end

private

def useless?(operation, number)
if number.zero?
true if %i[+ -].include?(operation)
elsif number == 1
true if %i[* / **].include?(operation)
end
end
end
end
end
end
113 changes: 113 additions & 0 deletions spec/rubocop/cop/lint/useless_numeric_operation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::UselessNumericOperation, :config do
it 'registers an offense when 0 is added to a variable' do
expect_offense(<<~RUBY)
x + 0
^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x
RUBY
end

it 'registers an offense when 0 is subtracted from a variable' do
expect_offense(<<~RUBY)
x - 0
^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x
RUBY
end

it 'registers an offense when a variable is multiplied by 1' do
expect_offense(<<~RUBY)
x * 1
^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x
RUBY
end

it 'registers an offense when a variable is divided by 1' do
expect_offense(<<~RUBY)
x / 1
^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x
RUBY
end

it 'registers an offense when a variable is raised to the power of 1' do
expect_offense(<<~RUBY)
x ** 1
^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x
RUBY
end

it 'registers an offense when a variable is set to itself plus zero via abbreviated assignment' do
expect_offense(<<~RUBY)
x += 0
^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x = x
RUBY
end

it 'registers an offense when a variable is set to itself minus zero via abbreviated assignment' do
expect_offense(<<~RUBY)
x -= 0
^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x = x
RUBY
end

it 'registers an offense when a variable is set to itself times one via abbreviated assignment' do
expect_offense(<<~RUBY)
x *= 1
^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x = x
RUBY
end

it 'registers an offense when a variable is set to itself divided by one via abbreviated assignment' do
expect_offense(<<~RUBY)
x /= 1
^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x = x
RUBY
end

it 'registers an offense when a variable is set to itself raised to the power of one via abbreviated assignment' do
expect_offense(<<~RUBY)
x **= 1
^^^^^^^ Do not apply inconsequential numeric operations to variables.
RUBY

expect_correction(<<~RUBY)
x = x
RUBY
end
end

0 comments on commit b05a51c

Please sign in to comment.