Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 43 additions & 23 deletions lib/steep/annotations_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,59 @@ def deprecated_annotation?(annotations)
nil
end

def deprecated_type_name?(type_name, env)
annotations =
def warning_annotation?(annotations)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you extract the warning annotation test to RBS::AST::Annotation#warning?? so that we can reuse it or clear explanations to the RBS users.

(Also for RBS::AST::Annotation#deprecation?)

annotations.reverse_each do |annotation|
if match = annotation.string.match(/\Awarning(:\s*(?<message>.+))?\z/)
return [annotation, match[:message]]
end
if match = annotation.string.match(/\Asteep:warning(:\s*(?<message>.+))?\z/)
return [annotation, match[:message]]
end
end

nil
end

def type_name_annotations(type_name, env)
case
when type_name.class?
case
when type_name.class?
case
when decl = env.class_decls.fetch(type_name, nil)
decl.each_decl.flat_map do |decl|
if decl.is_a?(RBS::AST::Declarations::Base)
decl.annotations
else
[]
end
end
when decl = env.class_alias_decls.fetch(type_name, nil)
if decl.decl.is_a?(RBS::AST::Declarations::Base)
decl.decl.annotations
when decl = env.class_decls.fetch(type_name, nil)
decl.each_decl.flat_map do |decl|
if decl.is_a?(RBS::AST::Declarations::Base)
decl.annotations
else
[] #: Array[RBS::AST::Annotation]
[]
end
end
when type_name.interface?
if decl = env.interface_decls.fetch(type_name, nil)
decl.decl.annotations
end
when type_name.alias?
if decl = env.type_alias_decls.fetch(type_name, nil)
when decl = env.class_alias_decls.fetch(type_name, nil)
if decl.decl.is_a?(RBS::AST::Declarations::Base)
decl.decl.annotations
else
[] #: Array[RBS::AST::Annotation]
end
end
when type_name.interface?
if decl = env.interface_decls.fetch(type_name, nil)
decl.decl.annotations
end
when type_name.alias?
if decl = env.type_alias_decls.fetch(type_name, nil)
decl.decl.annotations
end
end
end

if annotations
def deprecated_type_name?(type_name, env)
if annotations = type_name_annotations(type_name, env)
deprecated_annotation?(annotations)
end
end

def warning_type_name?(type_name, env)
if annotations = type_name_annotations(type_name, env)
warning_annotation?(annotations)
end
end
end
end
2 changes: 2 additions & 0 deletions lib/steep/diagnostic/lsp_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def format(diagnostic)
when Signature::DeprecatedTypeName
tags << LSP::Constant::DiagnosticTag::DEPRECATED
severity = LSP::Constant::DiagnosticSeverity::WARNING
when Signature::WarningTypeName
severity = LSP::Constant::DiagnosticSeverity::WARNING
end

json = {
Expand Down
33 changes: 33 additions & 0 deletions lib/steep/diagnostic/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,36 @@ def header_line
end
end

class WarningReference < Base
attr_reader :message

def initialize(node:, location:, message:)
super(node: node, location: location)
@message = message
end

def header_line
header =
case node&.type
when :send, :csend, :block, :numblock
"The method has a warning"
when :const, :casgn
"The constant has a warning"
when :gvar, :gvasgn
"The global variable has a warning"
else
raise "Unexpected node: #{node}"
end

if message
header = +header
header.concat(": ", message)
end

header
end
end

ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
if klass < Base
array << klass
Expand All @@ -1101,6 +1131,7 @@ def self.default
BlockTypeMismatch => :warning,
BreakTypeMismatch => :hint,
DeprecatedReference => :warning,
WarningReference => :warning,
DifferentMethodParameterKind => :hint,
FallbackAny => :hint,
FalseAssertion => :hint,
Expand Down Expand Up @@ -1166,6 +1197,7 @@ def self.strict
BlockTypeMismatch => :error,
BreakTypeMismatch => :error,
DeprecatedReference => :warning,
WarningReference => :warning,
DifferentMethodParameterKind => :error,
FallbackAny => :warning,
FalseAssertion => :error,
Expand Down Expand Up @@ -1230,6 +1262,7 @@ def self.lenient
BlockTypeMismatch => :information,
BreakTypeMismatch => :hint,
DeprecatedReference => :warning,
WarningReference => :warning,
DifferentMethodParameterKind => nil,
FallbackAny => nil,
FalseAssertion => nil,
Expand Down
20 changes: 20 additions & 0 deletions lib/steep/diagnostic/signature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,26 @@ def header_line
end
end

class WarningTypeName < Base
attr_reader :type_name
attr_reader :message

def initialize(type_name, message, location:)
super(location: location)
@type_name = type_name
@message = message
end

def header_line
buffer = "Type `#{type_name}` has a warning"
if message
buffer = +buffer
buffer << ": " << message
end
buffer
end
end

class InlineDiagnostic < Base
attr_reader :diagnostic

Expand Down
14 changes: 14 additions & 0 deletions lib/steep/signature/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def validate_type_0(type)

if type_name && location
validate_type_name_deprecation(type_name, location)
validate_type_name_warning(type_name, location)
end

type.each_type do |child|
Expand All @@ -179,6 +180,12 @@ def validate_type_name_deprecation(type_name, location)
end
end

def validate_type_name_warning(type_name, location)
if (_, message = AnnotationsHelper.warning_type_name?(type_name, env))
@errors << Diagnostic::Signature::WarningTypeName.new(type_name, message, location: location)
end
end

def ancestor_to_type(ancestor)
case ancestor
when RBS::Definition::Ancestor::Instance
Expand Down Expand Up @@ -328,6 +335,11 @@ def validate_one_class_decl(name, entry)
validate_type_name_deprecation(name, location[:name])
end
end
unless AnnotationsHelper.warning_annotation?(decl.annotations)
if location = decl.location
validate_type_name_warning(name, location[:name])
end
end
end
end

Expand Down Expand Up @@ -401,6 +413,7 @@ def validate_one_class_decl(name, entry)
end
if location
validate_type_name_deprecation(ancestor.name, location)
validate_type_name_warning(ancestor.name, location)
end
end
end
Expand Down Expand Up @@ -695,6 +708,7 @@ def validate_one_class_alias(name, entry)
validator.validate_class_alias(entry: entry)
if location = entry.decl.location
validate_type_name_deprecation(entry.decl.old_name, location[:old_name])
validate_type_name_warning(entry.decl.old_name, location[:old_name])
end
end
end
Expand Down
Loading