Merge pull request #12516 from Homebrew/dependabot/bundler/Library/Homebrew/rubocop-sorbet-0.6.3

build(deps): bump rubocop-sorbet from 0.6.2 to 0.6.3 in /Library/Homebrew
This commit is contained in:
Mike McQuaid 2021-12-06 10:03:31 +00:00 committed by GitHub
commit dbec9de77e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 740 additions and 394 deletions

View File

@ -404,6 +404,9 @@ Sorbet/FalseSigil:
- "Homebrew/test/**/Casks/**/*.rb"
Sorbet/StrictSigil:
inherit_mode:
override:
- Include
Enabled: true
Include:
- "**/*.rbi"

View File

@ -144,8 +144,8 @@ GEM
rubocop (>= 1.7.0, < 2.0)
rubocop-rspec (2.6.0)
rubocop (~> 1.19)
rubocop-sorbet (0.6.2)
rubocop
rubocop-sorbet (0.6.3)
rubocop (>= 0.90.0)
ruby-macho (2.5.1)
ruby-progressbar (1.11.0)
rubyntlm (0.6.3)

View File

@ -1,9 +1,9 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `rubocop-sorbet` gem.
# Please instead update this file by running `bin/tapioca gem rubocop-sorbet`.
# typed: true
module RuboCop; end
module RuboCop::Cop; end
module RuboCop::Cop::Sorbet; end
@ -76,10 +76,10 @@ class RuboCop::Cop::Sorbet::EnforceSignatures < ::RuboCop::Cop::Sorbet::Signatur
def accessor?(param0 = T.unsafe(nil)); end
def autocorrect(node); end
def on_block(node); end
def on_def(node); end
def on_defs(node); end
def on_send(node); end
def on_signature(node); end
def scope(node); end
private
@ -104,6 +104,17 @@ class RuboCop::Cop::Sorbet::EnforceSignatures::SigSuggestion
def generate_return; end
end
class RuboCop::Cop::Sorbet::EnforceSingleSigil < ::RuboCop::Cop::Sorbet::ValidSigil
include ::RuboCop::Cop::RangeHelp
def autocorrect(_node); end
def investigate(processed_source); end
protected
def extract_all_sigils(processed_source); end
end
class RuboCop::Cop::Sorbet::FalseSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end
end
@ -123,6 +134,7 @@ RuboCop::Cop::Sorbet::ForbidExtendTSigHelpersInShims::RESTRICT_ON_SEND = T.let(T
class RuboCop::Cop::Sorbet::ForbidIncludeConstLiteral < ::RuboCop::Cop::Cop
def initialize(*_arg0); end
def autocorrect(node); end
def not_lit_const_include?(param0 = T.unsafe(nil)); end
def on_send(node); end
def used_names; end
@ -131,13 +143,16 @@ end
RuboCop::Cop::Sorbet::ForbidIncludeConstLiteral::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::ForbidRBIOutsideOfSorbetDir < ::RuboCop::Cop::Cop
class RuboCop::Cop::Sorbet::ForbidRBIOutsideOfAllowedPaths < ::RuboCop::Cop::Cop
include ::RuboCop::Cop::RangeHelp
def investigate(processed_source); end
end
RuboCop::Cop::Sorbet::ForbidRBIOutsideOfSorbetDir::PATH_REGEXP = T.let(T.unsafe(nil), Regexp)
private
def allowed_paths; end
def message; end
end
class RuboCop::Cop::Sorbet::ForbidSuperclassConstLiteral < ::RuboCop::Cop::Cop
def not_lit_const_superclass?(param0 = T.unsafe(nil)); end
@ -194,16 +209,6 @@ end
RuboCop::Cop::Sorbet::OneAncestorPerLine::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Sorbet::ParametersOrderingInSignature < ::RuboCop::Cop::Sorbet::SignatureCop
def on_signature(node); end
def signature_params(param0); end
private
def check_for_inconsistent_param_ordering(sig_params_order, parameters); end
def extract_parameters(sig_params); end
end
class RuboCop::Cop::Sorbet::SignatureBuildOrder < ::RuboCop::Cop::Sorbet::SignatureCop
def autocorrect(node); end
def on_signature(node); end
@ -220,9 +225,12 @@ class RuboCop::Cop::Sorbet::SignatureBuildOrder::ModernBuilder < ::RuboCop::AST:
RuboCop::Cop::Sorbet::SignatureBuildOrder::ORDER = T.let(T.unsafe(nil), Hash)
class RuboCop::Cop::Sorbet::SignatureCop < ::RuboCop::Cop::Cop
def allowed_recv(recv); end
def on_block(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

View File

@ -90,7 +90,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.23.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.12.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.12.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.6.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.5.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.3/lib"

View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'rubocop/sorbet'
require_relative 'rubocop/sorbet/version'
require_relative 'rubocop/sorbet/inject'
RuboCop::Sorbet::Inject.defaults!
require_relative 'rubocop/cop/sorbet_cops'

View File

@ -1,138 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop ensures that callback conditionals are bound to the right type
# so that they are type checked properly.
#
# @example
#
# # bad
# class Post < ApplicationRecord
# before_create :do_it, if: -> { should_do_it? }
#
# def should_do_it?
# true
# end
# end
#
# # good
# class Post < ApplicationRecord
# before_create :do_it, if: -> { T.bind(self, Post).should_do_it? }
#
# def should_do_it?
# true
# end
# end
class CallbackConditionalsBinding < RuboCop::Cop::Cop
CALLBACKS = %i(
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)
lambda do |corrector|
options = node.each_child_node.find(&:hash_type?)
conditional = nil
options.each_pair do |keyword, block|
if keyword.value == :if || keyword.value == :unless
conditional = block
break
end
end
_, _, block = conditional.child_nodes
expected_class = node.parent_module_name
bind = if block.begin_type?
indentation = " " * block.child_nodes.first.loc.column
"T.bind(self, #{expected_class})\n#{indentation}"
elsif block.child_nodes.empty? && !block.ivar_type?
"T.bind(self, #{expected_class})."
else
"T.bind(self, #{expected_class}); "
end
corrector.insert_before(block, bind)
end
end
def on_send(node)
return unless CALLBACKS.include?(node.method_name)
options = node.each_child_node.find(&:hash_type?)
return if options.nil?
conditional = nil
options.each_pair do |keyword, block|
next unless keyword.sym_type?
if keyword.value == :if || keyword.value == :unless
conditional = block
break
end
end
return if conditional.nil? || conditional.child_nodes.empty?
type, _, block = conditional.child_nodes
return unless type.lambda_or_proc?
expected_class = node.parent_module_name
return if expected_class.nil?
unless block.source.include?("T.bind(self, #{expected_class})")
add_offense(
node,
message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})"
)
end
end
end
end
end
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop makes sure that RBI files are always located under sorbet/rbi/.
#
# @example
# # bad
# lib/some_file.rbi
# other_file.rbi
#
# # good
# sorbet/rbi/some_file.rbi
# sorbet/rbi/any/path/for/file.rbi
class ForbidRBIOutsideOfSorbetDir < RuboCop::Cop::Cop
include RangeHelp
PATH_REGEXP = %r{sorbet/rbi}
def investigate(processed_source)
add_offense(
nil,
location: source_range(processed_source.buffer, 1, 0),
message: "RBI files are only accepted in the sorbet/rbi/ directory."
) unless processed_source.file_path =~ PATH_REGEXP
end
end
end
end
end

