More Sorbet typed: strict RuboCops
				
					
				
			- Some of these I bumped to `typed: strict`, some of them I added intermediary type signatures to some of the methods to make my life easier in the (near, hopefully) future. - Turns out that RuboCop node matchers that end in `?` can return `nil` if they don't match anything, not `false`.
This commit is contained in:
		
							parent
							
								
									4ee6e96bdf
								
							
						
					
					
						commit
						0fc1eb534b
					
				@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -44,6 +44,7 @@ module RuboCop
 | 
			
		||||
          )
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).void }
 | 
			
		||||
        def on_or(node)
 | 
			
		||||
          nil_or_empty?(node) do |var1, var2|
 | 
			
		||||
            return if var1 != var2
 | 
			
		||||
@ -57,14 +58,16 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        private
 | 
			
		||||
 | 
			
		||||
        sig { params(corrector: RuboCop::Cop::Corrector, node: RuboCop::AST::Node).void }
 | 
			
		||||
        def autocorrect(corrector, node)
 | 
			
		||||
          variable1, _variable2 = nil_or_empty?(node)
 | 
			
		||||
          range = node.source_range
 | 
			
		||||
          corrector.replace(range, replacement(variable1))
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: T.nilable(RuboCop::AST::Node)).returns(String) }
 | 
			
		||||
        def replacement(node)
 | 
			
		||||
          node.respond_to?(:source) ? "#{node.source}.blank?" : "blank?"
 | 
			
		||||
          node.respond_to?(:source) ? "#{node&.source}.blank?" : "blank?"
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -174,12 +174,14 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(nodes: T::Array[RuboCop::AST::SendNode]).returns(T::Array[T.any(String, Symbol)]) }
 | 
			
		||||
        def sha256_order(nodes)
 | 
			
		||||
          nodes.map do |node|
 | 
			
		||||
            sha256_bottle_tag node
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: AST::SendNode).returns(T.any(String, Symbol)) }
 | 
			
		||||
        def sha256_bottle_tag(node)
 | 
			
		||||
          hash_pair = node.last_argument.pairs.last
 | 
			
		||||
          if hash_pair.key.sym_type?
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ module RuboCop
 | 
			
		||||
      class ArrayAlphabetization < Base
 | 
			
		||||
        extend AutoCorrector
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return unless [:zap, :uninstall].include?(node.method_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -23,6 +23,7 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(checksum: T.nilable(RuboCop::AST::Node)).void }
 | 
			
		||||
        def audit_sha256(checksum)
 | 
			
		||||
          return if checksum.nil?
 | 
			
		||||
 | 
			
		||||
@ -37,7 +38,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          return unless regex_match_group(checksum, /[^a-f0-9]+/i)
 | 
			
		||||
 | 
			
		||||
          add_offense(@offensive_source_range, message: "sha256 contains invalid characters")
 | 
			
		||||
          add_offense(T.must(@offensive_source_range), message: "sha256 contains invalid characters")
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -54,9 +55,9 @@ module RuboCop
 | 
			
		||||
            next unless regex_match_group(checksum, /[A-F]+/)
 | 
			
		||||
 | 
			
		||||
            add_offense(@offensive_source_range, message: "sha256 should be lowercase") do |corrector|
 | 
			
		||||
              correction = @offensive_node.source.downcase
 | 
			
		||||
              corrector.insert_before(@offensive_node.source_range, correction)
 | 
			
		||||
              corrector.remove(@offensive_node.source_range)
 | 
			
		||||
              correction = T.must(@offensive_node).source.downcase
 | 
			
		||||
              corrector.insert_before(T.must(@offensive_node).source_range, correction)
 | 
			
		||||
              corrector.remove(T.must(@offensive_node).source_range)
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,7 @@ module RuboCop
 | 
			
		||||
              (sym :blank?)))
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return unless bad_method?(node)
 | 
			
		||||
 | 
			
		||||
@ -74,6 +75,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        private
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).returns(T::Boolean) }
 | 
			
		||||
        def bad_method?(node)
 | 
			
		||||
          return true if reject_with_block_pass?(node)
 | 
			
		||||
 | 
			
		||||
@ -93,6 +95,7 @@ module RuboCop
 | 
			
		||||
          arguments.length == 2 && arguments[1].source == receiver_in_block.source
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).returns(Parser::Source::Range) }
 | 
			
		||||
        def offense_range(node)
 | 
			
		||||
          end_pos = if node.parent&.block_type? && node.parent&.send_node == node
 | 
			
		||||
            node.parent.source_range.end_pos
 | 
			
		||||
@ -103,6 +106,7 @@ module RuboCop
 | 
			
		||||
          range_between(node.loc.selector.begin_pos, end_pos)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).returns(String) }
 | 
			
		||||
        def preferred_method(node)
 | 
			
		||||
          node.method?(:reject) ? "compact_blank" : "compact_blank!"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -22,7 +22,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
            reason = parameters(conflicts_with_call).last.values.first
 | 
			
		||||
            offending_node(reason)
 | 
			
		||||
            name = Regexp.new(@formula_name, Regexp::IGNORECASE)
 | 
			
		||||
            name = Regexp.new(T.must(@formula_name), Regexp::IGNORECASE)
 | 
			
		||||
            reason_text = string_content(reason).sub(name, "")
 | 
			
		||||
            first_word = reason_text.split.first
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ module RuboCop
 | 
			
		||||
          if !tap_style_exception?(:versioned_formulae_conflicts_allowlist) && method_called_ever?(body_node,
 | 
			
		||||
                                                                                                   :conflicts_with)
 | 
			
		||||
            problem MSG do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "keg_only :versioned_formula")
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "keg_only :versioned_formula")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -61,13 +61,13 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
              if reason_string.start_with?("it ")
 | 
			
		||||
                problem "Do not start the reason with `it`" do |corrector|
 | 
			
		||||
                  corrector.replace(@offensive_node.source_range, "\"#{reason_string[3..]}\"")
 | 
			
		||||
                  corrector.replace(T.must(@offensive_node).source_range, "\"#{reason_string[3..]}\"")
 | 
			
		||||
                end
 | 
			
		||||
              end
 | 
			
		||||
 | 
			
		||||
              if PUNCTUATION_MARKS.include?(reason_string[-1])
 | 
			
		||||
                problem "Do not end the reason with a punctuation mark" do |corrector|
 | 
			
		||||
                  corrector.replace(@offensive_node.source_range, "\"#{reason_string.chop}\"")
 | 
			
		||||
                  corrector.replace(T.must(@offensive_node).source_range, "\"#{reason_string.chop}\"")
 | 
			
		||||
                end
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -17,7 +17,7 @@ module RuboCop
 | 
			
		||||
        def audit_formula(formula_nodes)
 | 
			
		||||
          body_node = formula_nodes.body_node
 | 
			
		||||
 | 
			
		||||
          @name = @formula_name
 | 
			
		||||
          @name = T.let(@formula_name, T.nilable(String))
 | 
			
		||||
          desc_call = find_node_method_by_name(body_node, :desc)
 | 
			
		||||
          offending_node(formula_nodes.class_node) if body_node.nil?
 | 
			
		||||
          audit_desc(:formula, @name, desc_call)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/shared/helper_functions"
 | 
			
		||||
