diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b5d0661ea4..c74292b2a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * [#7823](https://github.com/rubocop-hq/rubocop/pull/7823): Add `IgnoredMethods` configuration in `Metrics/AbcSize`, `Metrics/CyclomaticComplexity`, and `Metrics/PerceivedComplexity` cops. ([@drenmi][]) * [#7816](https://github.com/rubocop-hq/rubocop/pull/7816): Support Ruby 2.7's numbered parameter for `Style/Lambda`. ([@koic][]) * [#7829](https://github.com/rubocop-hq/rubocop/issues/7829): Fix an error for `Style/OneLineConditional` when one of the branches contains `next` keyword. ([@koic][]) +* [#7384](https://github.com/rubocop-hq/rubocop/pull/7384): Add new `Style/DisableCopsWithinSourceCodeDirective` cop. ([@egze][]) ### Bug fixes @@ -4424,3 +4425,4 @@ [@nikitasakov]: https://github.com/nikitasakov [@dmolesUC]: https://github.com/dmolesUC [@yuritomanek]: https://github.com/yuritomanek +[@egze]: https://github.com/egze diff --git a/config/default.yml b/config/default.yml index e0a4f83a298..3544924dfb8 100644 --- a/config/default.yml +++ b/config/default.yml @@ -2616,6 +2616,12 @@ Style/Dir: Enabled: true VersionAdded: '0.50' +Style/DisableCopsWithinSourceCodeDirective: + Description: >- + Forbids disabling/enabling cops within source code. + Enabled: false + VersionAdded: '0.75' + Style/Documentation: Description: 'Document classes and non-namespace modules.' Enabled: true diff --git a/lib/rubocop.rb b/lib/rubocop.rb index d9f4d8d6706..7809089beec 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -423,6 +423,7 @@ require_relative 'rubocop/cop/style/date_time' require_relative 'rubocop/cop/style/def_with_parentheses' require_relative 'rubocop/cop/style/dir' +require_relative 'rubocop/cop/style/disable_cops_within_source_code_directive' require_relative 'rubocop/cop/style/documentation_method' require_relative 'rubocop/cop/style/documentation' require_relative 'rubocop/cop/style/double_cop_disable_directive' diff --git a/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb b/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb new file mode 100644 index 00000000000..55fb434c0a1 --- /dev/null +++ b/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +# rubocop:disable Lint/RedundantCopDisableDirective + +module RuboCop + module Cop + module Style + # Detects comments to enable/disable RuboCop. + # This is useful if want to make sure that every RuboCop error gets fixed + # and not quickly disabled with a comment. + # + # @example + # # bad + # # rubocop:disable Metrics/AbcSize + # def f + # end + # # rubocop:enable Metrics/AbcSize + # + # # good + # def fixed_method_name_and_no_rubocop_comments + # end + # + class DisableCopsWithinSourceCodeDirective < Cop + # rubocop:enable Lint/RedundantCopDisableDirective + MSG = 'Comment to disable/enable RuboCop.' + + def investigate(processed_source) + processed_source.comments.each do |comment| + next unless rubocop_directive_comment?(comment) + + add_offense(comment) + end + end + + def autocorrect(comment) + lambda do |corrector| + corrector.replace(comment.loc.expression, '') + end + end + + private + + def rubocop_directive_comment?(comment) + comment.text =~ CommentConfig::COMMENT_DIRECTIVE_REGEXP + end + end + end + end +end diff --git a/manual/cops.md b/manual/cops.md index ae10d5af5d6..aafcfc2968e 100644 --- a/manual/cops.md +++ b/manual/cops.md @@ -334,6 +334,7 @@ In the following section you find all available cops: * [Style/DateTime](cops_style.md#styledatetime) * [Style/DefWithParentheses](cops_style.md#styledefwithparentheses) * [Style/Dir](cops_style.md#styledir) +* [Style/DisableCopsWithinSourceCodeDirective](cops_style.md#styledisablecopswithinsourcecodedirective) * [Style/Documentation](cops_style.md#styledocumentation) * [Style/DocumentationMethod](cops_style.md#styledocumentationmethod) * [Style/DoubleCopDisableDirective](cops_style.md#styledoublecopdisabledirective) diff --git a/manual/cops_style.md b/manual/cops_style.md index ea135748be3..856d78d29c8 100644 --- a/manual/cops_style.md +++ b/manual/cops_style.md @@ -1334,6 +1334,30 @@ path = File.dirname(File.realpath(__FILE__)) path = __dir__ ``` +## Style/DisableCopsWithinSourceCodeDirective + +Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged +--- | --- | --- | --- | --- +Disabled | Yes | Yes | 0.75 | - + +Detects comments to enable/disable RuboCop. +This is useful if want to make sure that every RuboCop error gets fixed +and not quickly disabled with a comment. + +### Examples + +```ruby +# bad +# rubocop:disable Metrics/AbcSize +def f +end +# rubocop:enable Metrics/AbcSize + +# good +def fixed_method_name_and_no_rubocop_comments +end +``` + ## Style/Documentation Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged diff --git a/spec/rubocop/cop/style/disable_cops_within_source_code_directive_spec.rb b/spec/rubocop/cop/style/disable_cops_within_source_code_directive_spec.rb new file mode 100644 index 00000000000..19eb00b4326 --- /dev/null +++ b/spec/rubocop/cop/style/disable_cops_within_source_code_directive_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Style::DisableCopsWithinSourceCodeDirective do + subject(:cop) { described_class.new } + + it 'registers an offense for disabled cop within source code' do + expect_offense(<<~RUBY) + def choose_move(who_to_move)# rubocop:disable Metrics/CyclomaticComplexity + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Comment to disable/enable RuboCop. + end + RUBY + expect_correction(<<~RUBY) + def choose_move(who_to_move) + end + RUBY + end + + it 'registers an offense for enabled cop within source code' do + expect_offense(<<~RUBY) + def choose_move(who_to_move)# rubocop:enable Metrics/CyclomaticComplexity + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Comment to disable/enable RuboCop. + end + RUBY + expect_correction(<<~RUBY) + def choose_move(who_to_move) + end + RUBY + end +end