spoom 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/spoom/cli/deadcode.rb +21 -17
  3. data/lib/spoom/deadcode/index.rb +178 -10
  4. data/lib/spoom/deadcode/indexer.rb +14 -435
  5. data/lib/spoom/deadcode/plugins/action_mailer.rb +3 -3
  6. data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +9 -3
  7. data/lib/spoom/deadcode/plugins/actionpack.rb +12 -9
  8. data/lib/spoom/deadcode/plugins/active_model.rb +8 -8
  9. data/lib/spoom/deadcode/plugins/active_record.rb +5 -5
  10. data/lib/spoom/deadcode/plugins/active_support.rb +4 -4
  11. data/lib/spoom/deadcode/plugins/base.rb +70 -57
  12. data/lib/spoom/deadcode/plugins/graphql.rb +8 -8
  13. data/lib/spoom/deadcode/plugins/minitest.rb +4 -3
  14. data/lib/spoom/deadcode/plugins/namespaces.rb +9 -12
  15. data/lib/spoom/deadcode/plugins/rails.rb +9 -9
  16. data/lib/spoom/deadcode/plugins/rubocop.rb +13 -17
  17. data/lib/spoom/deadcode/plugins/ruby.rb +9 -9
  18. data/lib/spoom/deadcode/plugins/sorbet.rb +15 -18
  19. data/lib/spoom/deadcode/plugins/thor.rb +5 -4
  20. data/lib/spoom/deadcode/plugins.rb +4 -5
  21. data/lib/spoom/deadcode/remover.rb +7 -7
  22. data/lib/spoom/deadcode/send.rb +1 -0
  23. data/lib/spoom/deadcode.rb +4 -73
  24. data/lib/spoom/location.rb +84 -0
  25. data/lib/spoom/model/builder.rb +246 -0
  26. data/lib/spoom/model/model.rb +328 -0
  27. data/lib/spoom/model/namespace_visitor.rb +50 -0
  28. data/lib/spoom/model/reference.rb +49 -0
  29. data/lib/spoom/model/references_visitor.rb +200 -0
  30. data/lib/spoom/model.rb +10 -0
  31. data/lib/spoom/parse.rb +28 -0
  32. data/lib/spoom/poset.rb +197 -0
  33. data/lib/spoom/sorbet/errors.rb +5 -3
  34. data/lib/spoom/sorbet/lsp/errors.rb +1 -1
  35. data/lib/spoom/sorbet.rb +1 -1
  36. data/lib/spoom/version.rb +1 -1
  37. data/lib/spoom/visitor.rb +755 -0
  38. data/lib/spoom.rb +2 -0
  39. metadata +20 -13
  40. data/lib/spoom/deadcode/location.rb +0 -86
  41. data/lib/spoom/deadcode/reference.rb +0 -34
  42. data/lib/spoom/deadcode/visitor.rb +0 -755
@@ -125,6 +125,14 @@ module Spoom
125
125
  end
126
126
  end
127
127
 
128
+ sig { returns(Index) }
129
+ attr_reader :index
130
+
131
+ sig { params(index: Index).void }
132
+ def initialize(index)
133
+ @index = index
134
+ end
135
+
128
136
  # Indexing event methods
129
137
 
130
138
  # Called when an accessor is defined.
@@ -135,20 +143,20 @@ module Spoom
135
143
  #
136
144
  # ~~~rb
137
145
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
138
- # def on_define_accessor(indexer, definition)
139
- # definition.ignored! if definition.name == "foo"
146
+ # def on_define_accessor(definition)
147
+ # @index.ignore(definition) if symbol_def.name == "foo"
140
148
  # end
141
149
  # end
142
150
  # ~~~
143
- sig { params(indexer: Indexer, definition: Definition).void }
144
- def on_define_accessor(indexer, definition)
151
+ sig { params(definition: Model::Attr).void }
152
+ def on_define_accessor(definition)
145
153
  # no-op
146
154
  end
147
155
 
148
156
  # Do not override this method, use `on_define_accessor` instead.
149
- sig { params(indexer: Indexer, definition: Definition).void }
150
- def internal_on_define_accessor(indexer, definition)
151
- on_define_accessor(indexer, definition)
157
+ sig { params(definition: Model::Attr).void }
158
+ def internal_on_define_accessor(definition)
159
+ on_define_accessor(definition)
152
160
  end
