Skip to content

Commit

Permalink
Add a new diagnostic type: NoMethodByNil
Browse files Browse the repository at this point in the history
Add a new diagnostic type; NoMethodByNil, that is emitted to no method
calls for the objects having optional types.  It's separated from
NoMethod to control the visiblity of these diagnostics individually.

It's useful to find the methods not having appropriate types on checking
the Ruby application by filtering NoMethod diagnostics.
  • Loading branch information
tk0miya committed Oct 22, 2023
1 parent 85bdb82 commit bae8066
Show file tree
Hide file tree
Showing 6 changed files with 655 additions and 618 deletions.
27 changes: 27 additions & 0 deletions lib/steep/diagnostic/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,30 @@ def header_line
end
end

class NoMethodByNil < Base
attr_reader :type
attr_reader :method

def initialize(node:, type:, method:)
loc = case node.type
when :send
loc = _ = nil
loc ||= node.loc.operator if node.loc.respond_to?(:operator)
loc ||= node.loc.selector if node.loc.respond_to?(:selector)
loc
when :block
node.children[0].loc.selector
end
super(node: node, location: loc || node.loc.expression)
@type = type
@method = method
end

def header_line
"Type `#{type}` does not have method `#{method}`"
end
end

class ReturnTypeMismatch < Base
attr_reader :expected
attr_reader :actual
Expand Down Expand Up @@ -1035,6 +1059,7 @@ def self.default
MethodReturnTypeAnnotationMismatch => :hint,
MultipleAssignmentConversionError => :hint,
NoMethod => :error,
NoMethodByNil => :error,
ProcHintIgnored => :hint,
ProcTypeExpected => :hint,
RBSError => :information,
Expand Down Expand Up @@ -1093,6 +1118,7 @@ def self.strict
MethodReturnTypeAnnotationMismatch => :error,
MultipleAssignmentConversionError => :error,
NoMethod => :error,
NoMethodByNil => :error,
ProcHintIgnored => :information,
ProcTypeExpected => :error,
RBSError => :error,
Expand Down Expand Up @@ -1151,6 +1177,7 @@ def self.lenient
MethodReturnTypeAnnotationMismatch => nil,
MultipleAssignmentConversionError => nil,
NoMethod => :information,
NoMethodByNil => :information,
ProcHintIgnored => nil,
ProcTypeExpected => nil,
RBSError => :information,
Expand Down
9 changes: 8 additions & 1 deletion lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3387,13 +3387,20 @@ def type_send_interface(node, interface:, receiver:, receiver_type:, method_name
end
end

interface_type = interface&.type || receiver_type
if interface_type.is_a?(AST::Types::Union) && interface_type.types.any? {|type| type.is_a?(AST::Types::Nil) }
error = Diagnostic::Ruby::NoMethodByNil.new(node: node, method: method_name, type: interface_type)
else
error = Diagnostic::Ruby::NoMethod.new(node: node, method: method_name, type: interface_type)
end

constr.add_call(
TypeInference::MethodCall::NoMethodError.new(
node: node,
context: context.call_context,
method_name: method_name,
receiver_type: receiver_type,
error: Diagnostic::Ruby::NoMethod.new(node: node, method: method_name, type: interface&.type || receiver_type)
error: error
)
)
end
Expand Down
3 changes: 3 additions & 0 deletions sig/steep/diagnostic/ruby.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ module Steep
def header_line: () -> ::String
end

class NoMethodByNil < NoMethod
end

class ReturnTypeMismatch < Base
attr_reader expected: untyped

Expand Down
Loading

0 comments on commit bae8066

Please sign in to comment.