@ -14,9 +14,10 @@ module RuboCop
 | 
			
		||||
      abstract!
 | 
			
		||||
      exclude_from_registry
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      attr_accessor :file_path
 | 
			
		||||
 | 
			
		||||
      @registry = Registry.global
 | 
			
		||||
      @registry = T.let(Registry.global, RuboCop::Cop::Registry)
 | 
			
		||||
 | 
			
		||||
      class FormulaNodes < T::Struct
 | 
			
		||||
        prop :node, RuboCop::AST::ClassNode
 | 
			
		||||
@ -26,15 +27,18 @@ module RuboCop
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # This method is called by RuboCop and is the main entry point.
 | 
			
		||||
      sig { params(node: RuboCop::AST::ClassNode).void }
 | 
			
		||||
      def on_class(node)
 | 
			
		||||
        @file_path = processed_source.file_path
 | 
			
		||||
        @file_path = T.let(processed_source.file_path, T.nilable(String))
 | 
			
		||||
        return unless file_path_allowed?
 | 
			
		||||
        return unless formula_class?(node)
 | 
			
		||||
 | 
			
		||||
        class_node, parent_class_node, @body = *node
 | 
			
		||||
        @formula_name = Pathname.new(@file_path).basename(".rb").to_s
 | 
			
		||||
        @tap_style_exceptions = nil
 | 
			
		||||
        audit_formula(FormulaNodes.new(node:, class_node:, parent_class_node:, body_node: @body))
 | 
			
		||||
        class_node, parent_class_node, body = *node
 | 
			
		||||
        @body = T.let(body, T.nilable(RuboCop::AST::Node))
 | 
			
		||||
 | 
			
		||||
        @formula_name = T.let(Pathname.new(@file_path).basename(".rb").to_s, T.nilable(String))
 | 
			
		||||
        @tap_style_exceptions = T.let(nil, T.nilable(T::Hash[Symbol, T::Array[String]]))
 | 
			
		||||
        audit_formula(FormulaNodes.new(node:, class_node:, parent_class_node:, body_node: T.must(@body)))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { abstract.params(formula_nodes: FormulaNodes).void }
 | 
			
		||||
@ -44,7 +48,13 @@ module RuboCop
 | 
			
		||||
      #
 | 
			
		||||
      # @param urls [Array] url/mirror method call nodes
 | 
			
		||||
      # @param regex [Regexp] pattern to match URLs
 | 
			
		||||
      def audit_urls(urls, regex)
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          urls: T::Array[RuboCop::AST::Node], regex: Regexp,
 | 
			
		||||
          _block: T.proc.params(arg0: T::Array[RuboCop::AST::Node], arg1: String, arg2: Integer).void
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_urls(urls, regex, &_block)
 | 
			
		||||
        urls.each_with_index do |url_node, index|
 | 
			
		||||
          url_string_node = parameters(url_node).first
 | 
			
		||||
          url_string = string_content(url_string_node)
 | 
			
		||||
@ -59,6 +69,7 @@ module RuboCop
 | 
			
		||||
      # Returns if the formula depends on dependency_name.
 | 
			
		||||
      #
 | 
			
		||||
      # @param dependency_name dependency's name
 | 
			
		||||
      sig { params(dependency_name: T.any(String, Symbol), types: Symbol).returns(T::Boolean) }
 | 
			
		||||
      def depends_on?(dependency_name, *types)
 | 
			
		||||
        return false if @body.nil?
 | 
			
		||||
 | 
			
		||||
