diff --git a/CHANGELOG.md b/CHANGELOG.md index 80ce86b27a6..7de2ab0aed6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * [#7868](https://github.com/rubocop-hq/rubocop/pull/7868): **(Breaking)** Extensive refactoring of internal classes `Team`, `Commissioner`, `Corrector`. `Cop::Cop#corrections` not completely compatible. See Upgrade Notes. ([@marcandre][]) * [#8156](https://github.com/rubocop-hq/rubocop/issues/8156): **(Breaking)** `rubocop -a / --autocorrect` no longer run unsafe corrections; `rubocop -A / --autocorrect-all` run both safe and unsafe corrections. Options `--safe-autocorrect` is deprecated. ([@marcandre][]) * [#8207](https://github.com/rubocop-hq/rubocop/pull/8207): **(Breaking)** Order for gems names now disregards underscores and dashes unless `ConsiderPunctuation` setting is set to `true`. ([@marcandre][]) +* [#8211](https://github.com/rubocop-hq/rubocop/pull/8211): `Style/ClassVars` cop now detects `class_variable_set`. ([@biinari][]) ## 0.86.0 (2020-06-22) diff --git a/docs/modules/ROOT/pages/cops_style.adoc b/docs/modules/ROOT/pages/cops_style.adoc index 6586aa98e32..a5010d2698a 100644 --- a/docs/modules/ROOT/pages/cops_style.adoc +++ b/docs/modules/ROOT/pages/cops_style.adoc @@ -951,6 +951,15 @@ class A @@test = 10 end +class A + def self.test(name, value) + class_variable_set("@@#{name}", value) + end +end + +class A; end +A.class_variable_set(:@@test, 10) + # good class A @test = 10 @@ -961,6 +970,12 @@ class A @@test # you can access class variable without offense end end + +class A + def self.test(name) + class_variable_get("@@#{name}") # you can access without offense + end +end ---- === References diff --git a/lib/rubocop/cop/style/class_vars.rb b/lib/rubocop/cop/style/class_vars.rb index aa5a10f637e..202dcb02c1b 100644 --- a/lib/rubocop/cop/style/class_vars.rb +++ b/lib/rubocop/cop/style/class_vars.rb @@ -19,6 +19,15 @@ module Style # @@test = 10 # end # + # class A + # def self.test(name, value) + # class_variable_set("@@#{name}", value) + # end + # end + # + # class A; end + # A.class_variable_set(:@@test, 10) + # # # good # class A # @test = 10 @@ -30,6 +39,12 @@ module Style # end # end # + # class A + # def self.test(name) + # class_variable_get("@@#{name}") # you can access without offense + # end + # end + # class ClassVars < Cop MSG = 'Replace class var %s with a class ' \ 'instance var.' @@ -38,6 +53,12 @@ def on_cvasgn(node) add_offense(node, location: :name) end + def on_send(node) + return unless node.method?(:class_variable_set) + + add_offense(node.first_argument) + end + def message(node) class_var, = *node format(MSG, class_var: class_var) diff --git a/spec/rubocop/cop/style/class_vars_spec.rb b/spec/rubocop/cop/style/class_vars_spec.rb index 4bcc7222c1a..d339deac320 100644 --- a/spec/rubocop/cop/style/class_vars_spec.rb +++ b/spec/rubocop/cop/style/class_vars_spec.rb @@ -10,6 +10,23 @@ class TestClass; @@test = 10; end RUBY end + it 'registers an offense for class variable set in class' do + expect_offense(<<~RUBY) + class TestClass + class_variable_set(:@@test, 2) + ^^^^^^^ Replace class var @@test with a class instance var. + end + RUBY + end + + it 'registers an offense for class variable set on class receiver' do + expect_offense(<<~RUBY) + class TestClass; end + TestClass.class_variable_set(:@@test, 42) + ^^^^^^^ Replace class var @@test with a class instance var. + RUBY + end + it 'does not register an offense for class variable usage' do expect_no_offenses('@@test.test(20)') end