spoom 1.2.4 → 1.3.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/README.md +54 -55
- data/lib/spoom/cli/deadcode.rb +172 -0
- data/lib/spoom/cli/helper.rb +20 -0
- data/lib/spoom/cli/srb/bump.rb +200 -0
- data/lib/spoom/cli/srb/coverage.rb +224 -0
- data/lib/spoom/cli/srb/lsp.rb +159 -0
- data/lib/spoom/cli/srb/tc.rb +150 -0
- data/lib/spoom/cli/srb.rb +27 -0
- data/lib/spoom/cli.rb +72 -32
- data/lib/spoom/context/git.rb +2 -2
- data/lib/spoom/context/sorbet.rb +2 -2
- data/lib/spoom/deadcode/definition.rb +11 -0
- data/lib/spoom/deadcode/indexer.rb +222 -224
- data/lib/spoom/deadcode/location.rb +2 -2
- data/lib/spoom/deadcode/plugins/action_mailer.rb +2 -2
- data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +19 -0
- data/lib/spoom/deadcode/plugins/actionpack.rb +4 -6
- data/lib/spoom/deadcode/plugins/active_model.rb +8 -8
- data/lib/spoom/deadcode/plugins/active_record.rb +9 -12
- data/lib/spoom/deadcode/plugins/active_support.rb +11 -0
- data/lib/spoom/deadcode/plugins/base.rb +1 -1
- data/lib/spoom/deadcode/plugins/graphql.rb +4 -4
- data/lib/spoom/deadcode/plugins/namespaces.rb +2 -4
- data/lib/spoom/deadcode/plugins/ruby.rb +8 -17
- data/lib/spoom/deadcode/plugins/sorbet.rb +4 -10
- data/lib/spoom/deadcode/plugins.rb +1 -0
- data/lib/spoom/deadcode/remover.rb +209 -174
- data/lib/spoom/deadcode/send.rb +9 -10
- data/lib/spoom/deadcode/visitor.rb +755 -0
- data/lib/spoom/deadcode.rb +40 -10
- data/lib/spoom/file_tree.rb +0 -16
- data/lib/spoom/sorbet/errors.rb +1 -1
- data/lib/spoom/sorbet/lsp/structures.rb +2 -2
- data/lib/spoom/version.rb +1 -1
- metadata +19 -15
- data/lib/spoom/cli/bump.rb +0 -198
- data/lib/spoom/cli/coverage.rb +0 -222
- data/lib/spoom/cli/lsp.rb +0 -168
- data/lib/spoom/cli/run.rb +0 -148
@@ -3,11 +3,11 @@
|
|
3
3
|
|
4
4
|
module Spoom
|
5
5
|
module Deadcode
|
6
|
-
class Indexer <
|
6
|
+
class Indexer < Visitor
|
7
7
|
extend T::Sig
|
8
8
|
|
9
9
|
sig { returns(String) }
|
10
|
-
attr_reader :path
|
10
|
+
attr_reader :path
|
11
11
|
|
12
12
|
sig { returns(Index) }
|
13
13
|
attr_reader :index
|
@@ -21,9 +21,9 @@ module Spoom
|
|
21
21
|
@source = source
|
22
22
|
@index = index
|
23
23
|
@plugins = plugins
|
24
|
-
@previous_node = T.let(nil, T.nilable(
|
24
|
+
@previous_node = T.let(nil, T.nilable(Prism::Node))
|
25
25
|
@names_nesting = T.let([], T::Array[String])
|
26
|
-
@nodes_nesting = T.let([], T::Array[
|
26
|
+
@nodes_nesting = T.let([], T::Array[Prism::Node])
|
27
27
|
@in_const_field = T.let(false, T::Boolean)
|
28
28
|
@in_opassign = T.let(false, T::Boolean)
|
29
29
|
@in_symbol_literal = T.let(false, T::Boolean)
|
@@ -31,7 +31,7 @@ module Spoom
|
|
31
31
|
|
32
32
|
# Visit
|
33
33
|
|
34
|
-
sig { override.params(node: T.nilable(
|
34
|
+
sig { override.params(node: T.nilable(Prism::Node)).void }
|
35
35
|
def visit(node)
|
36
36
|
return unless node
|
37
37
|
|
@@ -41,163 +41,233 @@ module Spoom
|
|
41
41
|
@previous_node = node
|
42
42
|
end
|
43
43
|
|
44
|
-
sig { override.params(node:
|
45
|
-
def
|
46
|
-
reference_method(
|
44
|
+
sig { override.params(node: Prism::AliasMethodNode).void }
|
45
|
+
def visit_alias_method_node(node)
|
46
|
+
reference_method(node.old_name.slice, node)
|
47
47
|
end
|
48
48
|
|
49
|
-
sig { override.params(node:
|
50
|
-
def
|
49
|
+
sig { override.params(node: Prism::AndNode).void }
|
50
|
+
def visit_and_node(node)
|
51
|
+
reference_method(node.operator_loc.slice, node)
|
51
52
|
super
|
52
|
-
|
53
|
-
reference_method("[]", node)
|
54
|
-
end
|
55
|
-
|
56
|
-
sig { override.params(node: SyntaxTree::ARefField).void }
|
57
|
-
def visit_aref_field(node)
|
58
|
-
super
|
59
|
-
|
60
|
-
reference_method("[]=", node)
|
61
53
|
end
|
62
54
|
|
63
|
-
sig { override.params(node:
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
when SyntaxTree::VCall
|
72
|
-
# If the block call is something like `x.select { ... }`, we need to visit the block
|
73
|
-
super
|
55
|
+
sig { override.params(node: Prism::BlockArgumentNode).void }
|
56
|
+
def visit_block_argument_node(node)
|
57
|
+
expression = node.expression
|
58
|
+
case expression
|
59
|
+
when Prism::SymbolNode
|
60
|
+
reference_method(expression.unescaped, expression)
|
61
|
+
else
|
62
|
+
visit(expression)
|
74
63
|
end
|
75
64
|
end
|
76
65
|
|
77
|
-
sig { override.params(node:
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
66
|
+
sig { override.params(node: Prism::CallAndWriteNode).void }
|
67
|
+
def visit_call_and_write_node(node)
|
68
|
+
visit(node.receiver)
|
69
|
+
reference_method(node.read_name.to_s, node)
|
70
|
+
reference_method(node.write_name.to_s, node)
|
71
|
+
visit(node.value)
|
72
|
+
end
|
82
73
|
|
83
|
-
|
84
|
-
|
74
|
+
sig { override.params(node: Prism::CallOperatorWriteNode).void }
|
75
|
+
def visit_call_operator_write_node(node)
|
76
|
+
visit(node.receiver)
|
77
|
+
reference_method(node.read_name.to_s, node)
|
78
|
+
reference_method(node.write_name.to_s, node)
|
79
|
+
visit(node.value)
|
80
|
+
end
|
85
81
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
82
|
+
sig { override.params(node: Prism::CallOrWriteNode).void }
|
83
|
+
def visit_call_or_write_node(node)
|
84
|
+
visit(node.receiver)
|
85
|
+
reference_method(node.read_name.to_s, node)
|
86
|
+
reference_method(node.write_name.to_s, node)
|
87
|
+
visit(node.value)
|
91
88
|
end
|
92
89
|
|
93
|
-
sig { override.params(node:
|
94
|
-
def
|
90
|
+
sig { override.params(node: Prism::CallNode).void }
|
91
|
+
def visit_call_node(node)
|
95
92
|
visit_send(
|
96
93
|
Send.new(
|
97
94
|
node: node,
|
98
|
-
name:
|
95
|
+
name: node.name.to_s,
|
99
96
|
recv: node.receiver,
|
100
|
-
args:
|
97
|
+
args: node.arguments&.arguments || [],
|
98
|
+
block: node.block,
|
101
99
|
),
|
102
100
|
)
|
103
101
|
end
|
104
102
|
|
105
|
-
sig { override.params(node:
|
106
|
-
def
|
107
|
-
|
108
|
-
|
109
|
-
|
103
|
+
sig { override.params(node: Prism::ClassNode).void }
|
104
|
+
def visit_class_node(node)
|
105
|
+
constant_path = node.constant_path.slice
|
106
|
+
|
107
|
+
if constant_path.start_with?("::")
|
108
|
+
full_name = constant_path.delete_prefix("::")
|
109
|
+
|
110
|
+
# We found a top level definition such as `class ::A; end`, we need to reset the name nesting
|
111
|
+
old_nesting = @names_nesting.dup
|
112
|
+
@names_nesting.clear
|
113
|
+
@names_nesting << full_name
|
110
114
|
|
111
|
-
|
112
|
-
|
113
|
-
|
115
|
+
define_class(T.must(constant_path.split("::").last), full_name, node)
|
116
|
+
|
117
|
+
# We do not call `super` here because we don't want to visit the `constant` again
|
118
|
+
visit(node.superclass) if node.superclass
|
119
|
+
visit(node.body)
|
120
|
+
|
121
|
+
# Restore the name nesting once we finished visited the class
|
122
|
+
@names_nesting.clear
|
123
|
+
@names_nesting = old_nesting
|
124
|
+
else
|
125
|
+
@names_nesting << constant_path
|
126
|
+
define_class(T.must(constant_path.split("::").last), @names_nesting.join("::"), node)
|
114
127
|
|
115
|
-
|
128
|
+
# We do not call `super` here because we don't want to visit the `constant` again
|
129
|
+
visit(node.superclass) if node.superclass
|
130
|
+
visit(node.body)
|
131
|
+
|
132
|
+
@names_nesting.pop
|
133
|
+
end
|
116
134
|
end
|
117
135
|
|
118
|
-
sig { override.params(node:
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
node: node,
|
123
|
-
name: node_string(node.message),
|
124
|
-
args: call_args(node.arguments),
|
125
|
-
block: node.block,
|
126
|
-
),
|
127
|
-
)
|
136
|
+
sig { override.params(node: Prism::ConstantAndWriteNode).void }
|
137
|
+
def visit_constant_and_write_node(node)
|
138
|
+
reference_constant(node.name.to_s, node)
|
139
|
+
visit(node.value)
|
128
140
|
end
|
129
141
|
|
130
|
-
sig { override.params(node:
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
)
|
142
|
+
sig { override.params(node: Prism::ConstantOperatorWriteNode).void }
|
143
|
+
def visit_constant_operator_write_node(node)
|
144
|
+
reference_constant(node.name.to_s, node)
|
145
|
+
visit(node.value)
|
146
|
+
end
|
147
|
+
|
148
|
+
sig { override.params(node: Prism::ConstantOrWriteNode).void }
|
149
|
+
def visit_constant_or_write_node(node)
|
150
|
+
reference_constant(node.name.to_s, node)
|
151
|
+
visit(node.value)
|
141
152
|
end
|
142
153
|
|
143
|
-
sig { override.params(node:
|
144
|
-
def
|
145
|
-
|
154
|
+
sig { override.params(node: Prism::ConstantPathWriteNode).void }
|
155
|
+
def visit_constant_path_write_node(node)
|
156
|
+
parent = node.target.parent
|
157
|
+
name = node.target.child.slice
|
158
|
+
|
159
|
+
if parent
|
160
|
+
visit(parent)
|
161
|
+
|
162
|
+
parent_name = parent.slice
|
163
|
+
full_name = [*@names_nesting, parent_name, name].compact.join("::")
|
164
|
+
define_constant(name, full_name, node)
|
165
|
+
else
|
166
|
+
define_constant(name, name, node)
|
167
|
+
end
|
168
|
+
|
169
|
+
visit(node.value)
|
146
170
|
end
|
147
171
|
|
148
|
-
sig { override.params(node:
|
149
|
-
def
|
150
|
-
|
151
|
-
|
172
|
+
sig { override.params(node: Prism::ConstantReadNode).void }
|
173
|
+
def visit_constant_read_node(node)
|
174
|
+
reference_constant(node.name.to_s, node)
|
175
|
+
end
|
152
176
|
|
153
|
-
|
154
|
-
|
177
|
+
sig { override.params(node: Prism::ConstantWriteNode).void }
|
178
|
+
def visit_constant_write_node(node)
|
179
|
+
name = node.name.to_s
|
180
|
+
full_name = [*@names_nesting, name].join("::")
|
155
181
|
define_constant(name, full_name, node)
|
182
|
+
visit(node.value)
|
156
183
|
end
|
157
184
|
|
158
|
-
sig { override.params(node:
|
159
|
-
def
|
160
|
-
name =
|
185
|
+
sig { override.params(node: Prism::DefNode).void }
|
186
|
+
def visit_def_node(node)
|
187
|
+
name = node.name.to_s
|
161
188
|
define_method(name, [*@names_nesting, name].join("::"), node)
|
162
189
|
|
163
190
|
super
|
164
191
|
end
|
165
192
|
|
166
|
-
sig { override.params(node:
|
167
|
-
def
|
168
|
-
|
193
|
+
sig { override.params(node: Prism::LocalVariableAndWriteNode).void }
|
194
|
+
def visit_local_variable_and_write_node(node)
|
195
|
+
name = node.name.to_s
|
196
|
+
reference_method(name, node)
|
197
|
+
reference_method("#{name}=", node)
|
198
|
+
visit(node.value)
|
199
|
+
end
|
169
200
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
when SyntaxTree::Ident
|
177
|
-
reference_method(name.value, node) if @in_opassign
|
178
|
-
reference_method("#{name.value}=", node)
|
179
|
-
end
|
201
|
+
sig { override.params(node: Prism::LocalVariableOperatorWriteNode).void }
|
202
|
+
def visit_local_variable_operator_write_node(node)
|
203
|
+
name = node.name.to_s
|
204
|
+
reference_method(name, node)
|
205
|
+
reference_method("#{name}=", node)
|
206
|
+
visit(node.value)
|
180
207
|
end
|
181
208
|
|
182
|
-
sig { override.params(node:
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
209
|
+
sig { override.params(node: Prism::LocalVariableOrWriteNode).void }
|
210
|
+
def visit_local_variable_or_write_node(node)
|
211
|
+
name = node.name.to_s
|
212
|
+
reference_method(name, node)
|
213
|
+
reference_method("#{name}=", node)
|
214
|
+
visit(node.value)
|
215
|
+
end
|
216
|
+
|
217
|
+
sig { override.params(node: Prism::LocalVariableWriteNode).void }
|
218
|
+
def visit_local_variable_write_node(node)
|
219
|
+
visit(node.value)
|
220
|
+
reference_method("#{node.name}=", node)
|
221
|
+
end
|
222
|
+
|
223
|
+
sig { override.params(node: Prism::ModuleNode).void }
|
224
|
+
def visit_module_node(node)
|
225
|
+
constant_path = node.constant_path.slice
|
226
|
+
|
227
|
+
if constant_path.start_with?("::")
|
228
|
+
full_name = constant_path.delete_prefix("::")
|
229
|
+
|
230
|
+
# We found a top level definition such as `class ::A; end`, we need to reset the name nesting
|
231
|
+
old_nesting = @names_nesting.dup
|
232
|
+
@names_nesting.clear
|
233
|
+
@names_nesting << full_name
|
234
|
+
|
235
|
+
define_module(T.must(constant_path.split("::").last), full_name, node)
|
236
|
+
|
237
|
+
visit(node.body)
|
238
|
+
|
239
|
+
# Restore the name nesting once we finished visited the class
|
240
|
+
@names_nesting.clear
|
241
|
+
@names_nesting = old_nesting
|
242
|
+
else
|
243
|
+
@names_nesting << constant_path
|
244
|
+
define_module(T.must(constant_path.split("::").last), @names_nesting.join("::"), node)
|
245
|
+
|
246
|
+
# We do not call `super` here because we don't want to visit the `constant` again
|
247
|
+
visit(node.body)
|
187
248
|
|
188
|
-
|
189
|
-
|
249
|
+
@names_nesting.pop
|
250
|
+
end
|
251
|
+
end
|
190
252
|
|
191
|
-
|
253
|
+
sig { override.params(node: Prism::MultiWriteNode).void }
|
254
|
+
def visit_multi_write_node(node)
|
255
|
+
node.lefts.each do |const|
|
256
|
+
case const
|
257
|
+
when Prism::ConstantTargetNode, Prism::ConstantPathTargetNode
|
258
|
+
name = const.slice
|
259
|
+
define_constant(T.must(name.split("::").last), [*@names_nesting, name].join("::"), const)
|
260
|
+
when Prism::LocalVariableTargetNode
|
261
|
+
reference_method("#{const.name}=", node)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
visit(node.value)
|
192
265
|
end
|
193
266
|
|
194
|
-
sig { override.params(node:
|
195
|
-
def
|
196
|
-
|
197
|
-
# a constant reference. We need to distinguish between the two cases.
|
198
|
-
@in_opassign = true
|
267
|
+
sig { override.params(node: Prism::OrNode).void }
|
268
|
+
def visit_or_node(node)
|
269
|
+
reference_method(node.operator_loc.slice, node)
|
199
270
|
super
|
200
|
-
@in_opassign = false
|
201
271
|
end
|
202
272
|
|
203
273
|
sig { params(send: Send).void }
|
@@ -207,23 +277,23 @@ module Spoom
|
|
207
277
|
case send.name
|
208
278
|
when "attr_reader"
|
209
279
|
send.args.each do |arg|
|
210
|
-
next unless arg.is_a?(
|
280
|
+
next unless arg.is_a?(Prism::SymbolNode)
|
211
281
|
|
212
|
-
name =
|
282
|
+
name = arg.unescaped
|
213
283
|
define_attr_reader(name, [*@names_nesting, name].join("::"), arg)
|
214
284
|
end
|
215
285
|
when "attr_writer"
|
216
286
|
send.args.each do |arg|
|
217
|
-
next unless arg.is_a?(
|
287
|
+
next unless arg.is_a?(Prism::SymbolNode)
|
218
288
|
|
219
|
-
name =
|
289
|
+
name = arg.unescaped
|
220
290
|
define_attr_writer("#{name}=", "#{[*@names_nesting, name].join("::")}=", arg)
|
221
291
|
end
|
222
292
|
when "attr_accessor"
|
223
293
|
send.args.each do |arg|
|
224
|
-
next unless arg.is_a?(
|
294
|
+
next unless arg.is_a?(Prism::SymbolNode)
|
225
295
|
|
226
|
-
name =
|
296
|
+
name = arg.unescaped
|
227
297
|
full_name = [*@names_nesting, name].join("::")
|
228
298
|
define_attr_reader(name, full_name, arg)
|
229
299
|
define_attr_writer("#{name}=", "#{full_name}=", arg)
|
@@ -234,50 +304,21 @@ module Spoom
|
|
234
304
|
end
|
235
305
|
|
236
306
|
reference_method(send.name, send.node)
|
237
|
-
visit_all(send.args)
|
238
|
-
visit(send.block)
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
sig { override.params(node: SyntaxTree::SymbolLiteral).void }
|
243
|
-
def visit_symbol_literal(node)
|
244
|
-
# Something like `:FOO` will yield a Const node but we do not want to treat it as a constant reference.
|
245
|
-
# So we need to distinguish between the two cases.
|
246
|
-
@in_symbol_literal = true
|
247
|
-
super
|
248
|
-
@in_symbol_literal = false
|
249
|
-
end
|
250
307
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
sig { override.params(node: SyntaxTree::VarField).void }
|
257
|
-
def visit_var_field(node)
|
258
|
-
value = node.value
|
259
|
-
case value
|
260
|
-
when SyntaxTree::Const
|
261
|
-
if @in_opassign
|
262
|
-
reference_constant(value.value, node)
|
263
|
-
else
|
264
|
-
name = value.value
|
265
|
-
define_constant(name, [*@names_nesting, name].join("::"), node)
|
308
|
+
case send.name
|
309
|
+
when "<", ">", "<=", ">="
|
310
|
+
# For comparison operators, we also reference the `<=>` method
|
311
|
+
reference_method("<=>", send.node)
|
266
312
|
end
|
267
|
-
when SyntaxTree::Ident
|
268
|
-
reference_method(value.value, node) if @in_opassign
|
269
|
-
reference_method("#{value.value}=", node)
|
270
|
-
end
|
271
|
-
end
|
272
313
|
|
273
|
-
|
274
|
-
|
275
|
-
|
314
|
+
visit_all(send.args)
|
315
|
+
visit(send.block)
|
316
|
+
end
|
276
317
|
end
|
277
318
|
|
278
319
|
# Definition indexing
|
279
320
|
|
280
|
-
sig { params(name: String, full_name: String, node:
|
321
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
281
322
|
def define_attr_reader(name, full_name, node)
|
282
323
|
definition = Definition.new(
|
283
324
|
kind: Definition::Kind::AttrReader,
|
@@ -289,7 +330,7 @@ module Spoom
|
|
289
330
|
@plugins.each { |plugin| plugin.internal_on_define_accessor(self, definition) }
|
290
331
|
end
|
291
332
|
|
292
|
-
sig { params(name: String, full_name: String, node:
|
333
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
293
334
|
def define_attr_writer(name, full_name, node)
|
294
335
|
definition = Definition.new(
|
295
336
|
kind: Definition::Kind::AttrWriter,
|
@@ -301,7 +342,7 @@ module Spoom
|
|
301
342
|
@plugins.each { |plugin| plugin.internal_on_define_accessor(self, definition) }
|
302
343
|
end
|
303
344
|
|
304
|
-
sig { params(name: String, full_name: String, node:
|
345
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
305
346
|
def define_class(name, full_name, node)
|
306
347
|
definition = Definition.new(
|
307
348
|
kind: Definition::Kind::Class,
|
@@ -313,7 +354,7 @@ module Spoom
|
|
313
354
|
@plugins.each { |plugin| plugin.internal_on_define_class(self, definition) }
|
314
355
|
end
|
315
356
|
|
316
|
-
sig { params(name: String, full_name: String, node:
|
357
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
317
358
|
def define_constant(name, full_name, node)
|
318
359
|
definition = Definition.new(
|
319
360
|
kind: Definition::Kind::Constant,
|
@@ -325,7 +366,7 @@ module Spoom
|
|
325
366
|
@plugins.each { |plugin| plugin.internal_on_define_constant(self, definition) }
|
326
367
|
end
|
327
368
|
|
328
|
-
sig { params(name: String, full_name: String, node:
|
369
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
329
370
|
def define_method(name, full_name, node)
|
330
371
|
definition = Definition.new(
|
331
372
|
kind: Definition::Kind::Method,
|
@@ -337,7 +378,7 @@ module Spoom
|
|
337
378
|
@plugins.each { |plugin| plugin.internal_on_define_method(self, definition) }
|
338
379
|
end
|
339
380
|
|
340
|
-
sig { params(name: String, full_name: String, node:
|
381
|
+
sig { params(name: String, full_name: String, node: Prism::Node).void }
|
341
382
|
def define_module(name, full_name, node)
|
342
383
|
definition = Definition.new(
|
343
384
|
kind: Definition::Kind::Module,
|
@@ -351,19 +392,19 @@ module Spoom
|
|
351
392
|
|
352
393
|
# Reference indexing
|
353
394
|
|
354
|
-
sig { params(name: String, node:
|
395
|
+
sig { params(name: String, node: Prism::Node).void }
|
355
396
|
def reference_constant(name, node)
|
356
397
|
@index.reference(Reference.new(name: name, kind: Reference::Kind::Constant, location: node_location(node)))
|
357
398
|
end
|
358
399
|
|
359
|
-
sig { params(name: String, node:
|
400
|
+
sig { params(name: String, node: Prism::Node).void }
|
360
401
|
def reference_method(name, node)
|
361
402
|
@index.reference(Reference.new(name: name, kind: Reference::Kind::Method, location: node_location(node)))
|
362
403
|
end
|
363
404
|
|
364
405
|
# Context
|
365
406
|
|
366
|
-
sig { returns(
|
407
|
+
sig { returns(Prism::Node) }
|
367
408
|
def current_node
|
368
409
|
T.must(@nodes_nesting.last)
|
369
410
|
end
|
@@ -377,33 +418,19 @@ module Spoom
|
|
377
418
|
nil
|
378
419
|
end
|
379
420
|
|
380
|
-
sig { returns(T.nilable(
|
421
|
+
sig { returns(T.nilable(Prism::ClassNode)) }
|
381
422
|
def nesting_class
|
382
|
-
nesting_node(
|
423
|
+
nesting_node(Prism::ClassNode)
|
383
424
|
end
|
384
425
|
|
385
|
-
sig { returns(T.nilable(
|
426
|
+
sig { returns(T.nilable(Prism::BlockNode)) }
|
386
427
|
def nesting_block
|
387
|
-
nesting_node(
|
388
|
-
end
|
389
|
-
|
390
|
-
sig { returns(T.nilable(SyntaxTree::MethodAddBlock)) }
|
391
|
-
def nesting_block_call
|
392
|
-
nesting_node(SyntaxTree::MethodAddBlock)
|
428
|
+
nesting_node(Prism::BlockNode)
|
393
429
|
end
|
394
430
|
|
395
|
-
sig { returns(T.nilable(
|
396
|
-
def
|
397
|
-
|
398
|
-
return unless block.is_a?(SyntaxTree::MethodAddBlock)
|
399
|
-
|
400
|
-
call = block.call
|
401
|
-
case call
|
402
|
-
when SyntaxTree::ARef
|
403
|
-
node_string(call.collection)
|
404
|
-
when SyntaxTree::CallNode, SyntaxTree::Command, SyntaxTree::CommandCall
|
405
|
-
node_string(call.message)
|
406
|
-
end
|
431
|
+
sig { returns(T.nilable(Prism::CallNode)) }
|
432
|
+
def nesting_call
|
433
|
+
nesting_node(Prism::CallNode)
|
407
434
|
end
|
408
435
|
|
409
436
|
sig { returns(T.nilable(String)) }
|
@@ -411,7 +438,7 @@ module Spoom
|
|
411
438
|
nesting_class = self.nesting_class
|
412
439
|
return unless nesting_class
|
413
440
|
|
414
|
-
|
441
|
+
nesting_class.name.to_s
|
415
442
|
end
|
416
443
|
|
417
444
|
sig { returns(T.nilable(String)) }
|
@@ -419,52 +446,23 @@ module Spoom
|
|
419
446
|
nesting_class_superclass = nesting_class&.superclass
|
420
447
|
return unless nesting_class_superclass
|
421
448
|
|
422
|
-
|
449
|
+
nesting_class_superclass.slice.delete_prefix("::")
|
423
450
|
end
|
424
451
|
|
425
452
|
sig { returns(T.nilable(String)) }
|
426
453
|
def last_sig
|
427
|
-
|
454
|
+
previous_call = @previous_node
|
455
|
+
return unless previous_call.is_a?(Prism::CallNode)
|
456
|
+
return unless previous_call.name == :sig
|
428
457
|
|
429
|
-
|
458
|
+
previous_call.slice
|
430
459
|
end
|
431
460
|
|
432
461
|
# Node utils
|
433
462
|
|
434
|
-
sig { params(node:
|
435
|
-
def node_string(node)
|
436
|
-
case node
|
437
|
-
when Symbol
|
438
|
-
node.to_s
|
439
|
-
else
|
440
|
-
T.must(@source[node.location.start_char...node.location.end_char])
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
sig { params(node: SyntaxTree::Node).returns(Location) }
|
463
|
+
sig { params(node: Prism::Node).returns(Location) }
|
445
464
|
def node_location(node)
|
446
|
-
Location.
|
447
|
-
end
|
448
|
-
|
449
|
-
sig { params(node: SyntaxTree::Node).returns(String) }
|
450
|
-
def symbol_string(node)
|
451
|
-
node_string(node).delete_prefix(":")
|
452
|
-
end
|
453
|
-
|
454
|
-
sig do
|
455
|
-
params(
|
456
|
-
node: T.any(SyntaxTree::Args, SyntaxTree::ArgParen, SyntaxTree::ArgsForward, NilClass),
|
457
|
-
).returns(T::Array[SyntaxTree::Node])
|
458
|
-
end
|
459
|
-
def call_args(node)
|
460
|
-
case node
|
461
|
-
when SyntaxTree::ArgParen
|
462
|
-
call_args(node.arguments)
|
463
|
-
when SyntaxTree::Args
|
464
|
-
node.parts
|
465
|
-
else
|
466
|
-
[]
|
467
|
-
end
|
465
|
+
Location.from_prism(@path, node.location)
|
468
466
|
end
|
469
467
|
end
|
470
468
|
end
|
@@ -30,8 +30,8 @@ module Spoom
|
|
30
30
|
new(file, start_line.to_i, start_column.to_i, end_line.to_i, end_column.to_i)
|
31
31
|
end
|
32
32
|
|
33
|
-
sig { params(file: String, location:
|
34
|
-
def
|
33
|
+
sig { params(file: String, location: Prism::Location).returns(Location) }
|
34
|
+
def from_prism(file, location)
|
35
35
|
new(file, location.start_line, location.start_column, location.end_line, location.end_column)
|
36
36
|
end
|
37
37
|
end
|
@@ -11,8 +11,8 @@ module Spoom
|
|
11
11
|
def on_send(indexer, send)
|
12
12
|
return unless send.recv.nil? && ActionPack::CALLBACKS.include?(send.name)
|
13
13
|
|
14
|
-
send.each_arg(
|
15
|
-
indexer.reference_method(
|
14
|
+
send.each_arg(Prism::SymbolNode) do |arg|
|
15
|
+
indexer.reference_method(arg.unescaped, send.node)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|