@ -69,13 +80,20 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
        return false if idx.nil?
 | 
			
		||||
 | 
			
		||||
        @offensive_node = dependency_nodes[idx]
 | 
			
		||||
        @offensive_node = T.let(dependency_nodes[idx], T.nilable(RuboCop::AST::Node))
 | 
			
		||||
 | 
			
		||||
        true
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Returns true if given dependency name and dependency type exist in given dependency method call node.
 | 
			
		||||
      # TODO: Add case where key of hash is an array
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          node: RuboCop::AST::Node, name: T.nilable(T.any(String, Symbol)), type: Symbol,
 | 
			
		||||
        ).returns(
 | 
			
		||||
          T::Boolean,
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      def depends_on_name_type?(node, name = nil, type = :required)
 | 
			
		||||
        name_match = !name # Match only by type when name is nil
 | 
			
		||||
 | 
			
		||||
@ -88,8 +106,8 @@ module RuboCop
 | 
			
		||||
          name_match ||= dependency_name_hash_match?(node, name) if type_match
 | 
			
		||||
        when :any
 | 
			
		||||
          type_match = true
 | 
			
		||||
          name_match ||= required_dependency_name?(node, name)
 | 
			
		||||
          name_match ||= dependency_name_hash_match?(node, name)
 | 
			
		||||
          name_match ||= required_dependency_name?(node, name) || false
 | 
			
		||||
          name_match ||= dependency_name_hash_match?(node, name) || false
 | 
			
		||||
        else
 | 
			
		||||
          type_match = false
 | 
			
		||||
        end
 | 
			
		||||
@ -115,13 +133,15 @@ module RuboCop
 | 
			
		||||
      EOS
 | 
			
		||||
 | 
			
		||||
      # Return all the caveats' string nodes in an array.
 | 
			
		||||
      sig { returns(T::Array[RuboCop::AST::Node]) }
 | 
			
		||||
      def caveats_strings
 | 
			
		||||
        return [] if @body.nil?
 | 
			
		||||
 | 
			
		||||
        find_strings(find_method_def(@body, :caveats))
 | 
			
		||||
        find_strings(find_method_def(@body, :caveats)).to_a
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Returns the sha256 str node given a sha256 call node.
 | 
			
		||||
      sig { params(call: RuboCop::AST::Node).returns(T.nilable(RuboCop::AST::Node)) }
 | 
			
		||||
      def get_checksum_node(call)
 | 
			
		||||
        return if parameters(call).empty? || parameters(call).nil?
 | 
			
		||||
 | 
			
		||||
@ -144,7 +164,8 @@ module RuboCop
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Yields to a block with comment text as parameter.
 | 
			
		||||
      def audit_comments
 | 
			
		||||
      sig { params(_block: T.proc.params(arg0: String).void).void }
 | 
			
		||||
      def audit_comments(&_block)
 | 
			
		||||
        processed_source.comments.each do |comment_node|
 | 
			
		||||
          @offensive_node = comment_node
 | 
			
		||||
          yield comment_node.text
 | 
			
		||||
@ -152,20 +173,26 @@ module RuboCop
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Returns true if the formula is versioned.
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def versioned_formula?
 | 
			
		||||
        return false if @formula_name.nil?
 | 
			
		||||
 | 
			
		||||
        @formula_name.include?("@")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Returns the formula tap.
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def formula_tap
 | 
			
		||||
        return unless (match_obj = @file_path.match(%r{/(homebrew-\w+)/}))
 | 
			
		||||
        return unless (match_obj = @file_path&.match(%r{/(homebrew-\w+)/}))
 | 
			
		||||
 | 
			
		||||
        match_obj[1]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Returns the style exceptions directory from the file path.
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def style_exceptions_dir
 | 
			
		||||
        file_directory = File.dirname(@file_path)
 | 
			
		||||
        file_directory = File.dirname(@file_path) if @file_path
 | 
			
		||||
        return unless file_directory
 | 
			
		||||
 | 
			
		||||
        # if we're in a sharded subdirectory, look below that.
 | 
			
		||||
        directory_name = File.basename(file_directory)
 | 
			
		||||
@ -189,6 +216,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
      # Returns whether the given formula exists in the given style exception list.
 | 
			
		||||
      # Defaults to the current formula being checked.
 | 
			
		||||
      sig { params(list: Symbol, formula: T.nilable(String)).returns(T::Boolean) }
 | 
			
		||||
      def tap_style_exception?(list, formula = nil)
 | 
			
		||||
        if @tap_style_exceptions.nil? && !formula_tap.nil?
 | 
			
		||||
          @tap_style_exceptions = {}
 | 
			
		||||
@ -209,11 +237,12 @@ module RuboCop
 | 
			
		||||
        return false if @tap_style_exceptions.nil? || @tap_style_exceptions.count.zero?
 | 
			
		||||
        return false unless @tap_style_exceptions.key? list
 | 
			
		||||
 | 
			
		||||
        @tap_style_exceptions[list].include?(formula || @formula_name)
 | 
			
		||||
        T.must(@tap_style_exceptions[list]).include?(formula || @formula_name)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(node: RuboCop::AST::Node).returns(T::Boolean) }
 | 
			
		||||
      def formula_class?(node)
 | 
			
		||||
        _, class_node, = *node
 | 
			
		||||
        class_names = %w[
 | 
			
		||||
@ -223,19 +252,24 @@ module RuboCop
 | 
			
		||||
          AmazonWebServicesFormula
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        class_node && class_names.include?(string_content(class_node))
 | 
			
		||||
        !!(class_node && class_names.include?(string_content(class_node)))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def file_path_allowed?
 | 
			
		||||
        return true if @file_path.nil? # file_path is nil when source is directly passed to the cop, e.g. in specs
 | 
			
		||||
 | 
			
		||||
        !@file_path.include?("/Library/Homebrew/test/")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Array[Symbol]) }
 | 
			
		||||
      def on_system_methods
 | 
			
		||||
        @on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersion::SYMBOLS.keys].map do |m|
 | 
			
		||||
          :"on_#{m}"
 | 
			
		||||
        end
 | 
			
		||||
        @on_system_methods ||= T.let(
 | 
			
		||||
          [:intel, :arm, :macos, :linux, :system, *MacOSVersion::SYMBOLS.keys].map do |m|
 | 
			
		||||
            :"on_#{m}"
 | 
			
		||||
          end,
 | 
			
		||||
          T.nilable(T::Array[Symbol]),
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -10,6 +10,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        RESTRICT_ON_SEND = [:read, :readlines].freeze
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return if node.receiver != s(:const, nil, :IO)
 | 
			
		||||
          return if safe?(node.arguments.first)
 | 
			
		||||
@ -19,10 +20,11 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        private
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).returns(T::Boolean) }
 | 
			
		||||
        def safe?(node)
 | 
			
		||||
          if node.str_type?
 | 
			
		||||
            !node.str_content.empty? && !node.str_content.start_with?("|")
 | 
			
		||||
          elsif node.dstr_type? || (node.send_type? && node.method?(:+))
 | 
			
		||||
          elsif node.dstr_type? || (node.send_type? && T.cast(node, RuboCop::AST::SendNode).method?(:+))
 | 
			
		||||
            safe?(node.children.first)
 | 
			
		||||
          else
 | 
			
		||||
            false
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -29,24 +29,25 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          reason = parameters(keg_only_node).first
 | 
			
		||||
          offending_node(reason)
 | 
			
		||||
          name = Regexp.new(@formula_name, Regexp::IGNORECASE)
 | 
			
		||||
          name = Regexp.new(T.must(@formula_name), Regexp::IGNORECASE)
 | 
			
		||||
          reason = string_content(reason).sub(name, "")
 | 
			
		||||
          first_word = reason.split.first
 | 
			
		||||
 | 
			
		||||
          if /\A[A-Z]/.match?(reason) && !reason.start_with?(*allowlist)
 | 
			
		||||
            problem "'#{first_word}' from the `keg_only` reason should be '#{first_word.downcase}'." do |corrector|
 | 
			
		||||
              reason[0] = reason[0].downcase
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "\"#{reason}\"")
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "\"#{reason}\"")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          return unless reason.end_with?(".")
 | 
			
		||||
 | 
			
		||||
          problem "`keg_only` reason should not end with a period." do |corrector|
 | 
			
		||||
            corrector.replace(@offensive_node.source_range, "\"#{reason.chop}\"")
 | 
			
		||||
            corrector.replace(T.must(@offensive_node).source_range, "\"#{reason.chop}\"")
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).void }
 | 
			
		||||
        def autocorrect(node)
 | 
			
		||||
          lambda do |corrector|
 | 
			
		||||
            reason = string_content(node)
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ module RuboCop
 | 
			
		||||
          return if begin_pos-end_pos == 3
 | 
			
		||||
 | 
			
		||||
          problem "Use a space in class inheritance: " \
 | 
			
		||||
                  "class #{@formula_name.capitalize} < #{class_name(parent_class_node)}"
 | 
			
		||||
                  "class #{T.must(@formula_name).capitalize} < #{class_name(parent_class_node)}"
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -181,9 +181,11 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).returns(T::Boolean) }
 | 
			
		||||
        def unless_modifier?(node)
 | 
			
		||||
          return false unless node.if_type?
 | 
			
		||||
 | 
			
		||||
          node = T.cast(node, RuboCop::AST::IfNode)
 | 
			
		||||
          node.modifier_form? && node.unless?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -207,8 +209,8 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :depends_on, "mpich") do
 | 
			
		||||
            problem "Formulae in homebrew/core should use 'depends_on \"open-mpi\"' " \
 | 
			
		||||
                    "instead of '#{@offensive_node.source}'." do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "depends_on \"open-mpi\"")
 | 
			
		||||
                    "instead of '#{T.must(@offensive_node).source}'." do |corrector|
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "depends_on \"open-mpi\"")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
@ -224,17 +226,19 @@ module RuboCop
 | 
			
		||||
          return if (body_node = formula_nodes.body_node).nil?
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :local_npm_install_args) do
 | 
			
		||||
            problem "Use 'std_npm_args' instead of '#{@offensive_node.method_name}'." do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "std_npm_args(prefix: false)")
 | 
			
		||||
            problem "Use 'std_npm_args' instead of '#{T.cast(@offensive_node,
 | 
			
		||||
                                                             RuboCop::AST::SendNode).method_name}'." do |corrector|
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "std_npm_args(prefix: false)")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :std_npm_install_args) do |method|
 | 
			
		||||
            problem "Use 'std_npm_args' instead of '#{@offensive_node.method_name}'." do |corrector|
 | 
			
		||||
            problem "Use 'std_npm_args' instead of '#{T.cast(@offensive_node,
 | 
			
		||||
                                                             RuboCop::AST::SendNode).method_name}'." do |corrector|
 | 
			
		||||
              if (param = parameters(method).first.source) == "libexec"
 | 
			
		||||
                corrector.replace(@offensive_node.source_range, "std_npm_args")
 | 
			
		||||
                corrector.replace(T.must(@offensive_node).source_range, "std_npm_args")
 | 
			
		||||
              else
 | 
			
		||||
                corrector.replace(@offensive_node.source_range, "std_npm_args(prefix: #{param})")
 | 
			
		||||
                corrector.replace(T.must(@offensive_node).source_range, "std_npm_args(prefix: #{param})")
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
@ -264,8 +268,8 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :depends_on, "quictls") do
 | 
			
		||||
            problem "Formulae in homebrew/core should use 'depends_on \"openssl@3\"' " \
 | 
			
		||||
                    "instead of '#{@offensive_node.source}'." do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "depends_on \"openssl@3\"")
 | 
			
		||||
                    "instead of '#{T.must(@offensive_node).source}'." do |corrector|
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "depends_on \"openssl@3\"")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
@ -281,7 +285,7 @@ module RuboCop
 | 
			
		||||
          return if formula_tap != "homebrew-core"
 | 
			
		||||
          return unless depends_on?("pyoxidizer")
 | 
			
		||||
 | 
			
		||||
          problem "Formulae in homebrew/core should not use '#{@offensive_node.source}'."
 | 
			
		||||
          problem "Formulae in homebrew/core should not use '#{T.must(@offensive_node).source}'."
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -307,7 +311,8 @@ module RuboCop
 | 
			
		||||
            find_instance_method_call(body_node, "Utils", unsafe_command) do |method|
 | 
			
		||||
              unless test_methods.include?(method.source_range)
 | 
			
		||||
                problem "Use `Utils.safe_#{unsafe_command}` instead of `Utils.#{unsafe_command}`" do |corrector|
 | 
			
		||||
                  corrector.replace(@offensive_node.loc.selector, "safe_#{@offensive_node.method_name}")
 | 
			
		||||
                  corrector.replace(T.must(@offensive_node).loc.selector,
 | 
			
		||||
                                    "safe_#{T.cast(@offensive_node, RuboCop::AST::SendNode).method_name}")
 | 
			
		||||
                end
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
@ -478,7 +483,10 @@ module RuboCop
 | 
			
		||||
      class MacOSOnLinux < FormulaCop
 | 
			
		||||
        include OnSystemConditionalsHelper
 | 
			
		||||
 | 
			
		||||
        ON_MACOS_BLOCKS = [:macos, *MACOS_VERSION_OPTIONS].map { |os| :"on_#{os}" }.freeze
 | 
			
		||||
        ON_MACOS_BLOCKS = T.let(
 | 
			
		||||
          [:macos, *MACOS_VERSION_OPTIONS].map { |os| :"on_#{os}" }.freeze,
 | 
			
		||||
          T::Array[Symbol],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        sig { override.params(formula_nodes: FormulaNodes).void }
 | 
			
		||||
        def audit_formula(formula_nodes)
 | 
			
		||||
@ -529,8 +537,8 @@ module RuboCop
 | 
			
		||||
            offending_node(node)
 | 
			
		||||
            replacement = "generate_completions_from_executable(#{replacement_args.join(", ")})"
 | 
			
		||||
 | 
			
		||||
            problem "Use `#{replacement}` instead of `#{@offensive_node.source}`." do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, replacement)
 | 
			
		||||
            problem "Use `#{replacement}` instead of `#{T.must(@offensive_node).source}`." do |corrector|
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, replacement)
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -539,7 +547,7 @@ module RuboCop
 | 
			
		||||
            next if node.source.match?(/{.*=>.*}/) # skip commands needing custom ENV variables
 | 
			
		||||
 | 
			
		||||
            offending_node(node)
 | 
			
		||||
            problem "Use `generate_completions_from_executable` DSL instead of `#{@offensive_node.source}`."
 | 
			
		||||
            problem "Use `generate_completions_from_executable` DSL instead of `#{T.must(@offensive_node).source}`."
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -608,7 +616,7 @@ module RuboCop
 | 
			
		||||
            problem "Use a single `generate_completions_from_executable` " \
 | 
			
		||||
                    "call combining all specified shells." do |corrector|
 | 
			
		||||
              # adjust range by -4 and +1 to also include & remove leading spaces and trailing \n
 | 
			
		||||
              corrector.replace(@offensive_node.source_range.adjust(begin_pos: -4, end_pos: 1), "")
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range.adjust(begin_pos: -4, end_pos: 1), "")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -616,17 +624,18 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          offending_node(offenses.last)
 | 
			
		||||
          replacement = if (%w[:bash :zsh :fish] - shells).empty?
 | 
			
		||||
            @offensive_node.source.sub(/shells: \[(:bash|:zsh|:fish)\]/, "")
 | 
			
		||||
                           .sub(", )", ")") # clean up dangling trailing comma
 | 
			
		||||
                           .sub("(, ", "(") # clean up dangling leading comma
 | 
			
		||||
                           .sub(", , ", ", ") # clean up dangling enclosed comma
 | 
			
		||||
            T.must(@offensive_node).source
 | 
			
		||||
             .sub(/shells: \[(:bash|:zsh|:fish)\]/, "")
 | 
			
		||||
             .sub(", )", ")") # clean up dangling trailing comma
 | 
			
		||||
             .sub("(, ", "(") # clean up dangling leading comma
 | 
			
		||||
             .sub(", , ", ", ") # clean up dangling enclosed comma
 | 
			
		||||
          else
 | 
			
		||||
            @offensive_node.source.sub(/shells: \[(:bash|:zsh|:fish)\]/,
 | 
			
		||||
                                       "shells: [#{shells.join(", ")}]")
 | 
			
		||||
            T.must(@offensive_node).source.sub(/shells: \[(:bash|:zsh|:fish)\]/,
 | 
			
		||||
                                               "shells: [#{shells.join(", ")}]")
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          problem "Use `#{replacement}` instead of `#{@offensive_node.source}`." do |corrector|
 | 
			
		||||
            corrector.replace(@offensive_node.source_range, replacement)
 | 
			
		||||
          problem "Use `#{replacement}` instead of `#{T.must(@offensive_node).source}`." do |corrector|
 | 
			
		||||
            corrector.replace(T.must(@offensive_node).source_range, replacement)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
