spoom 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +64 -55
  3. data/lib/spoom/backtrace_filter/minitest.rb +21 -0
  4. data/lib/spoom/cli/deadcode.rb +172 -0
  5. data/lib/spoom/cli/helper.rb +20 -0
  6. data/lib/spoom/cli/srb/bump.rb +200 -0
  7. data/lib/spoom/cli/srb/coverage.rb +224 -0
  8. data/lib/spoom/cli/srb/lsp.rb +159 -0
  9. data/lib/spoom/cli/srb/tc.rb +150 -0
  10. data/lib/spoom/cli/srb.rb +27 -0
  11. data/lib/spoom/cli.rb +72 -32
  12. data/lib/spoom/context/git.rb +2 -2
  13. data/lib/spoom/context/sorbet.rb +2 -2
  14. data/lib/spoom/deadcode/definition.rb +11 -0
  15. data/lib/spoom/deadcode/erb.rb +4 -4
  16. data/lib/spoom/deadcode/indexer.rb +266 -200
  17. data/lib/spoom/deadcode/location.rb +30 -2
  18. data/lib/spoom/deadcode/plugins/action_mailer.rb +21 -0
  19. data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +19 -0
  20. data/lib/spoom/deadcode/plugins/actionpack.rb +59 -0
  21. data/lib/spoom/deadcode/plugins/active_job.rb +13 -0
  22. data/lib/spoom/deadcode/plugins/active_model.rb +46 -0
  23. data/lib/spoom/deadcode/plugins/active_record.rb +108 -0
  24. data/lib/spoom/deadcode/plugins/active_support.rb +32 -0
  25. data/lib/spoom/deadcode/plugins/base.rb +165 -12
  26. data/lib/spoom/deadcode/plugins/graphql.rb +47 -0
  27. data/lib/spoom/deadcode/plugins/minitest.rb +28 -0
  28. data/lib/spoom/deadcode/plugins/namespaces.rb +32 -0
  29. data/lib/spoom/deadcode/plugins/rails.rb +31 -0
  30. data/lib/spoom/deadcode/plugins/rake.rb +12 -0
  31. data/lib/spoom/deadcode/plugins/rspec.rb +19 -0
  32. data/lib/spoom/deadcode/plugins/rubocop.rb +41 -0
  33. data/lib/spoom/deadcode/plugins/ruby.rb +10 -18
  34. data/lib/spoom/deadcode/plugins/sorbet.rb +40 -0
  35. data/lib/spoom/deadcode/plugins/thor.rb +21 -0
  36. data/lib/spoom/deadcode/plugins.rb +91 -0
  37. data/lib/spoom/deadcode/remover.rb +651 -0
  38. data/lib/spoom/deadcode/send.rb +27 -6
  39. data/lib/spoom/deadcode/visitor.rb +755 -0
  40. data/lib/spoom/deadcode.rb +41 -10
  41. data/lib/spoom/file_tree.rb +0 -16
  42. data/lib/spoom/sorbet/errors.rb +1 -1
  43. data/lib/spoom/sorbet/lsp/structures.rb +2 -2
  44. data/lib/spoom/version.rb +1 -1
  45. metadata +36 -15
  46. data/lib/spoom/cli/bump.rb +0 -198
  47. data/lib/spoom/cli/coverage.rb +0 -222
  48. data/lib/spoom/cli/lsp.rb +0 -168
  49. 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 < SyntaxTree::Visitor
6
+ class Indexer < Visitor
7
7
  extend T::Sig
8
8
 
9
9
  sig { returns(String) }
10
- attr_reader :path, :file_name
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(SyntaxTree::Node))
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[SyntaxTree::Node])
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(SyntaxTree::Node)).void }
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: SyntaxTree::AliasNode).void }
45
- def visit_alias(node)
46
- reference_method(node_string(node.right), node)
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: SyntaxTree::ARef).void }
50
- def visit_aref(node)
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: SyntaxTree::ARefField).void }
57
- def visit_aref_field(node)
58
- super
59
-
60
- reference_method("[]=", node)
61
- end
62
-
63
- sig { override.params(node: SyntaxTree::ArgBlock).void }
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: SyntaxTree::Binary).void }
78
- def visit_binary(node)
79
- super
80
-
81
- op = node.operator
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
- # Reference the operator itself
84
- reference_method(op.to_s, node)
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
- case op
87
- when :<, :>, :<=, :>=
88
- # For comparison operators, we also reference the `<=>` method
89
- reference_method("<=>", node)
90
- end
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: SyntaxTree::CallNode).void }
94
- def visit_call(node)
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: node_string(node.message),
95
+ name: node.name.to_s,
99
96
  recv: node.receiver,
100
- args: call_args(node.arguments),
97
+ args: node.arguments&.arguments || [],
98
+ block: node.block,
101
99
  ),
102
100
  )
103
101
  end
104
102
 
