Fix violations
This commit is contained in:
		
							parent
							
								
									c354377f3e
								
							
						
					
					
						commit
						eeb31d3050
					
				| @ -10,14 +10,10 @@ class PATH | ||||
| 
 | ||||
|   delegate each: :@paths | ||||
| 
 | ||||
|   # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|   # rubocop:disable Style/MutableConstant | ||||
|   Element = T.type_alias { T.nilable(T.any(Pathname, String, PATH)) } | ||||
|   private_constant :Element | ||||
|   Elements = T.type_alias { T.any(Element, T::Array[Element]) } | ||||
|   private_constant :Elements | ||||
|   # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|   sig { params(paths: Elements).void } | ||||
|   def initialize(*paths) | ||||
|     @paths = parse(paths) | ||||
|  | ||||
| @ -10,11 +10,7 @@ module Cask | ||||
| 
 | ||||
|     requires_ancestor { Kernel } | ||||
| 
 | ||||
|     # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|     # rubocop:disable Style/MutableConstant | ||||
|     Paths = T.type_alias { T.any(String, Pathname, T::Array[T.any(String, Pathname)]) } | ||||
|     # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|     sig { params(paths: Paths, permissions_str: String).void } | ||||
|     def set_permissions(paths, permissions_str) | ||||
|       full_paths = remove_nonexistent(paths) | ||||
|  | ||||
| @ -6,16 +6,12 @@ require "ostruct" | ||||
| module Homebrew | ||||
|   module CLI | ||||
|     class Args < OpenStruct | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       # Represents a processed option. The array elements are: | ||||
|       #   0: short option name (e.g. "-d") | ||||
|       #   1: long option name (e.g. "--debug") | ||||
|       #   2: option description (e.g. "Print debugging information") | ||||
|       #   3: whether the option is hidden | ||||
|       OptionsType = T.type_alias { T::Array[[String, T.nilable(String), String, T::Boolean]] } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|       sig { returns(T::Array[String]) } | ||||
|       attr_reader :options_only, :flags_only | ||||
| 
 | ||||
|  | ||||
| @ -13,10 +13,7 @@ require "utils/formatter" | ||||
| module Homebrew | ||||
|   module CLI | ||||
|     class Parser | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       ArgType = T.type_alias { T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]) } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
|       HIDDEN_DESC_PLACEHOLDER = "@@HIDDEN@@" | ||||
|       SYMBOL_TO_USAGE_MAPPING = T.let({ | ||||
|         text_or_regex: "<text>|`/`<regex>`/`", | ||||
|  | ||||
| @ -5,8 +5,6 @@ require "test_runner_formula" | ||||
| require "github_runner" | ||||
| 
 | ||||
| class GitHubRunnerMatrix | ||||
|   # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|   # rubocop:disable Style/MutableConstant | ||||
|   RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) } | ||||
|   private_constant :RunnerSpec | ||||
| 
 | ||||
| @ -36,8 +34,6 @@ class GitHubRunnerMatrix | ||||
| 
 | ||||
|   RunnerSpecHash = T.type_alias { T.any(LinuxRunnerSpecHash, MacOSRunnerSpecHash) } | ||||
|   private_constant :RunnerSpecHash | ||||
|   # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|   sig { returns(T::Array[GitHubRunner]) } | ||||
|   attr_reader :runners | ||||
| 
 | ||||
|  | ||||
| @ -13,12 +13,8 @@ module Tapioca | ||||
|         end.flatten.freeze, T::Array[String] | ||||
|       ) | ||||
| 
 | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       Parsable = T.type_alias { T.any(T.class_of(Homebrew::CLI::Args), T.class_of(Homebrew::AbstractCommand)) } | ||||
