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:
commit
c953076609
@ -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)
|
||||
|
||||
@ -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) }
|
||||
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
||||
@ -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!
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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}"
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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,
|
||||
)
|
||||
@ -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
|
||||
@ -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)
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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"
|
||||
@ -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:
|
||||
#
|
||||
@ -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"
|
||||
@ -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"
|
||||
@ -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"
|
||||
@ -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"
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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")
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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"
|
||||
@ -1,4 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rubocop/sorbet/version"
|
||||
require "yaml"
|
||||
|
||||
22
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.7.3/lib/rubocop/sorbet/inject.rb
vendored
Normal file
22
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.7.3/lib/rubocop/sorbet/inject.rb
vendored
Normal 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
|
||||
@ -1,6 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Sorbet
|
||||
VERSION = "0.7.0"
|
||||
VERSION = "0.7.3"
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user