diff --git a/.gitignore b/.gitignore index 49f15cd5b0..7e6cc16ced 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ !**/vendor/bundle/ruby/*/gems/*/lib !**/vendor/bundle/ruby/*/gems/rubocop-performance-*/config !**/vendor/bundle/ruby/*/gems/rubocop-rspec-*/config +!**/vendor/bundle/ruby/*/gems/rubocop-sorbet-*/config # Ignore partially included gems where we don't need all files **/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support.rb diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index 776b7abe6c..3390dc1ae3 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -25,4 +25,5 @@ gem "patchelf" gem "plist" gem "rubocop-performance" gem "rubocop-rspec" +gem "rubocop-sorbet" gem "ruby-macho" diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index e9b817767a..5acb823760 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -114,6 +114,8 @@ GEM rubocop-ast (>= 0.4.0) rubocop-rspec (1.43.2) rubocop (~> 0.87) + rubocop-sorbet (0.5.1) + rubocop ruby-macho (2.2.0) ruby-progressbar (1.10.1) simplecov (0.19.0) @@ -167,6 +169,7 @@ DEPENDENCIES rubocop rubocop-performance rubocop-rspec + rubocop-sorbet ruby-macho simplecov sorbet diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index ff51c2cae9..1850491132 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -75,6 +75,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.92.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.8.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.43.2/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.5.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5942-universal-darwin-19/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5942/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/config/default.yml b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/config/default.yml new file mode 100644 index 0000000000..4e1602c037 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/config/default.yml @@ -0,0 +1,128 @@ +inherit_mode: + merge: + - Exclude + +Sorbet/AllowIncompatibleOverride: + Description: 'Disallows using `.override(allow_incompatible: true)`.' + Enabled: true + VersionAdded: 0.2.0 + +Sorbet/BindingConstantWithoutTypeAlias: + Description: >- + 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`. + Enabled: true + VersionAdded: 0.2.0 + +Sorbet/CheckedTrueInSignature: + Description: 'Disallows the usage of `checked(true)` in signatures.' + Enabled: true + VersionAdded: 0.2.0 + +Sorbet/ConstantsFromStrings: + Description: >- + Forbids constant access through meta-programming. + + For example, things like `constantize` or `const_get` + are forbidden. + Enabled: true + VersionAdded: 0.2.0 + +Sorbet/EnforceSigilOrder: + Description: 'Ensures that Sorbet sigil comes first in a file.' + Enabled: true + VersionAdded: 0.3.4 + +Sorbet/EnforceSignatures: + Description: 'Ensures all methods have a valid signature.' + Enabled: false + VersionAdded: 0.3.4 + +Sorbet/FalseSigil: + Description: 'All files must be at least at strictness `false`.' + Enabled: true + VersionAdded: 0.3.3 + SuggestedStrictness: true + Include: + - "**/*.rb" + - "**/*.rbi" + - "**/*.rake" + - "**/*.ru" + Exclude: + - bin/**/* + - db/**/*.rb + - script/**/* + +Sorbet/ForbidIncludeConstLiteral: + Description: 'Forbids include of non-literal constants.' + Enabled: false + VersionAdded: 0.2.0 + VersionChanged: 0.5.0 + +Sorbet/ForbidSuperclassConstLiteral: + Description: 'Forbid superclasses which are non-literal constants.' + Enabled: false + VersionAdded: 0.2.0 + VersionChanged: 0.5.0 + +Sorbet/ForbidUntypedStructProps: + Description: >- + Disallows use of `T.untyped` or `T.nilable(T.untyped)` as a + prop type for `T::Struct` subclasses. + Enabled: true + VersionAdded: 0.4.0 + +Sorbet/HasSigil: + Description: 'Makes the Sorbet typed sigil mandatory in all files.' + Enabled: false + VersionAdded: 0.3.3 + +Sorbet/IgnoreSigil: + Description: 'All files must be at least at strictness `ignore`.' + Enabled: false + VersionAdded: 0.3.3 + +Sorbet/KeywordArgumentOrdering: + Description: >- + Enforces a compatible keyword arguments with Sorbet. + + All keyword arguments must be at the end of the parameters + list, and all keyword arguments with a default value must be + after those without default values. + Enabled: true + VersionAdded: 0.2.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. + + The order is first inheritance related builders, + then params, then return and finally the modifier + such as: `abstract.params(...).returns(...).soft`.' + Enabled: true + VersionAdded: 0.3.0 + +Sorbet/StrictSigil: + Description: 'All files must be at least at strictness `strict`.' + Enabled: false + VersionAdded: 0.3.3 + +Sorbet/StrongSigil: + Description: 'All files must be at least at strictness `strong`.' + Enabled: false + VersionAdded: 0.3.3 + +Sorbet/TrueSigil: + Description: 'All files must be at least at strictness `true`.' + Enabled: false + VersionAdded: 0.3.3 + +Sorbet/ValidSigil: + Description: 'All files must have a valid sigil.' + Enabled: true + VersionAdded: 0.3.3 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop-sorbet.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop-sorbet.rb new file mode 100644 index 0000000000..f3fd8d7c5c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop-sorbet.rb @@ -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' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/binding_constants_without_type_alias.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/binding_constants_without_type_alias.rb new file mode 100644 index 0000000000..b7885ff89e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/binding_constants_without_type_alias.rb @@ -0,0 +1,121 @@ +# 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?, <<-PATTERN) + ( + 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?(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 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/constants_from_strings.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/constants_from_strings.rb new file mode 100644 index 0000000000..d235527348 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/constants_from_strings.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'rubocop' + +module RuboCop + module Cop + module Sorbet + # This cop 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, + # more IDE-friendly, and more predictable. It leads to code that clearly + # expresses which values the constant can have. + # + # @example + # + # # bad + # class_name.constantize + # + # # bad + # constants.detect { |c| c.name == "User" } + # + # # bad + # const_get(class_name) + # + # # good + # case class_name + # when "User" + # User + # else + # raise ArgumentError + # end + # + # # good + # { "User" => User }.fetch(class_name) + class ConstantsFromStrings < ::RuboCop::Cop::Cop + 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." + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_include_const_literal.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_include_const_literal.rb new file mode 100644 index 0000000000..30c52390cf --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_include_const_literal.rb @@ -0,0 +1,58 @@ +# encoding: utf-8 +# frozen_string_literal: true + +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 + MSG = 'Includes must only contain constant literals' + + attr_accessor :used_names + + def_node_matcher :not_lit_const_include?, <<-PATTERN + (send nil? {:include :extend :prepend} + $_ + ) + PATTERN + + def initialize(*) + super + self.used_names = Set.new + end + + def on_send(node) + 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 + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb new file mode 100644 index 0000000000..e87e636a16 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb @@ -0,0 +1,45 @@ +# 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 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb new file mode 100644 index 0000000000..49b8887706 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb @@ -0,0 +1,58 @@ +# encoding: utf-8 +# frozen_string_literal: true + +require 'rubocop' + +module RuboCop + module Cop + module Sorbet + # This cop disallows use of `T.untyped` or `T.nilable(T.untyped)` + # as a prop type for `T::Struct`. + # + # @example + # + # # bad + # class SomeClass + # const :foo, T.untyped + # prop :bar, T.nilable(T.untyped) + # end + # + # # good + # class SomeClass + # const :foo, Integer + # prop :bar, T.nilable(String) + # end + class ForbidUntypedStructProps < RuboCop::Cop::Cop + MSG = 'Struct props cannot be T.untyped' + + def_node_matcher :t_struct, <<~PATTERN + (const (const nil? :T) :Struct) + PATTERN + + def_node_matcher :t_untyped, <<~PATTERN + (send (const nil? :T) :untyped) + PATTERN + + def_node_matcher :t_nilable_untyped, <<~PATTERN + (send (const nil? :T) :nilable {#t_untyped #t_nilable_untyped}) + PATTERN + + def_node_matcher :subclass_of_t_struct?, <<~PATTERN + (class (const ...) #t_struct ...) + PATTERN + + def_node_search :untyped_props, <<~PATTERN + (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]) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/enforce_sigil_order.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/enforce_sigil_order.rb new file mode 100644 index 0000000000..42feb2b610 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/enforce_sigil_order.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require 'rubocop' + +module RuboCop + module Cop + module Sorbet + # This cop checks that the Sorbet sigil comes as the first magic comment in the file. + # + # The expected order for magic comments is: typed, (en)?coding, warn_indent then frozen_string_literal. + # + # For example, the following bad ordering: + # + # ```ruby + # # frozen_string_literal: true + # # typed: true + # class Foo; end + # ``` + # + # Will be corrected as: + # + # ```ruby + # # typed: true + # # frozen_string_literal: true + # class Foo; end + # ``` + # + # Only `typed`, `(en)?coding`, `warn_indent` and `frozen_string_literal` magic comments are considered, + # other comments or magic comments are left in the same place. + class EnforceSigilOrder < ValidSigil + include RangeHelp + + def investigate(processed_source) + return if processed_source.tokens.empty? + + tokens = extract_magic_comments(processed_source) + return if tokens.empty? + + check_magic_comments_order(tokens) + end + + def autocorrect(_node) + lambda do |corrector| + tokens = extract_magic_comments(processed_source) + + # Get the magic comments tokens in their expected order + expected = PREFERRED_ORDER.keys.map do |re| + tokens.select { |token| re.match?(token.text) } + end.flatten + + tokens.each_with_index do |token, index| + corrector.replace(token.pos, expected[index].text) + end + + # Remove blank lines between the magic comments + lines = tokens.map(&:line).to_set + (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 + end + + protected + + CODING_REGEX = /#\s+(en)?coding:(?:\s+([\w]+))?/ + INDENT_REGEX = /#\s+warn_indent:(?:\s+([\w]+))?/ + 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', + }.freeze + + MAGIC_REGEX = Regexp.union(*PREFERRED_ORDER.keys) + + # extraction + + # Get all the tokens in `processed_source` that match `MAGIC_REGEX` + def extract_magic_comments(processed_source) + processed_source.tokens + .take_while { |token| token.type == :tCOMMENT } + .select { |token| MAGIC_REGEX.match?(token.text) } + end + + # checks + + def check_magic_comments_order(tokens) + # Get the current magic comments order + order = tokens.map do |token| + PREFERRED_ORDER.keys.find { |re| re.match?(token.text) } + end.compact.uniq + + # Get the expected magic comments order based on the one used in the actual source + expected = PREFERRED_ORDER.keys.select do |re| + tokens.any? { |token| re.match?(token.text) } + end.uniq + + if order != expected + tokens.each do |token| + add_offense( + token, + location: token.pos, + message: "Magic comments should be in the following order: #{PREFERRED_ORDER.values.join(', ')}." + ) + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/false_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/false_sigil.rb new file mode 100644 index 0000000000..1a3c8f18cb --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/false_sigil.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'has_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet `false` sigil mandatory in all files. + class FalseSigil < HasSigil + def minimum_strictness + 'false' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/has_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/has_sigil.rb new file mode 100644 index 0000000000..6fd2d6df34 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/has_sigil.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'valid_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet typed sigil mandatory in all files. + # + # Options: + # + # * `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 + # + # If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect. + class HasSigil < ValidSigil + @registry = Cop.registry # So we can properly subclass this cop + + def require_sigil_on_all_files? + true + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/ignore_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/ignore_sigil.rb new file mode 100644 index 0000000000..5f7cf9f75e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/ignore_sigil.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'has_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet `ignore` sigil mandatory in all files. + class IgnoreSigil < HasSigil + def minimum_strictness + 'ignore' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strict_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strict_sigil.rb new file mode 100644 index 0000000000..efe26d991b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strict_sigil.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'has_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet `strict` sigil mandatory in all files. + class StrictSigil < HasSigil + def minimum_strictness + 'strict' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strong_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strong_sigil.rb new file mode 100644 index 0000000000..0b4cf36b68 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/strong_sigil.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'has_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet `strong` sigil mandatory in all files. + class StrongSigil < HasSigil + def minimum_strictness + 'strong' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/true_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/true_sigil.rb new file mode 100644 index 0000000000..60b81b037b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/true_sigil.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'has_sigil' + +module RuboCop + module Cop + module Sorbet + # This cop makes the Sorbet `true` sigil mandatory in all files. + class TrueSigil < HasSigil + def minimum_strictness + 'true' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb new file mode 100644 index 0000000000..fbcc307ba4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb @@ -0,0 +1,160 @@ +# frozen_string_literal: true + +require 'rubocop' + +module RuboCop + module Cop + module Sorbet + # This cop checks that every Ruby file contains a valid Sorbet sigil. + # Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52 + # + # Options: + # + # * `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 + # + # If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect. + class ValidSigil < RuboCop::Cop::Cop + @registry = Cop.registry # So we can properly subclass this cop + + def investigate(processed_source) + return if processed_source.tokens.empty? + + sigil = extract_sigil(processed_source) + return unless check_sigil_present(sigil) + + strictness = extract_strictness(sigil) + return unless check_strictness_not_empty(sigil, strictness) + return unless check_strictness_valid(sigil, strictness) + return unless check_strictness_level(sigil, strictness) + end + + def autocorrect(_node) + lambda do |corrector| + return unless require_sigil_on_all_files? + return unless extract_sigil(processed_source).nil? + + token = processed_source.tokens.first + replace_with = suggested_strictness_level(minimum_strictness, suggested_strictness) + sigil = "# typed: #{replace_with}" + if token.text.start_with?("#!") # shebang line + corrector.insert_after(token.pos, "\n#{sigil}") + else + corrector.insert_before(token.pos, "#{sigil}\n") + end + end + end + + protected + + STRICTNESS_LEVELS = %w(ignore false true strict strong) + SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/ + + # extraction + + def extract_sigil(processed_source) + processed_source.tokens + .take_while { |token| token.type == :tCOMMENT } + .find { |token| SIGIL_REGEX.match?(token.text) } + end + + def extract_strictness(sigil) + sigil.text.match(SIGIL_REGEX)&.captures&.first + end + + # checks + + def check_sigil_present(sigil) + return true unless sigil.nil? + + token = processed_source.tokens.first + if require_sigil_on_all_files? + strictness = suggested_strictness_level(minimum_strictness, suggested_strictness) + 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)." + ) + end + false + end + + def suggested_strictness_level(minimum_strictness, suggested_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? + + # 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) + + suggested_level > minimum_level ? suggested_strictness : minimum_strictness + end + + def check_strictness_not_empty(sigil, strictness) + return true if strictness + + add_offense( + sigil, + location: sigil.pos, + message: 'Sorbet sigil should not be empty.' + ) + false + end + + def check_strictness_valid(sigil, strictness) + return true if STRICTNESS_LEVELS.include?(strictness) + + add_offense( + sigil, + location: sigil.pos, + message: "Invalid Sorbet sigil `#{strictness}`." + ) + false + end + + def check_strictness_level(sigil, strictness) + return true unless minimum_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 + end + true + end + + # options + + # Default is `false` + def require_sigil_on_all_files? + !!cop_config['RequireSigilOnAllFiles'] + end + + # Default is `'false'` + def suggested_strictness + STRICTNESS_LEVELS.include?(cop_config['SuggestedStrictness']) ? cop_config['SuggestedStrictness'] : 'false' + end + + # Default is `nil` + def minimum_strictness + cop_config['MinimumStrictness'] if STRICTNESS_LEVELS.include?(cop_config['MinimumStrictness']) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb new file mode 100644 index 0000000000..e4fc7eb273 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb @@ -0,0 +1,59 @@ +# 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 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb new file mode 100644 index 0000000000..d4e53a67b6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'signature_cop' + +module RuboCop + module Cop + module Sorbet + # This cop 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 + # be redundant; only `checked(false)` or `soft` would change the behaviour. + # + # @example + # + # # bad + # sig { void.checked(true) } + # + # # good + # sig { void } + class CheckedTrueInSignature < SignatureCop + include(RuboCop::Cop::RangeHelp) + + def_node_search(:offending_node, <<~PATTERN) + (send _ :checked (true)) + 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)`.' + private_constant(:MESSAGE) + + def on_signature(node) + error = offending_node(node).first + return unless error + + add_offense( + error, + location: source_range( + processed_source.buffer, + error.location.line, + (error.location.selector.begin_pos)..(error.location.end.begin_pos), + ), + message: MESSAGE + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb new file mode 100644 index 0000000000..92e1f73642 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +require 'rubocop' +require 'stringio' +require_relative 'signature_cop' + +module RuboCop + module Cop + module Sorbet + # This cop checks that every method definition and attribute accessor has a Sorbet signature. + # + # It also suggest an autocorrect with placeholders so the following code: + # + # ``` + # def foo(a, b, c); end + # ``` + # + # Will be corrected as: + # + # ``` + # sig { params(a: T.untyped, b: T.untyped, c: T.untyped).returns(T.untyped) + # def foo(a, b, c); end + # ``` + # + # You can configure the placeholders used by changing the following options: + # + # * `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped') + # * `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped') + class EnforceSignatures < SignatureCop + def_node_matcher(:accessor?, <<-PATTERN) + (send nil? {:attr_reader :attr_writer :attr_accessor} ...) + PATTERN + + def on_def(node) + check_node(node) + end + + def on_defs(node) + check_node(node) + end + + def on_send(node) + return unless accessor?(node) + check_node(node) + end + + def autocorrect(node) + lambda do |corrector| + suggest = SigSuggestion.new(node.loc.column, param_type_placeholder, return_type_placeholder) + + if node.is_a?(RuboCop::AST::DefNode) # def something + node.arguments.each do |arg| + suggest.params << arg.children.first + end + elsif accessor?(node) # attr reader, writer, accessor + 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 + end + + corrector.insert_before(node.loc.expression, suggest.to_autocorrect) + end + end + + private + + def check_node(node) + prev = previous_node(node) + unless signature?(prev) + add_offense( + node, + message: "Each method is required to have a signature." + ) + end + end + + def previous_node(node) + parent = node.parent + return nil unless parent + parent.children[node.sibling_index - 1] + end + + def param_type_placeholder + cop_config['ParameterTypePlaceholder'] || 'T.untyped' + end + + def return_type_placeholder + cop_config['ReturnTypePlaceholder'] || 'T.untyped' + end + + class SigSuggestion + attr_accessor :params, :returns + + def initialize(indent, param_placeholder, return_placeholder) + @params = [] + @returns = nil + @indent = indent + @param_placeholder = param_placeholder + @return_placeholder = return_placeholder + end + + def to_autocorrect + out = StringIO.new + out << 'sig { ' + out << generate_params + out << generate_return + out << " }\n" + out << ' ' * @indent # preserve indent for the next line + out.string + end + + private + + def generate_params + return if @params.empty? + out = StringIO.new + out << 'params(' + out << @params.map do |param| + "#{param}: #{@param_placeholder}" + end.join(", ") + out << ').' + out.string + end + + def generate_return + return "returns(#{@return_placeholder})" if @returns.nil? + return @returns if @returns == 'void' + "returns(#{@returns})" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb new file mode 100644 index 0000000000..800115304e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'signature_cop' + +module RuboCop + module Cop + module Sorbet + # This cop 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. + # + # @example + # + # # bad + # sig { params(a: Integer, b: String).void } + # def foo(a: 1, b:); end + # + # # good + # sig { params(b: String, a: Integer).void } + # def foo(b:, a: 1); end + class KeywordArgumentOrdering < SignatureCop + 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) + end + + private + + def check_order_for_kwoptargs(parameters) + out_of_kwoptarg = false + + parameters.reverse.each do |param| + out_of_kwoptarg = true unless param.type == :kwoptarg || param.type == :blockarg || param.type == :kwrestarg + + next unless param.type == :kwoptarg && out_of_kwoptarg + + add_offense( + param, + message: 'Optional keyword arguments must be at the end of the parameter list.' + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/parameters_ordering_in_signature.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/parameters_ordering_in_signature.rb new file mode 100644 index 0000000000..9c442fb005 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/parameters_ordering_in_signature.rb @@ -0,0 +1,70 @@ +# 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 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_build_order.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_build_order.rb new file mode 100644 index 0000000000..245cf8fbf3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_build_order.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require 'rubocop' +require_relative 'signature_cop' + +begin + require 'unparser' +rescue LoadError + nil +end + +module RuboCop + module Cop + module Sorbet + class SignatureBuildOrder < SignatureCop + ORDER = + [ + :abstract, + :override, + :overridable, + :type_parameters, + :params, + :returns, + :void, + :soft, + :checked, + :on_failure, + ].each_with_index.to_h.freeze + + 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? + + 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(', ')}." + + unless can_autocorrect? + message += ' For autocorrection, add the `unparser` gem to your project.' + end + + add_offense( + node.children[2], + message: message, + ) + node + end + + def autocorrect(node) + return nil unless can_autocorrect? + + lambda do |corrector| + tree = call_chain(node_with_index_sends(node)) + .sort_by { |call| ORDER[call.method_name] } + .reduce(nil) do |receiver, caller| + caller.updated(nil, [receiver] + caller.children.drop(1)) + end + + corrector.replace( + node.source_range, + Unparser.unparse(tree), + ) + end + end + + private + + def node_with_index_sends(node) + # This is really dirty hack to reparse the current node with index send + # emitting enabled, which is necessary to unparse them back as index accessors. + emit_index_value = RuboCop::AST::Builder.emit_index + RuboCop::AST::Builder.emit_index = true + RuboCop::AST::ProcessedSource.new(node.source, target_ruby_version, processed_source.path).ast + ensure + RuboCop::AST::Builder.emit_index = emit_index_value + end + + def can_autocorrect? + defined?(::Unparser) + end + + def call_chain(sig_child_node) + call_node = root_call(sig_child_node).first + return [] unless call_node + + calls = [] + while call_node != sig_child_node + calls << call_node + call_node = call_node.parent + end + + calls << sig_child_node + + calls + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_cop.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_cop.rb new file mode 100644 index 0000000000..d583799d81 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet/signatures/signature_cop.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rubocop' + +module RuboCop + module Cop + module Sorbet + # 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 + @registry = Cop.registry # So we can properly subclass this cop + + def_node_matcher(:signature?, <<~PATTERN) + (block (send nil? :sig) (args) ...) + PATTERN + + def on_block(node) + on_signature(node) if signature?(node) + end + + def on_signature(_) + # To be defined in subclasses + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet_cops.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet_cops.rb new file mode 100644 index 0000000000..b61037489f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/cop/sorbet_cops.rb @@ -0,0 +1,22 @@ +# 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/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' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet.rb new file mode 100644 index 0000000000..ddfa9e7a51 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +require "rubocop/sorbet/version" +require "yaml" + +module RuboCop + module Sorbet + class Error < StandardError; end + + PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze + CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze + CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze + + private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/inject.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/inject.rb new file mode 100644 index 0000000000..f0440faac0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/inject.rb @@ -0,0 +1,20 @@ +# 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 diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/version.rb new file mode 100644 index 0000000000..ea49b569f3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +module RuboCop + module Sorbet + VERSION = "0.5.1" + end +end