spoom 1.2.3 → 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 +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
|