105
- sig { override.params(node: SyntaxTree::ClassDeclaration).void }
106
- def visit_class(node)
107
- const_name = node_string(node.constant)
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
- # We do not call `super` here because we don't want to visit the `constant` again
112
- visit(node.superclass) if node.superclass
113
- visit(node.bodystmt)
107
+ if constant_path.start_with?("::")
108
+ full_name = constant_path.delete_prefix("::")
114
109
 
115
- @names_nesting.pop
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: SyntaxTree::Command).void }
119
- def visit_command(node)
120
- visit_send(
121
- Send.new(
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: SyntaxTree::CommandCall).void }
131
- def visit_command_call(node)
132
- visit_send(
133
- Send.new(
134
- node: node,
135
- name: node_string(node.message),
136
- recv: node.receiver,
137
- args: call_args(node.arguments),
138
- block: node.block,
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: SyntaxTree::Const).void }
144
- def visit_const(node)
145
- reference_constant(node.value, node) unless @in_symbol_literal
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: SyntaxTree::ConstPathField).void }
149
- def visit_const_path_field(node)
150
- # We do not call `super` here because we don't want to visit the `constant` again
151
- visit(node.parent)
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
- name = node.constant.value
154
- full_name = [*@names_nesting, node_string(node.parent), name].join("::")
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: SyntaxTree::DefNode).void }
159
- def visit_def(node)
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
- name = node_string(node.name)
163
- define_method(name, [*@names_nesting, name].join("::"), node)
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: SyntaxTree::Field).void }
167
- def visit_field(node)
168
- visit(node.parent)
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
- name = node.name
171
- case name
172
- when SyntaxTree::Const
173
- name = name.value
174
- full_name = [*@names_nesting, node_string(node.parent), name].join("::")
175
- define_constant(name, full_name, node)
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: SyntaxTree::ModuleDeclaration).void }
183
- def visit_module(node)
184
- const_name = node_string(node.constant)
185
- @names_nesting << const_name
186
- define_module(T.must(const_name.split("::").last), @names_nesting.join("::"), node)
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
- # We do not call `super` here because we don't want to visit the `constant` again
189
- visit(node.bodystmt)
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
- @names_nesting.pop
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: SyntaxTree::OpAssign).void }
195
- def visit_opassign(node)
196
- # Both `FOO = x` and `FOO += x` yield a VarField node, but the former is a constant definition and the latter is
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?(SyntaxTree::SymbolLiteral)
280
+ next unless arg.is_a?(Prism::SymbolNode)
211
281
 
212
- name = symbol_string(arg)
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?(SyntaxTree::SymbolLiteral)
287
+ next unless arg.is_a?(Prism::SymbolNode)
218
288
 
219
- name = symbol_string(arg)
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?(SyntaxTree::SymbolLiteral)
294
+ next unless arg.is_a?(Prism::SymbolNode)
225
295
 
226
- name = symbol_string(arg)
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.on_send(self, send)
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
- 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
- sig { override.params(node: SyntaxTree::VCall).void }
274
- def visit_vcall(node)
275
- visit_send(Send.new(node: node, name: node_string(node.value)))
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: SyntaxTree::Node).void }
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.on_define_accessor(self, definition) }
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: SyntaxTree::Node).void }
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.on_define_accessor(self, definition) }
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: SyntaxTree::Node).void }
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.on_define_class(self, definition) }
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: SyntaxTree::Node).void }
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.on_define_constant(self, definition) }
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: SyntaxTree::Node).void }
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.on_define_method(self, definition) }
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: SyntaxTree::Node).void }
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.on_define_module(self, definition) }
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: SyntaxTree::Node).void }
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: SyntaxTree::Node).void }
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
- # Node utils
405
+ # Context
365
406
 
366
- sig { params(node: T.any(Symbol, SyntaxTree::Node)).returns(String) }
367
- def node_string(node)
368
- case node
369
- when Symbol
370
- node.to_s
371
- else
372
- T.must(@source[node.location.start_char...node.location.end_char])
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 { params(node: SyntaxTree::Node).returns(Location) }
377
- def node_location(node)
378
- Location.from_syntax_tree(@path, node.location)
421
+ sig { returns(T.nilable(Prism::ClassNode)) }
422
+ def nesting_class
423
+ nesting_node(Prism::ClassNode)
379
424
  end
380
425
 
381
- sig { params(node: SyntaxTree::Node).returns(String) }
382
- def symbol_string(node)
383
- node_string(node).delete_prefix(":")
426
+ sig { returns(T.nilable(Prism::BlockNode)) }
427
+ def nesting_block
428
+ nesting_node(Prism::BlockNode)
384
429
  end
385
430
 
386
- sig do
387
- params(
388
- node: T.any(SyntaxTree::Args, SyntaxTree::ArgParen, SyntaxTree::ArgsForward, NilClass),
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
- def call_args(node)
392
- case node
393
- when SyntaxTree::ArgParen
394
- call_args(node.arguments)
395
- when SyntaxTree::Args
396
- node.parts
397
- else
398
- []
399
- end
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