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" - "Homebrew/test/**/Casks/**/*.rb"
Sorbet/StrictSigil: Sorbet/StrictSigil:
inherit_mode:
override:
- Include
Enabled: true Enabled: true
Include: Include:
- "**/*.rbi" - "**/*.rbi"

View File

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

View File

@ -1,9 +1,9 @@
# typed: true
# DO NOT EDIT MANUALLY # DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `rubocop-sorbet` gem. # 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`. # Please instead update this file by running `bin/tapioca gem rubocop-sorbet`.
# typed: true
module RuboCop; end module RuboCop; end
module RuboCop::Cop; end module RuboCop::Cop; end
module RuboCop::Cop::Sorbet; 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 accessor?(param0 = T.unsafe(nil)); end
def autocorrect(node); end def autocorrect(node); end
def on_block(node); end
def on_def(node); end def on_def(node); end
def on_defs(node); end def on_defs(node); end
def on_send(node); end def on_send(node); end
def on_signature(node); end
def scope(node); end def scope(node); end
private private
@ -104,6 +104,17 @@ class RuboCop::Cop::Sorbet::EnforceSignatures::SigSuggestion
def generate_return; end def generate_return; end
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 class RuboCop::Cop::Sorbet::FalseSigil < ::RuboCop::Cop::Sorbet::HasSigil
def minimum_strictness; end def minimum_strictness; end
end end
@ -123,6 +134,7 @@ RuboCop::Cop::Sorbet::ForbidExtendTSigHelpersInShims::RESTRICT_ON_SEND = T.let(T
class RuboCop::Cop::Sorbet::ForbidIncludeConstLiteral < ::RuboCop::Cop::Cop class RuboCop::Cop::Sorbet::ForbidIncludeConstLiteral < ::RuboCop::Cop::Cop
def initialize(*_arg0); end def initialize(*_arg0); end
def autocorrect(node); end
def not_lit_const_include?(param0 = T.unsafe(nil)); end def not_lit_const_include?(param0 = T.unsafe(nil)); end
def on_send(node); end def on_send(node); end
def used_names; end def used_names; end
@ -131,13 +143,16 @@ end
RuboCop::Cop::Sorbet::ForbidIncludeConstLiteral::MSG = T.let(T.unsafe(nil), String) 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 include ::RuboCop::Cop::RangeHelp
def investigate(processed_source); end 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 class RuboCop::Cop::Sorbet::ForbidSuperclassConstLiteral < ::RuboCop::Cop::Cop
def not_lit_const_superclass?(param0 = T.unsafe(nil)); end 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) 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 class RuboCop::Cop::Sorbet::SignatureBuildOrder < ::RuboCop::Cop::Sorbet::SignatureCop
def autocorrect(node); end def autocorrect(node); end
def on_signature(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) RuboCop::Cop::Sorbet::SignatureBuildOrder::ORDER = T.let(T.unsafe(nil), Hash)
class RuboCop::Cop::Sorbet::SignatureCop < ::RuboCop::Cop::Cop class RuboCop::Cop::Sorbet::SignatureCop < ::RuboCop::Cop::Cop
def allowed_recv(recv); end
def on_block(node); end def on_block(node); end
def on_signature(_); end def on_signature(_); end
def signature?(param0 = T.unsafe(nil)); 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 end
class RuboCop::Cop::Sorbet::SingleLineRbiClassModuleDefinitions < ::RuboCop::Cop::Cop 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-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-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-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/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-html-0.12.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.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: Sorbet/CallbackConditionalsBinding:
Description: 'Ensures callback conditionals are bound to the right type.' Description: 'Ensures callback conditionals are bound to the right type.'
Enabled: true Enabled: false
Safe: false
VersionAdded: 0.7.0 VersionAdded: 0.7.0
Sorbet/CheckedTrueInSignature: Sorbet/CheckedTrueInSignature:
@ -38,6 +39,11 @@ Sorbet/EnforceSigilOrder:
Enabled: true Enabled: true
VersionAdded: 0.3.4 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: Sorbet/EnforceSignatures:
Description: 'Ensures all methods have a valid signature.' Description: 'Ensures all methods have a valid signature.'
Enabled: false Enabled: false
@ -49,10 +55,7 @@ Sorbet/FalseSigil:
VersionAdded: 0.3.3 VersionAdded: 0.3.3
SuggestedStrictness: "false" SuggestedStrictness: "false"
Include: Include:
- "**/*.rb" - "**/*.{rb,rbi,rake,ru}"
- "**/*.rbi"
- "**/*.rake"
- "**/*.ru"
Exclude: Exclude:
- bin/**/* - bin/**/*
- db/**/*.rb - db/**/*.rb
@ -65,10 +68,12 @@ Sorbet/ForbidExtendTSigHelpersInShims:
Include: Include:
- "**/*.rbi" - "**/*.rbi"
Sorbet/ForbidRBIOutsideOfSorbetDir: Sorbet/ForbidRBIOutsideOfAllowedPaths:
Description: 'Forbids RBI files outside of the sorbet/ directory.' Description: 'Forbids RBI files outside of the allowed paths'
Enabled: true Enabled: true
VersionAdded: 0.6.1 VersionAdded: 0.6.1
AllowedPaths:
- "sorbet/rbi/**"
Include: Include:
- "**/*.rbi" - "**/*.rbi"
@ -105,12 +110,24 @@ Sorbet/HasSigil:
SuggestedStrictness: "false" SuggestedStrictness: "false"
MinimumStrictness: "false" MinimumStrictness: "false"
VersionAdded: 0.3.3 VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/IgnoreSigil: Sorbet/IgnoreSigil:
Description: 'All files must be at least at strictness `ignore`.' Description: 'All files must be at least at strictness `ignore`.'
Enabled: false Enabled: false
SuggestedStrictness: "ignore" SuggestedStrictness: "ignore"
VersionAdded: 0.3.3 VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/KeywordArgumentOrdering: Sorbet/KeywordArgumentOrdering:
Description: >- Description: >-
@ -127,11 +144,6 @@ Sorbet/OneAncestorPerLine:
Enabled: false Enabled: false
VersionAdded: '0.6.0' 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: Sorbet/SignatureBuildOrder:
Description: >- Description: >-
Enforces the order of parts in a signature. Enforces the order of parts in a signature.
@ -154,18 +166,36 @@ Sorbet/StrictSigil:
Enabled: false Enabled: false
SuggestedStrictness: "strict" SuggestedStrictness: "strict"
VersionAdded: 0.3.3 VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/StrongSigil: Sorbet/StrongSigil:
Description: 'All files must be at least at strictness `strong`.' Description: 'All files must be at least at strictness `strong`.'
Enabled: false Enabled: false
SuggestedStrictness: "strong" SuggestedStrictness: "strong"
VersionAdded: 0.3.3 VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/TrueSigil: Sorbet/TrueSigil:
Description: 'All files must be at least at strictness `true`.' Description: 'All files must be at least at strictness `true`.'
Enabled: false Enabled: false
SuggestedStrictness: "true" SuggestedStrictness: "true"
VersionAdded: 0.3.3 VersionAdded: 0.3.3
Include:
- "**/*.{rb,rbi,rake,ru}"
Exclude:
- bin/**/*
- db/**/*.rb
- script/**/*
Sorbet/ValidSigil: Sorbet/ValidSigil:
Description: 'All files must have a valid sigil.' Description: 'All files must have a valid sigil.'
@ -174,3 +204,9 @@ Sorbet/ValidSigil:
SuggestedStrictness: "false" SuggestedStrictness: "false"
MinimumStrictness: "false" MinimumStrictness: "false"
VersionAdded: 0.3.3 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 # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -94,16 +94,16 @@ module RuboCop
add_offense( add_offense(
node.children[2], node.children[2],
message: "It looks like you're using the old `T.type_alias` syntax. " \ 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" ' \ '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 return
end end
add_offense( add_offense(
node.children[2], node.children[2],
message: "It looks like you're trying to bind a type to a constant. " \ 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 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,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop

View File

@ -1,7 +1,7 @@
# encoding: utf-8 # encoding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
# Correct `send` expressions in include statements by constant literals. # Correct `send` expressions in include statements by constant literals.
# #
@ -27,7 +27,7 @@ module RuboCop
module Cop module Cop
module Sorbet module Sorbet
class ForbidIncludeConstLiteral < RuboCop::Cop::Cop class ForbidIncludeConstLiteral < RuboCop::Cop::Cop
MSG = 'Includes must only contain constant literals' MSG = "Includes must only contain constant literals"
attr_accessor :used_names attr_accessor :used_names
@ -52,6 +52,15 @@ module RuboCop
return unless [:module, :class, :sclass].include?(parent.type) return unless [:module, :class, :sclass].include?(parent.type)
add_offense(node) add_offense(node)
end end
def autocorrect(node)
lambda do |corrector|
corrector.replace(
node.source_range,
"T.unsafe(self).#{node.source}"
)
end
end
end end
end end
end end

View File

@ -1,7 +1,7 @@
# encoding: utf-8 # encoding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
# Correct superclass `send` expressions by constant literals. # Correct superclass `send` expressions by constant literals.
# #
@ -25,7 +25,7 @@ module RuboCop
module Cop module Cop
module Sorbet module Sorbet
class ForbidSuperclassConstLiteral < RuboCop::Cop::Cop 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 def_node_matcher :not_lit_const_superclass?, <<-PATTERN
(class (class

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -15,7 +15,7 @@ module RuboCop
# # good # # good
# foo # foo
class ForbidTUnsafe < RuboCop::Cop::Cop 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) def on_send(node)
add_offense(node, message: "Do not use `T.unsafe`.") if t_unsafe?(node) add_offense(node, message: "Do not use `T.unsafe`.") if t_unsafe?(node)

View File

@ -1,7 +1,7 @@
# encoding: utf-8 # encoding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -23,7 +23,7 @@ module RuboCop
# prop :bar, T.nilable(String) # prop :bar, T.nilable(String)
# end # end
class ForbidUntypedStructProps < RuboCop::Cop::Cop 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 def_node_matcher :t_struct, <<~PATTERN
(const (const nil? :T) :Struct) (const (const nil? :T) :Struct)

View File

@ -1,7 +1,7 @@
# encoding: utf-8 # encoding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -22,7 +22,7 @@ module RuboCop
# requires_ancestor Minitest::Assertions # requires_ancestor Minitest::Assertions
# end # end
class OneAncestorPerLine < RuboCop::Cop::Cop 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 def_node_search :requires_ancestors, <<~PATTERN
(send nil? :requires_ancestor ...) (send nil? :requires_ancestor ...)

View File

@ -25,7 +25,7 @@ module RuboCop
class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Cop class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Cop
include RangeHelp 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] RESTRICT_ON_SEND = [:extend]
def_node_matcher :extend_t_sig?, <<~PATTERN 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 # # good
# module SomeModule; end # module SomeModule; end
class SingleLineRbiClassModuleDefinitions < RuboCop::Cop::Cop 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) def on_module(node)
process_node(node) process_node(node)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -69,10 +69,10 @@ module RuboCop
FROZEN_REGEX = /#\s+frozen_string_literal:(?:\s+([\w]+))?/ FROZEN_REGEX = /#\s+frozen_string_literal:(?:\s+([\w]+))?/
PREFERRED_ORDER = { PREFERRED_ORDER = {
CODING_REGEX => 'encoding', CODING_REGEX => "encoding",
SIGIL_REGEX => 'typed', SIGIL_REGEX => "typed",
INDENT_REGEX => 'warn_indent', INDENT_REGEX => "warn_indent",
FROZEN_REGEX => 'frozen_string_literal', FROZEN_REGEX => "frozen_string_literal",
}.freeze }.freeze
MAGIC_REGEX = Regexp.union(*PREFERRED_ORDER.keys) MAGIC_REGEX = Regexp.union(*PREFERRED_ORDER.keys)
@ -104,7 +104,7 @@ module RuboCop
add_offense( add_offense(
token, token,
location: token.pos, 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
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 # frozen_string_literal: true
require 'rubocop' require "rubocop"
require_relative 'has_sigil' require_relative "has_sigil"
module RuboCop module RuboCop
module Cop module Cop
@ -9,7 +9,7 @@ module RuboCop
# This cop makes the Sorbet `false` sigil mandatory in all files. # This cop makes the Sorbet `false` sigil mandatory in all files.
class FalseSigil < HasSigil class FalseSigil < HasSigil
def minimum_strictness def minimum_strictness
'false' "false"
end end
end end
end end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -48,7 +48,7 @@ module RuboCop
protected protected
STRICTNESS_LEVELS = %w(ignore false true strict strong) STRICTNESS_LEVELS = ["ignore", "false", "true", "strict", "strong"]
SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/ SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/
# extraction # extraction
@ -74,7 +74,7 @@ module RuboCop
add_offense( add_offense(
token, token,
location: token.pos, 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)." "Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
) )
end end
@ -87,7 +87,7 @@ module RuboCop
return suggested_strictness unless minimum_strictness return suggested_strictness unless minimum_strictness
# special case: if you're using Sorbet/IgnoreSigil without config, we should recommend `ignore` # 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) # 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 # we want to compare the minimum strictness and suggested strictness. this is because
@ -106,7 +106,7 @@ module RuboCop
add_offense( add_offense(
sigil, sigil,
location: sigil.pos, location: sigil.pos,
message: 'Sorbet sigil should not be empty.' message: "Sorbet sigil should not be empty."
) )
false false
end end
@ -142,18 +142,18 @@ module RuboCop
# Default is `false` # Default is `false`
def require_sigil_on_all_files? def require_sigil_on_all_files?
!!cop_config['RequireSigilOnAllFiles'] !!cop_config["RequireSigilOnAllFiles"]
end end
# Default is `'false'` # Default is `'false'`
def suggested_strictness def suggested_strictness
config = cop_config['SuggestedStrictness'].to_s config = cop_config["SuggestedStrictness"].to_s
STRICTNESS_LEVELS.include?(config) ? config : 'false' STRICTNESS_LEVELS.include?(config) ? config : "false"
end end
# Default is `nil` # Default is `nil`
def minimum_strictness def minimum_strictness
config = cop_config['MinimumStrictness'].to_s config = cop_config["MinimumStrictness"].to_s
config if STRICTNESS_LEVELS.include?(config) config if STRICTNESS_LEVELS.include?(config)
end end
end end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -49,8 +49,8 @@ module RuboCop
return unless allow_incompatible_override?(node) return unless allow_incompatible_override?(node)
add_offense( add_offense(
node.children[2], node.children[2],
message: 'Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. '\ 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`', "Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`",
) )
end end
end end

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubocop' require "rubocop"
module RuboCop module RuboCop
module Cop module Cop
@ -12,9 +12,24 @@ module RuboCop
@registry = Cop.registry # So we can properly subclass this cop @registry = Cop.registry # So we can properly subclass this cop
def_node_matcher(:signature?, <<~PATTERN) def_node_matcher(:signature?, <<~PATTERN)
(block (send nil? :sig) (args) ...) (block (send #allowed_recv :sig) (args) ...)
PATTERN 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) def on_block(node)
on_signature(node) if signature?(node) on_signature(node) if signature?(node)
end 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 class Error < StandardError; end
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze 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 CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)

View File

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