spoom 1.2.3 → 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 +64 -55
- data/lib/spoom/backtrace_filter/minitest.rb +21 -0
- 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/erb.rb +4 -4
- data/lib/spoom/deadcode/indexer.rb +266 -200
- data/lib/spoom/deadcode/location.rb +30 -2
- data/lib/spoom/deadcode/plugins/action_mailer.rb +21 -0
- data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +19 -0
- data/lib/spoom/deadcode/plugins/actionpack.rb +59 -0
- data/lib/spoom/deadcode/plugins/active_job.rb +13 -0
- data/lib/spoom/deadcode/plugins/active_model.rb +46 -0
- data/lib/spoom/deadcode/plugins/active_record.rb +108 -0
- data/lib/spoom/deadcode/plugins/active_support.rb +32 -0
- data/lib/spoom/deadcode/plugins/base.rb +165 -12
- data/lib/spoom/deadcode/plugins/graphql.rb +47 -0
- data/lib/spoom/deadcode/plugins/minitest.rb +28 -0
- data/lib/spoom/deadcode/plugins/namespaces.rb +32 -0
- data/lib/spoom/deadcode/plugins/rails.rb +31 -0
- data/lib/spoom/deadcode/plugins/rake.rb +12 -0
- data/lib/spoom/deadcode/plugins/rspec.rb +19 -0
- data/lib/spoom/deadcode/plugins/rubocop.rb +41 -0
- data/lib/spoom/deadcode/plugins/ruby.rb +10 -18
- data/lib/spoom/deadcode/plugins/sorbet.rb +40 -0
- data/lib/spoom/deadcode/plugins/thor.rb +21 -0
- data/lib/spoom/deadcode/plugins.rb +91 -0
- data/lib/spoom/deadcode/remover.rb +651 -0
- data/lib/spoom/deadcode/send.rb +27 -6
- data/lib/spoom/deadcode/visitor.rb +755 -0
- data/lib/spoom/deadcode.rb +41 -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 +36 -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
53
|
end
|
55
54
|
|
56
|
-
sig { override.params(node:
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
def visit_arg_block(node)
|
65
|
-
value = node.value
|
66
|
-
|
67
|
-
case value
|
68
|
-
when SyntaxTree::SymbolLiteral
|
69
|
-
# If the block call is something like `x.select(&:foo)`, we need to reference the `foo` method
|
70
|
-
reference_method(symbol_string(value), node)
|
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
|
-
@names_nesting << const_name
|
109
|
-
define_class(T.must(const_name.split("::").last), @names_nesting.join("::"), node)
|
103
|
+
sig { override.params(node: Prism::ClassNode).void }
|
104
|
+
def visit_class_node(node)
|
105
|
+
constant_path = node.constant_path.slice
|
110
106
|
|
111
|
-
|
112
|
-
|
113
|
-
visit(node.bodystmt)
|
107
|
+
if constant_path.start_with?("::")
|
108
|
+
full_name = constant_path.delete_prefix("::")
|
114
109
|
|
115
|
-
|
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
|
114
|
+
|
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)
|
127
|
+
|
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
|
185
|
+
sig { override.params(node: Prism::DefNode).void }
|
186
|
+
def visit_def_node(node)
|
187
|
+
name = node.name.to_s
|
188
|
+
define_method(name, [*@names_nesting, name].join("::"), node)
|
189
|
+
|
160
190
|
super
|
191
|
+
end
|
161
192
|
|
162
|
-
|
163
|
-
|
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)
|
164
199
|
end
|
165
200
|
|
166
|
-
sig { override.params(node:
|
167
|
-
def
|
168
|
-
|
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)
|
207
|
+
end
|
169
208
|
|
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
|
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)
|
180
215
|
end
|
181
216
|
|
182
|
-
sig { override.params(node:
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
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)
|
187
238
|
|
188
|
-
|
189
|
-
|
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)
|
248
|
+
|
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,77 +277,48 @@ 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)
|
230
300
|
end
|
231
301
|
else
|
232
302
|
@plugins.each do |plugin|
|
233
|
-
plugin.
|
303
|
+
plugin.internal_on_send(self, send)
|
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
|
-
|
251
|
-
sig { override.params(node: SyntaxTree::TopConstField).void }
|
252
|
-
def visit_top_const_field(node)
|
253
|
-
define_constant(node.constant.value, node.constant.value, node)
|
254
|
-
end
|
255
307
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
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,
|
@@ -286,10 +327,10 @@ module Spoom
|
|
286
327
|
location: node_location(node),
|
287
328
|
)
|
288
329
|
@index.define(definition)
|
289
|
-
@plugins.each { |plugin| plugin.
|
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,
|
@@ -298,10 +339,10 @@ module Spoom
|
|
298
339
|
location: node_location(node),
|
299
340
|
)
|
300
341
|
@index.define(definition)
|
301
|
-
@plugins.each { |plugin| plugin.
|
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,
|
@@ -310,10 +351,10 @@ module Spoom
|
|
310
351
|
location: node_location(node),
|
311
352
|
)
|
312
353
|
@index.define(definition)
|
313
|
-
@plugins.each { |plugin| plugin.
|
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,
|
@@ -322,10 +363,10 @@ module Spoom
|
|
322
363
|
location: node_location(node),
|
323
364
|
)
|
324
365
|
@index.define(definition)
|
325
|
-
@plugins.each { |plugin| plugin.
|
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,
|
@@ -334,10 +375,10 @@ module Spoom
|
|
334
375
|
location: node_location(node),
|
335
376
|
)
|
336
377
|
@index.define(definition)
|
337
|
-
@plugins.each { |plugin| plugin.
|
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,
|
@@ -346,57 +387,82 @@ module Spoom
|
|
346
387
|
location: node_location(node),
|
347
388
|
)
|
348
389
|
@index.define(definition)
|
349
|
-
@plugins.each { |plugin| plugin.
|
390
|
+
@plugins.each { |plugin| plugin.internal_on_define_module(self, definition) }
|
350
391
|
end
|
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 {
|
367
|
-
def
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
407
|
+
sig { returns(Prism::Node) }
|
408
|
+
def current_node
|
409
|
+
T.must(@nodes_nesting.last)
|
410
|
+
end
|
411
|
+
|
412
|
+
sig { type_parameters(:N).params(type: T::Class[T.type_parameter(:N)]).returns(T.nilable(T.type_parameter(:N))) }
|
413
|
+
def nesting_node(type)
|
414
|
+
@nodes_nesting.reverse_each do |node|
|
415
|
+
return T.unsafe(node) if node.is_a?(type)
|
373
416
|
end
|
417
|
+
|
418
|
+
nil
|
374
419
|
end
|
375
420
|
|
376
|
-
sig {
|
377
|
-
def
|
378
|
-
|
421
|
+
sig { returns(T.nilable(Prism::ClassNode)) }
|
422
|
+
def nesting_class
|
423
|
+
nesting_node(Prism::ClassNode)
|
379
424
|
end
|
380
425
|
|
381
|
-
sig {
|
382
|
-
def
|
383
|
-
|
426
|
+
sig { returns(T.nilable(Prism::BlockNode)) }
|
427
|
+
def nesting_block
|
428
|
+
nesting_node(Prism::BlockNode)
|
384
429
|
end
|
385
430
|
|
386
|
-
sig
|
387
|
-
|
388
|
-
|
389
|
-
).returns(T::Array[SyntaxTree::Node])
|
431
|
+
sig { returns(T.nilable(Prism::CallNode)) }
|
432
|
+
def nesting_call
|
433
|
+
nesting_node(Prism::CallNode)
|
390
434
|
end
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
435
|
+
|
436
|
+
sig { returns(T.nilable(String)) }
|
437
|
+
def nesting_class_name
|
438
|
+
nesting_class = self.nesting_class
|
439
|
+
return unless nesting_class
|
440
|
+
|
441
|
+
nesting_class.name.to_s
|
442
|
+
end
|
443
|
+
|
444
|
+
sig { returns(T.nilable(String)) }
|
445
|
+
def nesting_class_superclass_name
|
446
|
+
nesting_class_superclass = nesting_class&.superclass
|
447
|
+
return unless nesting_class_superclass
|
448
|
+
|
449
|
+
nesting_class_superclass.slice.delete_prefix("::")
|
450
|
+
end
|
451
|
+
|
452
|
+
sig { returns(T.nilable(String)) }
|
453
|
+
def last_sig
|
454
|
+
previous_call = @previous_node
|
455
|
+
return unless previous_call.is_a?(Prism::CallNode)
|
456
|
+
return unless previous_call.name == :sig
|
457
|
+
|
458
|
+
previous_call.slice
|
459
|
+
end
|
460
|
+
|
461
|
+
# Node utils
|
462
|
+
|
463
|
+
sig { params(node: Prism::Node).returns(Location) }
|
464
|
+
def node_location(node)
|
465
|
+
Location.from_prism(@path, node.location)
|
400
466
|
end
|
401
467
|
end
|
402
468
|
end
|