Merge pull request #15883 from Homebrew/dependabot/bundler/Library/Homebrew/rubocop-sorbet-0.7.3

build(deps): bump rubocop-sorbet from 0.7.0 to 0.7.3 in /Library/Homebrew
This commit is contained in:
Mike McQuaid 2023-09-13 14:39:24 +01:00 committed by GitHub
commit c953076609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 910 additions and 558 deletions

View File

@ -118,7 +118,7 @@ GEM
rubocop-rspec (2.20.0)
rubocop (~> 1.33)
rubocop-capybara (~> 2.17)
rubocop-sorbet (0.7.0)
rubocop-sorbet (0.7.3)
rubocop (>= 0.90.0)
ruby-macho (4.0.0)
ruby-prof (1.4.3)

View File

@ -95,21 +95,17 @@ module OS
# directory or nil if Xcode.app is not installed.
sig { returns(T.nilable(Pathname)) }
def self.prefix
return @prefix if defined?(@prefix)
@prefix ||= begin
dir = MacOS.active_developer_dir
@prefix = T.let(@prefix, T.nilable(Pathname))
@prefix ||=
begin
dir = MacOS.active_developer_dir
if dir.empty? || dir == CLT::PKG_PATH || !File.directory?(dir)
path = bundle_path
path/"Contents/Developer" if path
else
# Use cleanpath to avoid pathological trailing slash
Pathname.new(dir).cleanpath
end
if dir.empty? || dir == CLT::PKG_PATH || !File.directory?(dir)
path = bundle_path
path/"Contents/Developer" if path
else
# Use cleanpath to avoid pathological trailing slash
Pathname.new(dir).cleanpath
end
end
end
sig { returns(Pathname) }

View File

@ -10,31 +10,34 @@ RuboCop::Cop::IgnoredMethods = RuboCop::Cop::AllowedMethods
RuboCop::Cop::IgnoredPattern = RuboCop::Cop::AllowedPattern
module RuboCop::Cop::Sorbet; end
class RuboCop::Cop::Sorbet::AllowIncompatibleOverride < ::RuboCop::Cop::Cop
def allow_incompatible?(param0); end
def allow_incompatible_override?(param0 = T.unsafe(nil)); end
def not_nil?(node); end
class RuboCop::Cop::Sorbet::AllowIncompatibleOverride < ::RuboCop::Cop::Base
def on_block(node); end
def on_numblock(node); end
def on_send(node); end
def override?(param0 = T.unsafe(nil)); end
def sig?(param0); end
def sig_dot_override?(param0 = T.unsafe(nil)); end
end
class RuboCop::Cop::Sorbet::BindingConstantWithoutTypeAlias < ::RuboCop::Cop::Cop
def autocorrect(node); end
def binding_unaliased_type?(param0 = T.unsafe(nil)); end
def dynamic_type_creation_with_block?(param0 = T.unsafe(nil)); end
def generic_parameter_decl_block_call?(param0 = T.unsafe(nil)); end
def generic_parameter_decl_call?(param0 = T.unsafe(nil)); end
def method_needing_aliasing_on_t?(param0); end
def not_dynamic_type_creation_with_block?(node); end
def not_generic_parameter_decl?(node); end
def not_nil?(node); end
def not_t_let?(node); end
RuboCop::Cop::Sorbet::AllowIncompatibleOverride::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Sorbet::AllowIncompatibleOverride::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Sorbet::BindingConstantWithoutTypeAlias < ::RuboCop::Cop::Base
extend ::RuboCop::Cop::AutoCorrector
def on_casgn(node); end
def t_let?(param0 = T.unsafe(nil)); end
def using_deprecated_type_alias_syntax?(param0 = T.unsafe(nil)); end
def using_type_alias?(param0 = T.unsafe(nil)); end
def requires_type_alias?(param0 = T.unsafe(nil)); end
def type_alias_with_block?(param0 = T.unsafe(nil)); end
def type_alias_without_block(param0 = T.unsafe(nil)); end
private
def send_leaf(node); end
end
RuboCop::Cop::Sorbet::BindingConstantWithoutTypeAlias::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Sorbet::BindingConstantWithoutTypeAlias::WITHOUT_BLOCK_MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::CallbackConditionalsBinding < ::RuboCop::Cop::Cop
def autocorrect(node); end
def on_send(node); end
@ -133,12 +136,11 @@ class RuboCop::Cop::Sorbet::FalseSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end
end
class RuboCop::Cop::Sorbet::ForbidExtendTSigHelpersInShims < ::RuboCop::Cop::Cop
class RuboCop::Cop::Sorbet::ForbidExtendTSigHelpersInShims < ::RuboCop::Cop::Base
include ::RuboCop::Cop::RangeHelp
extend ::RuboCop::Cop::AutoCorrector
def autocorrect(node); end
def extend_t_helpers?(param0 = T.unsafe(nil)); end
def extend_t_sig?(param0 = T.unsafe(nil)); end
def extend_t_sig_or_helpers?(param0 = T.unsafe(nil)); end
def on_send(node); end
end
@ -167,27 +169,32 @@ class RuboCop::Cop::Sorbet::ForbidRBIOutsideOfAllowedPaths < ::RuboCop::Cop::Cop
def allowed_paths; end
end
class RuboCop::Cop::Sorbet::ForbidSuperclassConstLiteral < ::RuboCop::Cop::Cop
def not_lit_const_superclass?(param0 = T.unsafe(nil)); end
class RuboCop::Cop::Sorbet::ForbidSuperclassConstLiteral < ::RuboCop::Cop::Base
def dynamic_superclass?(param0 = T.unsafe(nil)); end
def on_class(node); end
end
RuboCop::Cop::Sorbet::ForbidSuperclassConstLiteral::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::ForbidTUnsafe < ::RuboCop::Cop::Cop
class RuboCop::Cop::Sorbet::ForbidTUnsafe < ::RuboCop::Cop::Base
def on_send(node); end
def t_unsafe?(param0 = T.unsafe(nil)); end
end
class RuboCop::Cop::Sorbet::ForbidTUntyped < ::RuboCop::Cop::Cop
RuboCop::Cop::Sorbet::ForbidTUnsafe::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Sorbet::ForbidTUnsafe::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Sorbet::ForbidTUntyped < ::RuboCop::Cop::Base
def on_send(node); end
def t_untyped?(param0 = T.unsafe(nil)); end
end
class RuboCop::Cop::Sorbet::ForbidUntypedStructProps < ::RuboCop::Cop::Cop
RuboCop::Cop::Sorbet::ForbidTUntyped::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Sorbet::ForbidTUntyped::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Sorbet::ForbidUntypedStructProps < ::RuboCop::Cop::Base
def on_class(node); end
def subclass_of_t_struct?(param0 = T.unsafe(nil)); end
def t_immutable_struct(param0 = T.unsafe(nil)); end
def t_nilable_untyped(param0 = T.unsafe(nil)); end
def t_struct(param0 = T.unsafe(nil)); end
def t_untyped(param0 = T.unsafe(nil)); end
@ -204,6 +211,17 @@ class RuboCop::Cop::Sorbet::IgnoreSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end
end
class RuboCop::Cop::Sorbet::ImplicitConversionMethod < ::RuboCop::Cop::Base
def on_alias(node); end
def on_def(node); end
def on_defs(node); end
def on_send(node); end
end
RuboCop::Cop::Sorbet::ImplicitConversionMethod::IMPLICIT_CONVERSION_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Sorbet::ImplicitConversionMethod::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Sorbet::ImplicitConversionMethod::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Sorbet::KeywordArgumentOrdering < ::RuboCop::Cop::Sorbet::SignatureCop
def on_signature(node); end
@ -220,6 +238,22 @@ module RuboCop::Cop::Sorbet::MutableConstantSorbetAwareBehaviour
end
end
class RuboCop::Cop::Sorbet::ObsoleteStrictMemoization < ::RuboCop::Cop::Base
include ::RuboCop::Cop::RangeHelp
include ::RuboCop::Cop::MatchRange
include ::RuboCop::Cop::Alignment
include ::RuboCop::Cop::LineLengthHelp
include ::RuboCop::Cop::Sorbet::TargetSorbetVersion
extend ::RuboCop::Cop::AutoCorrector
extend ::RuboCop::Cop::Sorbet::TargetSorbetVersion::ClassMethods
def legacy_memoization_pattern?(param0 = T.unsafe(nil)); end
def on_begin(node); end
def relevant_file?(file); end
end
RuboCop::Cop::Sorbet::ObsoleteStrictMemoization::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::OneAncestorPerLine < ::RuboCop::Cop::Cop
def abstract?(param0); end
def autocorrect(node); end
@ -236,8 +270,9 @@ end
RuboCop::Cop::Sorbet::OneAncestorPerLine::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::RedundantExtendTSig < ::RuboCop::Cop::Cop
def autocorrect(node); end
class RuboCop::Cop::Sorbet::RedundantExtendTSig < ::RuboCop::Cop::Base
extend ::RuboCop::Cop::AutoCorrector
def extend_t_sig?(param0 = T.unsafe(nil)); end
def on_send(node); end
end
@ -262,21 +297,22 @@ RuboCop::Cop::Sorbet::SignatureBuildOrder::ORDER = T.let(T.unsafe(nil), Hash)
class RuboCop::Cop::Sorbet::SignatureCop < ::RuboCop::Cop::Cop
def on_block(node); end
def on_numblock(node); end
def on_signature(_); end
def signature?(param0 = T.unsafe(nil)); end
def with_runtime?(param0 = T.unsafe(nil)); end
def without_runtime?(param0 = T.unsafe(nil)); end
end
class RuboCop::Cop::Sorbet::SingleLineRbiClassModuleDefinitions < ::RuboCop::Cop::Cop
def autocorrect(node); end
class RuboCop::Cop::Sorbet::SingleLineRbiClassModuleDefinitions < ::RuboCop::Cop::Base
extend ::RuboCop::Cop::AutoCorrector
def on_class(node); end
def on_module(node); end
protected
private
def convert_newlines(source); end
def process_node(node); end
def convert_newlines_to_semicolons(source); end
end
RuboCop::Cop::Sorbet::SingleLineRbiClassModuleDefinitions::MSG = T.let(T.unsafe(nil), String)
@ -289,13 +325,30 @@ class RuboCop::Cop::Sorbet::StrongSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end
end
module RuboCop::Cop::Sorbet::TargetSorbetVersion
mixes_in_class_methods ::RuboCop::Cop::Sorbet::TargetSorbetVersion::ClassMethods
def enabled_for_sorbet_static_version?; end
def read_sorbet_static_version_from_bundler_lock_file; end
def target_sorbet_static_version_from_bundler_lock_file; end
class << self
def included(target); end
end
end
module RuboCop::Cop::Sorbet::TargetSorbetVersion::ClassMethods
def minimum_target_sorbet_static_version(version); end
def support_target_sorbet_static_version?(version); end
end
class RuboCop::Cop::Sorbet::TrueSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end
end
class RuboCop::Cop::Sorbet::TypeAliasName < ::RuboCop::Cop::Cop
def casgn_type_alias?(param0 = T.unsafe(nil)); end
class RuboCop::Cop::Sorbet::TypeAliasName < ::RuboCop::Cop::Base
def on_casgn(node); end
def underscored_type_alias?(param0 = T.unsafe(nil)); end
end
RuboCop::Cop::Sorbet::TypeAliasName::MSG = T.let(T.unsafe(nil), String)
@ -310,12 +363,13 @@ class RuboCop::Cop::Sorbet::ValidSigil < ::RuboCop::Cop::Cop
def check_strictness_level(sigil, strictness); end
def check_strictness_not_empty(sigil, strictness); end
def check_strictness_valid(sigil, strictness); end
def exact_strictness; end
def extract_sigil(processed_source); end
def extract_strictness(sigil); end
def minimum_strictness; end
def require_sigil_on_all_files?; end
def suggested_strictness; end
def suggested_strictness_level(minimum_strictness, suggested_strictness); end
def suggested_strictness_level; end
end
RuboCop::Cop::Sorbet::ValidSigil::SIGIL_REGEX = T.let(T.unsafe(nil), Regexp)