|       ConstantType = type_member { { fixed: Parsable } } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|       sig { override.returns(T::Enumerable[Parsable]) } | ||||
|       def self.gather_constants | ||||
|         # require all the commands to ensure the command subclasses are defined | ||||
|  | ||||
| @ -7,10 +7,7 @@ require "env_config" | ||||
| module Tapioca | ||||
|   module Compilers | ||||
|     class EnvConfig < Tapioca::Dsl::Compiler | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       ConstantType = type_member { { fixed: Module } } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|       sig { override.returns(T::Enumerable[Module]) } | ||||
|       def self.gather_constants = [Homebrew::EnvConfig] | ||||
|  | ||||
| @ -8,13 +8,9 @@ require_relative "../../../rubocops" | ||||
| module Tapioca | ||||
|   module Compilers | ||||
|     class RuboCop < Tapioca::Dsl::Compiler | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       # This should be a module whose singleton class contains RuboCop::AST::NodePattern::Macros, | ||||
|       #   but I don't know how to express that in Sorbet. | ||||
|       ConstantType = type_member { { fixed: Module } } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|       sig { override.returns(T::Enumerable[Module]) } | ||||
|       def self.gather_constants | ||||
|         all_modules.select do |klass| | ||||
|  | ||||
| @ -7,10 +7,7 @@ require "utils/tty" | ||||
| module Tapioca | ||||
|   module Compilers | ||||
|     class Tty < Tapioca::Dsl::Compiler | ||||
|       # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|       # rubocop:disable Style/MutableConstant | ||||
|       ConstantType = type_member { { fixed: Module } } | ||||
|       # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|       sig { override.returns(T::Enumerable[Module]) } | ||||
|       def self.gather_constants = [::Tty] | ||||
|  | ||||
| @ -1,630 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require "rubocops/extend/mutable_constant_exclude_unfreezable" | ||||
| 
 | ||||
| RSpec.describe(RuboCop::Cop::Style::MutableConstant, :config) do | ||||
|   let(:prefix) { nil } | ||||
| 
 | ||||
