@@ -741,6 +741,83 @@ rescue StandardError
741741end
742742----
743743
744+ [#lintconstantreassignment]
745+ == Lint/ConstantReassignment
746+
747+ |===
748+ | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
749+
750+ | Pending
751+ | Yes
752+ | No
753+ | 1.70
754+ | -
755+ |===
756+
757+ Checks for constant reassignments.
758+
759+ Emulates Ruby's runtime warning "already initialized constant X"
760+ when a constant is reassigned in the same file and namespace using the
761+ `NAME = value` syntax.
762+
763+ The cop cannot catch all offenses, like, for example, when a constant
764+ is reassigned in another file, or when using metaprogramming (`Module#const_set`).
765+
766+ The cop only takes into account constants assigned in a "simple" way: directly
767+ inside class/module definition, or within another constant. Other type of assignments
768+ (e.g., inside a conditional) are disregarded.
769+
770+ The cop also tracks constant removal using `Module#remove_const` with symbol
771+ or string argument.
772+
773+ [#examples-lintconstantreassignment]
774+ === Examples
775+
776+ [source,ruby]
777+ ----
778+ # bad
779+ X = :foo
780+ X = :bar
781+
782+ # bad
783+ class A
784+ X = :foo
785+ X = :bar
786+ end
787+
788+ # bad
789+ module A
790+ X = :foo
791+ X = :bar
792+ end
793+
794+ # good - keep only one assignment
795+ X = :bar
796+
797+ class A
798+ X = :bar
799+ end
800+
801+ module A
802+ X = :bar
803+ end
804+
805+ # good - use OR assignment
806+ X = :foo
807+ X ||= :bar
808+
809+ # good - use conditional assignment
810+ X = :foo
811+ X = :bar unless defined?(X)
812+
813+ # good - remove the assigned constant first
814+ class A
815+ X = :foo
816+ remove_const :X
817+ X = :bar
818+ end
819+ ----
820+
744821[#lintconstantresolution]
745822== Lint/ConstantResolution
746823
@@ -1730,7 +1807,7 @@ end
17301807| -
17311808|===
17321809
1733- Checks for duplicate literal, constant, or variable elements in Set.
1810+ Checks for duplicate literal, constant, or variable elements in Set and SortedSet .
17341811
17351812[#examples-lintduplicatesetelement]
17361813=== Examples
@@ -1754,6 +1831,18 @@ Set.new([:foo, :bar])
17541831
17551832# good
17561833[:foo, :bar].to_set
1834+
1835+ # bad
1836+ SortedSet[:foo, :bar, :foo]
1837+
1838+ # good
1839+ SortedSet[:foo, :bar]
1840+
1841+ # bad
1842+ SortedSet.new([:foo, :bar, :foo])
1843+
1844+ # good
1845+ SortedSet.new([:foo, :bar])
17571846----
17581847
17591848[#linteachwithobjectargument]
@@ -4386,33 +4475,30 @@ non_numbered_parameter_name = :value
43864475|===
43874476
43884477Certain numeric operations have a constant result, usually 0 or 1.
4389- Subtracting a number from itself or multiplying it by 0 will always return 0.
4390- Additionally, a variable modulo 0 or itself will always return 0.
4478+ Multiplying a number by 0 will always return 0.
43914479Dividing a number by itself or raising it to the power of 0 will always return 1.
43924480As such, they can be replaced with that result.
43934481These are probably leftover from debugging, or are mistakes.
43944482Other numeric operations that are similarly leftover from debugging or mistakes
43954483are handled by Lint/UselessNumericOperation.
43964484
4485+ NOTE: This cop doesn't detect offenses for the `-` and `%` operator because it
4486+ can't determine the type of `x`. If `x` is an Array or String, it doesn't perform
4487+ a numeric operation.
4488+
43974489[#examples-lintnumericoperationwithconstantresult]
43984490=== Examples
43994491
44004492[source,ruby]
44014493----
44024494# bad
4403- x - x
44044495x * 0
4405- x % 1
4406- x % x
44074496
44084497# good
440944980
44104499
44114500# bad
4412- x -= x
44134501x *= 0
4414- x %= 1
4415- x %= x
44164502
44174503# good
44184504x = 0
@@ -6172,6 +6258,71 @@ def some_method
61726258end
61736259----
61746260
6261+ [#lintsharedmutabledefault]
6262+ == Lint/SharedMutableDefault
6263+
6264+ |===
6265+ | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
6266+
6267+ | Pending
6268+ | Yes
6269+ | No
6270+ | 1.70
6271+ | -
6272+ |===
6273+
6274+ Checks for Hash creation with a mutable default value.
6275+ Creating a Hash in such a way will share the default value
6276+ across all keys, causing unexpected behavior when modifying it.
6277+
6278+ For example, when the Hash was created with an Array as the argument,
6279+ calling `hash[:foo] << 'bar'` will also change the value of all
6280+ other keys that have not been explicitly assigned to.
6281+
6282+ [#examples-lintsharedmutabledefault]
6283+ === Examples
6284+
6285+ [source,ruby]
6286+ ----
6287+ # bad
6288+ Hash.new([])
6289+ Hash.new({})
6290+ Hash.new(Array.new)
6291+ Hash.new(Hash.new)
6292+
6293+ # okay -- In rare cases that intentionally have this behavior,
6294+ # without disabling the cop, you can set the default explicitly.
6295+ h = Hash.new
6296+ h.default = []
6297+ h[:a] << 1
6298+ h[:b] << 2
6299+ h # => {:a => [1, 2], :b => [1, 2]}
6300+
6301+ # okay -- beware this will discard mutations and only remember assignments
6302+ Hash.new { Array.new }
6303+ Hash.new { Hash.new }
6304+ Hash.new { {} }
6305+ Hash.new { [] }
6306+
6307+ # good - frozen solution will raise an error when mutation attempted
6308+ Hash.new([].freeze)
6309+ Hash.new({}.freeze)
6310+
6311+ # good - using a proc will create a new object for each key
6312+ h = Hash.new
6313+ h.default_proc = ->(h, k) { [] }
6314+ h.default_proc = ->(h, k) { {} }
6315+
6316+ # good - using a block will create a new object for each key
6317+ Hash.new { |h, k| h[k] = [] }
6318+ Hash.new { |h, k| h[k] = {} }
6319+ ----
6320+
6321+ [#references-lintsharedmutabledefault]
6322+ === References
6323+
6324+ * https://rubystyle.guide#no-mutable-defaults
6325+
61756326[#lintstructnewoverride]
61766327== Lint/StructNewOverride
61776328
0 commit comments