View File

@ -1,70 +0,0 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'signature_cop'
module RuboCop
module Cop
module Sorbet
# This cop checks for inconsistent ordering of parameters between the
# signature and the method definition. The sorbet-runtime gem raises
# when such inconsistency occurs.
#
# @example
#
# # bad
# sig { params(a: Integer, b: String).void }
# def foo(b:, a:); end
#
# # good
# sig { params(a: Integer, b: String).void }
# def foo(a:, b:); end
class ParametersOrderingInSignature < SignatureCop
def_node_search(:signature_params, <<-PATTERN)
(send _ :params ...)
PATTERN
def on_signature(node)
sig_params = signature_params(node).first
sig_params_order = extract_parameters(sig_params)
return if sig_params_order.nil?
method_node = node.parent.children[node.sibling_index + 1]
return if method_node.nil? || method_node.type != :def
method_parameters = method_node.arguments
check_for_inconsistent_param_ordering(sig_params_order, method_parameters)
end
private
def extract_parameters(sig_params)
return [] if sig_params.nil?
arguments = sig_params.arguments.first
return arguments.keys.map(&:value) if RuboCop::AST::HashNode === arguments
add_offense(
sig_params,
message: "Invalid signature."
)
end
def check_for_inconsistent_param_ordering(sig_params_order, parameters)
parameters.each_with_index do |param, index|
param_name = param.children[0]
sig_param_name = sig_params_order[index]
next if param_name == sig_param_name
add_offense(
param,
message: "Inconsistent ordering of arguments at index #{index}. " \
"Expected `#{sig_param_name}` from sig above."
)
end
end
end
end
end
end

View File

