class RuboCop::Cop::Sorbet::EnforceSignatures

  • ‘ReturnTypePlaceholder`: placeholders used for return types (default: ’T.untyped’)
    * ‘ParameterTypePlaceholder`: placeholders used for parameter types (default: ’T.untyped’)
    You can configure the placeholders used by changing the following options:
    “‘
    def foo(a, b, c); end
    sig { params(a: T.untyped, b: T.untyped, c: T.untyped).returns(T.untyped)
    “`
    Will be corrected as:
    “`
    def foo(a, b, c); end
    “`
    It also suggest an autocorrect with placeholders so the following code:
    Checks that every method definition and attribute accessor has a Sorbet signature.

def autocorrect(corrector, node)

def autocorrect(corrector, node)
  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, suggest.to_autocorrect)
end

def check_node(node)

def check_node(node)
  scope = self.scope(node)
  unless @last_sig_for_scope[scope] || has_rbs_comment?(node)
    add_offense(
      node,
      message: "Each method is required to have a signature.",
    ) do |corrector|
      autocorrect(corrector, node)
    end
  end
  @last_sig_for_scope[scope] = nil
end

def has_rbs_comment?(node)

def has_rbs_comment?(node)
  return false unless cop_config["AllowRBS"] == true
  node = node.parent while RuboCop::AST::SendNode === node.parent
  return false if (comments = preceeding_comments(node)).empty?
  last_comment = comments.last
  return false if last_comment.loc.line + 1 < node.loc.line
  comments.any? { |comment| RBS_COMMENT_REGEX.match?(comment.text) }
end

def initialize(config = nil, options = nil)

def initialize(config = nil, options = nil)
  super(config, options)
  @last_sig_for_scope = {}
end

def on_def(node)

def on_def(node)
  check_node(node)
end

def on_defs(node)

def on_defs(node)
  check_node(node)
end

def on_send(node)

def on_send(node)
  check_node(node) if accessor?(node)
end

def on_signature(node)

def on_signature(node)
  @last_sig_for_scope[scope(node)] = node
end

def param_type_placeholder

def param_type_placeholder
  cop_config["ParameterTypePlaceholder"] || "T.untyped"
end

def preceeding_comments(node)

def preceeding_comments(node)
  processed_source.ast_with_comments[node].select { |comment| comment.loc.line < node.loc.line }
end

def return_type_placeholder

def return_type_placeholder
  cop_config["ReturnTypePlaceholder"] || "T.untyped"
end

def scope(node)

def scope(node)
  return unless node.parent
  return node.parent if [:begin, :block, :class, :module].include?(node.parent.type)
  scope(node.parent)
end