class RuboCop::Cop::Sorbet::CallbackConditionalsBinding

rubocop:todo InternalAffairs/InheritDeprecatedCopClass
end
end
true
def should_do_it?
}
should_do_it?
T.bind(self, Post)
before_create :do_it, if: -> {
class Post < ApplicationRecord
# good
end
end
true
def should_do_it?
before_create :do_it, if: -> { should_do_it? }
class Post < ApplicationRecord
# bad
@example
introduces new typing errors.
binding to the attached class. Auto-correcting those usages can lead to false positives and auto-correction
Auto-correction is unsafe because other libraries define similar style callbacks as Rails, but don’t always need
so that they are type checked properly.
Ensures that callback conditionals are bound to the right type

def autocorrect(node)

def autocorrect(node)
  lambda do |corrector|
    options = node.each_child_node.find(&:hash_type?)
    conditional = nil
    options.each_pair do |keyword, block|
      if keyword.value == :if || keyword.value == :unless
        conditional = block
        break
      end
    end
    _, _, block = conditional.child_nodes
    # Find the class node and check if it includes a namespace on the
    # same line e.g.: Namespace::Class, which will require the fully
    # qualified name
    klass = node.ancestors.find(&:class_type?)
    expected_class = if klass.children.first.children.first.nil?
      node.parent_module_name.split("::").last
    else
      klass.identifier.source
    end
    do_end_lambda = conditional.source.include?("do") && conditional.source.include?("end")
    unless do_end_lambda
      # We are converting a one line lambda into a multiline
      # Remove the space after the `{`
      if /{\s/.match?(conditional.source)
        corrector.remove_preceding(block, 1)
      end
      # Remove the last space and `}` and re-add it with a line break
      # and the correct indentation
      base_indentation = " " * node.loc.column
      chars_to_remove = /\s}/.match?(conditional.source) ? 2 : 1
      corrector.remove_trailing(conditional, chars_to_remove)
      corrector.insert_after(block, "\n#{base_indentation}}")
    end
    # Add the T.bind
    indentation = " " * (node.loc.column + 2)
    line_start = do_end_lambda ? "" : "\n#{indentation}"
    bind = "#{line_start}T.bind(self, #{expected_class})\n#{indentation}"
    corrector.insert_before(block, bind)
  end
end

def on_send(node)

def on_send(node)
  return unless CALLBACKS.include?(node.method_name)
  options = node.each_child_node.find(&:hash_type?)
  return if options.nil?
  conditional = nil
  options.each_pair do |keyword, block|
    next unless keyword.sym_type?
    if keyword.value == :if || keyword.value == :unless
      conditional = block
      break
    end
  end
  return if conditional.nil? || conditional.array_type? || conditional.child_nodes.empty?
  return unless conditional.arguments.empty?
  type, _, block = conditional.child_nodes
  return unless type.lambda_or_proc? || type.block_literal?
  klass = node.ancestors.find(&:class_type?)
  expected_class = if klass&.children&.first&.children&.first.nil?
    node.parent_module_name&.split("::")&.last
  else
    klass.identifier.source
  end
  return if expected_class.nil?
  unless block.source.include?("T.bind(self")
    add_offense(
      node,
      message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})",
    )
  end
end