@ -783,7 +792,7 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :system, /^(otool|install_name_tool|lipo)/) do
 | 
			
		||||
            problem "Use ruby-macho instead of calling #{@offensive_node.source}"
 | 
			
		||||
            problem "Use ruby-macho instead of calling #{T.must(@offensive_node).source}"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          problem "Use new-style test definitions (test do)" if find_method_def(body_node, :test)
 | 
			
		||||
@ -854,10 +863,11 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).returns(T::Boolean) }
 | 
			
		||||
        def modifier?(node)
 | 
			
		||||
          return false unless node.if_type?
 | 
			
		||||
 | 
			
		||||
          node.modifier_form?
 | 
			
		||||
          T.cast(node, RuboCop::AST::IfNode).modifier_form?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def_node_search :conditional_dependencies, <<~EOS
 | 
			
		||||
@ -892,7 +902,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          # Avoid build-time checks in homebrew/core
 | 
			
		||||
          find_every_method_call_by_name(formula_nodes.body_node, :system).each do |method|
 | 
			
		||||
            next if @formula_name.start_with?("lib")
 | 
			
		||||
            next if @formula_name&.start_with?("lib")
 | 
			
		||||
            next if tap_style_exception? :make_check_allowlist
 | 
			
		||||
 | 
			
		||||
            params = parameters(method)
 | 
			
		||||
