Skip to content

Commit d94c4a4

Browse files
fatkodimabbatsov
authored andcommitted
Add new Lint/BinaryOperatorWithIdenticalOperands cop
1 parent bf47e35 commit d94c4a4

File tree

11 files changed

+139
-91
lines changed

11 files changed

+139
-91
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* [#8322](https://github.com/rubocop-hq/rubocop/pull/8322): Support autocorrect for `Style/CaseEquality` cop. ([@fatkodima][])
88
* [#8291](https://github.com/rubocop-hq/rubocop/pull/8291): Add new `Lint/SelfAssignment` cop. ([@fatkodima][])
99
* [#8389](https://github.com/rubocop-hq/rubocop/pull/8389): Add new `Lint/DuplicateRescueException` cop. ([@fatkodima][])
10+
* [#8433](https://github.com/rubocop-hq/rubocop/pull/8433): Add new `Lint/BinaryOperatorWithIdenticalOperands` cop. ([@fatkodima][])
1011
* [#8430](https://github.com/rubocop-hq/rubocop/pull/8430): Add new `Lint/UnreachableLoop` cop. ([@fatkodima][])
1112
* [#8412](https://github.com/rubocop-hq/rubocop/pull/8412): Add new `Style/OptionalBooleanParameter` cop. ([@fatkodima][])
1213
* [#8432](https://github.com/rubocop-hq/rubocop/pull/8432): Add new `Lint/FloatComparison` cop. ([@fatkodima][])
@@ -45,6 +46,7 @@
4546
### Changes
4647

4748
* [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): `Style/MethodMissingSuper` cop is removed in favor of new `Lint/MissingSuper` cop. ([@fatkodima][])
49+
* [#8433](https://github.com/rubocop-hq/rubocop/pull/8433): `Lint/UselessComparison` cop is removed in favor of new `Lint/BinaryOperatorWithIdenticalOperands` cop. ([@fatkodima][])
4850
* [#8350](https://github.com/rubocop-hq/rubocop/pull/8350): Set default max line length to 120 for `Style/MultilineMethodSignature`. ([@koic][])
4951
* [#8338](https://github.com/rubocop-hq/rubocop/pull/8338): **potentially breaking**. Config#for_department now returns only the config specified for that department; the 'Enabled' attribute is no longer calculated. ([@marcandre][])
5052
* [#8037](https://github.com/rubocop-hq/rubocop/pull/8037): **(Breaking)** Cop `Metrics/AbcSize` now counts ||=, &&=, multiple assignments, for, yield, iterating blocks. `&.` now count as conditions too (unless repeated on the same variable). Default bumped from 15 to 17. Consider using `rubocop -a --disable-uncorrectable` to ease transition. ([@marcandre][])

config/default.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,12 @@ Lint/BigDecimalNew:
13551355
Enabled: true
13561356
VersionAdded: '0.53'
13571357

1358+
Lint/BinaryOperatorWithIdenticalOperands:
1359+
Description: 'This cop checks for places where binary operator has identical operands.'
1360+
Enabled: pending
1361+
Safe: false
1362+
VersionAdded: '0.89'
1363+
13581364
Lint/BooleanSymbol:
13591365
Description: 'Check for `:true` and `:false` symbols.'
13601366
Enabled: true
@@ -1906,11 +1912,6 @@ Lint/UselessAssignment:
19061912
Enabled: true
19071913
VersionAdded: '0.11'
19081914

1909-
Lint/UselessComparison:
1910-
Description: 'Checks for comparison of something with itself.'
1911-
Enabled: true
1912-
VersionAdded: '0.11'
1913-
19141915
Lint/UselessElseWithoutRescue:
19151916
Description: 'Checks for useless `else` in `begin..end` without `rescue`.'
19161917
Enabled: true

docs/modules/ROOT/pages/cops.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ In the following section you find all available cops:
185185
* xref:cops_lint.adoc#lintambiguousregexpliteral[Lint/AmbiguousRegexpLiteral]
186186
* xref:cops_lint.adoc#lintassignmentincondition[Lint/AssignmentInCondition]
187187
* xref:cops_lint.adoc#lintbigdecimalnew[Lint/BigDecimalNew]
188+
* xref:cops_lint.adoc#lintbinaryoperatorwithidenticaloperands[Lint/BinaryOperatorWithIdenticalOperands]
188189
* xref:cops_lint.adoc#lintbooleansymbol[Lint/BooleanSymbol]
189190
* xref:cops_lint.adoc#lintcircularargumentreference[Lint/CircularArgumentReference]
190191
* xref:cops_lint.adoc#lintconstantresolution[Lint/ConstantResolution]
@@ -269,7 +270,6 @@ In the following section you find all available cops:
269270
* xref:cops_lint.adoc#linturiregexp[Lint/UriRegexp]
270271
* xref:cops_lint.adoc#lintuselessaccessmodifier[Lint/UselessAccessModifier]
271272
* xref:cops_lint.adoc#lintuselessassignment[Lint/UselessAssignment]
272-
* xref:cops_lint.adoc#lintuselesscomparison[Lint/UselessComparison]
273273
* xref:cops_lint.adoc#lintuselesselsewithoutrescue[Lint/UselessElseWithoutRescue]
274274
* xref:cops_lint.adoc#lintuselesssettercall[Lint/UselessSetterCall]
275275
* xref:cops_lint.adoc#lintvoid[Lint/Void]

docs/modules/ROOT/pages/cops_lint.adoc

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,46 @@ BigDecimal.new(123.456, 3)
211211
BigDecimal(123.456, 3)
212212
----
213213

214+
== Lint/BinaryOperatorWithIdenticalOperands
215+
216+
|===
217+
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
218+
219+
| Pending
220+
| No
221+
| No
222+
| 0.89
223+
| -
224+
|===
225+
226+
This cop checks for places where binary operator has identical operands.
227+
228+
It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`;
229+
comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`;
230+
bitwise operators: `|`, `^`, `&`, `<<`, `>>`;
231+
boolean operators: `&&`, `||`
232+
and "spaceship" operator - `<=>`.
233+
234+
This cop is marked as unsafe as it does not consider side effects when calling methods
235+
and thus can generate false positives:
236+
if wr.take_char == '\0' && wr.take_char == '\0'
237+
238+
=== Examples
239+
240+
[source,ruby]
241+
----
242+
# bad
243+
x.top >= x.top
244+
245+
if a.x != 0 && a.x != 0
246+
do_something
247+
end
248+
249+
def childs?
250+
left_child || left_child
251+
end
252+
----
253+
214254
== Lint/BooleanSymbol
215255

216256
|===
@@ -4282,29 +4322,6 @@ end
42824322

42834323
* https://rubystyle.guide#underscore-unused-vars
42844324

4285-
== Lint/UselessComparison
4286-
4287-
|===
4288-
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
4289-
4290-
| Enabled
4291-
| Yes
4292-
| No
4293-
| 0.11
4294-
| -
4295-
|===
4296-
4297-
This cop checks for comparison of something with itself.
4298-
4299-
=== Examples
4300-
4301-
[source,ruby]
4302-
----
4303-
# bad
4304-
4305-
x.top >= x.top
4306-
----
4307-
43084325
== Lint/UselessElseWithoutRescue
43094326

43104327
|===

lib/rubocop.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@
242242
require_relative 'rubocop/cop/lint/ambiguous_regexp_literal'
243243
require_relative 'rubocop/cop/lint/assignment_in_condition'
244244
require_relative 'rubocop/cop/lint/big_decimal_new'
245+
require_relative 'rubocop/cop/lint/binary_operator_with_identical_operands'
245246
require_relative 'rubocop/cop/lint/boolean_symbol'
246247
require_relative 'rubocop/cop/lint/circular_argument_reference'
247248
require_relative 'rubocop/cop/lint/constant_resolution'
@@ -326,7 +327,6 @@
326327
require_relative 'rubocop/cop/lint/uri_regexp'
327328
require_relative 'rubocop/cop/lint/useless_access_modifier'
328329
require_relative 'rubocop/cop/lint/useless_assignment'
329-
require_relative 'rubocop/cop/lint/useless_comparison'
330330
require_relative 'rubocop/cop/lint/useless_else_without_rescue'
331331
require_relative 'rubocop/cop/lint/useless_setter_call'
332332
require_relative 'rubocop/cop/lint/void'

lib/rubocop/config_obsoletion.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ class ConfigObsoletion
8686
'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
8787
'`Layout/SpaceBeforeFirstArg` instead',
8888
'Style/MethodMissingSuper' => 'it has been superseded by `Lint/MissingSuper`. Please use ' \
89-
'`Lint/MissingSuper` instead'
89+
'`Lint/MissingSuper` instead',
90+
'Lint/UselessComparison' => 'it has been superseded by '\
91+
'`Lint/BinaryOperatorWithIdenticalOperands`. Please use '\
92+
'`Lint/BinaryOperatorWithIdenticalOperands` instead'
9093
}.map do |cop_name, reason|
9194
[cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
9295
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Lint
6+
# This cop checks for places where binary operator has identical operands.
7+
#
8+
# It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`;
9+
# comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`;
10+
# bitwise operators: `|`, `^`, `&`, `<<`, `>>`;
11+
# boolean operators: `&&`, `||`
12+
# and "spaceship" operator - `<=>`.
13+
#
14+
# This cop is marked as unsafe as it does not consider side effects when calling methods
15+
# and thus can generate false positives:
16+
# if wr.take_char == '\0' && wr.take_char == '\0'
17+
#
18+
# @example
19+
# # bad
20+
# x.top >= x.top
21+
#
22+
# if a.x != 0 && a.x != 0
23+
# do_something
24+
# end
25+
#
26+
# def childs?
27+
# left_child || left_child
28+
# end
29+
#
30+
class BinaryOperatorWithIdenticalOperands < Base
31+
MSG = 'Binary operator `%<op>s` has identical operands.'
32+
33+
def on_send(node)
34+
return unless node.binary_operation?
35+
36+
lhs, operation, rhs = *node
37+
return if node.arithmetic_operation? && lhs.basic_literal? && rhs.basic_literal?
38+
39+
add_offense(node, message: format(MSG, op: operation)) if lhs == rhs
40+
end
41+
42+
def on_and(node)
43+
add_offense(node, message: format(MSG, op: node.operator)) if node.lhs == node.rhs
44+
end
45+
alias on_or on_and
46+
end
47+
end
48+
end
49+
end

lib/rubocop/cop/lint/useless_comparison.rb

Lines changed: 0 additions & 28 deletions
This file was deleted.

spec/rubocop/config_obsoletion_spec.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
'Layout/SpaceBeforeModifierKeyword' => { 'Enabled': true },
7171
'Lint/InvalidCharacterLiteral' => { 'Enabled': true },
7272
'Style/MethodMissingSuper' => { 'Enabled': true },
73+
'Lint/UselessComparison' => { 'Enabled': true },
7374
'Lint/RescueWithoutErrorClass' => { 'Enabled': true },
7475
'Lint/SpaceBeforeFirstArg' => { 'Enabled': true },
7576
'Style/SpaceAfterControlKeyword' => { 'Enabled': true },
@@ -199,6 +200,8 @@
199200
(obsolete configuration found in example/.rubocop.yml, please update it)
200201
The `Style/MethodMissingSuper` cop has been removed since it has been superseded by `Lint/MissingSuper`. Please use `Lint/MissingSuper` instead.
201202
(obsolete configuration found in example/.rubocop.yml, please update it)
203+
The `Lint/UselessComparison` cop has been removed since it has been superseded by `Lint/BinaryOperatorWithIdenticalOperands`. Please use `Lint/BinaryOperatorWithIdenticalOperands` instead.
204+
(obsolete configuration found in example/.rubocop.yml, please update it)
202205
The `Style/MethodMissing` cop has been split into `Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.
203206
(obsolete configuration found in example/.rubocop.yml, please update it)
204207
OUTPUT
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Lint::BinaryOperatorWithIdenticalOperands do
4+
subject(:cop) { described_class.new }
5+
6+
it 'registers an offense when binary operator has identical nodes' do
7+
offenses = inspect_source(<<~RUBY)
8+
x == x
9+
y = x && x
10+
y = a.x + a.x
11+
a.x(arg) > a.x(arg)
12+
a.(x) > a.(x)
13+
RUBY
14+
15+
expect(offenses.size).to eq(5)
16+
end
17+
18+
it 'does not register an offense when using binary operator with different operands' do
19+
expect_no_offenses(<<~RUBY)
20+
x == y
21+
y = x && z
22+
y = a.x + b.x
23+
a.x(arg) > b.x(arg)
24+
a.(x) > b.(x)
25+
RUBY
26+
end
27+
28+
it 'does not register an offense when using arithmetic operator with numerics' do
29+
expect_no_offenses(<<~RUBY)
30+
x = 2 + 2
31+
RUBY
32+
end
33+
end

spec/rubocop/cop/lint/useless_comparison_spec.rb

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)