@ -1,29 +0,0 @@
# frozen_string_literal: true
require_relative 'sorbet/binding_constants_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/one_ancestor_per_line'
require_relative 'sorbet/callback_conditionals_binding'
require_relative 'sorbet/forbid_t_unsafe'
require_relative 'sorbet/rbi/forbid_extend_t_sig_helpers_in_shims'
require_relative 'sorbet/rbi/forbid_rbi_outside_of_sorbet_dir'
require_relative 'sorbet/rbi/single_line_rbi_class_module_definitions'
require_relative 'sorbet/signatures/allow_incompatible_override'
require_relative 'sorbet/signatures/checked_true_in_signature'
require_relative 'sorbet/signatures/keyword_argument_ordering'
require_relative 'sorbet/signatures/parameters_ordering_in_signature'
require_relative 'sorbet/signatures/signature_build_order'
require_relative 'sorbet/signatures/enforce_signatures'
require_relative 'sorbet/sigils/valid_sigil'
require_relative 'sorbet/sigils/has_sigil'
require_relative 'sorbet/sigils/ignore_sigil'
require_relative 'sorbet/sigils/false_sigil'
require_relative 'sorbet/sigils/true_sigil'
require_relative 'sorbet/sigils/strict_sigil'
require_relative 'sorbet/sigils/strong_sigil'
require_relative 'sorbet/sigils/enforce_sigil_order'

View File

@ -16,7 +16,8 @@ Sorbet/BindingConstantWithoutTypeAlias:
Sorbet/CallbackConditionalsBinding:
Description: 'Ensures callback conditionals are bound to the right type.'
Enabled: true
Enabled: false
Safe: false
VersionAdded: 0.7.0
Sorbet/CheckedTrueInSignature:
@ -38,6 +39,11 @@ Sorbet/EnforceSigilOrder:
Enabled: true
VersionAdded: 0.3.4
Sorbet/sigils/EnforceSingleSigil:
Description: 'Ensures that there is only one Sorbet sigil in a file.'
Enabled: true
VersionAdded: '<<next>>'
Sorbet/EnforceSignatures:
Description: 'Ensures all methods have a valid signature.'
Enabled: false
@ -49,10 +55,7 @@ Sorbet/FalseSigil:
VersionAdded: 0.3.3
SuggestedStrictness: "false"
Include:
- "**/*.rb"
- "**/*.rbi"
- "**/*.rake"
- "**/*.ru"
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
@ -65,10 +68,12 @@ Sorbet/ForbidExtendTSigHelpersInShims:
Include:
- "**/*.rbi"
Sorbet/ForbidRBIOutsideOfSorbetDir:
Description: 'Forbids RBI files outside of the sorbet/ directory.'
Sorbet/ForbidRBIOutsideOfAllowedPaths:
Description: 'Forbids RBI files outside of the allowed paths'
Enabled: true
VersionAdded: 0.6.1
AllowedPaths:
- "sorbet/rbi/**"
Include:
- "**/*.rbi"
@ -105,12 +110,24 @@ Sorbet/HasSigil:
SuggestedStrictness: "false"
MinimumStrictness: "false"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/IgnoreSigil:
Description: 'All files must be at least at strictness `ignore`.'
Enabled: false
SuggestedStrictness: "ignore"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/KeywordArgumentOrdering:
Description: >-
@ -127,11 +144,6 @@ Sorbet/OneAncestorPerLine:
Enabled: false
VersionAdded: '0.6.0'
Sorbet/ParametersOrderingInSignature:
Description: 'Enforces same parameter order between a method and its signature.'
Enabled: true
VersionAdded: 0.2.0
Sorbet/SignatureBuildOrder:
Description: >-
Enforces the order of parts in a signature.
@ -154,18 +166,36 @@ Sorbet/StrictSigil:
Enabled: false
SuggestedStrictness: "strict"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/StrongSigil:
Description: 'All files must be at least at strictness `strong`.'
Enabled: false
SuggestedStrictness: "strong"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/TrueSigil:
Description: 'All files must be at least at strictness `true`.'
Enabled: false
SuggestedStrictness: "true"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/ValidSigil:
Description: 'All files must have a valid sigil.'
@ -174,3 +204,9 @@ Sorbet/ValidSigil:
SuggestedStrictness: "false"
MinimumStrictness: "false"
VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*

View File