@ -933,8 +943,8 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          find_method_with_args(body_node, :depends_on, "rustup") do
 | 
			
		||||
            problem "Formulae in homebrew/core should use 'depends_on \"rust\"' " \
 | 
			
		||||
                    "instead of '#{@offensive_node.source}'." do |corrector|
 | 
			
		||||
              corrector.replace(@offensive_node.source_range, "depends_on \"rust\"")
 | 
			
		||||
                    "instead of '#{T.must(@offensive_node).source}'." do |corrector|
 | 
			
		||||
              corrector.replace(T.must(@offensive_node).source_range, "depends_on \"rust\"")
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -943,8 +953,8 @@ module RuboCop
 | 
			
		||||
          [:build, [:build, :test], [:test, :build]].each do |type|
 | 
			
		||||
            find_method_with_args(body_node, :depends_on, "rustup" => type) do
 | 
			
		||||
              problem "Formulae in homebrew/core should use 'depends_on \"rust\" => #{type}' " \
 | 
			
		||||
                      "instead of '#{@offensive_node.source}'." do |corrector|
 | 
			
		||||
                corrector.replace(@offensive_node.source_range, "depends_on \"rust\" => #{type}")
 | 
			
		||||
                      "instead of '#{T.must(@offensive_node).source}'." do |corrector|
 | 
			
		||||
                corrector.replace(T.must(@offensive_node).source_range, "depends_on \"rust\" => #{type}")
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -12,6 +12,7 @@ module RuboCop
 | 
			
		||||
          (send (const nil? :OS) {:mac? | :linux?})
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return unless os_check?(node)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -32,6 +32,7 @@ module RuboCop
 | 
			
		||||
          (send (send $!nil? :include? $_) :!)
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return unless (receiver, obj = negate_include_call?(node))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -14,7 +14,7 @@ module RuboCop
 | 
			
		||||
        sig { override.params(formula_nodes: FormulaNodes).void }
 | 
			
		||||
        def audit_formula(formula_nodes)
 | 
			
		||||
          node = formula_nodes.node
 | 
			
		||||
          @full_source_content = source_buffer(node).source
 | 
			
		||||
          @full_source_content = T.let(source_buffer(node).source, T.nilable(String))
 | 
			
		||||
 | 
			
		||||
          return if (body_node = formula_nodes.body_node).nil?
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        private
 | 
			
		||||
 | 
			
		||||
        sig { params(patch_url_node: RuboCop::AST::Node).void }
 | 
			
		||||
        def patch_problems(patch_url_node)
 | 
			
		||||
          patch_url = string_content(patch_url_node)
 | 
			
		||||
 | 
			
		||||