153
161
 
154
162
  # Called when a class is defined.
@@ -159,26 +167,26 @@ module Spoom
159
167
  #
160
168
  # ~~~rb
161
169
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
162
- # def on_define_class(indexer, definition)
163
- # definition.ignored! if definition.name == "Foo"
170
+ # def on_define_class(definition)
171
+ # @index.ignore(definition) if definition.name == "Foo"
164
172
  # end
165
173
  # end
166
174
  # ~~~
167
- sig { params(indexer: Indexer, definition: Definition).void }
168
- def on_define_class(indexer, definition)
175
+ sig { params(definition: Model::Class).void }
176
+ def on_define_class(definition)
169
177
  # no-op
170
178
  end
171
179
 
172
180
  # Do not override this method, use `on_define_class` instead.
173
- sig { params(indexer: Indexer, definition: Definition).void }
174
- def internal_on_define_class(indexer, definition)
181
+ sig { params(definition: Model::Class).void }
182
+ def internal_on_define_class(definition)
175
183
  if ignored_class_name?(definition.name)
176
- definition.ignored!
177
- elsif ignored_subclass?(indexer.nesting_class_superclass_name)
178
- definition.ignored!
184
+ @index.ignore(definition)
185
+ elsif ignored_subclass?(definition)
186
+ @index.ignore(definition)
179
187
  end
180
188
 
181
- on_define_class(indexer, definition)
189
+ on_define_class(definition)
182
190
  end
183
191
 
184
192
  # Called when a constant is defined.
@@ -189,22 +197,22 @@ module Spoom
189
197
  #
190
198
  # ~~~rb
191
199
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
192
- # def on_define_constant(indexer, definition)
193
- # definition.ignored! if definition.name == "FOO"
200
+ # def on_define_constant(definition)
201
+ # @index.ignore(definition) if definition.name == "FOO"
194
202
  # end
195
203
  # end
196
204
  # ~~~
197
- sig { params(indexer: Indexer, definition: Definition).void }
198
- def on_define_constant(indexer, definition)
205
+ sig { params(definition: Model::Constant).void }
206
+ def on_define_constant(definition)
199
207
  # no-op
200
208
  end
201
209
 
202
210
  # Do not override this method, use `on_define_constant` instead.
203
- sig { params(indexer: Indexer, definition: Definition).void }
204
- def internal_on_define_constant(indexer, definition)
205
- definition.ignored! if ignored_constant_name?(definition.name)
211
+ sig { params(definition: Model::Constant).void }
212
+ def internal_on_define_constant(definition)
213
+ @index.ignore(definition) if ignored_constant_name?(definition.name)
206
214
 
207
- on_define_constant(indexer, definition)
215
+ on_define_constant(definition)
208
216
  end
209
217
 
210
218
  # Called when a method is defined.
@@ -215,24 +223,22 @@ module Spoom
215
223
  #
216
224
  # ~~~rb
217
225
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
218
- # def on_define_method(indexer, definition)
219
- # super # So the `ignore_method_names` DSL is still applied
220
- #
221
- # definition.ignored! if definition.name == "foo"
226
+ # def on_define_method(definition)
227
+ # @index.ignore(definition) if definition.name == "foo"
222
228
  # end
223
229
  # end
224
230
  # ~~~
225
- sig { params(indexer: Indexer, definition: Definition).void }
226
- def on_define_method(indexer, definition)
231
+ sig { params(definition: Model::Method).void }
232
+ def on_define_method(definition)
227
233
  # no-op
228
234
  end
229
235
 
230
236
  # Do not override this method, use `on_define_method` instead.
231
- sig { params(indexer: Indexer, definition: Definition).void }
232
- def internal_on_define_method(indexer, definition)
233
- definition.ignored! if ignored_method_name?(definition.name)
237
+ sig { params(definition: Model::Method).void }
238
+ def internal_on_define_method(definition)
239
+ @index.ignore(definition) if ignored_method_name?(definition.name)
234
240
 
235
- on_define_method(indexer, definition)
241
+ on_define_method(definition)
236
242
  end
237
243
 
238
244
  # Called when a module is defined.