View File

@ -7102,6 +7102,7 @@ class RuboCop::AST::NodePattern::Parser
end
module RuboCop::AST::NodePattern::Sets
SET_ALL_ANY_CLASS_OF_ETC = ::T.let(nil, ::T.untyped)
SET_ARM_INTEL = ::T.let(nil, ::T.untyped)
SET_BASH_COMPLETION_ZSH_COMPLETION_FISH_COMPLETION = ::T.let(nil, ::T.untyped)
SET_BUILD_RECOMMENDED_TEST_OPTIONAL = ::T.let(nil, ::T.untyped)
@ -7111,6 +7112,8 @@ module RuboCop::AST::NodePattern::Sets
SET_ON_ARM_ON_INTEL_ON_SONOMA_ETC = ::T.let(nil, ::T.untyped)
SET_ON_INTEL_ON_ARM = ::T.let(nil, ::T.untyped)
SET_OR_NEWER_OR_OLDER = ::T.let(nil, ::T.untyped)
SET_SIG_HELPERS = ::T.let(nil, ::T.untyped)
SET_STRUCT_IMMUTABLESTRUCT = ::T.let(nil, ::T.untyped)
SET_SYSTEM_SHELL_OUTPUT_PIPE_OUTPUT = ::T.let(nil, ::T.untyped)
SET_WITH_WITHOUT = ::T.let(nil, ::T.untyped)
SET____ETC_4 = ::T.let(nil, ::T.untyped)

View File

@ -14,4 +14,6 @@ Homebrew.setup_gem_environment!(setup_path: false)
$LOAD_PATH.push HOMEBREW_LIBRARY_PATH.to_s unless $LOAD_PATH.include?(HOMEBREW_LIBRARY_PATH.to_s)
require_relative "../vendor/bundle/bundler/setup"
$LOAD_PATH.unshift "#{HOMEBREW_LIBRARY_PATH}/vendor/bundle/#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/" \
"bundler-#{Homebrew::HOMEBREW_BUNDLER_VERSION}/lib"
$LOAD_PATH.uniq!

View File

@ -99,7 +99,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-performance-1.17.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rails-2.19.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-2.20.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.7.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.7.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-macho-4.0.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/universal-darwin-22/#{Gem.extension_api_version}/ruby-prof-1.4.3")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-prof-1.4.3/lib")

View File

