diff --git a/changelog/new_add_new_lintunsafeglobalvariables_cop.md b/changelog/new_add_new_lintunsafeglobalvariables_cop.md new file mode 100644 index 00000000000..0653b41d04d --- /dev/null +++ b/changelog/new_add_new_lintunsafeglobalvariables_cop.md @@ -0,0 +1 @@ +* [#10204](https://github.com/rubocop/rubocop/issues/10204): Add new `Lint/UnsafeGlobalVariables` cop. ([@dmarcoux][]) diff --git a/config/default.yml b/config/default.yml index 572710c6aea..03c6c3fb527 100644 --- a/config/default.yml +++ b/config/default.yml @@ -2247,6 +2247,11 @@ Lint/UnreachableLoop: # eg. `exactly(2).times` - !ruby/regexp /(exactly|at_least|at_most)\(\d+\)\.times/ +Lint/UnsafeGlobalVariables: + Description: 'Do not use unsafe global variables.' + Enabled: pending + VersionAdded: '<>' + Lint/UnusedBlockArgument: Description: 'Checks for unused block arguments.' StyleGuide: '#underscore-unused-vars' diff --git a/lib/rubocop.rb b/lib/rubocop.rb index c6930cfc346..d3c2539632c 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -374,6 +374,7 @@ require_relative 'rubocop/cop/lint/unmodified_reduce_accumulator' require_relative 'rubocop/cop/lint/unreachable_code' require_relative 'rubocop/cop/lint/unreachable_loop' +require_relative 'rubocop/cop/lint/unsafe_global_variables' require_relative 'rubocop/cop/lint/unused_block_argument' require_relative 'rubocop/cop/lint/unused_method_argument' require_relative 'rubocop/cop/lint/uri_escape_unescape' diff --git a/lib/rubocop/cop/lint/unsafe_global_variables.rb b/lib/rubocop/cop/lint/unsafe_global_variables.rb new file mode 100644 index 00000000000..4b6ddc45cdf --- /dev/null +++ b/lib/rubocop/cop/lint/unsafe_global_variables.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Lint + # This cop looks for uses of unsafe global variables. + # + # @example + # + # # bad + # $! + # + # # bad + # $ERROR_INFO + # + # # bad + # $@ + # + # # bad + # $ERROR_POSITION + # + class UnsafeGlobalVariables < Base + MSG = 'Do not use unsafe global variable `%s`.' + + # built-in global variables and their English aliases + # https://www.zenspider.com/ruby/quickref.html + UNSAFE_GLOBAL_VARIABLES = %i[$! $ERROR_INFO $@ $ERROR_POSITION].freeze + + def on_gvar(node) + global_variable, = *node + + return unless UNSAFE_GLOBAL_VARIABLES.include?(global_variable) + + add_offense(node.loc.name, message: format(MSG, global_variable: global_variable)) + end + end + end + end +end diff --git a/lib/rubocop/result_cache.rb b/lib/rubocop/result_cache.rb index 3a686e58bfe..e999f76fbc7 100644 --- a/lib/rubocop/result_cache.rb +++ b/lib/rubocop/result_cache.rb @@ -52,7 +52,9 @@ def remove_oldest_files(files, dirs, cache_root, verbose) rescue Errno::ENOENT # This can happen if parallel RuboCop invocations try to remove the # same files. No problem. + # rubocop:disable Lint/UnsafeGlobalVariables puts $ERROR_INFO if verbose + # rubocop:enable Lint/UnsafeGlobalVariables end def remove_files(files, dirs, remove_count) diff --git a/spec/rubocop/cop/lint/unsafe_global_variables_spec.rb b/spec/rubocop/cop/lint/unsafe_global_variables_spec.rb new file mode 100644 index 00000000000..bf5dcc69c18 --- /dev/null +++ b/spec/rubocop/cop/lint/unsafe_global_variables_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Lint::UnsafeGlobalVariables, :config do + it 'registers an offense when using `$!`' do + expect_offense(<<~RUBY) + $! + ^^ Do not use unsafe global variable `$!`. + RUBY + end + + it 'registers an offense when using `$ERROR_INFO`' do + expect_offense(<<~RUBY) + $ERROR_INFO + ^^^^^^^^^^^ Do not use unsafe global variable `$ERROR_INFO`. + RUBY + end + + it 'registers an offense when using `$@`' do + expect_offense(<<~RUBY) + $@ + ^^ Do not use unsafe global variable `$@`. + RUBY + end + + it 'registers an offense when using `$ERROR_POSITION`' do + expect_offense(<<~RUBY) + $ERROR_POSITION + ^^^^^^^^^^^^^^^ Do not use unsafe global variable `$ERROR_POSITION`. + RUBY + end + + it 'does not register an offense when using a safe global variable' do + expect_no_offenses(<<~RUBY) + $0 + RUBY + end +end