@@ -243,52 +249,54 @@ module Spoom
243
249
  #
244
250
  # ~~~rb
245
251
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
246
- # def on_define_module(indexer, definition)
247
- # definition.ignored! if definition.name == "Foo"
252
+ # def on_define_module(definition)
253
+ # @index.ignore(definition) if definition.name == "Foo"
248
254
  # end
249
255
  # end
250
256
  # ~~~
251
- sig { params(indexer: Indexer, definition: Definition).void }
252
- def on_define_module(indexer, definition)
257
+ sig { params(definition: Model::Module).void }
258
+ def on_define_module(definition)
253
259
  # no-op
254
260
  end
255
261
 
256
262
  # Do not override this method, use `on_define_module` instead.
257
- sig { params(indexer: Indexer, definition: Definition).void }
258
- def internal_on_define_module(indexer, definition)
259
- definition.ignored! if ignored_module_name?(definition.name)
263
+ sig { params(definition: Model::Module).void }
264
+ def internal_on_define_module(definition)
265
+ @index.ignore(definition) if ignored_module_name?(definition.name)
260
266
 
261
- on_define_module(indexer, definition)
267
+ on_define_module(definition)
262
268
  end
263
269
 
264
270
  # Called when a send is being processed
265
271
  #
266
272
  # ~~~rb
267
273
  # class MyPlugin < Spoom::Deadcode::Plugins::Base
268
- # def on_send(indexer, send)
274
+ # def on_send(send)
269
275
  # return unless send.name == "dsl_method"
270
276
  # return if send.args.empty?
271
277
  #
272
278
  # method_name = send.args.first.slice.delete_prefix(":")
273
- # indexer.reference_method(method_name, send.node)
279
+ # @index.reference_method(method_name, send.node, send.loc)
274
280
  # end
275
281
  # end
276
282
  # ~~~
277
- sig { params(indexer: Indexer, send: Send).void }
278
- def on_send(indexer, send)
283
+ sig { params(send: Send).void }
284
+ def on_send(send)
279
285
  # no-op
280
286
  end
281
287
 
282
- # Do not override this method, use `on_send` instead.
283
- sig { params(indexer: Indexer, send: Send).void }
284
- def internal_on_send(indexer, send)
285
- on_send(indexer, send)
286
- end
287
-
288
288
  private
289
289
 
290
290
  # DSL support
291
291
 
292
+ sig { params(definition: Model::Namespace, superclass_name: String).returns(T::Boolean) }
293
+ def subclass_of?(definition, superclass_name)
294
+ superclass_symbol = @index.model.symbols[superclass_name]
295
+ return false unless superclass_symbol
296
+
297
+ @index.model.symbols_hierarchy.edge?(definition.symbol, superclass_symbol)
298
+ end
299
+
292
300
  sig { params(name: T.nilable(String)).returns(T::Boolean) }
293
301
  def ignored_class_name?(name)
294
302
  return false unless name
@@ -296,11 +304,16 @@ module Spoom
296
304
  ignored_name?(name, :@ignored_class_names, :@ignored_class_patterns)
297
305
  end
298
306
 
299
- sig { params(superclass_name: T.nilable(String)).returns(T::Boolean) }
300
- def ignored_subclass?(superclass_name)
301
- return false unless superclass_name
307
+ sig { params(definition: Model::Class).returns(T::Boolean) }
308
+ def ignored_subclass?(definition)
309
+ superclass_name = definition.superclass_name
310
+ return true if superclass_name && ignored_name?(
311
+ superclass_name,
312
+ :@ignored_subclasses_of_names,
313
+ :@ignored_subclasses_of_patterns,
314
+ )
302
315
 
303
- ignored_name?(superclass_name, :@ignored_subclasses_of_names, :@ignored_subclasses_of_patterns)
316
+ names(:@ignored_subclasses_of_names).any? { |superclass_name| subclass_of?(definition, superclass_name) }
304
317
  end
305
318
 
306
319
  sig { params(name: String).returns(T::Boolean) }
@@ -8,10 +8,10 @@ module Spoom
8
8
  extend T::Sig
9
9
 