|   shared_examples "mutable objects" do |o| | ||||
|     context "when using T.let" do | ||||
|       context "when assigning with =" do | ||||
|         it "registers an offense for #{o} assigned to a constant " \ | ||||
|            "and corrects by adding .freeze" do | ||||
|           expect_offense([prefix, <<~RUBY].compact.join("\n"), o:) | ||||
|             CONST = T.let(%<o>s, Object) | ||||
|                           ^{o} Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
|           expect_correction([prefix, <<~RUBY].compact.join("\n")) | ||||
|             CONST = T.let(#{o}.freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning with ||=" do | ||||
|         it "registers an offense for #{o} assigned to a constant " \ | ||||
|            "and corrects by adding .freeze" do | ||||
|           expect_offense([prefix, <<~RUBY].compact.join("\n"), o:) | ||||
|             CONST ||= T.let(%<o>s, Object) | ||||
|                             ^{o} Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
|           expect_correction([prefix, <<~RUBY].compact.join("\n")) | ||||
|             CONST ||= T.let(#{o}.freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "when not using T.let" do | ||||
|       context "when assigning with =" do | ||||
|         it "registers an offense for #{o} assigned to a constant " \ | ||||
|            "and corrects by adding .freeze" do | ||||
|           expect_offense([prefix, <<~RUBY].compact.join("\n"), o:) | ||||
|             CONST = %<o>s | ||||
|                     ^{o} Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
|           expect_correction([prefix, <<~RUBY].compact.join("\n")) | ||||
|             CONST = #{o}.freeze | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning with ||=" do | ||||
|         it "registers an offense for #{o} assigned to a constant " \ | ||||
|            "and corrects by adding .freeze" do | ||||
|           expect_offense([prefix, <<~RUBY].compact.join("\n"), o:) | ||||
|             CONST ||= %<o>s | ||||
|                       ^{o} Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
|           expect_correction([prefix, <<~RUBY].compact.join("\n")) | ||||
|             CONST ||= #{o}.freeze | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   shared_examples "immutable objects" do |o| | ||||
|     context "when using T.let" do | ||||
|       it "allows #{o} to be assigned to a constant" do | ||||
|         const = if o.start_with?("<<~HERE") | ||||
|           heredoc = o.delete_prefix("<<~HERE") | ||||
|           "CONST = T.let(<<~HERE, Object)#{heredoc}" | ||||
|         else | ||||
|           "CONST = T.let(#{o.chomp}, Object)" | ||||
|         end | ||||
|         source = [prefix, const].compact.join("\n") | ||||
|         expect_no_offenses(source) | ||||
|       end | ||||
| 
 | ||||
|       it "allows #{o} to be ||= to a constant" do | ||||
|         const = if o.start_with?("<<~HERE") | ||||
|           heredoc = o.delete_prefix("<<~HERE") | ||||
|           "CONST ||= T.let(<<~HERE, Object)#{heredoc}" | ||||
|         else | ||||
|           "CONST ||= T.let(#{o.chomp}, Object)" | ||||
|         end | ||||
|         source = [prefix, const].compact.join("\n") | ||||
|         expect_no_offenses(source) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "when not using T.let" do | ||||
|       it "allows #{o} to be assigned to a constant" do | ||||
|         source = [prefix, "CONST = #{o}"].compact.join("\n") | ||||
|         expect_no_offenses(source) | ||||
|       end | ||||
| 
 | ||||
|       it "allows #{o} to be ||= to a constant" do | ||||
|         source = [prefix, "CONST ||= #{o}"].compact.join("\n") | ||||
|         expect_no_offenses(source) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   shared_examples "literals that are frozen" do |o| | ||||
|     let(:prefix) { o } | ||||
| 
 | ||||
|     it_behaves_like "immutable objects", "[1, 2, 3]" | ||||
|     it_behaves_like "immutable objects", "%w(a b c)" | ||||
|     it_behaves_like "immutable objects", "{ a: 1, b: 2 }" | ||||
|     it_behaves_like "immutable objects", "'str'" | ||||
|     it_behaves_like "immutable objects", %Q("top#{1 + 2}") | ||||
|     it_behaves_like "immutable objects", "1" | ||||
|     it_behaves_like "immutable objects", "1.5" | ||||
|     it_behaves_like "immutable objects", ":sym" | ||||
|     it_behaves_like "immutable objects", "FOO + BAR" | ||||
|     it_behaves_like "immutable objects", "FOO - BAR" | ||||
|     it_behaves_like "immutable objects", "'foo' + 'bar'" | ||||
|     it_behaves_like "immutable objects", "ENV['foo']" | ||||
|     it_behaves_like "immutable objects", "::ENV['foo']" | ||||
|   end | ||||
| 
 | ||||
|   shared_examples "literals that are not frozen" do |o| | ||||
|     let(:prefix) { o } | ||||
| 
 | ||||
|     it_behaves_like "mutable objects", "[1, 2, 3]" | ||||
|     it_behaves_like "mutable objects", "%w(a b c)" | ||||
|     it_behaves_like "mutable objects", "{ a: 1, b: 2 }" | ||||
|     it_behaves_like "mutable objects", "'str'" | ||||
|     it_behaves_like "mutable objects", %Q("top#{1 + 2}") | ||||
| 
 | ||||
|     it_behaves_like "immutable objects", "1" | ||||
|     it_behaves_like "immutable objects", "1.5" | ||||
|     it_behaves_like "immutable objects", ":sym" | ||||
|     it_behaves_like "immutable objects", "FOO + BAR" | ||||
|     it_behaves_like "immutable objects", "FOO - BAR" | ||||
|     it_behaves_like "immutable objects", "'foo' + 'bar'" | ||||
|     it_behaves_like "immutable objects", "ENV['foo']" | ||||
|     it_behaves_like "immutable objects", "::ENV['foo']" | ||||
|   end | ||||
| 
 | ||||
|   shared_examples "string literal" do | ||||
|     # TODO : It is not yet decided when frozen string will be the default. | ||||
|     # It has been abandoned in the Ruby 3.0 period, but may default in | ||||
|     # the long run. So these tests are left with a provisional value of 4.0. | ||||
|     if RuboCop::TargetRuby.supported_versions.include?(4.0) | ||||
|       context "when the target ruby version >= 4.0" do | ||||
|         let(:ruby_version) { 4.0 } | ||||
| 
 | ||||
|         context "when the frozen string literal comment is missing" do | ||||
|           it_behaves_like "immutable objects", %Q("#{a}") | ||||
|         end | ||||
| 
 | ||||
|         context "when the frozen string literal comment is true" do | ||||
|           let(:prefix) { "# frozen_string_literal: true" } | ||||
| 
 | ||||
|           it_behaves_like "immutable objects", %Q("#{a}") | ||||
|         end | ||||
| 
 | ||||
|         context "when the frozen string literal comment is false" do | ||||
|           let(:prefix) { "# frozen_string_literal: false" } | ||||
| 
 | ||||
|           it_behaves_like "immutable objects", %Q("#{a}") | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with Ruby 3.0 or higher", :ruby30 do | ||||
|       context "when the frozen string literal comment is missing" do | ||||
|         it_behaves_like "mutable objects", %Q("#{a}") | ||||
|       end | ||||
| 
 | ||||
|       context "when the frozen string literal comment is true" do | ||||
|         let(:prefix) { "# frozen_string_literal: true" } | ||||
| 
 | ||||
|         it_behaves_like "mutable objects", %Q("#{a}") | ||||
|         it_behaves_like "immutable objects", <<~RUBY | ||||
|           <<~HERE | ||||
|             foo | ||||
|             bar | ||||
|           HERE | ||||
|         RUBY | ||||
|         it "registers an offense when using interpolated heredoc constant" do | ||||
|           expect_offense(<<~'RUBY') | ||||
|             # frozen_string_literal: true | ||||
| 
 | ||||
|             CONST = T.let(<<~HERE, Object) | ||||
|                           ^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|               foo #{use_interpolation} | ||||
|               bar | ||||
|             HERE | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not register an offense when using a multiline string" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             # frozen_string_literal: true | ||||
| 
 | ||||
|             CONST = T.let('foo' \ | ||||
|                     'bar', Object) | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "registers an offense when using a multiline string with interpolation" do | ||||
|           expect_offense(<<~'RUBY') | ||||
|             # frozen_string_literal: true | ||||
| 
 | ||||
|             CONST = T.let("#{foo}" \ | ||||
|                           ^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|                     'bar', Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when the frozen string literal comment is false" do | ||||
|         let(:prefix) { "# frozen_string_literal: false" } | ||||
| 
 | ||||
|         it_behaves_like "mutable objects", %Q("#{a}") | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with Ruby 2.7 or lower", :ruby27 do | ||||
|       context "when the frozen string literal comment is missing" do | ||||
|         it_behaves_like "mutable objects", %Q("#{a}") | ||||
|       end | ||||
| 
 | ||||
|       context "when the frozen string literal comment is true" do | ||||
|         let(:prefix) { "# frozen_string_literal: true" } | ||||
| 
 | ||||
|         it_behaves_like "immutable objects", %Q("#{a}") | ||||
|         it_behaves_like "immutable objects", <<~RUBY | ||||
|           <<~HERE | ||||
|             foo | ||||
|             bar | ||||
|           HERE | ||||
|         RUBY | ||||
|         it "does not register an offense when using interpolated heredoc constant" do | ||||
|           expect_no_offenses(<<~'RUBY') | ||||
|             # frozen_string_literal: true | ||||
| 
 | ||||
|             CONST = T.let(<<~HERE, Object) | ||||
|               foo #{use_interpolation} | ||||
|               bar | ||||
|             HERE | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not register an offense when using a multiline string" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             # frozen_string_literal: true | ||||
| 
 | ||||
|             CONST = T.let('foo' \ | ||||
|                     'bar', Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when the frozen string literal comment is false" do | ||||
|         let(:prefix) { "# frozen_string_literal: false" } | ||||
| 
 | ||||
|         it_behaves_like "mutable objects", %Q("#{a}") | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context "with Strict: false" do | ||||
|     let(:cop_config) { { "EnforcedStyle" => "literals" } } | ||||
| 
 | ||||
|     it_behaves_like "mutable objects", "[1, 2, 3]" | ||||
|     it_behaves_like "mutable objects", "%w(a b c)" | ||||
|     it_behaves_like "mutable objects", "{ a: 1, b: 2 }" | ||||
|     it_behaves_like "mutable objects", "'str'" | ||||
|     it_behaves_like "mutable objects", %Q("top#{1 + 2}") | ||||
| 
 | ||||
|     it_behaves_like "immutable objects", "1" | ||||
|     it_behaves_like "immutable objects", "1.5" | ||||
|     it_behaves_like "immutable objects", ":sym" | ||||
|     it_behaves_like "immutable objects", "FOO + BAR" | ||||
|     it_behaves_like "immutable objects", "FOO - BAR" | ||||
|     it_behaves_like "immutable objects", "'foo' + 'bar'" | ||||
|     it_behaves_like "immutable objects", "ENV['foo']" | ||||
|     it_behaves_like "immutable objects", "::ENV['foo']" | ||||
| 
 | ||||
|     it "allows method call assignments" do | ||||
|       expect_no_offenses("TOP_TEST = Something.new") | ||||
|     end | ||||
| 
 | ||||
|     context "when assigning an array without brackets" do | ||||
|       it "does not insert brackets for %w() arrays" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           XXX = T.let(%w(YYY ZZZ), Object) | ||||
|                       ^^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
| 
 | ||||
|         expect_correction(<<~RUBY) | ||||
|           XXX = T.let(%w(YYY ZZZ).freeze, Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     # Ruby 3.0's Regexp and Range literals are frozen. | ||||
|     # | ||||
|     # https://bugs.ruby-lang.org/issues/15504 | ||||
|     # https://bugs.ruby-lang.org/issues/16377 | ||||
|     context "with Ruby 3.0 or higher", :ruby30 do | ||||
|       context "when assigning a regexp" do | ||||
|         it "does not register an offense" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             XXX = T.let(/regexp/, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning a range (irange)" do | ||||
|         it "does not register an offense when without parenthesis" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             XXX = T.let(1..99, Object) | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not register an offense when with parenthesis" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             XXX = T.let((1..99), Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning a range (erange)" do | ||||
|         it "does not register an offense when without parenthesis" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             XXX = T.let(1...99, Object) | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not register an offense when with parenthesis" do | ||||
|           expect_no_offenses(<<~RUBY) | ||||
|             XXX = T.let((1...99), Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when using shareable_constant_value" do | ||||
|         it_behaves_like "literals that are frozen", "# shareable_constant_value: literal" | ||||
|         it_behaves_like "literals that are frozen", "# shareable_constant_value: experimental_everything" | ||||
|         it_behaves_like "literals that are frozen", "# shareable_constant_value: experimental_copy" | ||||
|         it_behaves_like "literals that are not frozen", "# shareable_constant_value: none" | ||||
|       end | ||||
| 
 | ||||
|       it "raises offense when shareable_constant_value is specified as an inline comment" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           X = T.let([1, 2, 3], Object) # shareable_constant_value: literal | ||||
|                     ^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           Y = T.let([4, 5, 6], Object) | ||||
|                     ^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "raises offense only for shareable_constant_value as none when set in the order of: " \ | ||||
|          "literal, none and experimental_everything" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           # shareable_constant_value: literal | ||||
|           X = T.let([1, 2, 3], Object) | ||||
|           # shareable_constant_value: none | ||||
|           Y = T.let([4, 5, 6], Object) | ||||
|                     ^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           # shareable_constant_value: experimental_everything | ||||
|           Z = T.let([7, 8, 9], Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with Ruby 2.7 or lower", :ruby27 do | ||||
|       context "when assigning a regexp" do | ||||
|         it "registers an offense" do | ||||
|           expect_offense(<<~RUBY) | ||||
|             XXX = T.let(/regexp/, Object) | ||||
|                         ^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             XXX = T.let(/regexp/.freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning a range (irange) without parenthesis" do | ||||
|         it "adds parenthesis when auto-correcting" do | ||||
|           expect_offense(<<~RUBY) | ||||
|             XXX = T.let(1..99, Object) | ||||
|                         ^^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             XXX = T.let((1..99).freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not insert parenthesis to range enclosed in parentheses" do | ||||
|           expect_offense(<<~RUBY) | ||||
|             XXX = T.let((1..99), Object) | ||||
|                         ^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             XXX = T.let((1..99).freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when assigning a range (erange) without parenthesis" do | ||||
|         it "adds parenthesis when auto-correcting" do | ||||
|           expect_offense(<<~RUBY) | ||||
|             XXX = T.let(1...99, Object) | ||||
|                         ^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             XXX = T.let((1...99).freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
| 
 | ||||
|         it "does not insert parenthesis to range enclosed in parentheses" do | ||||
|           expect_offense(<<~RUBY) | ||||
|             XXX = T.let((1...99), Object) | ||||
|                         ^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             XXX = T.let((1...99).freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context "when using shareable_constant_values" do | ||||
|         it_behaves_like "literals that are not frozen", "# shareable_constant_value: literal" | ||||
|         it_behaves_like "literals that are not frozen", "# shareable_constant_value: experimental_everything" | ||||
|         it_behaves_like "literals that are not frozen", "# shareable_constant_value: experimental_copy" | ||||
|         it_behaves_like "literals that are not frozen", "# shareable_constant_value: none" | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     it_behaves_like "string literal" | ||||
|   end | ||||
| 
 | ||||
|   context "with Strict: true" do | ||||
|     let(:cop_config) { { "EnforcedStyle" => "strict" } } | ||||
| 
 | ||||
|     it_behaves_like "mutable objects", "[1, 2, 3]" | ||||
|     it_behaves_like "mutable objects", "%w(a b c)" | ||||
|     it_behaves_like "mutable objects", "{ a: 1, b: 2 }" | ||||
|     it_behaves_like "mutable objects", "'str'" | ||||
|     it_behaves_like "mutable objects", %Q("top#{1 + 2}") | ||||
|     it_behaves_like "mutable objects", "Something.new" | ||||
| 
 | ||||
|     it_behaves_like "immutable objects", "1" | ||||
|     it_behaves_like "immutable objects", "1.5" | ||||
|     it_behaves_like "immutable objects", ":sym" | ||||
|     it_behaves_like "immutable objects", "ENV['foo']" | ||||
|     it_behaves_like "immutable objects", "::ENV['foo']" | ||||
|     it_behaves_like "immutable objects", "OTHER_CONST" | ||||
|     it_behaves_like "immutable objects", "::OTHER_CONST" | ||||
|     it_behaves_like "immutable objects", "Namespace::OTHER_CONST" | ||||
|     it_behaves_like "immutable objects", "::Namespace::OTHER_CONST" | ||||
|     it_behaves_like "immutable objects", "Struct.new" | ||||
|     it_behaves_like "immutable objects", "::Struct.new" | ||||
|     it_behaves_like "immutable objects", "Struct.new(:a, :b)" | ||||
|     it_behaves_like "immutable objects", "T.type_alias { T.nilable(T.any(Pathname, String)) }" | ||||
|     it_behaves_like "immutable objects", "::T.type_alias { T.nilable(T.any(Pathname, String)) }" | ||||
|     it_behaves_like "immutable objects", "type_member { { fixed: Module } }" | ||||
|     it_behaves_like "immutable objects", <<~RUBY | ||||
|       Struct.new(:node) do | ||||
|         def assignment? | ||||
|           true | ||||
|         end | ||||
|       end | ||||
|     RUBY | ||||
| 
 | ||||
|     it "allows calls to freeze" do | ||||
|       expect_no_offenses(<<~RUBY) | ||||
|         CONST = T.let([1].freeze, Object) | ||||
|       RUBY | ||||
|     end | ||||
| 
 | ||||
|     context "when assigning with an operator" do | ||||
|       shared_examples "operator methods" do |o| | ||||
|         it "registers an offense and corrects with parens and freeze" do | ||||
|           expect_offense(<<~RUBY, o:) | ||||
|             CONST = T.let(FOO %<o>s BAR, Object) | ||||
|                           ^^^^^{o}^^^^ Freeze mutable objects assigned to constants. | ||||
|           RUBY | ||||
| 
 | ||||
|           expect_correction(<<~RUBY) | ||||
|             CONST = T.let((FOO #{o} BAR).freeze, Object) | ||||
|           RUBY | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       it_behaves_like "operator methods", "+" | ||||
|       it_behaves_like "operator methods", "-" | ||||
|       it_behaves_like "operator methods", "*" | ||||
|       it_behaves_like "operator methods", "/" | ||||
|       it_behaves_like "operator methods", "%" | ||||
|       it_behaves_like "operator methods", "**" | ||||
|     end | ||||
| 
 | ||||
|     context "when assigning with multiple operator calls" do | ||||
|       it "registers an offense and corrects with parens and freeze" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           FOO = [1].freeze | ||||
|           BAR = [2].freeze | ||||
|           BAZ = [3].freeze | ||||
|           CONST = T.let(FOO + BAR + BAZ, Object) | ||||
|                         ^^^^^^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
| 
 | ||||
|         expect_correction(<<~RUBY) | ||||
|           FOO = [1].freeze | ||||
|           BAR = [2].freeze | ||||
|           BAZ = [3].freeze | ||||
|           CONST = T.let((FOO + BAR + BAZ).freeze, Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with methods and operators that produce frozen objects" do | ||||
|       it "accepts assigning to an environment variable with a fallback" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(ENV['foo'] || 'foo', Object) | ||||
|         RUBY | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(::ENV['foo'] || 'foo', Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts operating on a constant and an interger" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(FOO + 2, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts operating on multiple integers" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(1 + 2, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts operating on a constant and a float" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(FOO + 2.1, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts operating on multiple floats" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(1.2 + 2.1, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts comparison operators" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let(FOO == BAR, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "accepts checking fixed size" do | ||||
|         expect_no_offenses(<<~RUBY) | ||||
|           CONST = T.let('foo'.count, Object) | ||||
|           CONST = T.let('foo'.count('f'), Object) | ||||
|           CONST = T.let([1, 2, 3].count { |n| n > 2 }, Object) | ||||
|           CONST = T.let([1, 2, 3].count(2) { |n| n > 2 }, Object) | ||||
|           CONST = T.let('foo'.length, Object) | ||||
|           CONST = T.let('foo'.size, Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with operators that produce unfrozen objects" do | ||||
|       it "registers an offense when operating on a constant and a string" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           CONST = T.let(FOO + 'bar', Object) | ||||
|                         ^^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
| 
 | ||||
|         expect_correction(<<~RUBY) | ||||
|           CONST = T.let((FOO + 'bar').freeze, Object) | ||||
|         RUBY | ||||
|       end | ||||
| 
 | ||||
|       it "registers an offense when operating on multiple strings" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           CONST = T.let('foo' + 'bar' + 'baz', Object) | ||||
|                         ^^^^^^^^^^^^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
| 
 | ||||
|         expect_correction(<<~RUBY) | ||||
|           CONST = T.let(('foo' + 'bar' + 'baz').freeze, Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "when assigning an array without brackets" do | ||||
|       it "does not insert brackets for %w() arrays" do | ||||
|         expect_offense(<<~RUBY) | ||||
|           XXX = T.let(%w(YYY ZZZ), Object) | ||||
|                       ^^^^^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|         RUBY | ||||
| 
 | ||||
|         expect_correction(<<~RUBY) | ||||
|           XXX = T.let(%w(YYY ZZZ).freeze, Object) | ||||
|         RUBY | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     it "freezes a heredoc" do | ||||
|       expect_offense(<<~RUBY) | ||||
|         FOO = T.let(<<-HERE, Object) | ||||
|                     ^^^^^^^ Freeze mutable objects assigned to constants. | ||||
|           SOMETHING | ||||
|         HERE | ||||
|       RUBY | ||||
| 
 | ||||
|       expect_correction(<<~RUBY) | ||||
|         FOO = T.let(<<-HERE.freeze, Object) | ||||
|           SOMETHING | ||||
|         HERE | ||||
|       RUBY | ||||
|     end | ||||
| 
 | ||||
|     it_behaves_like "string literal" | ||||
|   end | ||||
| end | ||||
| @ -11,10 +11,7 @@ module UnpackStrategy | ||||
| 
 | ||||
|   requires_ancestor { Kernel } | ||||
| 
 | ||||
|   # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. | ||||
|   # rubocop:disable Style/MutableConstant | ||||
|   UnpackStrategyType = T.type_alias { T.all(T::Class[UnpackStrategy], UnpackStrategy::ClassMethods) } | ||||
|   # rubocop:enable Style/MutableConstant | ||||
| 
 | ||||
|   module ClassMethods | ||||
|     extend T::Helpers | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Douglas Eichelberger
						Douglas Eichelberger