From f24497f2854a79e9c9a73bcb7b12dca088e3e4bc Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Thu, 30 Jul 2020 11:25:58 -0400 Subject: [PATCH 1/3] Tweak Changelog [doc] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2ca8d77ff..72f6bae51e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ * [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): `Style/MethodMissingSuper` cop is removed in favor of new `Lint/MissingSuper` cop. ([@fatkodima][]) * [#8350](https://github.com/rubocop-hq/rubocop/pull/8350): Set default max line length to 120 for `Style/MultilineMethodSignature`. ([@koic][]) * [#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][]) -* [#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 16.5. ([@marcandre][]) +* [#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][]) * [#8276](https://github.com/rubocop-hq/rubocop/issues/8276): Cop `Metrics/CyclomaticComplexity` not longer counts `&.` when repeated on the same variable. ([@marcandre][]) ## 0.88.0 (2020-07-13) From bb25e4b29d583cbceb503d79abed5629b4ca589e Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 23 Jun 2020 15:56:57 -0400 Subject: [PATCH 2/3] Fix Metrics/PerceivedComplexity for case with else --- lib/rubocop/cop/metrics/perceived_complexity.rb | 5 +++-- .../cop/metrics/perceived_complexity_spec.rb | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/cop/metrics/perceived_complexity.rb b/lib/rubocop/cop/metrics/perceived_complexity.rb index 93bb75ea5ff..41cb33c601c 100644 --- a/lib/rubocop/cop/metrics/perceived_complexity.rb +++ b/lib/rubocop/cop/metrics/perceived_complexity.rb @@ -42,12 +42,13 @@ def complexity_score_for(node) # If cond is nil, that means each when has an expression that # evaluates to true or false. It's just an alternative to # if/elsif/elsif... so the when nodes count. + nb_branches = node.when_branches.length + (node.else_branch ? 1 : 0) if node.condition.nil? - node.when_branches.length + nb_branches else # Otherwise, the case node gets 0.8 complexity points and each # when gets 0.2. - (0.8 + 0.2 * node.when_branches.length).round + (0.8 + 0.2 * nb_branches).round end when :if node.else? && !node.elsif? ? 2 : 1 diff --git a/spec/rubocop/cop/metrics/perceived_complexity_spec.rb b/spec/rubocop/cop/metrics/perceived_complexity_spec.rb index 8eb470188a5..e53f09c1f92 100644 --- a/spec/rubocop/cop/metrics/perceived_complexity_spec.rb +++ b/spec/rubocop/cop/metrics/perceived_complexity_spec.rb @@ -156,6 +156,22 @@ def method_name RUBY end + it 'counts else in a case with no argument' do + expect_offense(<<~RUBY) + def method_name + ^^^^^^^^^^^^^^^ Perceived complexity for method_name is too high. [4/1] + case + when value == 1 + call_foo + when value == 2 + call_bar + else + call_baz + end + end + RUBY + end + it 'registers an offense for &&' do expect_offense(<<~RUBY) def method_name From e7ec360059f01ab702edae015176e8092a1de6f8 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 23 Jun 2020 16:32:27 -0400 Subject: [PATCH 3/3] Have Metrics/PerceivedComplexity inherit from CyclomaticComplexity. Bump default from 7 to 8. --- CHANGELOG.md | 1 + config/default.yml | 2 +- docs/modules/ROOT/pages/cops_metrics.adoc | 2 +- .../lint/redundant_cop_disable_directive.rb | 4 ++-- .../cop/metrics/perceived_complexity.rb | 10 ++++----- .../style/identical_conditional_branches.rb | 2 +- lib/rubocop/cop/variable_force/variable.rb | 4 ++-- .../cop/metrics/perceived_complexity_spec.rb | 21 +++++++++++++++++++ 8 files changed, 33 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f6bae51e6..2bc554fc211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * [#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][]) * [#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][]) * [#8276](https://github.com/rubocop-hq/rubocop/issues/8276): Cop `Metrics/CyclomaticComplexity` not longer counts `&.` when repeated on the same variable. ([@marcandre][]) +* [#8204](https://github.com/rubocop-hq/rubocop/pull/8204): **(Breaking)** Cop `Metrics/PerceivedComplexity` now counts `else` in `case` statements, `&.`, `||=`, `&&=` and blocks known to iterate. Default bumped from 7 to 8. Consider using `rubocop -a --disable-uncorrectable` to ease transition. ([@marcandre][]) ## 0.88.0 (2020-07-13) diff --git a/config/default.yml b/config/default.yml index 3ecbb89c509..db68e590113 100644 --- a/config/default.yml +++ b/config/default.yml @@ -2015,7 +2015,7 @@ Metrics/PerceivedComplexity: VersionAdded: '0.25' VersionChanged: '0.81' IgnoredMethods: [] - Max: 7 + Max: 8 ################## Migration ############################# diff --git a/docs/modules/ROOT/pages/cops_metrics.adoc b/docs/modules/ROOT/pages/cops_metrics.adoc index 35cb579a4db..be15e9604e3 100644 --- a/docs/modules/ROOT/pages/cops_metrics.adoc +++ b/docs/modules/ROOT/pages/cops_metrics.adoc @@ -472,6 +472,6 @@ end # 7 complexity points | Array | Max -| `7` +| `8` | Integer |=== diff --git a/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb b/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb index 872da67c3c5..73f1df74e01 100644 --- a/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +++ b/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb @@ -135,7 +135,7 @@ def each_already_disabled(line_ranges, disabled_ranges, comments) end end - # rubocop:todo Metrics/CyclomaticComplexity + # rubocop:todo Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def find_redundant(comment, offenses, cop, line_range, next_line_range) if all_disabled?(comment) # If there's a disable all comment followed by a comment @@ -153,7 +153,7 @@ def find_redundant(comment, offenses, cop, line_range, next_line_range) cop if cop_offenses.none? { |o| line_range.cover?(o.line) } end end - # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def all_disabled?(comment) /rubocop\s*:\s*(?:disable|todo)\s+all\b/.match?(comment.text) diff --git a/lib/rubocop/cop/metrics/perceived_complexity.rb b/lib/rubocop/cop/metrics/perceived_complexity.rb index 41cb33c601c..dfbb888d4a3 100644 --- a/lib/rubocop/cop/metrics/perceived_complexity.rb +++ b/lib/rubocop/cop/metrics/perceived_complexity.rb @@ -26,13 +26,11 @@ module Metrics # do_something until a && b # 2 # end # === # end # 7 complexity points - class PerceivedComplexity < Base - include MethodComplexity - + class PerceivedComplexity < CyclomaticComplexity MSG = 'Perceived complexity for %s is too high. ' \ '[%d/%d]' - COUNTED_NODES = %i[if case while until - for rescue and or].freeze + + COUNTED_NODES = (CyclomaticComplexity::COUNTED_NODES - [:when] + [:case]).freeze private @@ -53,7 +51,7 @@ def complexity_score_for(node) when :if node.else? && !node.elsif? ? 2 : 1 else - 1 + super end end end diff --git a/lib/rubocop/cop/style/identical_conditional_branches.rb b/lib/rubocop/cop/style/identical_conditional_branches.rb index 5edee294f57..5563a3261e2 100644 --- a/lib/rubocop/cop/style/identical_conditional_branches.rb +++ b/lib/rubocop/cop/style/identical_conditional_branches.rb @@ -81,7 +81,7 @@ def on_case(node) private - def check_branches(branches) # rubocop:todo Metrics/CyclomaticComplexity + def check_branches(branches) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity # return if any branch is empty. An empty branch can be an `if` # without an `else` or a branch that contains only comments. return if branches.any?(&:nil?) diff --git a/lib/rubocop/cop/variable_force/variable.rb b/lib/rubocop/cop/variable_force/variable.rb index 3855726f0bd..3295efd33ed 100644 --- a/lib/rubocop/cop/variable_force/variable.rb +++ b/lib/rubocop/cop/variable_force/variable.rb @@ -38,7 +38,7 @@ def referenced? !@references.empty? end - # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def reference!(node) reference = Reference.new(node, @scope) @references << reference @@ -63,7 +63,7 @@ def reference!(node) end end end - # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def in_modifier_if?(assignment) parent = assignment.node.parent diff --git a/spec/rubocop/cop/metrics/perceived_complexity_spec.rb b/spec/rubocop/cop/metrics/perceived_complexity_spec.rb index e53f09c1f92..8a8dbd60b15 100644 --- a/spec/rubocop/cop/metrics/perceived_complexity_spec.rb +++ b/spec/rubocop/cop/metrics/perceived_complexity_spec.rb @@ -242,6 +242,27 @@ def method_name_2 end RUBY end + + it 'does not count unknown block calls' do + expect_no_offenses(<<~RUBY) + def method_name + bar.baz(:qux) do |x| + raise x + end + end + RUBY + end + + it 'counts known iterating block' do + expect_offense(<<~RUBY) + def method_name + ^^^^^^^^^^^^^^^ Perceived complexity for method_name is too high. [2/1] + ary.each do |x| + foo(x) + end + end + RUBY + end end context 'when method is in list of ignored methods' do