10
10
  ignore_classes_inheriting_from(
11
- /^(::)?GraphQL::Schema::Enum$/,
12
- /^(::)?GraphQL::Schema::Object$/,
13
- /^(::)?GraphQL::Schema::Scalar$/,
14
- /^(::)?GraphQL::Schema::Union$/,
11
+ "GraphQL::Schema::Enum",
12
+ "GraphQL::Schema::Object",
13
+ "GraphQL::Schema::Scalar",
14
+ "GraphQL::Schema::Union",
15
15
  )
16
16
 
17
17
  ignore_methods_named(
@@ -24,21 +24,21 @@ module Spoom
24
24
  "unsubscribed",
25
25
  )
26
26
 
27
- sig { override.params(indexer: Indexer, send: Send).void }
28
- def on_send(indexer, send)
27
+ sig { override.params(send: Send).void }
28
+ def on_send(send)
29
29
  return unless send.recv.nil? && send.name == "field"
30
30
 
31
31
  arg = send.args.first
32
32
  return unless arg.is_a?(Prism::SymbolNode)
33
33
 
34
- indexer.reference_method(arg.unescaped, send.node)
34
+ @index.reference_method(arg.unescaped, send.location)
35
35
 
36
36
  send.each_arg_assoc do |key, value|
37
37
  key = key.slice.delete_suffix(":")
38
38
  next unless key == "resolver_method"
39
39
  next unless value
40
40
 
41
- indexer.reference_method(value.slice.delete_prefix(":"), send.node)
41
+ @index.reference_method(value.slice.delete_prefix(":"), send.location)
42
42
  end
43
43
  end
44
44
  end
@@ -18,9 +18,10 @@ module Spoom
18
18
  "teardown",
19
19
  )
20
20
 
21
- sig { override.params(indexer: Indexer, definition: Definition).void }
22
- def on_define_method(indexer, definition)
23
- definition.ignored! if indexer.path.match?(%r{test/.*test\.rb$}) && definition.name.match?(/^test_/)
21
+ sig { override.params(definition: Model::Method).void }
22
+ def on_define_method(definition)
23
+ file = definition.location.file
24
+ @index.ignore(definition) if file.match?(%r{test/.*test\.rb$}) && definition.name.match?(/^test_/)
24
25
  end
25
26
  end
26
27
  end
@@ -7,24 +7,21 @@ module Spoom
7
7
  class Namespaces < Base
8
8
  extend T::Sig
9
9
 
10
- sig { override.params(indexer: Indexer, definition: Definition).void }
11
- def on_define_class(indexer, definition)
12
- definition.ignored! if used_as_namespace?(indexer)
10
+ sig { override.params(definition: Model::Class).void }
11
+ def on_define_class(definition)
12
+ @index.ignore(definition) if used_as_namespace?(definition)
13
13
  end
14
14
 
15
- sig { override.params(indexer: Indexer, definition: Definition).void }
16
- def on_define_module(indexer, definition)
17
- definition.ignored! if used_as_namespace?(indexer)
15
+ sig { override.params(definition: Model::Module).void }
16
+ def on_define_module(definition)
17
+ @index.ignore(definition) if used_as_namespace?(definition)
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- sig { params(indexer: Indexer).returns(T::Boolean) }
23
- def used_as_namespace?(indexer)
24
- node = indexer.current_node
25
- return false unless node.is_a?(Prism::ClassNode) || node.is_a?(Prism::ModuleNode)
26
-
27
- !!node.body
22
+ sig { params(symbol_def: Model::Namespace).returns(T::Boolean) }
23
+ def used_as_namespace?(symbol_def)
24
+ symbol_def.children.any?
28
25
  end
29
26
  end
30
27
  end
@@ -9,21 +9,21 @@ module Spoom
9
9
 
10
10
  ignore_constants_named("APP_PATH", "ENGINE_PATH", "ENGINE_ROOT")
11
11
 
12
- sig { override.params(indexer: Indexer, definition: Definition).void }
13
- def on_define_class(indexer, definition)
14
- definition.ignored! if file_is_helper?(indexer)
12
+ sig { override.params(definition: Model::Class).void }
13
+ def on_define_class(definition)
14
+ @index.ignore(definition) if file_is_helper?(definition)
15
15
  end
16
16
 