@ -0,0 +1,262 @@
require:
- rubocop-sorbet
AllCops:
TargetRubyVersion: 3.0
DisabledByDefault: true
Include:
- '**/*.rbi'
## Layout
Layout/AccessModifierIndentation:
Enabled: true
Layout/ArgumentAlignment:
Enabled: true
Layout/BlockAlignment:
Enabled: true
Layout/BlockEndNewline:
Enabled: true
Layout/ClassStructure:
Enabled: true
ExpectedOrder:
- module_inclusion
- macros
- public_attribute_macros
- protected_attribute_macros
- private_attribute_macros
- initializer
- public_methods
- protected_methods
- private_methods
- public_class_methods
- constants
Layout/ClosingParenthesisIndentation:
Enabled: true
Layout/CommentIndentation:
Enabled: true
Layout/EmptyComment:
Enabled: true
Layout/EmptyLineAfterMagicComment:
Enabled: true
Layout/EmptyLineBetweenDefs:
Enabled: true
AllowAdjacentOneLineDefs: true
Layout/EmptyLines:
Enabled: true
Layout/EmptyLinesAroundAccessModifier:
Enabled: true
Layout/EmptyLinesAroundArguments:
Enabled: true
Layout/EmptyLinesAroundAttributeAccessor:
Enabled: true
Layout/EmptyLinesAroundBlockBody:
Enabled: true
Layout/EmptyLinesAroundClassBody:
Enabled: true
Layout/EmptyLinesAroundModuleBody:
Enabled: true
Layout/EndOfLine:
Enabled: true
EnforcedStyle: lf
Layout/ExtraSpacing:
Enabled: true
Layout/FirstMethodArgumentLineBreak:
Enabled: true
Layout/FirstMethodParameterLineBreak:
Enabled: true
Layout/FirstParameterIndentation:
Enabled: true
Layout/IndentationConsistency:
Enabled: true
Layout/IndentationStyle:
Enabled: true
EnforcedStyle: spaces
Layout/IndentationWidth:
Enabled: true
Layout/InitialIndentation:
Enabled: true
Layout/LeadingCommentSpace:
Enabled: true
Layout/LeadingEmptyLines:
Enabled: true
# TODO: make Tapioca break long lines?
Layout/LineLength:
Enabled: false
Layout/MultilineBlockLayout:
Enabled: true
Layout/MultilineMethodArgumentLineBreaks:
Enabled: true
Layout/MultilineMethodCallBraceLayout:
Enabled: true
Layout/MultilineMethodCallIndentation:
Enabled: true
Layout/ParameterAlignment:
Enabled: true
Layout/RedundantLineBreak:
Enabled: true
Layout/SpaceAfterColon:
Enabled: true
Layout/SpaceAfterComma:
Enabled: true
Layout/SpaceAfterMethodName:
Enabled: true
Layout/SpaceAfterSemicolon:
Enabled: true
Layout/SpaceAroundEqualsInParameterDefault:
Enabled: true
Layout/SpaceAroundKeyword:
Enabled: true
Layout/SpaceAroundMethodCallOperator:
Enabled: true
Layout/SpaceBeforeBlockBraces:
Enabled: true
Layout/SpaceBeforeBrackets:
Enabled: true
Layout/SpaceBeforeComma:
Enabled: true
Layout/SpaceBeforeComment:
Enabled: true
Layout/SpaceBeforeFirstArg:
Enabled: true
Layout/SpaceBeforeSemicolon:
Enabled: true
Layout/SpaceInsideParens:
Enabled: true
Layout/TrailingEmptyLines:
Enabled: true
EnforcedStyle: final_newline
Layout/TrailingWhitespace:
Enabled: true
## Lint
Lint/DuplicateMethods:
Enabled: true
Lint/EmptyFile:
Enabled: true
AllowComments: false
Lint/SyntaxError:
Enabled: true
## Sorbet
Sorbet:
DisabledByDefault: true
Sorbet/EnforceSigilOrder:
Enabled: true
Sorbet/ForbidExtendTSigHelpersInShims:
Enabled: true
Sorbet/ForbidIncludeConstLiteral:
Enabled: true
Sorbet/ForbidSuperclassConstLiteral:
Enabled: true
Sorbet/OneAncestorPerLine:
Enabled: true
Sorbet/SignatureBuildOrder:
Enabled: true
Sorbet/SingleLineRbiClassModuleDefinitions:
Enabled: true
Sorbet/ValidSigil:
Enabled: true
RequireSigilOnAllFiles: true
MinimumStrictness: "false"
SuggestedStrictness: "true"
## Style
Style/ClassAndModuleChildren:
Enabled: true
EnforcedStyle: compact
Style/DefWithParentheses:
Enabled: true
Style/EmptyMethod:
Enabled: true
EnforcedStyle: compact
Style/FrozenStringLiteralComment:
Enabled: true
EnforcedStyle: never
Style/MethodCallWithArgsParentheses:
Enabled: true
IgnoreMacros: true
Style/MethodCallWithoutArgsParentheses:
Enabled: true
Style/MethodDefParentheses:
Enabled: true
Style/MixinGrouping:
Enabled: true
EnforcedStyle: separated
Style/MixinUsage:
Enabled: true
Style/ModuleFunction:
Enabled: true
EnforcedStyle: forbidden

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
require "rubocop"
require_relative "rubocop/sorbet"
require_relative "rubocop/sorbet/version"
require_relative "rubocop/sorbet/inject"
RuboCop::Sorbet::Inject.defaults!
require_relative "rubocop/cop/sorbet_cops"

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -94,16 +94,16 @@ module RuboCop
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.' \
"`T.type_alias` now expects a block." \
'Run Sorbet with the options "--autocorrect --error-white-list=5043" ' \
'to automatically upgrade to the new syntax.'
"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`.'
"To do this, you must alias the type using `T.type_alias`."
)
end