@ -103,6 +104,7 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(patch: RuboCop::AST::Node).void }
 | 
			
		||||
        def inline_patch_problems(patch)
 | 
			
		||||
          return if !patch_data?(patch) || patch_end?
 | 
			
		||||
 | 
			
		||||
@ -119,13 +121,17 @@ module RuboCop
 | 
			
		||||
          /^__END__$/.match?(@full_source_content)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::Node).void }
 | 
			
		||||
        def offending_patch_end_node(node)
 | 
			
		||||
          @offensive_node = node
 | 
			
		||||
          @source_buf = source_buffer(node)
 | 
			
		||||
          @line_no = node.loc.last_line + 1
 | 
			
		||||
          @column = 0
 | 
			
		||||
          @length = 7 # "__END__".size
 | 
			
		||||
          @offense_source_range = source_range(@source_buf, @line_no, @column, @length)
 | 
			
		||||
          @offensive_node = T.let(node, T.nilable(RuboCop::AST::Node))
 | 
			
		||||
          @source_buf = T.let(source_buffer(node), T.nilable(Parser::Source::Buffer))
 | 
			
		||||
          @line_no = T.let(node.loc.last_line + 1, T.nilable(Integer))
 | 
			
		||||
          @column = T.let(0, T.nilable(Integer))
 | 
			
		||||
          @length = T.let(7, T.nilable(Integer)) # "__END__".size
 | 
			
		||||
          @offense_source_range = T.let(
 | 
			
		||||
            source_range(@source_buf, @line_no, @column, @length),
 | 
			
		||||
            T.nilable(Parser::Source::Range),
 | 
			
		||||
          )
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -78,6 +78,7 @@ module RuboCop
 | 
			
		||||
          }
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::IfNode).void }
 | 
			
		||||
        def on_if(node)
 | 
			
		||||
          return if ignore_if_node?(node)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -37,6 +37,7 @@ module RuboCop
 | 
			
		||||
          )
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::AndNode).void }
 | 
			
		||||
        def on_and(node)
 | 
			
		||||
          exists_and_not_empty?(node) do |var1, var2|
 | 
			
		||||
            return if var1 != var2
 | 
			
		||||
@ -49,6 +50,7 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::OrNode).void }
 | 
			
		||||
        def on_or(node)
 | 
			
		||||
          exists_and_not_empty?(node) do |var1, var2|
 | 
			
		||||
            return if var1 != var2
 | 
			
		||||
@ -59,6 +61,7 @@ module RuboCop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(corrector: RuboCop::Cop::Corrector, node: RuboCop::AST::Node).void }
 | 
			
		||||
        def autocorrect(corrector, node)
 | 
			
		||||
          variable1, _variable2 = exists_and_not_empty?(node)
 | 
			
		||||
          range = node.source_range
 | 
			
		||||
@ -67,8 +70,9 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        private
 | 
			
		||||
 | 
			
		||||
        sig { params(node: T.nilable(RuboCop::AST::Node)).returns(String) }
 | 
			
		||||
        def replacement(node)
 | 
			
		||||
          node.respond_to?(:source) ? "#{node.source}.present?" : "present?"
 | 
			
		||||
          node.respond_to?(:source) ? "#{node&.source}.present?" : "present?"
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RuboCop
 | 
			
		||||
@ -36,6 +36,7 @@ module RuboCop
 | 
			
		||||
          (if $(csend ... :blank?) ...)
 | 
			
		||||
        PATTERN
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::IfNode).void }
 | 
			
		||||
        def on_if(node)
 | 
			
		||||
          return unless safe_navigation_blank_in_conditional?(node)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -10,14 +10,17 @@ module RuboCop
 | 
			
		||||
      class Service < FormulaCop
 | 
			
		||||
        extend AutoCorrector
 | 
			
		||||
 | 
			
		||||
        CELLAR_PATH_AUDIT_CORRECTIONS = {
 | 
			
		||||
          bin:      :opt_bin,
 | 
			
		||||
          libexec:  :opt_libexec,
 | 
			
		||||
          pkgshare: :opt_pkgshare,
 | 
			
		||||
          prefix:   :opt_prefix,
 | 
			
		||||
          sbin:     :opt_sbin,
 | 
			
		||||
          share:    :opt_share,
 | 
			
		||||
        }.freeze
 | 
			
		||||
        CELLAR_PATH_AUDIT_CORRECTIONS = T.let(
 | 
			
		||||
          {
 | 
			
		||||
            bin:      :opt_bin,
 | 
			
		||||
            libexec:  :opt_libexec,
 | 
			
		||||
            pkgshare: :opt_pkgshare,
 | 
			
		||||
            prefix:   :opt_prefix,
 | 
			
		||||
            sbin:     :opt_sbin,
 | 
			
		||||
            share:    :opt_share,
 | 
			
		||||
          }.freeze,
 | 
			
		||||
          T::Hash[Symbol, Symbol],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # At least one of these methods must be defined in a service block.
 | 
			
		||||
        REQUIRED_METHOD_CALLS = [:run, :name].freeze
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ module RuboCop
 | 
			
		||||
        macOS
 | 
			
		||||
      ].freeze
 | 
			
		||||
 | 
			
		||||
      sig { params(type: Symbol, name: T.nilable(String), desc_call: T.nilable(RuboCop::AST::Node)).void }
 | 
			
		||||
      def audit_desc(type, name, desc_call)
 | 
			
		||||
        # Check if a desc is present.
 | 
			
		||||
        if desc_call.nil?
 | 
			
		||||