17
- sig { override.params(indexer: Indexer, definition: Definition).void }
18
- def on_define_module(indexer, definition)
19
- definition.ignored! if file_is_helper?(indexer)
17
+ sig { override.params(definition: Model::Module).void }
18
+ def on_define_module(definition)
19
+ @index.ignore(definition) if file_is_helper?(definition)
20
20
  end
21
21
 
22
22
  private
23
23
 
24
- sig { params(indexer: Indexer).returns(T::Boolean) }
25
- def file_is_helper?(indexer)
26
- indexer.path.match?(%r{app/helpers/.*\.rb$})
24
+ sig { params(symbol_def: Model::Namespace).returns(T::Boolean) }
25
+ def file_is_helper?(symbol_def)
26
+ symbol_def.location.file.match?(%r{app/helpers/.*\.rb$})
27
27
  end
28
28
  end
29
29
  end
@@ -10,30 +10,26 @@ module Spoom
10
10
  RUBOCOP_CONSTANTS = T.let(["MSG", "RESTRICT_ON_SEND"].to_set.freeze, T::Set[String])
11
11
 
12
12
  ignore_classes_inheriting_from(
13
- /^(::)?RuboCop::Cop::Cop$/,
14
- /^(::)?RuboCop::Cop::Base$/,
13
+ "RuboCop::Cop::Cop",
14
+ "RuboCop::Cop::Base",
15
15
  )
16
16
 
17
- sig { override.params(indexer: Indexer, definition: Definition).void }
18
- def on_define_constant(indexer, definition)
19
- definition.ignored! if rubocop_constant?(indexer, definition)
20
- end
17
+ sig { override.params(definition: Model::Constant).void }
18
+ def on_define_constant(definition)
19
+ owner = definition.owner
20
+ return false unless owner.is_a?(Model::Class)
21
21
 
22
- sig { override.params(indexer: Indexer, definition: Definition).void }
23
- def on_define_method(indexer, definition)
24
- definition.ignored! if rubocop_method?(indexer, definition)
22
+ @index.ignore(definition) if ignored_subclass?(owner) && RUBOCOP_CONSTANTS.include?(definition.name)
25
23
  end
26
24
 
27
- private
25
+ sig { override.params(definition: Model::Method).void }
26
+ def on_define_method(definition)
27
+ return unless definition.name == "on_send"
28
28
 
29
- sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
30
- def rubocop_constant?(indexer, definition)
31
- ignored_subclass?(indexer.nesting_class_superclass_name) && RUBOCOP_CONSTANTS.include?(definition.name)
32
- end
29
+ owner = definition.owner
30
+ return unless owner.is_a?(Model::Class)
33
31
 
34
- sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
35
- def rubocop_method?(indexer, definition)
36
- ignored_subclass?(indexer.nesting_class_superclass_name) && definition.name == "on_send"
32
+ @index.ignore(definition) if ignored_subclass?(owner)
37
33
  end
38
34
  end
39
35
  end
@@ -20,33 +20,33 @@ module Spoom
20
20
  "to_s",
21
21
  )
22
22
 
23
- sig { override.params(indexer: Indexer, send: Send).void }
24
- def on_send(indexer, send)
23
+ sig { override.params(send: Send).void }
24
+ def on_send(send)
25
25
  case send.name
26
26
  when "const_defined?", "const_get", "const_source_location"
27
- reference_symbol_as_constant(indexer, send, T.must(send.args.first))
27
+ reference_symbol_as_constant(send, T.must(send.args.first))
28
28
  when "send", "__send__", "try"
29
29
  arg = send.args.first
30
- indexer.reference_method(arg.unescaped, send.node) if arg.is_a?(Prism::SymbolNode)
30
+ @index.reference_method(arg.unescaped, send.location) if arg.is_a?(Prism::SymbolNode)
31
31
  when "alias_method"
32
32
  last_arg = send.args.last
33
33
 
34
34
  if last_arg.is_a?(Prism::SymbolNode) || last_arg.is_a?(Prism::StringNode)
35
- indexer.reference_method(last_arg.unescaped, send.node)
35
+ @index.reference_method(last_arg.unescaped, send.location)
36
36
  end
37
37
  end
38
38
  end
39
39
 
40
40
  private
41
41
 