View File

@ -0,0 +1,142 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop 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
# binding to the attached class. Auto-correcting those usages can lead to false positives and auto-correction
# introduces new typing errors.
#
# @example
#
# # bad
# class Post < ApplicationRecord
# before_create :do_it, if: -> { should_do_it? }
#
# def should_do_it?
# true
# end
# end
#
# # good
# class Post < ApplicationRecord
# before_create :do_it, if: -> {
# T.bind(self, Post)
# should_do_it?
# }
#
# def should_do_it?
# true
# end
# end
class CallbackConditionalsBinding < RuboCop::Cop::Cop
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
].freeze
def autocorrect(node)
lambda do |corrector|
options = node.each_child_node.find(&:hash_type?)
conditional = nil
options.each_pair do |keyword, block|
if keyword.value == :if || keyword.value == :unless
conditional = block
break
end
end
_, _, block = conditional.child_nodes
# Find the class node and check if it includes a namespace on the
# same line e.g.: Namespace::Class, which will require the fully
# qualified name
klass = node.ancestors.find(&:class_type?)
expected_class = if klass.children.first.children.first.nil?
node.parent_module_name.split("::").last
else
klass.identifier.source
end
do_end_lambda = conditional.source.include?("do") && conditional.source.include?("end")
unless do_end_lambda
# We are converting a one line lambda into a multiline
# Remove the space after the `{`
if /{\s/.match?(conditional.source)
corrector.remove_preceding(block, 1)
end
# Remove the last space and `}` and re-add it with a line break
# and the correct indentation
base_indentation = " " * node.loc.column
chars_to_remove = /\s}/.match?(conditional.source) ? 2 : 1
corrector.remove_trailing(conditional, chars_to_remove)
corrector.insert_after(block, "\n#{base_indentation}}")
end
# Add the T.bind
indentation = " " * (node.loc.column + 2)
line_start = do_end_lambda ? "" : "\n#{indentation}"
bind = "#{line_start}T.bind(self, #{expected_class})\n#{indentation}"
corrector.insert_before(block, bind)
end
end
def on_send(node)
return unless CALLBACKS.include?(node.method_name)
options = node.each_child_node.find(&:hash_type?)
return if options.nil?
conditional = nil
options.each_pair do |keyword, block|
next unless keyword.sym_type?
if keyword.value == :if || keyword.value == :unless
conditional = block
break
end
end
return if conditional.nil? || conditional.array_type? || conditional.child_nodes.empty?
return unless conditional.arguments.empty?
type, _, block = conditional.child_nodes
return unless type.lambda_or_proc? || type.block_literal?
klass = node.ancestors.find(&:class_type?)
expected_class = if klass&.children&.first&.children&.first.nil?
node.parent_module_name&.split("::")&.last
else
klass.identifier.source
end
return if expected_class.nil?
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})"
)
end
end
end
end
end
end

View File

@ -1,7 +1,7 @@
# encoding: utf-8
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
# Correct `send` expressions in include statements by constant literals.
#
@ -27,7 +27,7 @@ module RuboCop
module Cop
module Sorbet
class ForbidIncludeConstLiteral < RuboCop::Cop::Cop
MSG = 'Includes must only contain constant literals'
MSG = "Includes must only contain constant literals"
attr_accessor :used_names
@ -52,6 +52,15 @@ module RuboCop
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}"
)
end
end
end
end
end

View File