@ -26,7 +27,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        @offensive_node = desc_call
 | 
			
		||||
 | 
			
		||||
        desc = desc_call.first_argument
 | 
			
		||||
        desc = T.cast(desc_call, RuboCop::AST::SendNode).first_argument
 | 
			
		||||
 | 
			
		||||
        # Check if the desc is empty.
 | 
			
		||||
        desc_length = string_content(desc).length
 | 
			
		||||
@ -56,7 +57,7 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Check if the desc starts with the formula's or cask's name.
 | 
			
		||||
        name_regex = name.delete("-").chars.join('[\s\-]?')
 | 
			
		||||
        name_regex = T.must(name).delete("-").chars.join('[\s\-]?')
 | 
			
		||||
        if regex_match_group(desc, /^#{name_regex}\b/i)
 | 
			
		||||
          desc_problem "Description shouldn't start with the #{type} name."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,10 @@ module RuboCop
 | 
			
		||||
        @line_no = line_number(node)
 | 
			
		||||
        @source_buf = source_buffer(node)
 | 
			
		||||
        @offensive_node = node
 | 
			
		||||
        @offensive_source_range = source_range(@source_buf, @line_no, @column, @length)
 | 
			
		||||
        @offensive_source_range = T.let(
 | 
			
		||||
          source_range(@source_buf, @line_no, @column, @length),
 | 
			
		||||
          T.nilable(Parser::Source::Range),
 | 
			
		||||
        )
 | 
			
		||||
        match_object
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -53,6 +56,7 @@ module RuboCop
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Source buffer is required as an argument to report style violations.
 | 
			
		||||
      sig { params(node: RuboCop::AST::Node).returns(Parser::Source::Buffer) }
 | 
			
		||||
      def source_buffer(node)
 | 
			
		||||
        node.source_range.source_buffer
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/shared/helper_functions"
 | 
			
		||||
@ -9,8 +9,15 @@ module RuboCop
 | 
			
		||||
    module HomepageHelper
 | 
			
		||||
      include HelperFunctions
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          type: Symbol, content: String,
 | 
			
		||||
          homepage_node: RuboCop::AST::Node,
 | 
			
		||||
          homepage_parameter_node: RuboCop::AST::Node
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_homepage(type, content, homepage_node, homepage_parameter_node)
 | 
			
		||||
        @offensive_node = homepage_node
 | 
			
		||||
        @offensive_node = T.let(homepage_node, T.nilable(RuboCop::AST::Node))
 | 
			
		||||
 | 
			
		||||
        problem "#{type.to_s.capitalize} should have a homepage." if content.empty?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "macos_version"
 | 
			
		||||
@ -13,16 +13,23 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
      ARCH_OPTIONS = [:arm, :intel].freeze
 | 
			
		||||
      BASE_OS_OPTIONS = [:macos, :linux].freeze
 | 
			
		||||
      MACOS_VERSION_OPTIONS = MacOSVersion::SYMBOLS.keys.freeze
 | 
			
		||||
      ON_SYSTEM_OPTIONS = [*ARCH_OPTIONS, *BASE_OS_OPTIONS, *MACOS_VERSION_OPTIONS, :system].freeze
 | 
			
		||||
      MACOS_VERSION_OPTIONS = T.let(MacOSVersion::SYMBOLS.keys.freeze, T::Array[Symbol])
 | 
			
		||||
      ON_SYSTEM_OPTIONS = T.let(
 | 
			
		||||
        [*ARCH_OPTIONS, *BASE_OS_OPTIONS, *MACOS_VERSION_OPTIONS, :system].freeze,
 | 
			
		||||
        T::Array[Symbol],
 | 
			
		||||
      )
 | 
			
		||||
      MACOS_MODULE_NAMES = ["MacOS", "OS::Mac"].freeze
 | 
			
		||||
 | 
			
		||||
      MACOS_VERSION_CONDITIONALS = {
 | 
			
		||||
        "==" => nil,
 | 
			
		||||
        "<=" => :or_older,
 | 
			
		||||
        ">=" => :or_newer,
 | 
			
		||||
      }.freeze
 | 
			
		||||
      MACOS_VERSION_CONDITIONALS = T.let(
 | 
			
		||||
        {
 | 
			
		||||
          "==" => nil,
 | 
			
		||||
          "<=" => :or_older,
 | 
			
		||||
          ">=" => :or_newer,
 | 
			
		||||
        }.freeze,
 | 
			
		||||
        T::Hash[String, T.nilable(Symbol)],
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      sig { params(body_node: RuboCop::AST::Node, parent_name: Symbol).void }
 | 
			
		||||
      def audit_on_system_blocks(body_node, parent_name)
 | 
			
		||||
        parent_string = if body_node.def_type?
 | 
			
		||||
          "def #{parent_name}"
 | 
			
		||||
@ -77,6 +84,12 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          body_node: RuboCop::AST::Node, allowed_methods: T::Array[Symbol],
 | 
			
		||||
          allowed_blocks: T::Array[Symbol]
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_arch_conditionals(body_node, allowed_methods: [], allowed_blocks: [])
 | 
			
		||||
        ARCH_OPTIONS.each do |arch_option|
 | 
			
		||||
          else_method = (arch_option == :arm) ? :on_intel : :on_arm
 | 
			
		||||
@ -100,6 +113,12 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          body_node: RuboCop::AST::Node, allowed_methods: T::Array[Symbol],
 | 
			
		||||
          allowed_blocks: T::Array[Symbol]
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_base_os_conditionals(body_node, allowed_methods: [], allowed_blocks: [])
 | 
			
		||||
        BASE_OS_OPTIONS.each do |base_os_option|
 | 
			
		||||
          os_method, else_method = if base_os_option == :macos
 | 
			
		||||
@ -116,12 +135,21 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          body_node:           RuboCop::AST::Node,
 | 
			
		||||
          allowed_methods:     T::Array[Symbol],
 | 
			
		||||
          allowed_blocks:      T::Array[Symbol],
 | 
			
		||||
          recommend_on_system: T::Boolean,
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_macos_version_conditionals(body_node, allowed_methods: [], allowed_blocks: [],
 | 
			
		||||
                                           recommend_on_system: true)
 | 
			
		||||
        MACOS_VERSION_OPTIONS.each do |macos_version_option|
 | 
			
		||||
          if_macos_version_node_search(body_node, os_version: macos_version_option) do |if_node, operator, else_node|
 | 
			
		||||
            next if node_is_allowed?(if_node, allowed_methods:, allowed_blocks:)
 | 
			
		||||
 | 
			
		||||
            else_node = T.let(else_node, T.nilable(RuboCop::AST::Node))
 | 
			
		||||
            autocorrect = else_node.blank? && MACOS_VERSION_CONDITIONALS.key?(operator.to_s)
 | 
			
		||||
            on_system_method_string = if recommend_on_system && operator == :<
 | 
			
		||||
              "on_system"
 | 
			
		||||
@ -148,6 +176,13 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          body_node:       RuboCop::AST::Node,
 | 
			
		||||
          allowed_methods: T::Array[Symbol],
 | 
			
		||||
          allowed_blocks:  T::Array[Symbol],
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def audit_macos_references(body_node, allowed_methods: [], allowed_blocks: [])
 | 
			
		||||
        MACOS_MODULE_NAMES.each do |macos_module_name|
 | 
			
		||||
          find_const(body_node, macos_module_name) do |node|
 | 
			
		||||
@ -161,6 +196,16 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          if_node:                 RuboCop::AST::IfNode,
 | 
			
		||||
          if_statement_string:     String,
 | 
			
		||||
          on_system_method_string: String,
 | 
			
		||||
          else_method:             T.nilable(Symbol),
 | 
			
		||||
          else_node:               T.nilable(RuboCop::AST::Node),
 | 
			
		||||
          autocorrect:             T::Boolean,
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def if_statement_problem(if_node, if_statement_string, on_system_method_string,
 | 
			
		||||
                               else_method: nil, else_node: nil, autocorrect: true)
 | 
			
		||||
        offending_node(if_node)
 | 
			
		||||
@ -180,6 +225,12 @@ module RuboCop
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          node: RuboCop::AST::Node, allowed_methods: T::Array[Symbol],
 | 
			
		||||
          allowed_blocks: T::Array[Symbol]
 | 
			
		||||
        ).returns(T::Boolean)
 | 
			
		||||
      }
 | 
			
		||||
      def node_is_allowed?(node, allowed_methods: [], allowed_blocks: [])
 | 
			
		||||
        # TODO: check to see if it's legal
 | 
			
		||||
        valid = T.let(false, T::Boolean)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "extend/array"
 | 
			
		||||
