From 8fafbaf8d1abf8f3b9f2b307f024306623333851 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Thu, 9 Jul 2020 20:39:56 +0300 Subject: [PATCH] Add new `Lint/DuplicateElsifCondition` cop --- CHANGELOG.md | 1 + config/default.yml | 5 ++ docs/modules/ROOT/pages/cops.adoc | 1 + docs/modules/ROOT/pages/cops_lint.adoc | 33 ++++++++++++ lib/rubocop.rb | 1 + .../cop/lint/duplicate_elsif_condition.rb | 39 ++++++++++++++ .../lint/duplicate_elsif_condition_spec.rb | 54 +++++++++++++++++++ 7 files changed, 134 insertions(+) create mode 100644 lib/rubocop/cop/lint/duplicate_elsif_condition.rb create mode 100644 spec/rubocop/cop/lint/duplicate_elsif_condition_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 312143af6f5..32c2cd461c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [#7333](https://github.com/rubocop-hq/rubocop/issues/7333): Add new `Style/RedundantFileExtensionInRequire` cop. ([@fatkodima][]) * [#8242](https://github.com/rubocop-hq/rubocop/pull/8242): Internal profiling available with `bin/rubocop-profile` and rake tasks. ([@marcandre][]) +* [#8293](https://github.com/rubocop-hq/rubocop/pull/8293): Add new `Lint/DuplicateElsifCondition` cop. ([@fatkodima][]) * [#7736](https://github.com/rubocop-hq/rubocop/issues/7736): Add new `Style/CaseLikeIf` cop. ([@fatkodima][]) * [#4286](https://github.com/rubocop-hq/rubocop/issues/4286): Add new `Style/HashAsLastArrayItem` cop. ([@fatkodima][]) * [#8247](https://github.com/rubocop-hq/rubocop/issues/8247): Add new `Style/HashLikeCase` cop. ([@fatkodima][]) diff --git a/config/default.yml b/config/default.yml index 5c51a729ae9..fc7f50ee3b2 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1403,6 +1403,11 @@ Lint/DuplicateCaseCondition: Enabled: true VersionAdded: '0.45' +Lint/DuplicateElsifCondition: + Description: 'Do not repeat conditions used in if `elsif`.' + Enabled: 'pending' + VersionAdded: '0.88' + Lint/DuplicateHashKey: Description: 'Check for duplicate keys in hash literals.' Enabled: true diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index 6e85cba1f79..0d61d80c856 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -193,6 +193,7 @@ In the following section you find all available cops: * xref:cops_lint.adoc#lintdeprecatedopensslconstant[Lint/DeprecatedOpenSSLConstant] * xref:cops_lint.adoc#lintdisjunctiveassignmentinconstructor[Lint/DisjunctiveAssignmentInConstructor] * xref:cops_lint.adoc#lintduplicatecasecondition[Lint/DuplicateCaseCondition] +* xref:cops_lint.adoc#lintduplicateelsifcondition[Lint/DuplicateElsifCondition] * xref:cops_lint.adoc#lintduplicatehashkey[Lint/DuplicateHashKey] * xref:cops_lint.adoc#lintduplicatemethods[Lint/DuplicateMethods] * xref:cops_lint.adoc#linteachwithobjectargument[Lint/EachWithObjectArgument] diff --git a/docs/modules/ROOT/pages/cops_lint.adoc b/docs/modules/ROOT/pages/cops_lint.adoc index d97306b859d..7fa7577c45f 100644 --- a/docs/modules/ROOT/pages/cops_lint.adoc +++ b/docs/modules/ROOT/pages/cops_lint.adoc @@ -609,6 +609,39 @@ when 'second' end ---- +== Lint/DuplicateElsifCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.88 +| - +|=== + +This cop checks that there are no repeated conditions used in if 'elsif'. + +=== Examples + +[source,ruby] +---- +# bad +if x == 1 + do_something +elsif x == 1 + do_something_else +end + +# good +if x == 1 + do_something +elsif x == 2 + do_something_else +end +---- + == Lint/DuplicateHashKey |=== diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 5549611abb9..1b617cac079 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -251,6 +251,7 @@ require_relative 'rubocop/cop/lint/deprecated_open_ssl_constant' require_relative 'rubocop/cop/lint/disjunctive_assignment_in_constructor' require_relative 'rubocop/cop/lint/duplicate_case_condition' +require_relative 'rubocop/cop/lint/duplicate_elsif_condition' require_relative 'rubocop/cop/lint/duplicate_hash_key' require_relative 'rubocop/cop/lint/duplicate_methods' require_relative 'rubocop/cop/lint/each_with_object_argument' diff --git a/lib/rubocop/cop/lint/duplicate_elsif_condition.rb b/lib/rubocop/cop/lint/duplicate_elsif_condition.rb new file mode 100644 index 00000000000..0dfb9ad0f8b --- /dev/null +++ b/lib/rubocop/cop/lint/duplicate_elsif_condition.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Lint + # This cop checks that there are no repeated conditions used in if 'elsif'. + # + # @example + # # bad + # if x == 1 + # do_something + # elsif x == 1 + # do_something_else + # end + # + # # good + # if x == 1 + # do_something + # elsif x == 2 + # do_something_else + # end + # + class DuplicateElsifCondition < Base + MSG = 'Duplicate `elsif` condition detected.' + + def on_if(node) + previous = [] + while node.if? || node.elsif? + condition = node.condition + add_offense(condition) if previous.include?(condition) + previous << condition + node = node.else_branch + break unless node&.if_type? + end + end + end + end + end +end diff --git a/spec/rubocop/cop/lint/duplicate_elsif_condition_spec.rb b/spec/rubocop/cop/lint/duplicate_elsif_condition_spec.rb new file mode 100644 index 00000000000..9bc424c96b8 --- /dev/null +++ b/spec/rubocop/cop/lint/duplicate_elsif_condition_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Lint::DuplicateElsifCondition do + subject(:cop) { described_class.new } + + it 'registers an offense for repeated elsif conditions' do + expect_offense(<<~RUBY) + if x == 1 + elsif x == 2 + elsif x == 1 + ^^^^^^ Duplicate `elsif` condition detected. + end + RUBY + end + + it 'registers an offense for subsequent repeated elsif conditions' do + expect_offense(<<~RUBY) + if x == 1 + elsif x == 2 + elsif x == 2 + ^^^^^^ Duplicate `elsif` condition detected. + end + RUBY + end + + it 'registers multiple offenses for multiple repeated elsif conditions' do + expect_offense(<<~RUBY) + if x == 1 + elsif x == 2 + elsif x == 1 + ^^^^^^ Duplicate `elsif` condition detected. + elsif x == 2 + ^^^^^^ Duplicate `elsif` condition detected. + end + RUBY + end + + it 'does not register an offense for non-repeated elsif conditions' do + expect_no_offenses(<<~RUBY) + if x == 1 + elsif x == 2 + else + end + RUBY + end + + it 'does not register an offense for partially repeated elsif conditions' do + expect_no_offenses(<<~RUBY) + if x == 1 + elsif x == 1 && x == 2 + end + RUBY + end +end