@ -1,7 +1,7 @@
# encoding: utf-8
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
# Correct superclass `send` expressions by constant literals.
#
@ -25,7 +25,7 @@ module RuboCop
module Cop
module Sorbet
class ForbidSuperclassConstLiteral < RuboCop::Cop::Cop
MSG = 'Superclasses must only contain constant literals'
MSG = "Superclasses must only contain constant literals"
def_node_matcher :not_lit_const_superclass?, <<-PATTERN
(class

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -15,7 +15,7 @@ module RuboCop
# # good
# foo
class ForbidTUnsafe < RuboCop::Cop::Cop
def_node_matcher(:t_unsafe?, '(send (const nil? :T) :unsafe _)')
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)

View File

@ -1,7 +1,7 @@
# encoding: utf-8
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -23,7 +23,7 @@ module RuboCop
# prop :bar, T.nilable(String)
# end
class ForbidUntypedStructProps < RuboCop::Cop::Cop
MSG = 'Struct props cannot be T.untyped'
MSG = "Struct props cannot be T.untyped"
def_node_matcher :t_struct, <<~PATTERN
(const (const nil? :T) :Struct)

View File

@ -1,7 +1,7 @@
# encoding: utf-8
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -22,7 +22,7 @@ module RuboCop
# requires_ancestor Minitest::Assertions
# end
class OneAncestorPerLine < RuboCop::Cop::Cop
MSG = 'Cannot require more than one ancestor per line'
MSG = "Cannot require more than one ancestor per line"
def_node_search :requires_ancestors, <<~PATTERN
(send nil? :requires_ancestor ...)

View File

@ -25,7 +25,7 @@ module RuboCop
class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Cop
include RangeHelp
MSG = 'Extending T::Sig or T::Helpers in a shim is unnecessary'
MSG = "Extending T::Sig or T::Helpers in a shim is unnecessary"
RESTRICT_ON_SEND = [:extend]
def_node_matcher :extend_t_sig?, <<~PATTERN

View File

@ -0,0 +1,47 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop makes sure that RBI files are always located under the defined allowed paths.
#
# Options:
#
# * `AllowedPaths`: A list of the paths where RBI files are allowed (default: ["sorbet/rbi/**"])
#
# @example
# # bad
# # lib/some_file.rbi
# # other_file.rbi
#
# # good
# # sorbet/rbi/some_file.rbi
# # sorbet/rbi/any/path/for/file.rbi
class ForbidRBIOutsideOfAllowedPaths < RuboCop::Cop::Cop
include RangeHelp
def investigate(processed_source)
add_offense(
nil,
location: source_range(processed_source.buffer, 1, 0),
message: message
) if allowed_paths.none? { |pattern| File.fnmatch(pattern, processed_source.file_path) }
end
private
def allowed_paths
cop_config["AllowedPaths"]&.compact || []
end
def message
if allowed_paths.empty?
"RBI files should be located in an allowed path, but AllowedPaths is empty or nil"
else
"RBI file path should match one of: #{allowed_paths.join(", ")}"
end
end
end
end
end
end

View File

@ -15,7 +15,7 @@ module RuboCop
# # good
# module SomeModule; end
class SingleLineRbiClassModuleDefinitions < RuboCop::Cop::Cop
MSG = 'Empty class/module definitions in RBI files should be on a single line.'
MSG = "Empty class/module definitions in RBI files should be on a single line."
def on_module(node)
process_node(node)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -69,10 +69,10 @@ module RuboCop
FROZEN_REGEX = /#\s+frozen_string_literal:(?:\s+([\w]+))?/
PREFERRED_ORDER = {
CODING_REGEX => 'encoding',
SIGIL_REGEX => 'typed',
INDENT_REGEX => 'warn_indent',
FROZEN_REGEX => 'frozen_string_literal',
CODING_REGEX => "encoding",
SIGIL_REGEX => "typed",
INDENT_REGEX => "warn_indent",
FROZEN_REGEX => "frozen_string_literal",
}.freeze
MAGIC_REGEX = Regexp.union(*PREFERRED_ORDER.keys)
@ -104,7 +104,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

