diff --git a/changelog/new_add_new_lint_require_relative_self_path_cop.md b/changelog/new_add_new_lint_require_relative_self_path_cop.md new file mode 100644 index 00000000000..3d98e75948b --- /dev/null +++ b/changelog/new_add_new_lint_require_relative_self_path_cop.md @@ -0,0 +1 @@ +* [#10084](https://github.com/rubocop/rubocop/issues/10084): Add new `Lint/RequireRelativeSelfPath` cop. ([@koic][]) diff --git a/config/default.yml b/config/default.yml index 5f7b357ce2a..802a74b7888 100644 --- a/config/default.yml +++ b/config/default.yml @@ -2045,6 +2045,11 @@ Lint/RequireParentheses: Enabled: true VersionAdded: '0.18' +Lint/RequireRelativeSelfPath: + Description: 'Checks for uses a file requiring itself with `require_relative`.' + Enabled: pending + VersionAdded: '<>' + Lint/RescueException: Description: 'Avoid rescuing the Exception class.' StyleGuide: '#no-blind-rescues' diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 250643fc466..9feeae3bec2 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -346,6 +346,7 @@ require_relative 'rubocop/cop/lint/redundant_with_object' require_relative 'rubocop/cop/lint/regexp_as_condition' require_relative 'rubocop/cop/lint/require_parentheses' +require_relative 'rubocop/cop/lint/require_relative_self_path' require_relative 'rubocop/cop/lint/rescue_exception' require_relative 'rubocop/cop/lint/rescue_type' require_relative 'rubocop/cop/lint/return_in_void_context' diff --git a/lib/rubocop/cop/lint/require_relative_self_path.rb b/lib/rubocop/cop/lint/require_relative_self_path.rb new file mode 100644 index 00000000000..9a135ecb3a7 --- /dev/null +++ b/lib/rubocop/cop/lint/require_relative_self_path.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Lint + # Checks for uses a file requiring itself with `require_relative`. + # + # @example + # + # # bad + # + # # foo.rb + # require_relative 'foo' + # require_relative 'bar' + # + # # good + # + # # foo.rb + # require_relative 'bar' + # + class RequireRelativeSelfPath < Base + include RangeHelp + extend AutoCorrector + + MSG = 'Remove the `require_relative` that requires itself.' + RESTRICT_ON_SEND = %i[require_relative].freeze + + def on_send(node) + return unless (required_feature = node.first_argument) + return unless remove_ext(processed_source.file_path) == remove_ext(required_feature.value) + + add_offense(node) do |corrector| + corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true)) + end + end + + private + + def remove_ext(file_path) + File.basename(file_path, File.extname(file_path)) + end + end + end + end +end diff --git a/spec/rubocop/cop/lint/require_relative_self_path_spec.rb b/spec/rubocop/cop/lint/require_relative_self_path_spec.rb new file mode 100644 index 00000000000..5eb8225fe7e --- /dev/null +++ b/spec/rubocop/cop/lint/require_relative_self_path_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Lint::RequireRelativeSelfPath, :config do + it 'registers an offense when using `require_relative` with self file path argument' do + expect_offense(<<~RUBY, 'foo.rb') + require_relative 'foo' + ^^^^^^^^^^^^^^^^^^^^^^ Remove the `require_relative` that requires itself. + require_relative 'bar' + RUBY + + expect_correction(<<~RUBY) + require_relative 'bar' + RUBY + end + + it 'registers an offense when using `require_relative` with self file path argument (with ext)' do + expect_offense(<<~RUBY, 'foo.rb') + require_relative 'foo.rb' + ^^^^^^^^^^^^^^^^^^^^^^^^^ Remove the `require_relative` that requires itself. + require_relative 'bar' + RUBY + + expect_correction(<<~RUBY) + require_relative 'bar' + RUBY + end + + it 'does not register an offense when using `require_relative` without self file path argument' do + expect_no_offenses(<<~RUBY, 'foo.rb') + require_relative 'bar' + RUBY + end + + it 'does not register an offense when using `require_relative` without argument' do + expect_no_offenses(<<~RUBY, 'foo.rb') + require_relative + RUBY + end +end