@ -64,8 +64,12 @@ module RuboCop
 | 
			
		||||
        ].freeze
 | 
			
		||||
        private_constant :TARGET_METHODS
 | 
			
		||||
 | 
			
		||||
        RESTRICT_ON_SEND = TARGET_METHODS.map(&:second).uniq.freeze
 | 
			
		||||
        RESTRICT_ON_SEND = T.let(
 | 
			
		||||
          TARGET_METHODS.map(&:second).uniq.freeze,
 | 
			
		||||
          T::Array[T.nilable(Symbol)],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          TARGET_METHODS.each do |target_class, target_method|
 | 
			
		||||
            next if node.method_name != target_method
 | 
			
		||||
@ -119,6 +123,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        RESTRICT_ON_SEND = [:exec].freeze
 | 
			
		||||
 | 
			
		||||
        sig { params(node: RuboCop::AST::SendNode).void }
 | 
			
		||||
        def on_send(node)
 | 
			
		||||
          return if node.receiver.present? && node.receiver != s(:const, nil, :Kernel)
 | 
			
		||||
          return if node.arguments.count != 1
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
@ -133,7 +133,7 @@ module RuboCop
 | 
			
		||||
            problem "`env :userpaths` in homebrew/core formulae is deprecated"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          share_path_starts_with(body_node, @formula_name) do |share_node|
 | 
			
		||||
          share_path_starts_with(body_node, T.must(@formula_name)) do |share_node|
 | 
			
		||||
            offending_node(share_node)
 | 
			
		||||
            problem "Use `pkgshare` instead of `share/\"#{@formula_name}\"`"
 | 
			
		||||
          end
 | 
			
		||||
@ -162,11 +162,13 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
        # Check whether value starts with the formula name and then a "/", " " or EOS.
 | 
			
		||||
        # If we're checking for "#{bin}", we also check for "-" since similar binaries also don't need interpolation.
 | 
			
		||||
        sig { params(path: String, starts_with: String, bin: T::Boolean).returns(T::Boolean) }
 | 
			
		||||
        def path_starts_with?(path, starts_with, bin: false)
 | 
			
		||||
          ending = bin ? "/|-|$" : "/| |$"
 | 
			
		||||
          path.match?(/^#{Regexp.escape(starts_with)}(#{ending})/)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(path: String, starts_with: String).returns(T::Boolean) }
 | 
			
		||||
        def path_starts_with_bin?(path, starts_with)
 | 
			
		||||
          return false if path.include?(" ")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          # Check for binary URLs
 | 
			
		||||
          audit_urls(urls, /(darwin|macos|osx)/i) do |match, url|
 | 
			
		||||
            next if @formula_name.include?(match.to_s.downcase)
 | 
			
		||||
            next if T.must(@formula_name).include?(match.to_s.downcase)
 | 
			
		||||
            next if url.match?(/.(patch|diff)(\?full_index=1)?$/)
 | 
			
		||||
            next if tap_style_exception? :not_a_binary_url_prefix_allowlist
 | 
			
		||||
            next if tap_style_exception? :binary_bootstrap_formula_urls_allowlist
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "rubocops/extend/formula_cop"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user