42
- sig { params(indexer: Indexer, send: Send, node: Prism::Node).void }
43
- def reference_symbol_as_constant(indexer, send, node)
42
+ sig { params(send: Send, node: Prism::Node).void }
43
+ def reference_symbol_as_constant(send, node)
44
44
  case node
45
45
  when Prism::SymbolNode
46
- indexer.reference_constant(node.unescaped, send.node)
46
+ @index.reference_constant(node.unescaped, send.location)
47
47
  when Prism::StringNode
48
48
  node.unescaped.split("::").each do |name|
49
- indexer.reference_constant(name, send.node) unless name.empty?
49
+ @index.reference_constant(name, send.location) unless name.empty?
50
50
  end
51
51
  end
52
52
  end
@@ -7,32 +7,29 @@ module Spoom
7
7
  class Sorbet < Base
8
8
  extend T::Sig
9
9
 
10
- sig { override.params(indexer: Indexer, definition: Definition).void }
11
- def on_define_constant(indexer, definition)
12
- definition.ignored! if sorbet_type_member?(indexer, definition) || sorbet_enum_constant?(indexer, definition)
10
+ sig { override.params(definition: Model::Constant).void }
11
+ def on_define_constant(definition)
12
+ @index.ignore(definition) if sorbet_type_member?(definition) || sorbet_enum_constant?(definition)
13
13
  end
14
14
 
15
- sig { override.params(indexer: Indexer, definition: Definition).void }
16
- def on_define_method(indexer, definition)
17
- definition.ignored! if indexer.last_sig =~ /(override|overridable)/
15
+ sig { override.params(definition: Model::Method).void }
16
+ def on_define_method(definition)
17
+ @index.ignore(definition) if definition.sigs.any? { |sig| sig.string =~ /(override|overridable)/ }
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
23
- def sorbet_type_member?(indexer, definition)
24
- assign = indexer.nesting_node(Prism::ConstantWriteNode)
25
- return false unless assign
26
-
27
- value = assign.value
28
- return false unless value.is_a?(Prism::CallNode)
29
-
30
- value.name == :type_member || value.name == :type_template
22
+ sig { params(definition: Model::Constant).returns(T::Boolean) }
23
+ def sorbet_type_member?(definition)
24
+ definition.value.match?(/^(type_member|type_template)/)
31
25
  end
32
26
 
33
- sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
34
- def sorbet_enum_constant?(indexer, definition)
35
- /^(::)?T::Enum$/.match?(indexer.nesting_class_superclass_name) && indexer.nesting_call&.name == :enums
27
+ sig { params(definition: Model::Constant).returns(T::Boolean) }
28
+ def sorbet_enum_constant?(definition)
29
+ owner = definition.owner
30
+ return false unless owner.is_a?(Model::Class)
31
+
32
+ subclass_of?(owner, "T::Enum")
36
33
  end
37
34
  end
38
35
  end
@@ -9,11 +9,12 @@ module Spoom
9
9
 
10
10
  ignore_methods_named("exit_on_failure?")
11
11
 
12
- sig { override.params(indexer: Indexer, definition: Definition).void }
13
- def on_define_method(indexer, definition)
14
- return if indexer.nesting_block # method defined in `no_commands do ... end`, we don't want to ignore it
12
+ sig { override.params(definition: Model::Method).void }
13
+ def on_define_method(definition)
14
+ owner = definition.owner
15
+ return unless owner.is_a?(Model::Class)
15
16
 
16
- definition.ignored! if indexer.nesting_class_superclass_name =~ /^(::)?Thor$/
17
+ @index.ignore(definition) if subclass_of?(owner, "Thor")
17
18
  end
18
19
  end
19
20
  end
@@ -57,7 +57,7 @@ module Spoom
57
57
  class << self
58
58
  extend T::Sig
59
59
 
60
- sig { params(context: Context).returns(T::Array[Plugins::Base]) }
60
+ sig { params(context: Context).returns(T::Set[T.class_of(Plugins::Base)]) }
61
61
  def plugins_from_gemfile_lock(context)
62
62
  # These plugins are always loaded
63
63
  plugin_classes = DEFAULT_PLUGINS.dup
@@ -68,16 +68,16 @@ module Spoom
68
68
  plugin_classes << plugin_class if plugin_class
