spoom 1.3.1 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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