@ -1,127 +0,0 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows binding the return value of `T.any`, `T.all`, `T.enum`
# to a constant directly. To bind the value, one must use `T.type_alias`.
#
# @example
#
# # bad
# FooOrBar = T.any(Foo, Bar)
#
# # good
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
class BindingConstantWithoutTypeAlias < RuboCop::Cop::Cop
def_node_matcher(:binding_unaliased_type?, <<-PATTERN)
(casgn _ _ [#not_nil? #not_t_let? #not_dynamic_type_creation_with_block? #not_generic_parameter_decl? #method_needing_aliasing_on_t?])
PATTERN
def_node_matcher(:using_type_alias?, <<-PATTERN)
(block
(send
(const nil? :T) :type_alias)
_
_
)
PATTERN
def_node_matcher(:using_deprecated_type_alias_syntax?, <<-PATTERN)
(
send
(const nil? :T)
:type_alias
_
)
PATTERN
def_node_matcher(:t_let?, <<-PATTERN)
(
send
(const nil? :T)
:let
_
_
)
PATTERN
def_node_matcher(:dynamic_type_creation_with_block?, <<-PATTERN)
(block
(send
const :new ...)
_
_
)
PATTERN
def_node_matcher(:generic_parameter_decl_call?, <<-PATTERN)
(
send nil? {:type_template :type_member} ...
)
PATTERN
def_node_matcher(:generic_parameter_decl_block_call?, <<-PATTERN)
(block
(send nil? {:type_template :type_member} ...) ...
)
PATTERN
def_node_search(:method_needing_aliasing_on_t?, <<-PATTERN)
(
send
(const nil? :T)
{:any :all :noreturn :class_of :untyped :nilable :self_type :enum :proc}
...
)
PATTERN
def not_t_let?(node)
!t_let?(node)
end
def not_dynamic_type_creation_with_block?(node)
!dynamic_type_creation_with_block?(node)
end
def not_generic_parameter_decl?(node)
!generic_parameter_decl_call?(node) && !generic_parameter_decl_block_call?(node)
end
def not_nil?(node)
!node.nil?
end
def on_casgn(node)
return unless binding_unaliased_type?(node) && !using_type_alias?(node.children[2])
if using_deprecated_type_alias_syntax?(node.children[2])
add_offense(
node.children[2],
message: "It looks like you're using the old `T.type_alias` syntax. " \
"`T.type_alias` now expects a block." \
'Run Sorbet with the options "--autocorrect --error-white-list=5043" ' \
"to automatically upgrade to the new syntax."
)
return
end
add_offense(
node.children[2],
message: "It looks like you're trying to bind a type to a constant. " \
"To do this, you must alias the type using `T.type_alias`."
)
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(
node.source_range,
"T.type_alias { #{node.source} }"
)
end
end
end
end
end
end

View File

@ -1,45 +0,0 @@
# encoding: utf-8
# frozen_string_literal: true
require "rubocop"
# Correct superclass `send` expressions by constant literals.
#
# Sorbet, the static checker, is not (yet) able to support constructs on the
# following form:
#
# ```ruby
# class Foo < send_expr; end
# ```
#
# Multiple occurences of this can be found in Shopify's code base like:
#
# ```ruby
# class ShopScope < Component::TrustedIdScope[ShopIdentity::ShopId]
# ```
# or
# ```ruby
# class ApiClientEligibility < Struct.new(:api_client, :match_results, :shop)
# ```
module RuboCop
module Cop
module Sorbet
class ForbidSuperclassConstLiteral < RuboCop::Cop::Cop
MSG = "Superclasses must only contain constant literals"
def_node_matcher :not_lit_const_superclass?, <<-PATTERN
(class
(const ...)
(send ...)
...
)
PATTERN
def on_class(node)
return unless not_lit_const_superclass?(node)
add_offense(node.child_nodes[1])
end
end
end
end
end

View File

@ -1,53 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop ensures RBI shims do not include a call to extend T::Sig
# or to extend T::Helpers
#
# @example
#
# # bad
# module SomeModule
# extend T::Sig
# extend T::Helpers
#
# sig { returns(String) }
# def foo; end
# end
#
# # good
# module SomeModule
# sig { returns(String) }
# def foo; end
# end
class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Cop
include RangeHelp
MSG = "Extending T::Sig or T::Helpers in a shim is unnecessary"
RESTRICT_ON_SEND = [:extend]
def_node_matcher :extend_t_sig?, <<~PATTERN
(send nil? :extend (const (const nil? :T) :Sig))
PATTERN
def_node_matcher :extend_t_helpers?, <<~PATTERN
(send nil? :extend (const (const nil? :T) :Helpers))
PATTERN
def autocorrect(node)
-> (corrector) do
corrector.remove(
range_by_whole_lines(node.source_range, include_final_newline: true)
)
end
end
def on_send(node)
add_offense(node) if extend_t_helpers?(node) || extend_t_sig?(node)
end
end
end
end
end

View File

@ -1,59 +0,0 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows using `.override(allow_incompatible: true)`.
# Using `allow_incompatible` suggests a violation of the Liskov
# Substitution Principle, meaning that a subclass is not a valid
# subtype of it's superclass. This Cop prevents these design smells
# from occurring.
#
# @example
#
# # bad
# sig.override(allow_incompatible: true)
#
# # good
# sig.override
class AllowIncompatibleOverride < RuboCop::Cop::Cop
def_node_search(:sig?, <<-PATTERN)
(
send
nil?
:sig
...
)
PATTERN
def not_nil?(node)
!node.nil?
end
def_node_search(:allow_incompatible?, <<-PATTERN)
(pair (sym :allow_incompatible) (true))
PATTERN
def_node_matcher(:allow_incompatible_override?, <<-PATTERN)
(
send
[#not_nil? #sig?]
:override
[#not_nil? #allow_incompatible?]
)
PATTERN
def on_send(node)
return unless allow_incompatible_override?(node)
add_offense(
node.children[2],
message: "Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. "\
"Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`",
)
end
end
end
end
end

View File

@ -1,45 +0,0 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop ensures all constants used as `T.type_alias` are using CamelCase.
#
# @example
#
# # bad
# FOO_OR_BAR = T.type_alias { T.any(Foo, Bar) }
#
# # good
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
class TypeAliasName < RuboCop::Cop::Cop
MSG = "Type alias constant name should be in CamelCase"
def_node_matcher(:casgn_type_alias?, <<-PATTERN)
(casgn
_
_
(block
(send
(const nil? :T) :type_alias)
_
_
))
PATTERN
def on_casgn(node)
return unless casgn_type_alias?(node)
name = node.children[1]
# From https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/naming/class_and_module_camel_case.rb
return unless /_/.match?(name)
add_offense(node)
end
end
end
end
end

View File

@ -1,20 +0,0 @@
# frozen_string_literal: true
# The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
# See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
module RuboCop
module Sorbet
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
# bit of our configuration.
module Inject
def self.defaults!
path = CONFIG_DEFAULT.to_s
hash = ConfigLoader.send(:load_yaml_configuration, path)
config = Config.new(hash, path).tap(&:make_excludes_absolute)
puts "configuration from #{path}" if ConfigLoader.debug?
config = ConfigLoader.merge_with_default(config, path)
ConfigLoader.instance_variable_set(:@default_configuration, config)
end
end
end
end

View File

@ -120,7 +120,8 @@ Sorbet/HasSigil:
Description: 'Makes the Sorbet typed sigil mandatory in all files.'
Enabled: false
SuggestedStrictness: "false"
MinimumStrictness: "false"
MinimumStrictness: nil
ExactStrictness: nil
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
@ -141,6 +142,13 @@ Sorbet/IgnoreSigil:
- db/**/*.rb
- script/**/*
Sorbet/ImplicitConversionMethod:
Description: >-
This cop disallows declaring implicit conversion methods, as sorbet does
not support implicit conversion.
Enabled: false
VersionAdded: '<<next>>'
Sorbet/KeywordArgumentOrdering:
Description: >-
Enforces a compatible keyword arguments with Sorbet.
@ -151,6 +159,18 @@ Sorbet/KeywordArgumentOrdering:
Enabled: true
VersionAdded: 0.2.0
Sorbet/ObsoleteStrictMemoization:
Description: >-
This cop checks for the obsolete pattern for initializing instance variables that was required for older Sorbet
versions in `#typed: strict` files.
It's no longer required, as of Sorbet 0.5.10210
See https://sorbet.org/docs/type-assertions#put-type-assertions-behind-memoization
Enabled: true
VersionAdded: '0.7.1'
Safe: true
SafeAutoCorrect: true
Sorbet/OneAncestorPerLine:
Description: 'Enforces one ancestor per call to requires_ancestor'
Enabled: false
@ -235,7 +255,8 @@ Sorbet/ValidSigil:
Enabled: true
RequireSigilOnAllFiles: false
SuggestedStrictness: "false"
MinimumStrictness: "false"
MinimumStrictness: nil
ExactStrictness: nil
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"

View File

@ -0,0 +1,105 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Disallows binding the return value of `T.any`, `T.all`, `T.enum`
# to a constant directly. To bind the value, one must use `T.type_alias`.
#
# @example
#
# # bad
# FooOrBar = T.any(Foo, Bar)
#
# # good
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
class BindingConstantWithoutTypeAlias < RuboCop::Cop::Base
extend AutoCorrector
MSG = "It looks like you're trying to bind a type to a constant. " \
"To do this, you must alias the type using `T.type_alias`."
WITHOUT_BLOCK_MSG = "It looks like you're using the old `T.type_alias` syntax. " \
"`T.type_alias` now expects a block." \
'Run Sorbet with the options "--autocorrect --error-white-list=5043" ' \
"to automatically upgrade to the new syntax."
# @!method type_alias_without_block(node)
def_node_matcher :type_alias_without_block, <<~PATTERN
(send
(const {nil? cbase} :T)
:type_alias
$_
)
PATTERN
# @!method type_alias_with_block?(node)
def_node_matcher :type_alias_with_block?, <<~PATTERN
(block
(send
(const {nil? cbase} :T)
:type_alias)
...
)
PATTERN
# @!method requires_type_alias?(node)
def_node_matcher :requires_type_alias?, <<~PATTERN
(send
(const {nil? cbase} :T)
{
:all
:any
:class_of
:nilable
:noreturn
:proc
:self_type
:untyped
}
...
)
PATTERN
def on_casgn(node)
expression = node.expression
return if expression.nil? # multiple assignment
type_alias_without_block(expression) do |type|
return add_offense(expression, message: WITHOUT_BLOCK_MSG) do |corrector|
corrector.replace(expression, "T.type_alias { #{type.source} }")
end
end
return if type_alias_with_block?(expression)
requires_type_alias?(send_leaf(expression)) do
return add_offense(expression) do |corrector|
corrector.replace(expression, "T.type_alias { #{expression.source} }")
end
end
end
private
# Given nested send nodes, returns the leaf with explicit receiver.
#
# i.e. in Ruby
#
# a.b.c.d.e.f
# ^^^
#
# i.e. in AST
#
# (send (send (send (send (send (send nil :a) :b) :c) :d) :e) :f)
# ^^^^^^^^^^^^^^^^^^^^^^^
#
def send_leaf(node)
node = node.receiver while node&.receiver&.send_type?
node
end
end
end
end
end

View File

@ -3,7 +3,7 @@
module RuboCop
module Cop
module Sorbet
# This cop ensures that callback conditionals are bound to the right type
# Ensures that callback conditionals are bound to the right type
# so that they are type checked properly.
#
# Auto-correction is unsafe because other libraries define similar style callbacks as Rails, but don't always need
@ -32,16 +32,44 @@ module RuboCop
# true
# end
# end
class CallbackConditionalsBinding < RuboCop::Cop::Cop
class CallbackConditionalsBinding < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
CALLBACKS = [
:validate, :validates, :validates_with, :before_validation, :around_validation, :before_create,
:before_save, :before_destroy, :before_update, :after_create, :after_save, :after_destroy,
:after_update, :after_touch, :after_initialize, :after_find, :around_create, :around_save,
:around_destroy, :around_update, :before_commit, :after_commit, :after_create_commit,
:after_destroy_commit, :after_rollback, :after_save_commit, :after_update_commit,
:before_action, :prepend_before_action, :append_before_action, :around_action,
:prepend_around_action, :append_around_action, :after_action, :prepend_after_action,
:append_after_action
:validate,
:validates,
:validates_with,
:before_validation,
:around_validation,
:before_create,
:before_save,
:before_destroy,
:before_update,
:after_create,
:after_save,
:after_destroy,
:after_update,
:after_touch,
:after_initialize,
:after_find,
:around_create,
:around_save,
:around_destroy,
:around_update,
:before_commit,
:after_commit,
:after_create_commit,
:after_destroy_commit,
:after_rollback,
:after_save_commit,
:after_update_commit,
:before_action,
:prepend_before_action,
:append_before_action,
:around_action,
:prepend_around_action,
:append_around_action,
:after_action,
:prepend_after_action,
:append_after_action,
].freeze
def autocorrect(node)
@ -132,7 +160,7 @@ module RuboCop
unless block.source.include?("T.bind(self")
add_offense(
node,
message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})"
message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})",
)
end
end