69
69
  end
70
70
 
71
- plugin_classes.map(&:new)
71
+ plugin_classes
72
72
  end
73
73
 
74
- sig { params(context: Context).returns(T::Array[Plugins::Base]) }
74
+ sig { params(context: Context).returns(T::Array[T.class_of(Plugins::Base)]) }
75
75
  def load_custom_plugins(context)
76
76
  context.glob("#{DEFAULT_CUSTOM_PLUGINS_PATH}/*.rb").each do |path|
77
77
  require("#{context.absolute_path}/#{path}")
78
78
  end
79
79
 
80
- ObjectSpace
80
+ T.unsafe(ObjectSpace)
81
81
  .each_object(Class)
82
82
  .select do |klass|
83
83
  next unless T.unsafe(klass).name # skip anonymous classes, we only use them in tests
@@ -89,7 +89,6 @@ module Spoom
89
89
 
90
90
  true
91
91
  end
92
- .map { |klass| T.unsafe(klass).new }
93
92
  end
94
93
  end
95
94
  end
@@ -145,7 +145,7 @@ module Spoom
145
145
  delete_chars(node.location.start_offset, next_node.location.start_offset)
146
146
  else
147
147
  # Should have been removed as a single MLHS node
148
- raise "Unexpected case while removing constant assignment"
148
+ raise Error, "Unexpected case while removing constant assignment"
149
149
  end
150
150
  end
151
151
 
@@ -202,7 +202,7 @@ module Spoom
202
202
  # ~~~
203
203
  delete_chars(context.node.location.start_offset, next_node.location.start_offset)
204
204
  else
205
- raise "Unexpected case while removing attr_accessor"
205
+ raise Error, "Unexpected case while removing attr_accessor"
206
206
  end
207
207
 
208
208
  insert_accessor(context.node, send_context, was_removed: false) if need_accessor
@@ -399,7 +399,7 @@ module Spoom
399
399
  sig { returns(Prism::Node) }
400
400
  def parent_node
401
401
  parent = @nesting.last
402
- raise "No parent for node #{node}" unless parent
402
+ raise Error, "No parent for node #{node}" unless parent
403
403
 
404
404
  parent
405
405
  end
@@ -408,7 +408,7 @@ module Spoom
408
408
  def parent_context
409
409
  nesting = @nesting.dup
410
410
  parent = nesting.pop
411
- raise "No parent context for node #{@node}" unless parent
411
+ raise Error, "No parent context for node #{@node}" unless parent
412
412
 
413
413
  NodeContext.new(@source, @comments, parent, nesting)
414
414
  end
@@ -419,7 +419,7 @@ module Spoom
419
419
  child_nodes = parent.child_nodes.compact
420
420
 
421
421
  index = child_nodes.index(@node)
422
- raise "Node #{@node} not found in parent #{parent}" unless index
422
+ raise Error, "Node #{@node} not found in parent #{parent}" unless index
423
423
 
424
424
  T.must(child_nodes[0...index])
425
425
  end
@@ -435,7 +435,7 @@ module Spoom
435
435
  child_nodes = parent.child_nodes.compact
436
436
 
437
437
  index = child_nodes.index(node)
438
- raise "Node #{@node} not found in nesting node #{parent}" unless index
438
+ raise Error, "Node #{@node} not found in nesting node #{parent}" unless index
439
439
 
440
440
  T.must(child_nodes.compact[(index + 1)..-1])
441
441
  end
@@ -561,7 +561,7 @@ module Spoom
561
561
  "#{e.message} (at #{e.location.start_line}:#{e.location.start_column})."
562
562
  end.join(" ")
563
563
 
564
- raise ParserError, "Error while parsing #{location.file}: #{message}"
564
+ raise ParseError, "Error while parsing #{location.file}: #{message}"
565
565
  end
566
566
 
567
567
  visitor = new(location, kind)
@@ -12,6 +12,7 @@ module Spoom
12
12
  const :recv, T.nilable(Prism::Node), default: nil
13
13
  const :args, T::Array[Prism::Node], default: []
14
14
  const :block, T.nilable(Prism::Node), default: nil
15
+ const :location, Location
15
16
 
16
17
  sig do
17
18
  type_parameters(:T)