class RuboCop::Cop::Sorbet::CallbackConditionalsBinding
This cop ensures that callback conditionals are bound to the right type so that they are type checked properly.
@example
# bad class Post < ApplicationRecord before_create :do_it, if: -> { should_do_it? } def should_do_it? true end end # good class Post < ApplicationRecord before_create :do_it, if: -> { T.bind(self, Post).should_do_it? } def should_do_it? true end end
Constants
- CALLBACKS
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/sorbet/callback_conditionals_binding.rb, line 76 def autocorrect(node) lambda do |corrector| options = node.each_child_node.find(&:hash_type?) conditional = nil options.each_pair do |keyword, block| if keyword.value == :if || keyword.value == :unless conditional = block break end end _, _, block = conditional.child_nodes expected_class = node.parent_module_name bind = if block.begin_type? indentation = " " * block.child_nodes.first.loc.column "T.bind(self, #{expected_class})\n#{indentation}" elsif block.child_nodes.empty? && !block.ivar_type? "T.bind(self, #{expected_class})." else "T.bind(self, #{expected_class}); " end corrector.insert_before(block, bind) end end
on_send(node)
click to toggle source
# File lib/rubocop/cop/sorbet/callback_conditionals_binding.rb, line 104 def on_send(node) return unless CALLBACKS.include?(node.method_name) options = node.each_child_node.find(&:hash_type?) return if options.nil? conditional = nil options.each_pair do |keyword, block| next unless keyword.sym_type? if keyword.value == :if || keyword.value == :unless conditional = block break end end return if conditional.nil? || conditional.child_nodes.empty? type, _, block = conditional.child_nodes return unless type.lambda_or_proc? expected_class = node.parent_module_name return if expected_class.nil? unless block.source.include?("T.bind(self, #{expected_class})") add_offense( node, message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})" ) end end