spoom 1.6.3 → 1.7.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/lib/spoom/cli/srb/assertions.rb +1 -1
- data/lib/spoom/cli/srb/sigs.rb +8 -10
- data/lib/spoom/deadcode/index.rb +2 -2
- data/lib/spoom/deadcode/plugins/active_record.rb +19 -0
- data/lib/spoom/model/builder.rb +10 -15
- data/lib/spoom/model/model.rb +1 -1
- data/lib/spoom/parse.rb +4 -18
- data/lib/spoom/rbs.rb +77 -0
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +239 -0
- data/lib/spoom/sorbet/translate/sorbet_assertions_to_rbs_comments.rb +123 -0
- data/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb +293 -0
- data/lib/spoom/sorbet/translate/strip_sorbet_sigs.rb +23 -0
- data/lib/spoom/sorbet/translate/translator.rb +71 -0
- data/lib/spoom/sorbet/translate.rb +49 -0
- data/lib/spoom/sorbet.rb +1 -1
- data/lib/spoom/source/rewriter.rb +167 -0
- data/lib/spoom/source.rb +4 -0
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +2 -0
- data/rbi/spoom.rbi +241 -155
- metadata +25 -4
- data/lib/spoom/sorbet/assertions.rb +0 -278
- data/lib/spoom/sorbet/sigs.rb +0 -281
@@ -1,278 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "rbi"
|
5
|
-
|
6
|
-
module Spoom
|
7
|
-
module Sorbet
|
8
|
-
class Assertions
|
9
|
-
class << self
|
10
|
-
#: (String, file: String) -> String
|
11
|
-
def rbi_to_rbs(ruby_contents, file:)
|
12
|
-
old_encoding = ruby_contents.encoding
|
13
|
-
ruby_contents = ruby_contents.encode("UTF-8") unless old_encoding == "UTF-8"
|
14
|
-
ruby_bytes = ruby_contents.bytes
|
15
|
-
|
16
|
-
assigns = collect_assigns(ruby_contents, file: file)
|
17
|
-
|
18
|
-
assigns.reverse.each do |assign|
|
19
|
-
# Adjust the end offset to locate the end of the line:
|
20
|
-
#
|
21
|
-
# So this:
|
22
|
-
#
|
23
|
-
# (a = T.let(nil, T.nilable(String)))
|
24
|
-
#
|
25
|
-
# properly becomes:
|
26
|
-
#
|
27
|
-
# (a = nil) #: String?
|
28
|
-
#
|
29
|
-
# This is important to avoid translating the `nil` as `nil` instead of `nil #: String?`
|
30
|
-
end_offset = assign.node.location.end_offset
|
31
|
-
end_offset += 1 while (ruby_bytes[end_offset] != "\n".ord) && (end_offset < ruby_bytes.size)
|
32
|
-
T.unsafe(ruby_bytes).insert(end_offset, *" #: #{assign.rbs_type}".bytes)
|
33
|
-
|
34
|
-
# Rewrite the value
|
35
|
-
start_offset = assign.operator_loc.end_offset
|
36
|
-
end_offset = assign.node.value.location.start_offset + assign.node.value.location.length
|
37
|
-
ruby_bytes[start_offset...end_offset] = " #{dedent_value(assign)}".bytes
|
38
|
-
end
|
39
|
-
|
40
|
-
ruby_bytes.pack("C*").force_encoding(old_encoding)
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
#: (String, file: String) -> Array[AssignNode]
|
46
|
-
def collect_assigns(ruby_contents, file:)
|
47
|
-
node = Spoom.parse_ruby(ruby_contents, file: file)
|
48
|
-
visitor = Locator.new
|
49
|
-
visitor.visit(node)
|
50
|
-
visitor.assigns
|
51
|
-
end
|
52
|
-
|
53
|
-
#: (AssignNode) -> String
|
54
|
-
def dedent_value(assign)
|
55
|
-
if assign.value.location.start_line == assign.node.location.start_line
|
56
|
-
# The value is on the same line as the assign, so we can just return the slice as is:
|
57
|
-
# ```rb
|
58
|
-
# a = T.let(nil, T.nilable(String))
|
59
|
-
# ```
|
60
|
-
# becomes
|
61
|
-
# ```rb
|
62
|
-
# a = nil #: String?
|
63
|
-
# ```
|
64
|
-
return assign.value.slice
|
65
|
-
end
|
66
|
-
|
67
|
-
# The value is on a different line, so we need to dedent it:
|
68
|
-
# ```rb
|
69
|
-
# a = T.let(
|
70
|
-
# [
|
71
|
-
# 1, 2, 3,
|
72
|
-
# ],
|
73
|
-
# T::Array[Integer],
|
74
|
-
# )
|
75
|
-
# ```
|
76
|
-
# becomes
|
77
|
-
# ```rb
|
78
|
-
# a = [
|
79
|
-
# 1, 2, 3,
|
80
|
-
# ] #: Array[Integer]
|
81
|
-
# ```
|
82
|
-
indent = assign.value.location.start_line - assign.node.location.start_line
|
83
|
-
lines = assign.value.slice.lines
|
84
|
-
if lines.size > 1
|
85
|
-
lines[1..]&.each_with_index do |line, i|
|
86
|
-
lines[i + 1] = line.delete_prefix(" " * indent)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
lines.join
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
AssignType = T.type_alias do
|
94
|
-
T.any(
|
95
|
-
Prism::ClassVariableAndWriteNode,
|
96
|
-
Prism::ClassVariableOrWriteNode,
|
97
|
-
Prism::ClassVariableOperatorWriteNode,
|
98
|
-
Prism::ClassVariableWriteNode,
|
99
|
-
Prism::ConstantAndWriteNode,
|
100
|
-
Prism::ConstantOrWriteNode,
|
101
|
-
Prism::ConstantOperatorWriteNode,
|
102
|
-
Prism::ConstantWriteNode,
|
103
|
-
Prism::ConstantPathAndWriteNode,
|
104
|
-
Prism::ConstantPathOrWriteNode,
|
105
|
-
Prism::ConstantPathOperatorWriteNode,
|
106
|
-
Prism::ConstantPathWriteNode,
|
107
|
-
Prism::GlobalVariableAndWriteNode,
|
108
|
-
Prism::GlobalVariableOrWriteNode,
|
109
|
-
Prism::GlobalVariableOperatorWriteNode,
|
110
|
-
Prism::GlobalVariableWriteNode,
|
111
|
-
Prism::InstanceVariableAndWriteNode,
|
112
|
-
Prism::InstanceVariableOperatorWriteNode,
|
113
|
-
Prism::InstanceVariableOrWriteNode,
|
114
|
-
Prism::InstanceVariableWriteNode,
|
115
|
-
Prism::LocalVariableAndWriteNode,
|
116
|
-
Prism::LocalVariableOperatorWriteNode,
|
117
|
-
Prism::LocalVariableOrWriteNode,
|
118
|
-
Prism::LocalVariableWriteNode,
|
119
|
-
)
|
120
|
-
end
|
121
|
-
|
122
|
-
class AssignNode
|
123
|
-
#: AssignType
|
124
|
-
attr_reader :node
|
125
|
-
|
126
|
-
#: Prism::Location
|
127
|
-
attr_reader :operator_loc
|
128
|
-
|
129
|
-
#: Prism::Node
|
130
|
-
attr_reader :value, :type
|
131
|
-
|
132
|
-
#: (AssignType, Prism::Location, Prism::Node, Prism::Node) -> void
|
133
|
-
def initialize(node, operator_loc, value, type)
|
134
|
-
@node = node
|
135
|
-
@operator_loc = operator_loc
|
136
|
-
@value = value
|
137
|
-
@type = type
|
138
|
-
end
|
139
|
-
|
140
|
-
#: -> String
|
141
|
-
def rbs_type
|
142
|
-
RBI::Type.parse_node(type).rbs_string
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
class Locator < Spoom::Visitor
|
147
|
-
ANNOTATION_METHODS = [:let] #: Array[Symbol]
|
148
|
-
|
149
|
-
#: Array[AssignNode]
|
150
|
-
attr_reader :assigns
|
151
|
-
|
152
|
-
#: -> void
|
153
|
-
def initialize
|
154
|
-
super
|
155
|
-
@assigns = [] #: Array[AssignNode]
|
156
|
-
end
|
157
|
-
|
158
|
-
#: (AssignType) -> void
|
159
|
-
def visit_assign(node)
|
160
|
-
call = node.value
|
161
|
-
return unless call.is_a?(Prism::CallNode) && t_annotation?(call)
|
162
|
-
|
163
|
-
# We do not support translating heredocs yet because the `#: ` would need to be added to the first line
|
164
|
-
# and it will requires us to adapt the annotation detection in Sorbet. But Sorbet desugars them into bare
|
165
|
-
# strings making them impossible to detect.
|
166
|
-
value = T.must(call.arguments&.arguments&.first)
|
167
|
-
return if contains_heredoc?(value)
|
168
|
-
|
169
|
-
operator_loc = case node
|
170
|
-
when Prism::ClassVariableOperatorWriteNode,
|
171
|
-
Prism::ConstantOperatorWriteNode,
|
172
|
-
Prism::ConstantPathOperatorWriteNode,
|
173
|
-
Prism::GlobalVariableOperatorWriteNode,
|
174
|
-
Prism::InstanceVariableOperatorWriteNode,
|
175
|
-
Prism::LocalVariableOperatorWriteNode
|
176
|
-
node.binary_operator_loc
|
177
|
-
else
|
178
|
-
node.operator_loc
|
179
|
-
end
|
180
|
-
|
181
|
-
@assigns << AssignNode.new(
|
182
|
-
node,
|
183
|
-
operator_loc,
|
184
|
-
value,
|
185
|
-
T.must(call.arguments&.arguments&.last),
|
186
|
-
)
|
187
|
-
end
|
188
|
-
|
189
|
-
alias_method(:visit_class_variable_and_write_node, :visit_assign)
|
190
|
-
alias_method(:visit_class_variable_operator_write_node, :visit_assign)
|
191
|
-
alias_method(:visit_class_variable_or_write_node, :visit_assign)
|
192
|
-
alias_method(:visit_class_variable_write_node, :visit_assign)
|
193
|
-
|
194
|
-
alias_method(:visit_constant_and_write_node, :visit_assign)
|
195
|
-
alias_method(:visit_constant_operator_write_node, :visit_assign)
|
196
|
-
alias_method(:visit_constant_or_write_node, :visit_assign)
|
197
|
-
alias_method(:visit_constant_write_node, :visit_assign)
|
198
|
-
|
199
|
-
alias_method(:visit_constant_path_and_write_node, :visit_assign)
|
200
|
-
alias_method(:visit_constant_path_operator_write_node, :visit_assign)
|
201
|
-
alias_method(:visit_constant_path_or_write_node, :visit_assign)
|
202
|
-
alias_method(:visit_constant_path_write_node, :visit_assign)
|
203
|
-
|
204
|
-
alias_method(:visit_global_variable_and_write_node, :visit_assign)
|
205
|
-
alias_method(:visit_global_variable_operator_write_node, :visit_assign)
|
206
|
-
alias_method(:visit_global_variable_or_write_node, :visit_assign)
|
207
|
-
alias_method(:visit_global_variable_write_node, :visit_assign)
|
208
|
-
|
209
|
-
alias_method(:visit_instance_variable_and_write_node, :visit_assign)
|
210
|
-
alias_method(:visit_instance_variable_operator_write_node, :visit_assign)
|
211
|
-
alias_method(:visit_instance_variable_or_write_node, :visit_assign)
|
212
|
-
alias_method(:visit_instance_variable_write_node, :visit_assign)
|
213
|
-
|
214
|
-
alias_method(:visit_local_variable_and_write_node, :visit_assign)
|
215
|
-
alias_method(:visit_local_variable_operator_write_node, :visit_assign)
|
216
|
-
alias_method(:visit_local_variable_or_write_node, :visit_assign)
|
217
|
-
alias_method(:visit_local_variable_write_node, :visit_assign)
|
218
|
-
|
219
|
-
alias_method(:visit_multi_write_node, :visit_assign)
|
220
|
-
|
221
|
-
# Is this node a `T` or `::T` constant?
|
222
|
-
#: (Prism::Node?) -> bool
|
223
|
-
def t?(node)
|
224
|
-
case node
|
225
|
-
when Prism::ConstantReadNode
|
226
|
-
node.name == :T
|
227
|
-
when Prism::ConstantPathNode
|
228
|
-
node.parent.nil? && node.name == :T
|
229
|
-
else
|
230
|
-
false
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# Is this node a `T.let` or `T.cast`?
|
235
|
-
#: (Prism::CallNode) -> bool
|
236
|
-
def t_annotation?(node)
|
237
|
-
return false unless t?(node.receiver)
|
238
|
-
return false unless ANNOTATION_METHODS.include?(node.name)
|
239
|
-
return false unless node.arguments&.arguments&.size == 2
|
240
|
-
|
241
|
-
true
|
242
|
-
end
|
243
|
-
|
244
|
-
#: (Prism::Node) -> bool
|
245
|
-
def contains_heredoc?(node)
|
246
|
-
visitor = HeredocVisitor.new
|
247
|
-
visitor.visit(node)
|
248
|
-
visitor.contains_heredoc
|
249
|
-
end
|
250
|
-
|
251
|
-
class HeredocVisitor < Spoom::Visitor
|
252
|
-
#: bool
|
253
|
-
attr_reader :contains_heredoc
|
254
|
-
|
255
|
-
#: -> void
|
256
|
-
def initialize
|
257
|
-
@contains_heredoc = false #: bool
|
258
|
-
|
259
|
-
super
|
260
|
-
end
|
261
|
-
|
262
|
-
# @override
|
263
|
-
#: (Prism::Node?) -> void
|
264
|
-
def visit(node)
|
265
|
-
return if node.nil?
|
266
|
-
|
267
|
-
case node
|
268
|
-
when Prism::StringNode, Prism::InterpolatedStringNode
|
269
|
-
return @contains_heredoc = !!node.opening_loc&.slice&.match?(/<<~|<<-/)
|
270
|
-
end
|
271
|
-
|
272
|
-
super
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
data/lib/spoom/sorbet/sigs.rb
DELETED
@@ -1,281 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "rbi"
|
5
|
-
|
6
|
-
module Spoom
|
7
|
-
module Sorbet
|
8
|
-
class Sigs
|
9
|
-
class Error < Spoom::Error; end
|
10
|
-
class << self
|
11
|
-
#: (String ruby_contents) -> String
|
12
|
-
def strip(ruby_contents)
|
13
|
-
sigs = collect_sorbet_sigs(ruby_contents)
|
14
|
-
lines_to_strip = sigs.flat_map { |sig, _| (sig.loc&.begin_line..sig.loc&.end_line).to_a }
|
15
|
-
|
16
|
-
lines = []
|
17
|
-
ruby_contents.lines.each_with_index do |line, index|
|
18
|
-
lines << line unless lines_to_strip.include?(index + 1)
|
19
|
-
end
|
20
|
-
lines.join
|
21
|
-
end
|
22
|
-
|
23
|
-
#: (String ruby_contents, positional_names: bool) -> String
|
24
|
-
def rbi_to_rbs(ruby_contents, positional_names: true)
|
25
|
-
ruby_contents = ruby_contents.dup
|
26
|
-
sigs = collect_sorbet_sigs(ruby_contents)
|
27
|
-
|
28
|
-
sigs.each do |sig, node|
|
29
|
-
scanner = Scanner.new(ruby_contents)
|
30
|
-
start_index = scanner.find_char_position(
|
31
|
-
T.must(sig.loc&.begin_line&.pred),
|
32
|
-
T.must(sig.loc).begin_column,
|
33
|
-
)
|
34
|
-
end_index = scanner.find_char_position(
|
35
|
-
sig.loc&.end_line&.pred,
|
36
|
-
T.must(sig.loc).end_column,
|
37
|
-
)
|
38
|
-
rbs = RBIToRBSTranslator.translate(sig, node, positional_names: positional_names)
|
39
|
-
ruby_contents[start_index...end_index] = rbs
|
40
|
-
end
|
41
|
-
|
42
|
-
ruby_contents
|
43
|
-
end
|
44
|
-
|
45
|
-
#: (String ruby_contents) -> String
|
46
|
-
def rbs_to_rbi(ruby_contents)
|
47
|
-
ruby_contents = ruby_contents.dup
|
48
|
-
rbs_comments = collect_rbs_comments(ruby_contents)
|
49
|
-
|
50
|
-
rbs_comments.each do |rbs_comment, node|
|
51
|
-
scanner = Scanner.new(ruby_contents)
|
52
|
-
start_index = scanner.find_char_position(
|
53
|
-
T.must(rbs_comment.loc&.begin_line&.pred),
|
54
|
-
T.must(rbs_comment.loc).begin_column,
|
55
|
-
)
|
56
|
-
end_index = scanner.find_char_position(
|
57
|
-
rbs_comment.loc&.end_line&.pred,
|
58
|
-
T.must(rbs_comment.loc).end_column,
|
59
|
-
)
|
60
|
-
rbi = RBSToRBITranslator.translate(rbs_comment, node)
|
61
|
-
next unless rbi
|
62
|
-
|
63
|
-
ruby_contents[start_index...end_index] = rbi
|
64
|
-
end
|
65
|
-
|
66
|
-
ruby_contents
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
#: (String ruby_contents) -> Array[[RBI::Sig, (RBI::Method | RBI::Attr)]]
|
72
|
-
def collect_sorbet_sigs(ruby_contents)
|
73
|
-
tree = RBI::Parser.parse_string(ruby_contents)
|
74
|
-
visitor = SigsLocator.new
|
75
|
-
visitor.visit(tree)
|
76
|
-
visitor.sigs.sort_by { |sig, _node| -T.must(sig.loc&.begin_line) }
|
77
|
-
end
|
78
|
-
|
79
|
-
#: (String ruby_contents) -> Array[[RBI::RBSComment, (RBI::Method | RBI::Attr)]]
|
80
|
-
def collect_rbs_comments(ruby_contents)
|
81
|
-
tree = RBI::Parser.parse_string(ruby_contents)
|
82
|
-
visitor = SigsLocator.new
|
83
|
-
visitor.visit(tree)
|
84
|
-
visitor.rbs_comments.sort_by { |comment, _node| -T.must(comment.loc&.begin_line) }
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class SigsLocator < RBI::Visitor
|
89
|
-
#: Array[[RBI::Sig, (RBI::Method | RBI::Attr)]]
|
90
|
-
attr_reader :sigs
|
91
|
-
|
92
|
-
#: Array[[RBI::RBSComment, (RBI::Method | RBI::Attr)]]
|
93
|
-
attr_reader :rbs_comments
|
94
|
-
|
95
|
-
#: -> void
|
96
|
-
def initialize
|
97
|
-
super
|
98
|
-
@sigs = [] #: Array[[RBI::Sig, (RBI::Method | RBI::Attr)]]
|
99
|
-
@rbs_comments = [] #: Array[[RBI::RBSComment, (RBI::Method | RBI::Attr)]]
|
100
|
-
end
|
101
|
-
|
102
|
-
# @override
|
103
|
-
#: (RBI::Node? node) -> void
|
104
|
-
def visit(node)
|
105
|
-
return unless node
|
106
|
-
|
107
|
-
case node
|
108
|
-
when RBI::Method, RBI::Attr
|
109
|
-
node.sigs.each do |sig|
|
110
|
-
next if sig.is_abstract
|
111
|
-
|
112
|
-
@sigs << [sig, node]
|
113
|
-
end
|
114
|
-
node.comments.grep(RBI::RBSComment).each do |rbs_comment|
|
115
|
-
@rbs_comments << [rbs_comment, node]
|
116
|
-
end
|
117
|
-
when RBI::Tree
|
118
|
-
visit_all(node.nodes)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class RBIToRBSTranslator
|
124
|
-
class << self
|
125
|
-
#: (RBI::Sig sig, (RBI::Method | RBI::Attr) node, positional_names: bool) -> String
|
126
|
-
def translate(sig, node, positional_names: true)
|
127
|
-
case node
|
128
|
-
when RBI::Method
|
129
|
-
translate_method_sig(sig, node, positional_names: positional_names)
|
130
|
-
when RBI::Attr
|
131
|
-
translate_attr_sig(sig, node, positional_names: positional_names)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
#: (RBI::Sig sig, RBI::Method node, positional_names: bool) -> String
|
138
|
-
def translate_method_sig(sig, node, positional_names: true)
|
139
|
-
out = StringIO.new
|
140
|
-
p = RBI::RBSPrinter.new(out: out, indent: sig.loc&.begin_column, positional_names: positional_names)
|
141
|
-
|
142
|
-
if sig.without_runtime
|
143
|
-
p.printn("# @without_runtime")
|
144
|
-
p.printt
|
145
|
-
end
|
146
|
-
|
147
|
-
if node.sigs.any?(&:is_final)
|
148
|
-
p.printn("# @final")
|
149
|
-
p.printt
|
150
|
-
end
|
151
|
-
|
152
|
-
if node.sigs.any?(&:is_abstract)
|
153
|
-
p.printn("# @abstract")
|
154
|
-
p.printt
|
155
|
-
end
|
156
|
-
|
157
|
-
if node.sigs.any?(&:is_override)
|
158
|
-
if node.sigs.any?(&:allow_incompatible_override)
|
159
|
-
p.printn("# @override(allow_incompatible: true)")
|
160
|
-
else
|
161
|
-
p.printn("# @override")
|
162
|
-
end
|
163
|
-
p.printt
|
164
|
-
end
|
165
|
-
|
166
|
-
if node.sigs.any?(&:is_overridable)
|
167
|
-
p.printn("# @overridable")
|
168
|
-
p.printt
|
169
|
-
end
|
170
|
-
|
171
|
-
p.print("#: ")
|
172
|
-
p.send(:print_method_sig, node, sig)
|
173
|
-
|
174
|
-
out.string
|
175
|
-
end
|
176
|
-
|
177
|
-
#: (RBI::Sig sig, RBI::Attr node, positional_names: bool) -> String
|
178
|
-
def translate_attr_sig(sig, node, positional_names: true)
|
179
|
-
out = StringIO.new
|
180
|
-
p = RBI::RBSPrinter.new(out: out, positional_names: positional_names)
|
181
|
-
p.print_attr_sig(node, sig)
|
182
|
-
"#: #{out.string}"
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
class RBSToRBITranslator
|
188
|
-
class << self
|
189
|
-
extend T::Sig
|
190
|
-
|
191
|
-
#: (RBI::RBSComment comment, (RBI::Method | RBI::Attr) node) -> String?
|
192
|
-
def translate(comment, node)
|
193
|
-
case node
|
194
|
-
when RBI::Method
|
195
|
-
translate_method_sig(comment, node)
|
196
|
-
when RBI::Attr
|
197
|
-
translate_attr_sig(comment, node)
|
198
|
-
end
|
199
|
-
rescue RBS::ParsingError
|
200
|
-
nil
|
201
|
-
end
|
202
|
-
|
203
|
-
private
|
204
|
-
|
205
|
-
#: (RBI::RBSComment rbs_comment, RBI::Method node) -> String
|
206
|
-
def translate_method_sig(rbs_comment, node)
|
207
|
-
method_type = ::RBS::Parser.parse_method_type(rbs_comment.text)
|
208
|
-
translator = RBI::RBS::MethodTypeTranslator.new(node)
|
209
|
-
translator.visit(method_type)
|
210
|
-
|
211
|
-
# TODO: move this to `rbi`
|
212
|
-
res = translator.result
|
213
|
-
node.comments.each do |comment|
|
214
|
-
case comment.text
|
215
|
-
when "@abstract"
|
216
|
-
res.is_abstract = true
|
217
|
-
when "@final"
|
218
|
-
res.is_final = true
|
219
|
-
when "@override"
|
220
|
-
res.is_override = true
|
221
|
-
when "@override(allow_incompatible: true)"
|
222
|
-
res.is_override = true
|
223
|
-
res.allow_incompatible_override = true
|
224
|
-
when "@overridable"
|
225
|
-
res.is_overridable = true
|
226
|
-
when "@without_runtime"
|
227
|
-
res.without_runtime = true
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
res.string.strip
|
232
|
-
end
|
233
|
-
|
234
|
-
#: (RBI::RBSComment comment, RBI::Attr node) -> String
|
235
|
-
def translate_attr_sig(comment, node)
|
236
|
-
attr_type = ::RBS::Parser.parse_type(comment.text)
|
237
|
-
sig = RBI::Sig.new
|
238
|
-
|
239
|
-
if node.is_a?(RBI::AttrWriter)
|
240
|
-
if node.names.size != 1
|
241
|
-
raise Error, "AttrWriter must have exactly one name"
|
242
|
-
end
|
243
|
-
|
244
|
-
name = T.must(node.names.first)
|
245
|
-
sig.params << RBI::SigParam.new(name.to_s, RBI::RBS::TypeTranslator.translate(attr_type))
|
246
|
-
end
|
247
|
-
|
248
|
-
sig.return_type = RBI::RBS::TypeTranslator.translate(attr_type)
|
249
|
-
sig.string.strip
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
# From https://github.com/Shopify/ruby-lsp/blob/9154bfc6ef/lib/ruby_lsp/document.rb#L127
|
255
|
-
class Scanner
|
256
|
-
LINE_BREAK = 0x0A #: Integer
|
257
|
-
|
258
|
-
#: (String source) -> void
|
259
|
-
def initialize(source)
|
260
|
-
@current_line = 0 #: Integer
|
261
|
-
@pos = 0 #: Integer
|
262
|
-
@source = source.codepoints #: Array[Integer]
|
263
|
-
end
|
264
|
-
|
265
|
-
# Finds the character index inside the source string for a given line and column
|
266
|
-
#: (Integer line, Integer character) -> Integer
|
267
|
-
def find_char_position(line, character)
|
268
|
-
# Find the character index for the beginning of the requested line
|
269
|
-
until @current_line == line
|
270
|
-
@pos += 1 until LINE_BREAK == @source[@pos]
|
271
|
-
@pos += 1
|
272
|
-
@current_line += 1
|
273
|
-
end
|
274
|
-
|
275
|
-
# The final position is the beginning of the line plus the requested column
|
276
|
-
@pos + character
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|