class RuboCop::Cop::Style::MutableConstant


CONST = [1, 2, 3]
# shareable_constant_value: literal
# good
CONST = [1, 2, 3]
# bad
# Magic comment - shareable_constant_value: literal
@example
end.freeze
end
puts 1
def foo
CONST = Struct.new do
# good
CONST = Something.new.freeze
# good
end
end
puts 1
def foo
CONST = Struct.new do
# bad
CONST = Something.new
# bad
@example EnforcedStyle: strict
CONST = Something.new
# good
TESTING
This is a heredoc
CONST = <<~TESTING.freeze
# good
CONST = [1, 2, 3].freeze
# good
CONST = [1, 2, 3]
# bad
@example EnforcedStyle: literals (default)
and will need to be manually refactored.
are made frozen will change from being accepted to raising ‘FrozenError`,
This cop’s autocorrection is unsafe since any mutations on objects that
@safety
the ‘shareable_constant_value` directive is used.
NOTE: From Ruby 3.0, this cop allows explicit freezing of constants when
freezing for such strings.
`# frozen-string-literal: true` is used, so this cop enforces explicit
NOTE: From Ruby 3.0, interpolated strings are not frozen when
NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
raised by this cop. It enforces frozen state.
acceptable value other than none, it will suppress the offenses
’shareable_constant_value’. When this magic comment is set to any
From Ruby 3.0, this cop honours the magic comment
frozen object.
positives. Luckily, there is no harm in freezing an already
frozen objects so there is a decent chance of getting some false
updated with an exhaustive list of all methods that will produce
Strict mode is considered an experimental feature. It has not been
just literals.
Strict mode can be used to freeze all constants, rather than
mutable literal (e.g. array or hash).
Checks whether some constant value isn’t a

def autocorrect(corrector, node)

def autocorrect(corrector, node)
  expr = node.source_range
  splat_value = splat_value(node)
  if splat_value
    correct_splat_expansion(corrector, expr, splat_value)
  elsif node.array_type? && !node.bracketed?
    corrector.wrap(expr, '[', ']')
  elsif requires_parentheses?(node)
    corrector.wrap(expr, '(', ')')
  end
  corrector.insert_after(expr, '.freeze')
end

def check(value)

def check(value)
  range_enclosed_in_parentheses = range_enclosed_in_parentheses?(value)
  return unless mutable_literal?(value) ||
                (target_ruby_version <= 2.7 && range_enclosed_in_parentheses)
  return if frozen_string_literal?(value)
  return if shareable_constant_value?(value)
  add_offense(value) { |corrector| autocorrect(corrector, value) }
end

def correct_splat_expansion(corrector, expr, splat_value)

def correct_splat_expansion(corrector, expr, splat_value)
  if range_enclosed_in_parentheses?(splat_value)
    corrector.replace(expr, "#{splat_value.source}.to_a")
  else
    corrector.replace(expr, "(#{splat_value.source}).to_a")
  end
end

def frozen_regexp_or_range_literals?(node)

def frozen_regexp_or_range_literals?(node)
  target_ruby_version >= 3.0 && node.type?(:regexp, :range)
end

def immutable_literal?(node)

def immutable_literal?(node)
  frozen_regexp_or_range_literals?(node) || node.immutable_literal?
end

def mutable_literal?(value)

def mutable_literal?(value)
  return false if frozen_regexp_or_range_literals?(value)
  value.mutable_literal?
end

def on_assignment(value)

def on_assignment(value)
  if style == :strict
    strict_check(value)
  else
    check(value)
  end
end

def on_casgn(node)

def on_casgn(node)
  if node.expression.nil? # This is only the case for `CONST += ...` or similarg66
    parent = node.parent
    return unless parent.or_asgn_type? # We only care about `CONST ||= ...`
    on_assignment(parent.children.last)
  else
    on_assignment(node.expression)
  end
end

def requires_parentheses?(node)

def requires_parentheses?(node)
  node.range_type? || (node.send_type? && node.loc.dot.nil?)
end

def shareable_constant_value?(node)

def shareable_constant_value?(node)
  return false if target_ruby_version < 3.0
  recent_shareable_value? node
end

def strict_check(value)

def strict_check(value)
  return if immutable_literal?(value)
  return if operation_produces_immutable_object?(value)
  return if frozen_string_literal?(value)
  return if shareable_constant_value?(value)
  add_offense(value) { |corrector| autocorrect(corrector, value) }
end