spoom 1.3.1 → 1.3.3
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/lib/spoom/cli/deadcode.rb +21 -17
- data/lib/spoom/deadcode/index.rb +178 -10
- data/lib/spoom/deadcode/indexer.rb +14 -435
- data/lib/spoom/deadcode/plugins/action_mailer.rb +3 -3
- data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +9 -3
- data/lib/spoom/deadcode/plugins/actionpack.rb +12 -9
- data/lib/spoom/deadcode/plugins/active_model.rb +8 -8
- data/lib/spoom/deadcode/plugins/active_record.rb +5 -5
- data/lib/spoom/deadcode/plugins/active_support.rb +4 -4
- data/lib/spoom/deadcode/plugins/base.rb +70 -57
- data/lib/spoom/deadcode/plugins/graphql.rb +8 -8
- data/lib/spoom/deadcode/plugins/minitest.rb +4 -3
- data/lib/spoom/deadcode/plugins/namespaces.rb +9 -12
- data/lib/spoom/deadcode/plugins/rails.rb +9 -9
- data/lib/spoom/deadcode/plugins/rubocop.rb +13 -17
- data/lib/spoom/deadcode/plugins/ruby.rb +9 -9
- data/lib/spoom/deadcode/plugins/sorbet.rb +15 -18
- data/lib/spoom/deadcode/plugins/thor.rb +5 -4
- data/lib/spoom/deadcode/plugins.rb +4 -5
- data/lib/spoom/deadcode/remover.rb +14 -10
- data/lib/spoom/deadcode/send.rb +1 -0
- data/lib/spoom/deadcode.rb +4 -73
- data/lib/spoom/location.rb +84 -0
- data/lib/spoom/model/builder.rb +246 -0
- data/lib/spoom/model/model.rb +328 -0
- data/lib/spoom/model/namespace_visitor.rb +50 -0
- data/lib/spoom/model/reference.rb +49 -0
- data/lib/spoom/model/references_visitor.rb +200 -0
- data/lib/spoom/model.rb +10 -0
- data/lib/spoom/parse.rb +28 -0
- data/lib/spoom/poset.rb +197 -0
- data/lib/spoom/sorbet/errors.rb +5 -3
- data/lib/spoom/sorbet/lsp/errors.rb +1 -1
- data/lib/spoom/sorbet.rb +1 -1
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom/visitor.rb +755 -0
- data/lib/spoom.rb +2 -0
- metadata +20 -13
- data/lib/spoom/deadcode/location.rb +0 -86
- data/lib/spoom/deadcode/reference.rb +0 -34
- 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(
|
139
|
-
# definition
|
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(
|
144
|
-
def on_define_accessor(
|
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(
|
150
|
-
def internal_on_define_accessor(
|
151
|
-
on_define_accessor(
|
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(
|
163
|
-
# definition
|
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(
|
168
|
-
def on_define_class(
|
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(
|
174
|
-
def internal_on_define_class(
|
181
|
+
sig { params(definition: Model::Class).void }
|
182
|
+
def internal_on_define_class(definition)
|
175
183
|
if ignored_class_name?(definition.name)
|
176
|
-
definition
|
177
|
-
elsif ignored_subclass?(
|
178
|
-
definition
|
184
|
+
@index.ignore(definition)
|
185
|
+
elsif ignored_subclass?(definition)
|
186
|
+
@index.ignore(definition)
|
179
187
|
end
|
180
188
|
|
181
|
-
on_define_class(
|
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(
|
193
|
-
# definition
|
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(
|
198
|
-
def on_define_constant(
|
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(
|
204
|
-
def internal_on_define_constant(
|
205
|
-
definition
|
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(
|
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(
|
219
|
-
#
|
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(
|
226
|
-
def on_define_method(
|
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(
|
232
|
-
def internal_on_define_method(
|
233
|
-
definition
|
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(
|
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(
|
247
|
-
# definition
|
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(
|
252
|
-
def on_define_module(
|
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(
|
258
|
-
def internal_on_define_module(
|
259
|
-
definition
|
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(
|
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(
|
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
|
-
#
|
279
|
+
# @index.reference_method(method_name, send.node, send.loc)
|
274
280
|
# end
|
275
281
|
# end
|
276
282
|
# ~~~
|
277
|
-
sig { params(
|
278
|
-
def on_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(
|
300
|
-
def ignored_subclass?(
|
301
|
-
|
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
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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(
|
28
|
-
def on_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
|
-
|
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
|
-
|
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(
|
22
|
-
def on_define_method(
|
23
|
-
|
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(
|
11
|
-
def on_define_class(
|
12
|
-
definition
|
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(
|
16
|
-
def on_define_module(
|
17
|
-
definition
|
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(
|
23
|
-
def used_as_namespace?(
|
24
|
-
|
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(
|
13
|
-
def on_define_class(
|
14
|
-
definition
|
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(
|
18
|
-
def on_define_module(
|
19
|
-
definition
|
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(
|
25
|
-
def file_is_helper?(
|
26
|
-
|
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
|
-
|
14
|
-
|
13
|
+
"RuboCop::Cop::Cop",
|
14
|
+
"RuboCop::Cop::Base",
|
15
15
|
)
|
16
16
|
|
17
|
-
sig { override.params(
|
18
|
-
def on_define_constant(
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
-
|
25
|
+
sig { override.params(definition: Model::Method).void }
|
26
|
+
def on_define_method(definition)
|
27
|
+
return unless definition.name == "on_send"
|
28
28
|
|
29
|
-
|
30
|
-
|
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
|
-
|
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(
|
24
|
-
def on_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(
|
27
|
+
reference_symbol_as_constant(send, T.must(send.args.first))
|
28
28
|
when "send", "__send__", "try"
|
29
29
|
arg = send.args.first
|
30
|
-
|
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
|
-
|
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(
|
43
|
-
def reference_symbol_as_constant(
|
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
|
-
|
46
|
+
@index.reference_constant(node.unescaped, send.location)
|
47
47
|
when Prism::StringNode
|
48
48
|
node.unescaped.split("::").each do |name|
|
49
|
-
|
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(
|
11
|
-
def on_define_constant(
|
12
|
-
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(
|
16
|
-
def on_define_method(
|
17
|
-
definition
|
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(
|
23
|
-
def sorbet_type_member?(
|
24
|
-
|
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(
|
34
|
-
def sorbet_enum_constant?(
|
35
|
-
|
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(
|
13
|
-
def on_define_method(
|
14
|
-
|
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
|
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::
|
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
|
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,10 +561,10 @@ module Spoom
|
|
561
561
|
"#{e.message} (at #{e.location.start_line}:#{e.location.start_column})."
|
562
562
|
end.join(" ")
|
563
563
|
|
564
|
-
raise
|
564
|
+
raise ParseError, "Error while parsing #{location.file}: #{message}"
|
565
565
|
end
|
566
566
|
|
567
|
-
visitor = new(location)
|
567
|
+
visitor = new(location, kind)
|
568
568
|
visitor.visit(result.value)
|
569
569
|
|
570
570
|
node = visitor.node
|
@@ -617,10 +617,11 @@ module Spoom
|
|
617
617
|
sig { returns(T::Array[Prism::Node]) }
|
618
618
|
attr_reader :nodes_nesting
|
619
619
|
|
620
|
-
sig { params(location: Location).void }
|
621
|
-
def initialize(location)
|
620
|
+
sig { params(location: Location, kind: T.nilable(Definition::Kind)).void }
|
621
|
+
def initialize(location, kind)
|
622
622
|
super()
|
623
623
|
@location = location
|
624
|
+
@kind = kind
|
624
625
|
@node = T.let(nil, T.nilable(Prism::Node))
|
625
626
|
@nodes_nesting = T.let([], T::Array[Prism::Node])
|
626
627
|
end
|
@@ -635,6 +636,9 @@ module Spoom
|
|
635
636
|
# We found the node we're looking for at `@location`
|
636
637
|
@node = node
|
637
638
|
|
639
|
+
# The node we found matches the kind we're looking for, we can stop here
|
640
|
+
return if @kind && self.class.node_match_kind?(node, @kind)
|
641
|
+
|
638
642
|
# There may be a more precise child inside the node that also matches `@location`, let's visit them
|
639
643
|
@nodes_nesting << node
|
640
644
|
super(node)
|
data/lib/spoom/deadcode/send.rb
CHANGED