spoom 1.2.4 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|