View File

@ -5,7 +5,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows the calls that are used to get constants fom Strings
# Disallows the calls that are used to get constants fom Strings
# such as +constantize+, +const_get+, and +constants+.
#
# The goal of this cop is to make the code easier to statically analyze,
@ -33,18 +33,20 @@ module RuboCop
#
# # good
# { "User" => User }.fetch(class_name)
class ConstantsFromStrings < ::RuboCop::Cop::Cop
class ConstantsFromStrings < ::RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
# @!method constant_from_string?(node)
def_node_matcher(:constant_from_string?, <<-PATTERN)
(send _ {:constantize :constants :const_get} ...)
PATTERN
def on_send(node)
return unless constant_from_string?(node)
add_offense(
node,
location: :selector,
message: "Don't use `#{node.method_name}`, it makes the code harder to understand, less editor-friendly, " \
"and impossible to analyze. Replace `#{node.method_name}` with a case/when or a hash."
"and impossible to analyze. Replace `#{node.method_name}` with a case/when or a hash.",
)
end
end

View File

@ -3,34 +3,35 @@
require "rubocop"
# Correct `send` expressions in include statements by constant literals.
#
# Sorbet, the static checker, is not (yet) able to support constructs on the
# following form:
#
# ```ruby
# class MyClass
# include send_expr
# end
# ```
#
# Multiple occurences of this can be found in Shopify's code base like:
#
# ```ruby
# include Rails.application.routes.url_helpers
# ```
# or
# ```ruby
# include Polaris::Engine.helpers
# ```
module RuboCop
module Cop
module Sorbet
class ForbidIncludeConstLiteral < RuboCop::Cop::Cop
# Correct `send` expressions in include statements by constant literals.
#
# Sorbet, the static checker, is not (yet) able to support constructs on the
# following form:
#
# ```ruby
# class MyClass
# include send_expr
# end
# ```
#
# Multiple occurences of this can be found in Shopify's code base like:
#
# ```ruby
# include Rails.application.routes.url_helpers
# ```
# or
# ```ruby
# include Polaris::Engine.helpers
# ```
class ForbidIncludeConstLiteral < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
MSG = "Includes must only contain constant literals"
attr_accessor :used_names
# @!method not_lit_const_include?(node)
def_node_matcher :not_lit_const_include?, <<-PATTERN
(send nil? {:include :extend :prepend}
$_
@ -46,18 +47,21 @@ module RuboCop
return unless not_lit_const_include?(node) do |send_argument|
![:const, :self].include?(send_argument.type)
end
parent = node.parent
return unless parent
parent = parent.parent if [:begin, :block].include?(parent.type)
return unless [:module, :class, :sclass].include?(parent.type)
add_offense(node)
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(
node.source_range,
"T.unsafe(self).#{node.source}"
node,
"T.unsafe(self).#{node.source}",
)
end
end

View File

@ -0,0 +1,44 @@
# encoding: utf-8
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Correct superclass `send` expressions by constant literals.
#
# Sorbet, the static checker, is not (yet) able to support constructs on the
# following form:
#
# ```ruby
# class Foo < send_expr; end
# ```
#
# Multiple occurences of this can be found in Shopify's code base like:
#
# ```ruby
# class ShopScope < Component::TrustedIdScope[ShopIdentity::ShopId]
# ```
# or
# ```ruby
# class ApiClientEligibility < Struct.new(:api_client, :match_results, :shop)
# ```
class ForbidSuperclassConstLiteral < RuboCop::Cop::Base
MSG = "Superclasses must only contain constant literals"
# @!method dynamic_superclass?(node)
def_node_matcher :dynamic_superclass?, <<-PATTERN
(class (const ...) $(send ...) ...)
PATTERN
def on_class(node)
dynamic_superclass?(node) do |superclass|
add_offense(superclass)
end
end
end
end
end
end

View File

@ -5,7 +5,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows using `T.unsafe` anywhere.
# Disallows using `T.unsafe` anywhere.
#
# @example
#
@ -14,11 +14,15 @@ module RuboCop
#
# # good
# foo
class ForbidTUnsafe < RuboCop::Cop::Cop
class ForbidTUnsafe < RuboCop::Cop::Base
MSG = "Do not use `T.unsafe`."
RESTRICT_ON_SEND = [:unsafe].freeze
# @!method t_unsafe?(node)
def_node_matcher(:t_unsafe?, "(send (const nil? :T) :unsafe _)")
def on_send(node)
add_offense(node, message: "Do not use `T.unsafe`.") if t_unsafe?(node)
add_offense(node) if t_unsafe?(node)
end
end
end

View File

@ -5,7 +5,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows using `T.untyped` anywhere.
# Disallows using `T.untyped` anywhere.
#
# @example
#
@ -17,11 +17,15 @@ module RuboCop
# sig { params(my_argument: String).void }
# def foo(my_argument); end
#
class ForbidTUntyped < RuboCop::Cop::Cop
class ForbidTUntyped < RuboCop::Cop::Base
MSG = "Do not use `T.untyped`."
RESTRICT_ON_SEND = [:untyped].freeze
# @!method t_untyped?(node)
def_node_matcher(:t_untyped?, "(send (const nil? :T) :untyped)")
def on_send(node)
add_offense(node, message: "Do not use `T.untyped`.") if t_untyped?(node)
add_offense(node) if t_untyped?(node)
end
end
end

View File

@ -6,7 +6,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop disallows use of `T.untyped` or `T.nilable(T.untyped)`
# Disallows use of `T.untyped` or `T.nilable(T.untyped)`
# as a prop type for `T::Struct` or `T::ImmutableStruct`.
#
# @example
@ -22,38 +22,40 @@ module RuboCop
# const :foo, Integer
# prop :bar, T.nilable(String)
# end
class ForbidUntypedStructProps < RuboCop::Cop::Cop
class ForbidUntypedStructProps < RuboCop::Cop::Base
MSG = "Struct props cannot be T.untyped"
# @!method t_struct(node)
def_node_matcher :t_struct, <<~PATTERN
(const (const nil? :T) :Struct)
PATTERN
def_node_matcher :t_immutable_struct, <<~PATTERN
(const (const nil? :T) :ImmutableStruct)
(const (const nil? :T) {:Struct :ImmutableStruct})
PATTERN
# @!method t_untyped(node)
def_node_matcher :t_untyped, <<~PATTERN
(send (const nil? :T) :untyped)
PATTERN
# @!method t_nilable_untyped(node)
def_node_matcher :t_nilable_untyped, <<~PATTERN
(send (const nil? :T) :nilable {#t_untyped #t_nilable_untyped})
PATTERN
# @!method subclass_of_t_struct?(node)
def_node_matcher :subclass_of_t_struct?, <<~PATTERN
(class (const ...) {#t_struct #t_immutable_struct} ...)
(class (const ...) #t_struct ...)
PATTERN
# @!method untyped_props(node)
# Search for untyped prop/const declarations and capture their types
def_node_search :untyped_props, <<~PATTERN
(send nil? {:prop :const} _ {#t_untyped #t_nilable_untyped} ...)
(send nil? {:prop :const} _ ${#t_untyped #t_nilable_untyped} ...)
PATTERN
def on_class(node)
return unless subclass_of_t_struct?(node)
untyped_props(node).each do |untyped_prop|
add_offense(untyped_prop.child_nodes[1])
untyped_props(node).each do |prop_type|
add_offense(prop_type)
end
end
end

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Disallows declaring implicit conversion methods.
# Since Sorbet is a nominal (not structural) type system,
# implicit conversion is currently unsupported.
#
# @example
#
# # bad
# def to_str; end
#
# # good
# def to_str(x); end
#
# # bad
# def self.to_str; end
#
# # good
# def self.to_str(x); end
#
# # bad
# alias to_str to_s
#
# @see https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html
# @note Since the arity of aliased methods is not checked, false positives may result.
class ImplicitConversionMethod < RuboCop::Cop::Base
IMPLICIT_CONVERSION_METHODS = [:to_ary, :to_int, :to_hash, :to_str].freeze
MSG = "Avoid implicit conversion methods, as Sorbet does not support them. " \
"Explicity convert to the desired type instead."
RESTRICT_ON_SEND = [:alias_method].freeze
def on_alias(node)
new_id = node.new_identifier
add_offense(new_id) if IMPLICIT_CONVERSION_METHODS.include?(new_id.value)
end
def on_def(node)
return unless IMPLICIT_CONVERSION_METHODS.include?(node.method_name)
return unless node.arguments.empty?
add_offense(node)
end
alias_method :on_defs, :on_def
def on_send(node)
add_offense(node.first_argument) if IMPLICIT_CONVERSION_METHODS.include?(node.first_argument.value)
end
end
end
end
end

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
module TargetSorbetVersion
class << self
def included(target)
target.extend(ClassMethods)
end
end
module ClassMethods
# The version of the Sorbet static type checker required by this cop
def minimum_target_sorbet_static_version(version)
@minimum_target_sorbet_static_version = Gem::Version.new(version)
end
def support_target_sorbet_static_version?(version)
@minimum_target_sorbet_static_version <= Gem::Version.new(version)
end
end
def enabled_for_sorbet_static_version?
sorbet_static_version = target_sorbet_static_version_from_bundler_lock_file
return false unless sorbet_static_version
self.class.support_target_sorbet_static_version?(sorbet_static_version)
end
def target_sorbet_static_version_from_bundler_lock_file
# Do memoization with the `defined?` pattern since sorbet-static version might be `nil`
if defined?(@target_sorbet_static_version_from_bundler_lock_file)
@target_sorbet_static_version_from_bundler_lock_file
else
@target_sorbet_static_version_from_bundler_lock_file = read_sorbet_static_version_from_bundler_lock_file
end
end
def read_sorbet_static_version_from_bundler_lock_file
require "bundler"
::Bundler.locked_gems.specs.find { |spec| spec.name == "sorbet-static" }&.version
rescue LoadError, Bundler::GemfileNotFound
nil
end
end
end
end
end

View File

@ -6,10 +6,13 @@ module RuboCop
module Cop
module Sorbet
module MutableConstantSorbetAwareBehaviour
def self.prepended(base)
base.def_node_matcher(:t_let, <<~PATTERN)
(send (const nil? :T) :let $_constant _type)
PATTERN
class << self
def prepended(base)
# @!method t_let(node)
base.def_node_matcher(:t_let, <<~PATTERN)
(send (const nil? :T) :let $_constant _type)
PATTERN
end
end
def on_assignment(value)
@ -25,5 +28,5 @@ module RuboCop
end
RuboCop::Cop::Style::MutableConstant.prepend(
RuboCop::Cop::Sorbet::MutableConstantSorbetAwareBehaviour
RuboCop::Cop::Sorbet::MutableConstantSorbetAwareBehaviour,
)

View File

@ -0,0 +1,92 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Checks for the obsolete pattern for initializing instance variables that was required for older Sorbet
# versions in `#typed: strict` files.
#
# It's no longer required, as of Sorbet 0.5.10210
# See https://sorbet.org/docs/type-assertions#put-type-assertions-behind-memoization
#
# @example
#
# # bad
# sig { returns(Foo) }
# def foo
# @foo = T.let(@foo, T.nilable(Foo))
# @foo ||= Foo.new
# end
#
# # bad
# sig { returns(Foo) }
# def foo
# # This would have been a mistake, causing the memoized value to be discarded and recomputed on every call.
# @foo = T.let(nil, T.nilable(Foo))
# @foo ||= Foo.new
# end
#
# # good
# sig { returns(Foo) }
# def foo
# @foo ||= T.let(Foo.new, T.nilable(Foo))
# end
#
class ObsoleteStrictMemoization < RuboCop::Cop::Base
include RuboCop::Cop::MatchRange
include RuboCop::Cop::Alignment
include RuboCop::Cop::LineLengthHelp
include RuboCop::Cop::RangeHelp
extend AutoCorrector
include TargetSorbetVersion
minimum_target_sorbet_static_version "0.5.10210"
MSG = "This two-stage workaround for memoization in `#typed: strict` files is no longer necessary. " \
"See https://sorbet.org/docs/type-assertions#put-type-assertions-behind-memoization."
# @!method legacy_memoization_pattern?(node)
def_node_matcher :legacy_memoization_pattern?, <<~PATTERN
(begin
... # Ignore any other lines that come first.
$(ivasgn $_ivar # First line: @_ivar = ...
(send # T.let(_ivar, T.nilable(_ivar_type))
$(const {nil? cbase} :T) :let
{(ivar _ivar) nil}
(send (const {nil? cbase} :T) :nilable $_ivar_type))) # T.nilable(_ivar_type)
$(or-asgn (ivasgn _ivar) $_initialization_expr)) # Second line: @_ivar ||= _initialization_expr
PATTERN
def on_begin(node)
legacy_memoization_pattern?(node) do |first_asgn_node, ivar, t, ivar_type, second_or_asgn_node, init_expr| # rubocop:disable Metrics/ParameterLists
add_offense(first_asgn_node) do |corrector|
indent = offset(node)
correction = "#{ivar} ||= #{t.source}.let(#{init_expr.source}, #{t.source}.nilable(#{ivar_type.source}))"
# We know good places to put line breaks, if required.
if line_length(indent + correction) > max_line_length || correction.include?("\n")
correction = <<~RUBY.chomp
#{ivar} ||= #{t.source}.let(
#{indent} #{init_expr.source.gsub("\n", "\n#{indent}")},
#{indent} #{t.source}.nilable(#{ivar_type.source.gsub("\n", "\n#{indent}")}),
#{indent})
RUBY
end
corrector.replace(
range_between(first_asgn_node.source_range.begin_pos, second_or_asgn_node.source_range.end_pos),
correction,
)
end
end
end
def relevant_file?(file)
super && enabled_for_sorbet_static_version?
end
end
end
end
end

View File

@ -6,7 +6,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop ensures one ancestor per requires_ancestor line
# Ensures one ancestor per requires_ancestor line
# rather than chaining them as a comma-separated list.
#
# @example
@ -21,17 +21,20 @@ module RuboCop
# requires_ancestor Kernel
# requires_ancestor Minitest::Assertions
# end
class OneAncestorPerLine < RuboCop::Cop::Cop
class OneAncestorPerLine < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
MSG = "Cannot require more than one ancestor per line"
# @!method requires_ancestors(node)
def_node_search :requires_ancestors, <<~PATTERN
(send nil? :requires_ancestor ...)
PATTERN
# @!method more_than_one_ancestor(node)
def_node_matcher :more_than_one_ancestor, <<~PATTERN
(send nil? :requires_ancestor const const+)
PATTERN
# @!method abstract?(node)
def_node_search :abstract?, <<~PATTERN
(send nil? :abstract!)
PATTERN
@ -39,17 +42,19 @@ module RuboCop
def on_module(node)
return unless node.body
return unless requires_ancestors(node)
process_node(node)
end
def on_class(node)
return unless abstract?(node)
return unless requires_ancestors(node)
process_node(node)
end
def autocorrect(node)
-> (corrector) do
->(corrector) do
ra_call = node.parent
split_ra_calls = ra_call.source.gsub(/,\s+/, new_ra_line(ra_call.loc.column))
corrector.replace(ra_call, split_ra_calls)

View File

@ -0,0 +1,47 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# Ensures RBI shims do not include a call to extend T::Sig
# or to extend T::Helpers
#
# @example
#
# # bad
# module SomeModule
# extend T::Sig
# extend T::Helpers
#
# sig { returns(String) }
# def foo; end
# end
#
# # good
# module SomeModule
# sig { returns(String) }
# def foo; end
# end
class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Base
extend AutoCorrector
include RangeHelp
MSG = "Extending T::Sig or T::Helpers in a shim is unnecessary"
RESTRICT_ON_SEND = [:extend].freeze
# @!method extend_t_sig_or_helpers?(node)
def_node_matcher :extend_t_sig_or_helpers?, <<~PATTERN
(send nil? :extend (const (const nil? :T) {:Sig :Helpers}))
PATTERN
def on_send(node)
extend_t_sig_or_helpers?(node) do
add_offense(node) do |corrector|
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
end
end
end
end
end
end
end

View File

@ -5,7 +5,7 @@ require "pathname"
module RuboCop
module Cop
module Sorbet
# This cop makes sure that RBI files are always located under the defined allowed paths.
# Makes sure that RBI files are always located under the defined allowed paths.
#
# Options:
#
@ -20,7 +20,7 @@ module RuboCop
# # rbi/external_interface.rbi
# # sorbet/rbi/some_file.rbi
# # sorbet/rbi/any/path/for/file.rbi
class ForbidRBIOutsideOfAllowedPaths < RuboCop::Cop::Cop
class ForbidRBIOutsideOfAllowedPaths < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
include RangeHelp
def investigate(processed_source)
@ -30,14 +30,14 @@ module RuboCop
add_offense(
nil,
location: source_range(processed_source.buffer, 1, 0),
message: "AllowedPaths expects an array"
message: "AllowedPaths expects an array",
)
return
elsif paths.empty?
add_offense(
nil,
location: source_range(processed_source.buffer, 1, 0),
message: "AllowedPaths cannot be empty"
message: "AllowedPaths cannot be empty",
)
return
end
@ -49,15 +49,16 @@ module RuboCop
add_offense(
nil,
location: source_range(processed_source.buffer, 1, 0),
message: "RBI file path should match one of: #{paths.join(", ")}"
message: "RBI file path should match one of: #{paths.join(", ")}",
) if paths.none? { |pattern| File.fnmatch(pattern, rel_path) }
end
private
def allowed_paths
paths = cop_config["AllowedPaths"]
return nil unless paths.is_a?(Array)
paths = cop_config["AllowedPaths"] # rubocop:todo InternalAffairs/UndefinedConfig
return unless paths.is_a?(Array)
paths.compact
end
end

View File

@ -3,7 +3,7 @@
module RuboCop
module Cop
module Sorbet
# This cop ensures empty class/module definitions in RBI files are
# Ensures empty class/module definitions in RBI files are
# done on a single line rather than being split across multiple lines.
#
# @example
@ -14,31 +14,25 @@ module RuboCop
#
# # good
# module SomeModule; end
class SingleLineRbiClassModuleDefinitions < RuboCop::Cop::Cop
class SingleLineRbiClassModuleDefinitions < RuboCop::Cop::Base
extend AutoCorrector
MSG = "Empty class/module definitions in RBI files should be on a single line."
def on_module(node)
process_node(node)
end
def on_class(node)
process_node(node)
end
def autocorrect(node)
-> (corrector) { corrector.replace(node, convert_newlines(node.source)) }
end
protected
def convert_newlines(source)
source.sub(/[\r\n]+\s*[\r\n]*/, "; ")
end
def process_node(node)
return if node.body
return if node.single_line?
add_offense(node)
add_offense(node) do |corrector|
corrector.replace(node, convert_newlines_to_semicolons(node.source))
end
end
alias_method :on_class, :on_module
private
def convert_newlines_to_semicolons(source)
source.sub(/[\r\n]+\s*[\r\n]*/, "; ")
end
end
end

View File

@ -25,10 +25,13 @@ module RuboCop
# def no_op; end
# end
#
class RedundantExtendTSig < RuboCop::Cop::Cop
class RedundantExtendTSig < RuboCop::Cop::Base
extend AutoCorrector
MSG = "Do not redundantly `extend T::Sig` when it is already included in all modules."
RESTRICT_ON_SEND = [:extend].freeze
# @!method extend_t_sig?(node)
def_node_matcher :extend_t_sig?, <<~PATTERN
(send _ :extend (const (const {nil? | cbase} :T) :Sig))
PATTERN
@ -36,11 +39,7 @@ module RuboCop
def on_send(node)
return unless extend_t_sig?(node)
add_offense(node)
end
def autocorrect(node)
lambda do |corrector|
add_offense(node) do |corrector|
corrector.remove(node)
end
end

View File

@ -5,7 +5,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop checks that the Sorbet sigil comes as the first magic comment in the file.
# Checks that the Sorbet sigil comes as the first magic comment in the file.
#
# The expected order for magic comments is: (en)?coding, typed, warn_indent then frozen_string_literal.
#
@ -57,6 +57,7 @@ module RuboCop
(lines.min...lines.max).each do |line|
next if lines.include?(line)
next unless processed_source[line - 1].empty?
corrector.remove(source_range(processed_source.buffer, line, 0))
end
end
@ -104,7 +105,7 @@ module RuboCop
add_offense(
token,
location: token.pos,
message: "Magic comments should be in the following order: #{PREFERRED_ORDER.values.join(", ")}."
message: "Magic comments should be in the following order: #{PREFERRED_ORDER.values.join(", ")}.",
)
end
end

View File

@ -3,7 +3,7 @@
module RuboCop
module Cop
module Sorbet
# This cop checks that there is only one Sorbet sigil in a given file
# Checks that there is only one Sorbet sigil in a given file
#
# For example, the following class with two sigils
#
@ -28,8 +28,9 @@ module RuboCop
def investigate(processed_source)
return if processed_source.tokens.empty?
sigils = extract_all_sigils(processed_source)
return unless sigils.size > 1
return if sigils.empty?
sigils[1..sigils.size].each do |token|
add_offense(token, location: token.pos, message: "Files must only contain one sigil")
@ -37,14 +38,14 @@ module RuboCop
end
def autocorrect(_node)
-> (corrector) do
->(corrector) do
sigils = extract_all_sigils(processed_source)
return unless sigils.size > 1
return if sigils.empty?
# The first sigil encountered represents the "real" strictness so remove any below
sigils[1..sigils.size].each do |token|
corrector.remove(
source_range(processed_source.buffer, token.line, (0..token.pos.last_column))
source_range(processed_source.buffer, token.line, (0..token.pos.last_column)),
)
end
end

View File

@ -6,7 +6,7 @@ require_relative "has_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet `false` sigil mandatory in all files.
# Makes the Sorbet `false` sigil mandatory in all files.
class FalseSigil < HasSigil
def minimum_strictness
"false"

View File

@ -6,7 +6,7 @@ require_relative "valid_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet typed sigil mandatory in all files.
# Makes the Sorbet typed sigil mandatory in all files.
#
# Options:
#

View File

@ -6,7 +6,7 @@ require_relative "has_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet `ignore` sigil mandatory in all files.
# Makes the Sorbet `ignore` sigil mandatory in all files.
class IgnoreSigil < HasSigil
def minimum_strictness
"ignore"

View File

@ -6,7 +6,7 @@ require_relative "has_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet `strict` sigil mandatory in all files.
# Makes the Sorbet `strict` sigil mandatory in all files.
class StrictSigil < HasSigil
def minimum_strictness
"strict"

View File

@ -6,7 +6,7 @@ require_relative "has_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet `strong` sigil mandatory in all files.
# Makes the Sorbet `strong` sigil mandatory in all files.
class StrongSigil < HasSigil
def minimum_strictness
"strong"

View File

@ -6,7 +6,7 @@ require_relative "has_sigil"
module RuboCop
module Cop
module Sorbet
# This cop makes the Sorbet `true` sigil mandatory in all files.
# Makes the Sorbet `true` sigil mandatory in all files.
class TrueSigil < HasSigil
def minimum_strictness
"true"

View File

@ -5,7 +5,7 @@ require "rubocop"
module RuboCop
module Cop
module Sorbet
# This cop checks that every Ruby file contains a valid Sorbet sigil.
# Checks that every Ruby file contains a valid Sorbet sigil.
# Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
#
# Options:
@ -13,9 +13,11 @@ module RuboCop
# * `RequireSigilOnAllFiles`: make offense if the Sorbet typed is not found in the file (default: false)
# * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
# * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
# * `ExactStrictness`: If set, make offense if the strictness level in the file is different than this one
#
# If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
class ValidSigil < RuboCop::Cop::Cop
# If an `ExactStrictness` level is specified, it will be used in offense messages and autocorrect.
# Otherwise, if a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
class ValidSigil < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
@registry = Cop.registry # So we can properly subclass this cop
def investigate(processed_source)
@ -36,7 +38,7 @@ module RuboCop
return unless extract_sigil(processed_source).nil?
token = processed_source.tokens.first
replace_with = suggested_strictness_level(minimum_strictness, suggested_strictness)
replace_with = suggested_strictness_level
sigil = "# typed: #{replace_with}"
if token.text.start_with?("#!") # shebang line
corrector.insert_after(token.pos, "\n#{sigil}")
@ -49,7 +51,7 @@ module RuboCop
protected
STRICTNESS_LEVELS = ["ignore", "false", "true", "strict", "strong"]
SIGIL_REGEX = /^\s*#\s+typed:(?:\s+([\w]+))?/
SIGIL_REGEX = /^[[:blank:]]*#[[:blank:]]+typed:(?:[[:blank:]]+([\S]+))?/
# extraction
@ -70,34 +72,37 @@ module RuboCop
token = processed_source.tokens.first
if require_sigil_on_all_files?
strictness = suggested_strictness_level(minimum_strictness, suggested_strictness)
strictness = suggested_strictness_level
add_offense(
token,
location: token.pos,
message: "No Sorbet sigil found in file. " \
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this).",
)
end
false
end
def suggested_strictness_level(minimum_strictness, suggested_strictness)
def suggested_strictness_level
return exact_strictness if exact_strictness
# if no minimum strictness is set (eg. using Sorbet/HasSigil without config) then
# we always use the suggested strictness which defaults to `false`
return suggested_strictness unless minimum_strictness
# special case: if you're using Sorbet/IgnoreSigil without config, we should recommend `ignore`
return "ignore" if minimum_strictness == "ignore" && cop_config["SuggestedStrictness"].nil?
return "ignore" if minimum_strictness == "ignore" && cop_config["SuggestedStrictness"].nil? # rubocop:todo InternalAffairs/UndefinedConfig
# if a minimum strictness is set (eg. you're using Sorbet/FalseSigil)
# we want to compare the minimum strictness and suggested strictness. this is because
# the suggested strictness might be higher than the minimum (eg. if you want all new files
# at a higher strictness level, without having to migrate existing files at lower levels).
suggested_level = STRICTNESS_LEVELS.index(suggested_strictness)
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
levels = [
STRICTNESS_LEVELS.index(suggested_strictness),
STRICTNESS_LEVELS.index(minimum_strictness),
]
suggested_level > minimum_level ? suggested_strictness : minimum_strictness
STRICTNESS_LEVELS[levels.compact.max]
end
def check_strictness_not_empty(sigil, strictness)
@ -106,7 +111,7 @@ module RuboCop
add_offense(
sigil,
location: sigil.pos,
message: "Sorbet sigil should not be empty."
message: "Sorbet sigil should not be empty.",
)
false
end
@ -117,24 +122,38 @@ module RuboCop
add_offense(
sigil,
location: sigil.pos,
message: "Invalid Sorbet sigil `#{strictness}`."
message: "Invalid Sorbet sigil `#{strictness}`.",
)
false
end
def check_strictness_level(sigil, strictness)
return true unless minimum_strictness
return true if !minimum_strictness && !exact_strictness
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
current_level = STRICTNESS_LEVELS.index(strictness)
if current_level < minimum_level
add_offense(
sigil,
location: sigil.pos,
message: "Sorbet sigil should be at least `#{minimum_strictness}` got `#{strictness}`."
)
return false
if exact_strictness
exact_level = STRICTNESS_LEVELS.index(exact_strictness)
if current_level != exact_level
add_offense(
sigil,
location: sigil.pos,
message: "Sorbet sigil should be `#{exact_strictness}` got `#{strictness}`.",
)
return false
end
else
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
if current_level < minimum_level
add_offense(
sigil,
location: sigil.pos,
message: "Sorbet sigil should be at least `#{minimum_strictness}` got `#{strictness}`.",
)
return false
end
end
true
end
@ -142,18 +161,24 @@ module RuboCop
# Default is `false`
def require_sigil_on_all_files?
!!cop_config["RequireSigilOnAllFiles"]
!!cop_config["RequireSigilOnAllFiles"] # rubocop:todo InternalAffairs/UndefinedConfig
end
# Default is `'false'`
def suggested_strictness
config = cop_config["SuggestedStrictness"].to_s
config = cop_config["SuggestedStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
STRICTNESS_LEVELS.include?(config) ? config : "false"
end
# Default is `nil`
def minimum_strictness
config = cop_config["MinimumStrictness"].to_s
config = cop_config["MinimumStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
config if STRICTNESS_LEVELS.include?(config)
end
# Default is `nil`
def exact_strictness
config = cop_config["ExactStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
config if STRICTNESS_LEVELS.include?(config)
end
end

View File

@ -0,0 +1,76 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Disallows using `.override(allow_incompatible: true)`.
# Using `allow_incompatible` suggests a violation of the Liskov
# Substitution Principle, meaning that a subclass is not a valid
# subtype of its superclass. This Cop prevents these design smells
# from occurring.
#
# @example
#
# # bad
# sig.override(allow_incompatible: true)
#
# # good
# sig.override
class AllowIncompatibleOverride < RuboCop::Cop::Base
MSG = "Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. " \
"Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`"
RESTRICT_ON_SEND = [:override].freeze
# @!method sig_dot_override?(node)
def_node_matcher(:sig_dot_override?, <<~PATTERN)
(send
[!nil? #sig?]
:override
(hash <$(pair (sym :allow_incompatible) true) ...>)
)
PATTERN
# @!method sig?(node)
def_node_search(:sig?, <<~PATTERN)
(send _ :sig ...)
PATTERN
# @!method override?(node)
def_node_matcher(:override?, <<~PATTERN)
(send
_
:override
(hash <$(pair (sym :allow_incompatible) true) ...>)
)
PATTERN
def on_send(node)
sig_dot_override?(node) do |allow_incompatible_pair|
add_offense(allow_incompatible_pair)
end
end
def on_block(node)
return unless sig?(node.send_node)
block = node.children.last
return unless block.send_type?
receiver = block.receiver
while receiver
allow_incompatible_pair = override?(receiver)
if allow_incompatible_pair
add_offense(allow_incompatible_pair)
break
end
receiver = receiver.receiver
end
end
alias_method :on_numblock, :on_block
end
end
end
end

View File

@ -6,7 +6,7 @@ require_relative "signature_cop"
module RuboCop
module Cop
module Sorbet
# This cop disallows the usage of `checked(true)`. This usage could cause
# Disallows the usage of `checked(true)`. This usage could cause
# confusion; it could lead some people to believe that a method would be checked
# even if runtime checks have not been enabled on the class or globally.
# Additionally, in the event where checks are enabled, `checked(true)` would
@ -22,6 +22,7 @@ module RuboCop
class CheckedTrueInSignature < SignatureCop
include(RuboCop::Cop::RangeHelp)
# @!method offending_node(node)
def_node_search(:offending_node, <<~PATTERN)
(send _ :checked (true))
PATTERN
@ -44,7 +45,7 @@ module RuboCop
error.location.line,
(error.location.selector.begin_pos)..(error.location.end.begin_pos),
),
message: MESSAGE
message: MESSAGE,
)
end
end

View File

@ -5,7 +5,7 @@ require_relative "signature_cop"
module RuboCop
module Cop
module Sorbet
# This cop checks for blank lines after signatures.
# Checks for blank lines after signatures.
#
# It also suggests an autocorrect
#
@ -31,10 +31,10 @@ module RuboCop
end
def autocorrect(node)
-> (corrector) do
->(corrector) do
offending_range = node.source_range.with(
begin_pos: node.source_range.end_pos + 1,
end_pos: processed_source.buffer.line_range(next_method(node).line).begin_pos
end_pos: processed_source.buffer.line_range(next_method(node).line).begin_pos,
)
corrector.remove(offending_range)
clean_range = offending_range.source.split("\n").reject(&:empty?).join("\n")

View File

@ -7,7 +7,7 @@ require_relative "signature_cop"
module RuboCop
module Cop
module Sorbet
# This cop checks that every method definition and attribute accessor has a Sorbet signature.
# Checks that every method definition and attribute accessor has a Sorbet signature.
#
# It also suggest an autocorrect with placeholders so the following code:
#
@ -32,6 +32,7 @@ module RuboCop
@last_sig_for_scope = {}
end
# @!method accessor?(node)
def_node_matcher(:accessor?, <<-PATTERN)
(send nil? {:attr_reader :attr_writer :attr_accessor} ...)
PATTERN
@ -67,13 +68,14 @@ module RuboCop
suggest.returns = "void" if method == :attr_writer
end
corrector.insert_before(node.loc.expression, suggest.to_autocorrect)
corrector.insert_before(node, suggest.to_autocorrect)
end
end
def scope(node)
return nil unless node.parent
return unless node.parent
return node.parent if [:begin, :block, :class, :module].include?(node.parent.type)
scope(node.parent)
end
@ -84,7 +86,7 @@ module RuboCop
unless @last_sig_for_scope[scope]
add_offense(
node,
message: "Each method is required to have a signature."
message: "Each method is required to have a signature.",
)
end
@last_sig_for_scope[scope] = nil
@ -123,6 +125,7 @@ module RuboCop
def generate_params
return if @params.empty?
out = StringIO.new
out << "params("
out << @params.map do |param|
@ -135,6 +138,7 @@ module RuboCop
def generate_return
return "returns(#{@return_placeholder})" if @returns.nil?
return @returns if @returns == "void"
"returns(#{@returns})"
end
end

View File

@ -6,7 +6,7 @@ require_relative "signature_cop"
module RuboCop
module Cop
module Sorbet
# This cop checks for the ordering of keyword arguments required by
# Checks for the ordering of keyword arguments required by
# sorbet-runtime. The ordering requires that all keyword arguments
# are at the end of the parameters list, and all keyword arguments
# with a default value must be after those without default values.
@ -24,6 +24,7 @@ module RuboCop
def on_signature(node)
method_node = node.parent.children[node.sibling_index + 1]
return if method_node.nil?
method_parameters = method_node.arguments
check_order_for_kwoptargs(method_parameters)
@ -35,13 +36,13 @@ module RuboCop
out_of_kwoptarg = false
parameters.reverse.each do |param|
out_of_kwoptarg = true unless param.type == :kwoptarg || param.type == :blockarg || param.type == :kwrestarg
out_of_kwoptarg = true unless param.kwoptarg_type? || param.blockarg_type? || param.kwrestarg_type?
next unless param.type == :kwoptarg && out_of_kwoptarg
next unless param.kwoptarg_type? && out_of_kwoptarg
add_offense(
param,
message: "Optional keyword arguments must be at the end of the parameter list."
message: "Optional keyword arguments must be at the end of the parameter list.",
)
end
end

View File

@ -27,13 +27,18 @@ module RuboCop
:on_failure,
].each_with_index.to_h.freeze
# @!method root_call(node)
def_node_search(:root_call, <<~PATTERN)
(send nil? {#{ORDER.keys.map(&:inspect).join(" ")}} ...)
PATTERN
def on_signature(node)
calls = call_chain(node.children[2]).map(&:method_name)
return unless calls.any?
return if calls.empty?
# While the developer is typing, we may have an incomplete call statement, which means `ORDER[call]` will
# return `nil`. In that case, invoking `sort_by` will raise
return if calls.any? { |call| ORDER[call].nil? }
expected_order = calls.sort_by { |call| ORDER[call] }
return if expected_order == calls
@ -52,7 +57,7 @@ module RuboCop
end
def autocorrect(node)
return nil unless can_autocorrect?
return unless can_autocorrect?
lambda do |corrector|
tree = call_chain(node_reparsed_with_modern_features(node))
@ -62,7 +67,7 @@ module RuboCop
end
corrector.replace(
node.source_range,
node,
Unparser.unparse(tree),
)
end

View File

@ -8,9 +8,10 @@ module RuboCop
# Abstract cop specific to Sorbet signatures
#
# You can subclass it to use the `on_signature` trigger and the `signature?` node matcher.
class SignatureCop < RuboCop::Cop::Cop
class SignatureCop < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
@registry = Cop.registry # So we can properly subclass this cop
# @!method signature?(node)
def_node_matcher(:signature?, <<~PATTERN)
(block (send
{nil? #with_runtime? #without_runtime?}
@ -19,10 +20,12 @@ module RuboCop
) (args) ...)
PATTERN
# @!method with_runtime?(node)
def_node_matcher(:with_runtime?, <<~PATTERN)
(const (const nil? :T) :Sig)
PATTERN
# @!method without_runtime?(node)
def_node_matcher(:without_runtime?, <<~PATTERN)
(const (const (const nil? :T) :Sig) :WithoutRuntime)
PATTERN
@ -31,6 +34,8 @@ module RuboCop
on_signature(node) if signature?(node)
end
alias_method :on_numblock, :on_block
def on_signature(_)
# To be defined in subclasses
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require "rubocop"
module RuboCop
module Cop
module Sorbet
# Ensures all constants used as `T.type_alias` are using CamelCase.
#
# @example
#
# # bad
# FOO_OR_BAR = T.type_alias { T.any(Foo, Bar) }
#
# # good
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
class TypeAliasName < RuboCop::Cop::Base
MSG = "Type alias constant name should be in CamelCase"
# @!method underscored_type_alias?(node)
def_node_matcher(:underscored_type_alias?, <<-PATTERN)
(casgn
_
/_/ # Name matches underscore
(block
(send (const nil? :T) :type_alias)
...
)
)
PATTERN
def on_casgn(node)
add_offense(node) if underscored_type_alias?(node)
end
end
end
end
end

View File

@ -1,15 +1,20 @@
# frozen_string_literal: true
require_relative "sorbet/binding_constants_without_type_alias"
require_relative "sorbet/mixin/target_sorbet_version.rb"
require_relative "sorbet/binding_constant_without_type_alias"
require_relative "sorbet/constants_from_strings"
require_relative "sorbet/forbid_superclass_const_literal"
require_relative "sorbet/forbid_include_const_literal"
require_relative "sorbet/forbid_untyped_struct_props"
require_relative "sorbet/implicit_conversion_method"
require_relative "sorbet/one_ancestor_per_line"
require_relative "sorbet/callback_conditionals_binding"
require_relative "sorbet/forbid_t_unsafe"
require_relative "sorbet/forbid_t_untyped"
require_relative "sorbet/redundant_extend_t_sig"
require_relative "sorbet/type_alias_name"
require_relative "sorbet/obsolete_strict_memoization"
require_relative "sorbet/rbi/forbid_extend_t_sig_helpers_in_shims"
require_relative "sorbet/rbi/forbid_rbi_outside_of_allowed_paths"

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
# The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
# See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
module RuboCop
module Sorbet
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
# bit of our configuration.
module Inject
class << self
def defaults!
path = CONFIG_DEFAULT.to_s
hash = ConfigLoader.send(:load_yaml_configuration, path)
config = Config.new(hash, path).tap(&:make_excludes_absolute)
puts "configuration from #{path}" if ConfigLoader.debug?
config = ConfigLoader.merge_with_default(config, path)
ConfigLoader.instance_variable_set(:@default_configuration, config)
end
end
end
end
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
module RuboCop
module Sorbet
VERSION = "0.7.0"
VERSION = "0.7.3"
end
end