@ -0,0 +1,63 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sorbet
# This cop checks that there is only one Sorbet sigil in a given file
#
# For example, the following class with two sigils
#
# ```ruby
# # typed: true
# # typed: true
# # frozen_string_literal: true
# class Foo; end
# ```
#
# Will be corrected as:
#
# ```ruby
# # typed: true
# # frozen_string_literal: true
# class Foo; end
# ```
#
# Other comments or magic comments are left in place.
class EnforceSingleSigil < ValidSigil
include RangeHelp
def investigate(processed_source)
return if processed_source.tokens.empty?
sigils = extract_all_sigils(processed_source)
return unless sigils.size > 1
sigils[1..sigils.size].each do |token|
add_offense(token, location: token.pos, message: "Files must only contain one sigil")
end
end
def autocorrect(_node)
-> (corrector) do
sigils = extract_all_sigils(processed_source)
return unless sigils.size > 1
# 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))
)
end
end
end
protected
def extract_all_sigils(processed_source)
processed_source.tokens
.take_while { |token| token.type == :tCOMMENT }
.find_all { |token| SIGIL_REGEX.match?(token.text) }
end
end
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'has_sigil'
require "rubocop"
require_relative "has_sigil"
module RuboCop
module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `false` sigil mandatory in all files.
class FalseSigil < HasSigil
def minimum_strictness
'false'
"false"
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'valid_sigil'
require "rubocop"
require_relative "valid_sigil"
module RuboCop
module Cop

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'has_sigil'
require "rubocop"
require_relative "has_sigil"
module RuboCop
module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `ignore` sigil mandatory in all files.
class IgnoreSigil < HasSigil
def minimum_strictness
'ignore'
"ignore"
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'has_sigil'
require "rubocop"
require_relative "has_sigil"
module RuboCop
module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `strict` sigil mandatory in all files.
class StrictSigil < HasSigil
def minimum_strictness
'strict'
"strict"
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'has_sigil'
require "rubocop"
require_relative "has_sigil"
module RuboCop
module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `strong` sigil mandatory in all files.
class StrongSigil < HasSigil
def minimum_strictness
'strong'
"strong"
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'has_sigil'
require "rubocop"
require_relative "has_sigil"
module RuboCop
module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `true` sigil mandatory in all files.
class TrueSigil < HasSigil
def minimum_strictness
'true'
"true"
end
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -48,7 +48,7 @@ module RuboCop
protected
STRICTNESS_LEVELS = %w(ignore false true strict strong)
STRICTNESS_LEVELS = ["ignore", "false", "true", "strict", "strong"]
SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/
# extraction
@ -74,7 +74,7 @@ module RuboCop
add_offense(
token,
location: token.pos,
message: 'No Sorbet sigil found in file. ' \
message: "No Sorbet sigil found in file. " \
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
)
end
@ -87,7 +87,7 @@ module RuboCop
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?
# 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
@ -106,7 +106,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
@ -142,18 +142,18 @@ module RuboCop
# Default is `false`
def require_sigil_on_all_files?
!!cop_config['RequireSigilOnAllFiles']
!!cop_config["RequireSigilOnAllFiles"]
end
# Default is `'false'`
def suggested_strictness
config = cop_config['SuggestedStrictness'].to_s
STRICTNESS_LEVELS.include?(config) ? config : 'false'
config = cop_config["SuggestedStrictness"].to_s
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
config if STRICTNESS_LEVELS.include?(config)
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -49,8 +49,8 @@ module RuboCop
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`',
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

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'signature_cop'
require "rubocop"
require_relative "signature_cop"
module RuboCop
module Cop
@ -27,10 +27,10 @@ module RuboCop
PATTERN
MESSAGE =
'Using `checked(true)` in a method signature definition is not allowed. ' \
'`checked(true)` is the default behavior for modules/classes with runtime checks enabled. ' \
'To enable typechecking at runtime for this module, regardless of global settings, ' \
'`include(WaffleCone::RuntimeChecks)` to this module and set other methods to `checked(false)`.'
"Using `checked(true)` in a method signature definition is not allowed. " \
"`checked(true)` is the default behavior for modules/classes with runtime checks enabled. " \
"To enable typechecking at runtime for this module, regardless of global settings, " \
"`include(WaffleCone::RuntimeChecks)` to this module and set other methods to `checked(false)`."
private_constant(:MESSAGE)
def on_signature(node)

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'rubocop'
require 'stringio'
require_relative 'signature_cop'
require "rubocop"
require "stringio"
require_relative "signature_cop"
module RuboCop
module Cop
@ -48,8 +48,8 @@ module RuboCop
check_node(node) if accessor?(node)
end
def on_block(node)
@last_sig_for_scope[scope(node)] = node if signature?(node)
def on_signature(node)
@last_sig_for_scope[scope(node)] = node
end
def autocorrect(node)
@ -64,7 +64,7 @@ module RuboCop
method = node.children[1]
symbol = node.children[2]
suggest.params << symbol.value if symbol && (method == :attr_writer || method == :attr_accessor)
suggest.returns = 'void' if method == :attr_writer
suggest.returns = "void" if method == :attr_writer
end
corrector.insert_before(node.loc.expression, suggest.to_autocorrect)
@ -91,11 +91,11 @@ module RuboCop
end
def param_type_placeholder
cop_config['ParameterTypePlaceholder'] || 'T.untyped'
cop_config["ParameterTypePlaceholder"] || "T.untyped"
end
def return_type_placeholder
cop_config['ReturnTypePlaceholder'] || 'T.untyped'
cop_config["ReturnTypePlaceholder"] || "T.untyped"
end
class SigSuggestion
@ -111,11 +111,11 @@ module RuboCop
def to_autocorrect
out = StringIO.new
out << 'sig { '
out << "sig { "
out << generate_params
out << generate_return
out << " }\n"
out << ' ' * @indent # preserve indent for the next line
out << " " * @indent # preserve indent for the next line
out.string
end
@ -124,17 +124,17 @@ module RuboCop
def generate_params
return if @params.empty?
out = StringIO.new
out << 'params('
out << "params("
out << @params.map do |param|
"#{param}: #{@param_placeholder}"
end.join(", ")
out << ').'
out << ")."
out.string
end
def generate_return
return "returns(#{@return_placeholder})" if @returns.nil?
return @returns if @returns == 'void'
return @returns if @returns == "void"
"returns(#{@returns})"
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'signature_cop'
require "rubocop"
require_relative "signature_cop"
module RuboCop
module Cop
@ -41,7 +41,7 @@ module RuboCop
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

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'rubocop'
require_relative 'signature_cop'
require "rubocop"
require_relative "signature_cop"
begin
require 'unparser'
require "unparser"
rescue LoadError
nil
end
@ -28,7 +28,7 @@ module RuboCop
].each_with_index.to_h.freeze
def_node_search(:root_call, <<~PATTERN)
(send nil? {#{ORDER.keys.map(&:inspect).join(' ')}} ...)
(send nil? {#{ORDER.keys.map(&:inspect).join(" ")}} ...)
PATTERN
def on_signature(node)
@ -38,10 +38,10 @@ module RuboCop
expected_order = calls.sort_by { |call| ORDER[call] }
return if expected_order == calls
message = "Sig builders must be invoked in the following order: #{expected_order.join(', ')}."
message = "Sig builders must be invoked in the following order: #{expected_order.join(", ")}."
unless can_autocorrect?
message += ' For autocorrection, add the `unparser` gem to your project.'
message += " For autocorrection, add the `unparser` gem to your project."
end
add_offense(

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'rubocop'
require "rubocop"
module RuboCop
module Cop
@ -12,9 +12,24 @@ module RuboCop
@registry = Cop.registry # So we can properly subclass this cop
def_node_matcher(:signature?, <<~PATTERN)
(block (send nil? :sig) (args) ...)
(block (send #allowed_recv :sig) (args) ...)
PATTERN
def_node_matcher(:with_runtime?, <<~PATTERN)
(const (const nil? :T) :Sig)
PATTERN
def_node_matcher(:without_runtime?, <<~PATTERN)
(const (const (const nil? :T) :Sig) :WithoutRuntime)
PATTERN
def allowed_recv(recv)
return true unless recv
return true if with_runtime?(recv)
return true if without_runtime?(recv)
false
end
def on_block(node)
on_signature(node) if signature?(node)
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
require_relative "sorbet/binding_constants_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/one_ancestor_per_line"
require_relative "sorbet/callback_conditionals_binding"
require_relative "sorbet/forbid_t_unsafe"
require_relative "sorbet/rbi/forbid_extend_t_sig_helpers_in_shims"
require_relative "sorbet/rbi/forbid_rbi_outside_of_allowed_paths"
require_relative "sorbet/rbi/single_line_rbi_class_module_definitions"
require_relative "sorbet/signatures/allow_incompatible_override"
require_relative "sorbet/signatures/checked_true_in_signature"
require_relative "sorbet/signatures/keyword_argument_ordering"
require_relative "sorbet/signatures/signature_build_order"
require_relative "sorbet/signatures/enforce_signatures"
require_relative "sorbet/sigils/valid_sigil"
require_relative "sorbet/sigils/has_sigil"
require_relative "sorbet/sigils/ignore_sigil"
require_relative "sorbet/sigils/false_sigil"
require_relative "sorbet/sigils/true_sigil"
require_relative "sorbet/sigils/strict_sigil"
require_relative "sorbet/sigils/strong_sigil"
require_relative "sorbet/sigils/enforce_sigil_order"
require_relative "sorbet/sigils/enforce_single_sigil"

View File

@ -7,7 +7,7 @@ module RuboCop
class Error < StandardError; end
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
module RuboCop
module Sorbet
VERSION = "0.6.2"
VERSION = "0.6.3"
end
end