rbs 3.10.4 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +14 -14
- data/.github/workflows/bundle-update.yml +60 -0
- data/.github/workflows/c-check.yml +7 -5
- data/.github/workflows/comments.yml +2 -2
- data/.github/workflows/dependabot.yml +2 -2
- data/.github/workflows/ruby.yml +16 -26
- data/.github/workflows/rust.yml +95 -0
- data/.github/workflows/typecheck.yml +1 -1
- data/.github/workflows/windows.yml +2 -2
- data/.rubocop.yml +2 -2
- data/.vscode/extensions.json +5 -0
- data/.vscode/settings.json +19 -0
- data/CHANGELOG.md +202 -2
- data/Rakefile +9 -23
- data/Steepfile +2 -0
- data/config.yml +457 -13
- data/core/array.rbs +218 -188
- data/core/basic_object.rbs +9 -8
- data/core/binding.rbs +0 -2
- data/core/builtin.rbs +2 -2
- data/core/class.rbs +6 -5
- data/core/comparable.rbs +45 -31
- data/core/complex.rbs +66 -55
- data/core/dir.rbs +57 -45
- data/core/encoding.rbs +6 -6
- data/core/enumerable.rbs +105 -91
- data/core/enumerator/arithmetic_sequence.rbs +70 -0
- data/core/enumerator.rbs +24 -3
- data/core/errno.rbs +3 -2
- data/core/errors.rbs +31 -29
- data/core/exception.rbs +12 -12
- data/core/fiber.rbs +47 -36
- data/core/file.rbs +242 -169
- data/core/file_test.rbs +2 -2
- data/core/float.rbs +42 -68
- data/core/gc.rbs +78 -70
- data/core/hash.rbs +70 -60
- data/core/integer.rbs +32 -75
- data/core/io/buffer.rbs +36 -36
- data/core/io/wait.rbs +7 -7
- data/core/io.rbs +192 -146
- data/core/kernel.rbs +198 -147
- data/core/marshal.rbs +3 -3
- data/core/match_data.rbs +14 -12
- data/core/math.rbs +69 -67
- data/core/method.rbs +6 -8
- data/core/module.rbs +148 -88
- data/core/nil_class.rbs +4 -3
- data/core/numeric.rbs +53 -50
- data/core/object.rbs +6 -8
- data/core/object_space.rbs +11 -10
- data/core/pathname.rbs +131 -81
- data/core/proc.rbs +65 -34
- data/core/process.rbs +221 -201
- data/core/ractor.rbs +15 -11
- data/core/random.rbs +21 -3
- data/core/range.rbs +152 -49
- data/core/rational.rbs +5 -56
- data/core/rbs/unnamed/argf.rbs +58 -51
- data/core/rbs/unnamed/env_class.rbs +18 -13
- data/core/rbs/unnamed/main_class.rbs +123 -0
- data/core/rbs/unnamed/random.rbs +7 -116
- data/core/regexp.rbs +236 -197
- data/core/ruby.rbs +1 -1
- data/core/ruby_vm.rbs +32 -30
- data/core/rubygems/config_file.rbs +5 -5
- data/core/rubygems/errors.rbs +1 -1
- data/core/rubygems/requirement.rbs +5 -5
- data/core/rubygems/rubygems.rbs +5 -3
- data/core/set.rbs +17 -16
- data/core/signal.rbs +2 -2
- data/core/string.rbs +318 -298
- data/core/struct.rbs +26 -25
- data/core/symbol.rbs +25 -24
- data/core/thread.rbs +40 -41
- data/core/time.rbs +47 -42
- data/core/trace_point.rbs +34 -31
- data/core/true_class.rbs +2 -2
- data/core/unbound_method.rbs +10 -10
- data/core/warning.rbs +7 -7
- data/docs/collection.md +1 -1
- data/docs/config.md +171 -0
- data/docs/inline.md +576 -0
- data/docs/syntax.md +46 -16
- data/docs/type_fingerprint.md +21 -0
- data/exe/rbs +1 -1
- data/ext/rbs_extension/ast_translation.c +595 -98
- data/ext/rbs_extension/class_constants.c +30 -0
- data/ext/rbs_extension/class_constants.h +15 -0
- data/ext/rbs_extension/legacy_location.c +30 -53
- data/ext/rbs_extension/legacy_location.h +37 -0
- data/ext/rbs_extension/main.c +125 -24
- data/include/rbs/ast.h +485 -150
- data/include/rbs/lexer.h +11 -4
- data/include/rbs/location.h +25 -44
- data/include/rbs/parser.h +20 -2
- data/include/rbs/util/rbs_constant_pool.h +0 -3
- data/include/rbs.h +8 -0
- data/lib/rbs/ast/annotation.rb +1 -1
- data/lib/rbs/ast/comment.rb +1 -1
- data/lib/rbs/ast/declarations.rb +10 -10
- data/lib/rbs/ast/members.rb +14 -14
- data/lib/rbs/ast/ruby/annotations.rb +409 -0
- data/lib/rbs/ast/ruby/comment_block.rb +245 -0
- data/lib/rbs/ast/ruby/declarations.rb +281 -0
- data/lib/rbs/ast/ruby/helpers/constant_helper.rb +28 -0
- data/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
- data/lib/rbs/ast/ruby/members.rb +723 -0
- data/lib/rbs/ast/type_param.rb +24 -4
- data/lib/rbs/buffer.rb +105 -20
- data/lib/rbs/cli/diff.rb +16 -15
- data/lib/rbs/cli/validate.rb +62 -125
- data/lib/rbs/cli.rb +55 -23
- data/lib/rbs/collection/config/lockfile_generator.rb +8 -4
- data/lib/rbs/collection/sources/git.rb +1 -0
- data/lib/rbs/collection.rb +0 -1
- data/lib/rbs/definition.rb +6 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +119 -63
- data/lib/rbs/definition_builder/method_builder.rb +65 -30
- data/lib/rbs/definition_builder.rb +177 -20
- data/lib/rbs/diff.rb +7 -1
- data/lib/rbs/environment/class_entry.rb +69 -0
- data/lib/rbs/environment/module_entry.rb +66 -0
- data/lib/rbs/environment.rb +338 -155
- data/lib/rbs/environment_loader.rb +2 -2
- data/lib/rbs/errors.rb +30 -20
- data/lib/rbs/inline_parser/comment_association.rb +117 -0
- data/lib/rbs/inline_parser.rb +542 -0
- data/lib/rbs/location_aux.rb +36 -4
- data/lib/rbs/locator.rb +5 -1
- data/lib/rbs/method_type.rb +5 -3
- data/lib/rbs/namespace.rb +0 -7
- data/lib/rbs/parser_aux.rb +31 -8
- data/lib/rbs/prototype/helpers.rb +57 -0
- data/lib/rbs/prototype/rb.rb +3 -28
- data/lib/rbs/prototype/rbi.rb +3 -20
- data/lib/rbs/prototype/runtime.rb +10 -2
- data/lib/rbs/resolver/type_name_resolver.rb +0 -8
- data/lib/rbs/source.rb +99 -0
- data/lib/rbs/subtractor.rb +4 -3
- data/lib/rbs/test/type_check.rb +5 -2
- data/lib/rbs/type_name.rb +1 -8
- data/lib/rbs/types.rb +88 -78
- data/lib/rbs/unit_test/convertibles.rb +1 -0
- data/lib/rbs/unit_test/type_assertions.rb +35 -8
- data/lib/rbs/validator.rb +2 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs.rb +12 -1
- data/rbs.gemspec +3 -2
- data/rust/.gitignore +1 -0
- data/rust/Cargo.lock +378 -0
- data/rust/Cargo.toml +7 -0
- data/rust/ruby-rbs/Cargo.toml +22 -0
- data/rust/ruby-rbs/build.rs +764 -0
- data/rust/ruby-rbs/examples/locations.rs +60 -0
- data/rust/ruby-rbs/src/lib.rs +1 -0
- data/rust/ruby-rbs/src/node/mod.rs +742 -0
- data/rust/ruby-rbs/tests/sanity.rs +47 -0
- data/rust/ruby-rbs/vendor/rbs/config.yml +1 -0
- data/rust/ruby-rbs-sys/Cargo.toml +23 -0
- data/rust/ruby-rbs-sys/build.rs +204 -0
- data/rust/ruby-rbs-sys/src/lib.rs +50 -0
- data/rust/ruby-rbs-sys/vendor/rbs/include +1 -0
- data/rust/ruby-rbs-sys/vendor/rbs/src +1 -0
- data/rust/ruby-rbs-sys/wrapper.h +1 -0
- data/schema/typeParam.json +17 -1
- data/sig/ancestor_builder.rbs +1 -1
- data/sig/ast/ruby/annotations.rbs +421 -0
- data/sig/ast/ruby/comment_block.rbs +127 -0
- data/sig/ast/ruby/declarations.rbs +158 -0
- data/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
- data/sig/ast/ruby/helpers/location_helper.rbs +15 -0
- data/sig/ast/ruby/members.rbs +178 -0
- data/sig/buffer.rbs +63 -5
- data/sig/cli/diff.rbs +5 -11
- data/sig/cli/validate.rbs +12 -8
- data/sig/cli.rbs +18 -18
- data/sig/definition.rbs +6 -0
- data/sig/definition_builder.rbs +3 -1
- data/sig/environment/class_entry.rbs +50 -0
- data/sig/environment/module_entry.rbs +50 -0
- data/sig/environment.rbs +37 -81
- data/sig/errors.rbs +26 -20
- data/sig/inline_parser/comment_association.rbs +71 -0
- data/sig/inline_parser.rbs +124 -0
- data/sig/location.rbs +32 -7
- data/sig/locator.rbs +0 -2
- data/sig/method_builder.rbs +9 -4
- data/sig/namespace.rbs +0 -5
- data/sig/parser.rbs +47 -13
- data/sig/prototype/helpers.rbs +2 -0
- data/sig/resolver/type_name_resolver.rbs +0 -3
- data/sig/source.rbs +48 -0
- data/sig/type_param.rbs +13 -8
- data/sig/typename.rbs +0 -5
- data/sig/types.rbs +6 -7
- data/sig/unit_test/spy.rbs +0 -8
- data/sig/unit_test/type_assertions.rbs +11 -0
- data/src/ast.c +491 -143
- data/src/lexer.c +1552 -1314
- data/src/lexer.re +7 -0
- data/src/lexstate.c +8 -1
- data/src/location.c +8 -48
- data/src/parser.c +1107 -409
- data/src/util/rbs_constant_pool.c +0 -4
- data/stdlib/bigdecimal/0/big_decimal.rbs +16 -16
- data/stdlib/cgi-escape/0/escape.rbs +4 -4
- data/stdlib/coverage/0/coverage.rbs +4 -3
- data/stdlib/date/0/date.rbs +33 -28
- data/stdlib/date/0/date_time.rbs +24 -23
- data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
- data/stdlib/digest/0/digest.rbs +110 -0
- data/stdlib/erb/0/erb.rbs +64 -53
- data/stdlib/etc/0/etc.rbs +55 -50
- data/stdlib/fileutils/0/fileutils.rbs +140 -126
- data/stdlib/forwardable/0/forwardable.rbs +10 -10
- data/stdlib/io-console/0/io-console.rbs +2 -2
- data/stdlib/json/0/json.rbs +158 -131
- data/stdlib/monitor/0/monitor.rbs +3 -3
- data/stdlib/net-http/0/net-http.rbs +159 -134
- data/stdlib/objspace/0/objspace.rbs +8 -30
- data/stdlib/open-uri/0/open-uri.rbs +8 -8
- data/stdlib/open3/0/open3.rbs +469 -10
- data/stdlib/openssl/0/openssl.rbs +144 -129
- data/stdlib/optparse/0/optparse.rbs +23 -14
- data/stdlib/pathname/0/pathname.rbs +2 -2
- data/stdlib/pp/0/pp.rbs +9 -8
- data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
- data/stdlib/pstore/0/pstore.rbs +35 -30
- data/stdlib/psych/0/psych.rbs +62 -9
- data/stdlib/psych/0/store.rbs +2 -4
- data/stdlib/pty/0/pty.rbs +9 -6
- data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
- data/stdlib/rdoc/0/code_object.rbs +2 -1
- data/stdlib/rdoc/0/parser.rbs +1 -1
- data/stdlib/rdoc/0/store.rbs +1 -1
- data/stdlib/ripper/0/ripper.rbs +20 -17
- data/stdlib/securerandom/0/manifest.yaml +2 -0
- data/stdlib/securerandom/0/securerandom.rbs +7 -20
- data/stdlib/shellwords/0/shellwords.rbs +2 -2
- data/stdlib/socket/0/addrinfo.rbs +9 -9
- data/stdlib/socket/0/basic_socket.rbs +3 -3
- data/stdlib/socket/0/ip_socket.rbs +10 -8
- data/stdlib/socket/0/socket.rbs +10 -9
- data/stdlib/socket/0/tcp_server.rbs +1 -1
- data/stdlib/socket/0/tcp_socket.rbs +1 -1
- data/stdlib/socket/0/udp_socket.rbs +1 -1
- data/stdlib/socket/0/unix_server.rbs +1 -1
- data/stdlib/stringio/0/stringio.rbs +55 -54
- data/stdlib/strscan/0/string_scanner.rbs +46 -44
- data/stdlib/tempfile/0/tempfile.rbs +24 -20
- data/stdlib/time/0/time.rbs +7 -5
- data/stdlib/tsort/0/tsort.rbs +7 -6
- data/stdlib/uri/0/common.rbs +31 -18
- data/stdlib/uri/0/file.rbs +2 -2
- data/stdlib/uri/0/generic.rbs +9 -2
- data/stdlib/uri/0/http.rbs +2 -2
- data/stdlib/uri/0/ldap.rbs +2 -2
- data/stdlib/uri/0/mailto.rbs +3 -3
- data/stdlib/uri/0/rfc2396_parser.rbs +6 -5
- data/stdlib/zlib/0/deflate.rbs +4 -3
- data/stdlib/zlib/0/gzip_reader.rbs +6 -6
- data/stdlib/zlib/0/gzip_writer.rbs +14 -12
- data/stdlib/zlib/0/inflate.rbs +1 -1
- data/stdlib/zlib/0/need_dict.rbs +1 -1
- metadata +66 -3
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBS
|
|
4
|
+
class InlineParser
|
|
5
|
+
class Result
|
|
6
|
+
attr_reader :buffer, :prism_result, :declarations, :diagnostics
|
|
7
|
+
|
|
8
|
+
def initialize(buffer, prism)
|
|
9
|
+
@buffer = buffer
|
|
10
|
+
@prism_result = prism
|
|
11
|
+
@declarations = []
|
|
12
|
+
@diagnostics = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def type_fingerprint
|
|
16
|
+
declarations.map(&:type_fingerprint)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Diagnostic
|
|
21
|
+
class Base
|
|
22
|
+
attr_reader :message, :location
|
|
23
|
+
|
|
24
|
+
def initialize(location, message)
|
|
25
|
+
@location = location
|
|
26
|
+
@message = message
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
NotImplementedYet = _ = Class.new(Base)
|
|
31
|
+
NonConstantClassName = _ = Class.new(Base)
|
|
32
|
+
NonConstantModuleName = _ = Class.new(Base)
|
|
33
|
+
NonConstantSuperClassName = _ = Class.new(Base)
|
|
34
|
+
TopLevelMethodDefinition = _ = Class.new(Base)
|
|
35
|
+
TopLevelAttributeDefinition = _ = Class.new(Base)
|
|
36
|
+
NonConstantConstantDeclaration = _ = Class.new(Base)
|
|
37
|
+
UnusedInlineAnnotation = _ = Class.new(Base)
|
|
38
|
+
AnnotationSyntaxError = _ = Class.new(Base)
|
|
39
|
+
MixinMultipleArguments = _ = Class.new(Base)
|
|
40
|
+
MixinNonConstantModule = _ = Class.new(Base)
|
|
41
|
+
AttributeNonSymbolName = _ = Class.new(Base)
|
|
42
|
+
ClassModuleAliasDeclarationMissingTypeName = _ = Class.new(Base)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.parse(buffer, prism)
|
|
46
|
+
result = Result.new(buffer, prism)
|
|
47
|
+
|
|
48
|
+
parser = Parser.new(result)
|
|
49
|
+
parser.visit(prism.value)
|
|
50
|
+
parser.comments.each_unassociated_block do |block|
|
|
51
|
+
parser.report_unused_block(block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Parser < Prism::Visitor
|
|
58
|
+
attr_reader :module_nesting, :result, :comments
|
|
59
|
+
|
|
60
|
+
include AST::Ruby::Helpers::ConstantHelper
|
|
61
|
+
include AST::Ruby::Helpers::LocationHelper
|
|
62
|
+
|
|
63
|
+
def initialize(result)
|
|
64
|
+
@result = result
|
|
65
|
+
@module_nesting = []
|
|
66
|
+
@comments = CommentAssociation.build(result.buffer, result.prism_result)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def buffer
|
|
70
|
+
result.buffer
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_module
|
|
74
|
+
module_nesting.last
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def current_module!
|
|
78
|
+
current_module || raise("#current_module is nil")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def diagnostics
|
|
82
|
+
result.diagnostics
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def push_module_nesting(mod)
|
|
86
|
+
module_nesting.push(mod)
|
|
87
|
+
yield
|
|
88
|
+
ensure
|
|
89
|
+
module_nesting.pop()
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def skip_node?(node)
|
|
93
|
+
if ref = comments.leading_block(node)
|
|
94
|
+
if ref.block.each_paragraph([]).any? { _1.is_a?(AST::Ruby::Annotations::SkipAnnotation) }
|
|
95
|
+
ref.associate!
|
|
96
|
+
return true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def visit_class_node(node)
|
|
104
|
+
return if skip_node?(node)
|
|
105
|
+
|
|
106
|
+
unless class_name = constant_as_type_name(node.constant_path)
|
|
107
|
+
diagnostics << Diagnostic::NonConstantClassName.new(
|
|
108
|
+
rbs_location(node.constant_path.location),
|
|
109
|
+
"Class name must be a constant"
|
|
110
|
+
)
|
|
111
|
+
return
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Parse super class if present
|
|
115
|
+
super_class = if node.superclass
|
|
116
|
+
node.inheritance_operator_loc or raise
|
|
117
|
+
parse_super_class(node.superclass, node.inheritance_operator_loc)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class_decl = AST::Ruby::Declarations::ClassDecl.new(buffer, class_name, node, super_class)
|
|
121
|
+
insert_declaration(class_decl)
|
|
122
|
+
push_module_nesting(class_decl) do
|
|
123
|
+
visit_child_nodes(node)
|
|
124
|
+
|
|
125
|
+
node.child_nodes.each do |child_node|
|
|
126
|
+
if child_node
|
|
127
|
+
comments.each_enclosed_block(child_node) do |block|
|
|
128
|
+
report_unused_block(block)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
comments.each_enclosed_block(node) do |block|
|
|
135
|
+
unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation]
|
|
136
|
+
|
|
137
|
+
block.each_paragraph([]) do |paragraph|
|
|
138
|
+
case paragraph
|
|
139
|
+
when AST::Ruby::Annotations::InstanceVariableAnnotation
|
|
140
|
+
class_decl.members << AST::Ruby::Members::InstanceVariableMember.new(buffer, paragraph)
|
|
141
|
+
when Location
|
|
142
|
+
# Skip
|
|
143
|
+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
|
|
144
|
+
unused_annotations << paragraph
|
|
145
|
+
else
|
|
146
|
+
unused_annotations << paragraph
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
report_unused_annotation(*unused_annotations)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class_decl.members.sort_by! { _1.location.start_line }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def visit_module_node(node)
|
|
157
|
+
return if skip_node?(node)
|
|
158
|
+
|
|
159
|
+
unless module_name = constant_as_type_name(node.constant_path)
|
|
160
|
+
diagnostics << Diagnostic::NonConstantModuleName.new(
|
|
161
|
+
rbs_location(node.constant_path.location),
|
|
162
|
+
"Module name must be a constant"
|
|
163
|
+
)
|
|
164
|
+
return
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
module_decl = AST::Ruby::Declarations::ModuleDecl.new(buffer, module_name, node)
|
|
168
|
+
insert_declaration(module_decl)
|
|
169
|
+
push_module_nesting(module_decl) do
|
|
170
|
+
visit_child_nodes(node)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
comments.each_enclosed_block(node) do |block|
|
|
174
|
+
report_unused_block(block)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def visit_def_node(node)
|
|
179
|
+
return if skip_node?(node)
|
|
180
|
+
|
|
181
|
+
if node.receiver
|
|
182
|
+
diagnostics << Diagnostic::NotImplementedYet.new(
|
|
183
|
+
rbs_location(node.receiver.location),
|
|
184
|
+
"Singleton method definition is not supported yet"
|
|
185
|
+
)
|
|
186
|
+
return
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
case current = current_module
|
|
190
|
+
when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
|
|
191
|
+
leading_block = comments.leading_block!(node)
|
|
192
|
+
|
|
193
|
+
if node.end_keyword_loc
|
|
194
|
+
# Not an end-less def
|
|
195
|
+
end_loc = node.rparen_loc || node.parameters&.location || node.name_loc
|
|
196
|
+
trailing_block = comments.trailing_block!(end_loc)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [], node)
|
|
200
|
+
report_unused_annotation(trailing_unused, *leading_unuseds)
|
|
201
|
+
|
|
202
|
+
defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block)
|
|
203
|
+
current.members << defn
|
|
204
|
+
|
|
205
|
+
# Skip other comments in `def` node
|
|
206
|
+
comments.each_enclosed_block(node) do |block|
|
|
207
|
+
report_unused_block(block)
|
|
208
|
+
end
|
|
209
|
+
else
|
|
210
|
+
diagnostics << Diagnostic::TopLevelMethodDefinition.new(
|
|
211
|
+
rbs_location(node.name_loc),
|
|
212
|
+
"Top-level method definition is not supported"
|
|
213
|
+
)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def visit_call_node(node)
|
|
218
|
+
return unless node.receiver.nil? # Only handle top-level calls like include, extend, prepend, attr_*
|
|
219
|
+
|
|
220
|
+
case node.name
|
|
221
|
+
when :include, :extend, :prepend
|
|
222
|
+
return if skip_node?(node)
|
|
223
|
+
|
|
224
|
+
case current = current_module
|
|
225
|
+
when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
|
|
226
|
+
parse_mixin_call(node)
|
|
227
|
+
end
|
|
228
|
+
when :attr_reader, :attr_writer, :attr_accessor
|
|
229
|
+
return if skip_node?(node)
|
|
230
|
+
|
|
231
|
+
case current = current_module
|
|
232
|
+
when AST::Ruby::Declarations::ClassDecl, AST::Ruby::Declarations::ModuleDecl
|
|
233
|
+
parse_attribute_call(node)
|
|
234
|
+
when nil
|
|
235
|
+
# Top-level attribute definition
|
|
236
|
+
diagnostics << Diagnostic::TopLevelAttributeDefinition.new(
|
|
237
|
+
rbs_location(node.message_loc || node.location),
|
|
238
|
+
"Top-level attribute definition is not supported"
|
|
239
|
+
)
|
|
240
|
+
end
|
|
241
|
+
else
|
|
242
|
+
visit_child_nodes(node)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def visit_constant_write_node(node)
|
|
247
|
+
return if skip_node?(node)
|
|
248
|
+
|
|
249
|
+
# Parse constant declaration (both top-level and in classes/modules)
|
|
250
|
+
parse_constant_declaration(node)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def visit_constant_path_write_node(node)
|
|
254
|
+
return if skip_node?(node)
|
|
255
|
+
|
|
256
|
+
parse_constant_declaration(node)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def parse_mixin_call(node)
|
|
260
|
+
# Check for multiple arguments
|
|
261
|
+
if node.arguments && node.arguments.arguments.length > 1
|
|
262
|
+
diagnostics << Diagnostic::MixinMultipleArguments.new(
|
|
263
|
+
rbs_location(node.location),
|
|
264
|
+
"Mixing multiple modules with one call is not supported"
|
|
265
|
+
)
|
|
266
|
+
return
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Check for missing arguments
|
|
270
|
+
unless node.arguments && node.arguments.arguments.length == 1
|
|
271
|
+
# This shouldn't happen in valid Ruby code, but handle it gracefully
|
|
272
|
+
return
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
first_arg = node.arguments.arguments.first
|
|
276
|
+
|
|
277
|
+
# Check if the argument is a constant
|
|
278
|
+
unless module_name = constant_as_type_name(first_arg)
|
|
279
|
+
diagnostics << Diagnostic::MixinNonConstantModule.new(
|
|
280
|
+
rbs_location(first_arg.location),
|
|
281
|
+
"Module name must be a constant"
|
|
282
|
+
)
|
|
283
|
+
return
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Look for type application annotation in trailing comments
|
|
287
|
+
# For single-line calls like "include Bar #[String]", the annotation is trailing
|
|
288
|
+
trailing_block = comments.trailing_block!(node.location)
|
|
289
|
+
annotation = nil
|
|
290
|
+
|
|
291
|
+
if trailing_block
|
|
292
|
+
case trailing_annotation = trailing_block.trailing_annotation([])
|
|
293
|
+
when AST::Ruby::Annotations::TypeApplicationAnnotation
|
|
294
|
+
annotation = trailing_annotation
|
|
295
|
+
else
|
|
296
|
+
report_unused_annotation(trailing_annotation)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Create the appropriate member based on the method name
|
|
301
|
+
member = case node.name
|
|
302
|
+
when :include
|
|
303
|
+
AST::Ruby::Members::IncludeMember.new(buffer, node, module_name, annotation)
|
|
304
|
+
when :extend
|
|
305
|
+
AST::Ruby::Members::ExtendMember.new(buffer, node, module_name, annotation)
|
|
306
|
+
when :prepend
|
|
307
|
+
AST::Ruby::Members::PrependMember.new(buffer, node, module_name, annotation)
|
|
308
|
+
else
|
|
309
|
+
raise "Unexpected mixin method: #{node.name}"
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
current_module!.members << member
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def parse_attribute_call(node)
|
|
316
|
+
# Get the name nodes (arguments to attr_*)
|
|
317
|
+
unless node.arguments && !node.arguments.arguments.empty?
|
|
318
|
+
return # No arguments, nothing to do
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
name_nodes = [] #: Array[Prism::SymbolNode]
|
|
322
|
+
node.arguments.arguments.each do |arg|
|
|
323
|
+
case arg
|
|
324
|
+
when Prism::SymbolNode
|
|
325
|
+
name_nodes << arg
|
|
326
|
+
else
|
|
327
|
+
# Non-symbol argument, report error
|
|
328
|
+
diagnostics << Diagnostic::AttributeNonSymbolName.new(
|
|
329
|
+
rbs_location(arg.location),
|
|
330
|
+
"Attribute name must be a symbol"
|
|
331
|
+
)
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
return if name_nodes.empty?
|
|
336
|
+
|
|
337
|
+
# Look for leading comment block
|
|
338
|
+
leading_block = comments.leading_block!(node)
|
|
339
|
+
|
|
340
|
+
# Look for trailing type annotation (#: Type)
|
|
341
|
+
trailing_block = comments.trailing_block!(node.location)
|
|
342
|
+
type_annotation = nil
|
|
343
|
+
|
|
344
|
+
if trailing_block
|
|
345
|
+
case annotation = trailing_block.trailing_annotation([])
|
|
346
|
+
when AST::Ruby::Annotations::NodeTypeAssertion
|
|
347
|
+
type_annotation = annotation
|
|
348
|
+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
|
|
349
|
+
diagnostics << Diagnostic::AnnotationSyntaxError.new(
|
|
350
|
+
annotation.location, "Syntax error: " + annotation.error.error_message
|
|
351
|
+
)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Report unused leading annotations since @rbs annotations are not used for attributes
|
|
356
|
+
if leading_block
|
|
357
|
+
report_unused_block(leading_block)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Create the appropriate member type
|
|
361
|
+
member = case node.name
|
|
362
|
+
when :attr_reader
|
|
363
|
+
AST::Ruby::Members::AttrReaderMember.new(buffer, node, name_nodes, leading_block, type_annotation)
|
|
364
|
+
when :attr_writer
|
|
365
|
+
AST::Ruby::Members::AttrWriterMember.new(buffer, node, name_nodes, leading_block, type_annotation)
|
|
366
|
+
when :attr_accessor
|
|
367
|
+
AST::Ruby::Members::AttrAccessorMember.new(buffer, node, name_nodes, leading_block, type_annotation)
|
|
368
|
+
else
|
|
369
|
+
raise "Unexpected attribute method: #{node.name}"
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
current_module!.members << member
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def parse_constant_declaration(node)
|
|
376
|
+
# Create TypeName for the constant
|
|
377
|
+
unless constant_name = constant_as_type_name(node)
|
|
378
|
+
location =
|
|
379
|
+
case node
|
|
380
|
+
when Prism::ConstantWriteNode
|
|
381
|
+
node.name_loc
|
|
382
|
+
when Prism::ConstantPathWriteNode
|
|
383
|
+
node.target.location
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
diagnostics << Diagnostic::NonConstantConstantDeclaration.new(
|
|
387
|
+
rbs_location(location),
|
|
388
|
+
"Constant name must be a constant"
|
|
389
|
+
)
|
|
390
|
+
return
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Look for leading comment block
|
|
394
|
+
leading_block = comments.leading_block!(node)
|
|
395
|
+
report_unused_block(leading_block) if leading_block
|
|
396
|
+
|
|
397
|
+
# Look for trailing type annotation (#: Type)
|
|
398
|
+
trailing_block = comments.trailing_block!(node.location)
|
|
399
|
+
type_annotation = nil
|
|
400
|
+
alias_annotation = nil
|
|
401
|
+
|
|
402
|
+
if trailing_block
|
|
403
|
+
case annotation = trailing_block.trailing_annotation([])
|
|
404
|
+
when AST::Ruby::Annotations::NodeTypeAssertion
|
|
405
|
+
type_annotation = annotation
|
|
406
|
+
when AST::Ruby::Annotations::ClassAliasAnnotation, AST::Ruby::Annotations::ModuleAliasAnnotation
|
|
407
|
+
alias_annotation = annotation
|
|
408
|
+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
|
|
409
|
+
diagnostics << Diagnostic::AnnotationSyntaxError.new(
|
|
410
|
+
annotation.location, "Syntax error: " + annotation.error.error_message
|
|
411
|
+
)
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# Handle class/module alias declarations
|
|
416
|
+
if alias_annotation
|
|
417
|
+
# Try to infer the old name from the right-hand side
|
|
418
|
+
infered_old_name = constant_as_type_name(node.value)
|
|
419
|
+
|
|
420
|
+
# Check if we have either an explicit type name or can infer one
|
|
421
|
+
if alias_annotation.type_name.nil? && infered_old_name.nil?
|
|
422
|
+
message =
|
|
423
|
+
if alias_annotation.is_a?(AST::Ruby::Annotations::ClassAliasAnnotation)
|
|
424
|
+
"Class name is missing in class alias declaration"
|
|
425
|
+
else
|
|
426
|
+
"Module name is missing in module alias declaration"
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
diagnostics << Diagnostic::ClassModuleAliasDeclarationMissingTypeName.new(
|
|
430
|
+
alias_annotation.location,
|
|
431
|
+
message
|
|
432
|
+
)
|
|
433
|
+
return
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# Create class/module alias declaration
|
|
437
|
+
alias_decl = AST::Ruby::Declarations::ClassModuleAliasDecl.new(
|
|
438
|
+
buffer,
|
|
439
|
+
node,
|
|
440
|
+
constant_name,
|
|
441
|
+
infered_old_name,
|
|
442
|
+
leading_block,
|
|
443
|
+
alias_annotation
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
# Insert the alias declaration appropriately
|
|
447
|
+
|
|
448
|
+
if current_module
|
|
449
|
+
current_module.members << alias_decl
|
|
450
|
+
else
|
|
451
|
+
result.declarations << alias_decl
|
|
452
|
+
end
|
|
453
|
+
else
|
|
454
|
+
# Create regular constant declaration
|
|
455
|
+
constant_decl = AST::Ruby::Declarations::ConstantDecl.new(
|
|
456
|
+
buffer,
|
|
457
|
+
constant_name,
|
|
458
|
+
node,
|
|
459
|
+
leading_block,
|
|
460
|
+
type_annotation
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# Insert the constant declaration appropriately
|
|
464
|
+
if current_module
|
|
465
|
+
current_module.members << constant_decl
|
|
466
|
+
else
|
|
467
|
+
result.declarations << constant_decl
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
def insert_declaration(decl)
|
|
473
|
+
if current_module
|
|
474
|
+
current_module.members << decl
|
|
475
|
+
else
|
|
476
|
+
result.declarations << decl
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def report_unused_annotation(*annotations)
|
|
481
|
+
annotations.each do |annotation|
|
|
482
|
+
case annotation
|
|
483
|
+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
|
|
484
|
+
diagnostics << Diagnostic::AnnotationSyntaxError.new(
|
|
485
|
+
annotation.location, "Syntax error: " + annotation.error.error_message
|
|
486
|
+
)
|
|
487
|
+
when AST::Ruby::Annotations::Base
|
|
488
|
+
diagnostics << Diagnostic::UnusedInlineAnnotation.new(
|
|
489
|
+
annotation.location, "Unused inline rbs annotation"
|
|
490
|
+
)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def report_unused_block(block)
|
|
496
|
+
return unless block.leading?
|
|
497
|
+
|
|
498
|
+
block.each_paragraph([]) do |paragraph|
|
|
499
|
+
case paragraph
|
|
500
|
+
when Location
|
|
501
|
+
# noop
|
|
502
|
+
else
|
|
503
|
+
report_unused_annotation(paragraph)
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def parse_super_class(super_class_expr, inheritance_operator_loc)
|
|
509
|
+
# Check if the superclass is a constant
|
|
510
|
+
unless super_class_name = constant_as_type_name(super_class_expr)
|
|
511
|
+
diagnostics << Diagnostic::NonConstantSuperClassName.new(
|
|
512
|
+
rbs_location(super_class_expr.location),
|
|
513
|
+
"Super class name must be a constant"
|
|
514
|
+
)
|
|
515
|
+
return nil
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# Look for type application annotation in trailing comments
|
|
519
|
+
# For example: class StringArray < Array #[String]
|
|
520
|
+
trailing_block = comments.trailing_block!(super_class_expr.location)
|
|
521
|
+
type_annotation = nil
|
|
522
|
+
|
|
523
|
+
if trailing_block
|
|
524
|
+
case annotation = trailing_block.trailing_annotation([])
|
|
525
|
+
when AST::Ruby::Annotations::TypeApplicationAnnotation
|
|
526
|
+
type_annotation = annotation
|
|
527
|
+
else
|
|
528
|
+
report_unused_annotation(annotation)
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
# Create SuperClass object
|
|
533
|
+
AST::Ruby::Declarations::ClassDecl::SuperClass.new(
|
|
534
|
+
rbs_location(super_class_expr.location),
|
|
535
|
+
rbs_location(inheritance_operator_loc),
|
|
536
|
+
super_class_name,
|
|
537
|
+
type_annotation
|
|
538
|
+
)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
end
|
data/lib/rbs/location_aux.rb
CHANGED
|
@@ -28,6 +28,14 @@ module RBS
|
|
|
28
28
|
|
|
29
29
|
WithChildren = self
|
|
30
30
|
|
|
31
|
+
def start_pos
|
|
32
|
+
buffer.absolute_position(_start_pos) || raise
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def end_pos
|
|
36
|
+
buffer.absolute_position(_end_pos) || raise
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
def name
|
|
32
40
|
buffer.name
|
|
33
41
|
end
|
|
@@ -49,11 +57,11 @@ module RBS
|
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
def start_loc
|
|
52
|
-
@start_loc ||= buffer.pos_to_loc(start_pos)
|
|
60
|
+
@start_loc ||= buffer.top_buffer.pos_to_loc(start_pos)
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
def end_loc
|
|
56
|
-
@end_loc ||= buffer.pos_to_loc(end_pos)
|
|
64
|
+
@end_loc ||= buffer.top_buffer.pos_to_loc(end_pos)
|
|
57
65
|
end
|
|
58
66
|
|
|
59
67
|
def range
|
|
@@ -61,7 +69,7 @@ module RBS
|
|
|
61
69
|
end
|
|
62
70
|
|
|
63
71
|
def source
|
|
64
|
-
@source ||= (buffer.content[range] || raise)
|
|
72
|
+
@source ||= (buffer.top_buffer.content[range] || raise)
|
|
65
73
|
end
|
|
66
74
|
|
|
67
75
|
def to_s
|
|
@@ -75,7 +83,7 @@ module RBS
|
|
|
75
83
|
other.end_pos == end_pos
|
|
76
84
|
end
|
|
77
85
|
|
|
78
|
-
def to_json(state =
|
|
86
|
+
def to_json(state = nil)
|
|
79
87
|
{
|
|
80
88
|
start: {
|
|
81
89
|
line: start_line,
|
|
@@ -134,5 +142,29 @@ module RBS
|
|
|
134
142
|
def required_key?(name)
|
|
135
143
|
_required_keys.include?(name)
|
|
136
144
|
end
|
|
145
|
+
|
|
146
|
+
def local_location
|
|
147
|
+
loc = Location.new(buffer.detach, _start_pos, _end_pos)
|
|
148
|
+
|
|
149
|
+
each_optional_key do |key|
|
|
150
|
+
value = self[key]
|
|
151
|
+
if value
|
|
152
|
+
loc.add_optional_child(key, value._start_pos...value._end_pos)
|
|
153
|
+
else
|
|
154
|
+
loc.add_optional_child(key, nil)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
each_required_key do |key|
|
|
159
|
+
value = self[key] or raise
|
|
160
|
+
loc.add_required_child(key, value._start_pos...value._end_pos)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
loc #: self
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def local_source
|
|
167
|
+
local_location.source
|
|
168
|
+
end
|
|
137
169
|
end
|
|
138
170
|
end
|
data/lib/rbs/locator.rb
CHANGED
|
@@ -177,6 +177,10 @@ module RBS
|
|
|
177
177
|
find_in_type(pos, type: upper_bound, array: array) and return true
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
if lower_bound = type_param.lower_bound_type
|
|
181
|
+
find_in_type(pos, type: lower_bound, array: array) and return true
|
|
182
|
+
end
|
|
183
|
+
|
|
180
184
|
if default_type = type_param.default_type
|
|
181
185
|
find_in_type(pos, type: default_type, array: array) and return true
|
|
182
186
|
end
|
|
@@ -234,7 +238,7 @@ module RBS
|
|
|
234
238
|
|
|
235
239
|
def test_loc(pos, location:)
|
|
236
240
|
if location
|
|
237
|
-
location.
|
|
241
|
+
location.start_pos <= pos && pos <= location.end_pos
|
|
238
242
|
else
|
|
239
243
|
false
|
|
240
244
|
end
|
data/lib/rbs/method_type.rb
CHANGED
|
@@ -21,7 +21,7 @@ module RBS
|
|
|
21
21
|
other.block == block
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def to_json(state =
|
|
24
|
+
def to_json(state = nil)
|
|
25
25
|
{
|
|
26
26
|
type_params: type_params,
|
|
27
27
|
type: type,
|
|
@@ -129,11 +129,13 @@ module RBS
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
def with_nonreturn_void?
|
|
132
|
-
if type.with_nonreturn_void?
|
|
132
|
+
if type.with_nonreturn_void? # steep:ignore DeprecatedReference
|
|
133
133
|
true
|
|
134
134
|
else
|
|
135
135
|
if block = block()
|
|
136
|
-
block.type.with_nonreturn_void? ||
|
|
136
|
+
block.type.with_nonreturn_void? || # steep:ignore DeprecatedReference
|
|
137
|
+
block.self_type&.with_nonreturn_void? || # steep:ignore DeprecatedReference
|
|
138
|
+
false
|
|
137
139
|
else
|
|
138
140
|
false
|
|
139
141
|
end
|
data/lib/rbs/namespace.rb
CHANGED