Sha256: 6450eafc406e381db368e476e178bead6d4d129d7ede0d7ddd185b331ddd79c9

Contents?: true

Size: 1.94 KB

Versions: 12

Compression:

Stored size: 1.94 KB

Contents

# encoding: utf-8
# frozen_string_literal: true

require "rubocop"

module RuboCop
  module Cop
    module Sorbet
      # Correct `send` expressions in include statements by constant literals.
      #
      # Sorbet, the static checker, is not (yet) able to support constructs on the
      # following form:
      #
      # ```ruby
      # class MyClass
      #   include send_expr
      # end
      # ```
      #
      # Multiple occurences of this can be found in Shopify's code base like:
      #
      # ```ruby
      # include Rails.application.routes.url_helpers
      # ```
      # or
      # ```ruby
      # include Polaris::Engine.helpers
      # ```
      class ForbidIncludeConstLiteral < RuboCop::Cop::Base
        extend AutoCorrector

        MSG = "`%<inclusion_method>s` must only be used with constant literals as arguments"
        RESTRICT_ON_SEND = [:include, :extend, :prepend].freeze

        # @!method dynamic_inclusion?(node)
        def_node_matcher :dynamic_inclusion?, <<~PATTERN
          (send nil? ${:include :extend :prepend} $#neither_const_nor_self?)
        PATTERN

        def on_send(node)
          dynamic_inclusion?(node) do |inclusion_method, included|
            return unless within_onymous_module?(node)

            add_offense(node, message: format(MSG, inclusion_method: inclusion_method)) do |corrector|
              corrector.replace(node, "T.unsafe(self).#{inclusion_method} #{included.source}")
            end
          end
        end

        private

        def neither_const_nor_self?(node)
          !node.const_type? && !node.self_type?
        end

        # Returns true if the node is within a module declaration that is not anonymous.
        def within_onymous_module?(node)
          parent = node.parent
          parent = parent.parent while parent&.begin_type? || parent&.block_type?
          parent && (parent.module_type? || parent.class_type? || parent.sclass_type?)
        end
      end
    end
  end
end

Version data entries

12 entries across 12 versions & 1 rubygems

Version Path
rubocop-sorbet-0.8.7 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.6 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.5 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.4 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.3 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.2 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.1 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.8.0 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.7.8 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.7.7 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.7.6 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
rubocop-sorbet-0.7.5 lib/rubocop/cop/sorbet/forbid_include_const_literal.rb