spoom 1.2.3 → 1.2.4
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/README.md +10 -0
- data/lib/spoom/backtrace_filter/minitest.rb +21 -0
- data/lib/spoom/deadcode/erb.rb +4 -4
- data/lib/spoom/deadcode/indexer.rb +77 -9
- data/lib/spoom/deadcode/location.rb +28 -0
- data/lib/spoom/deadcode/plugins/action_mailer.rb +21 -0
- data/lib/spoom/deadcode/plugins/actionpack.rb +61 -0
- data/lib/spoom/deadcode/plugins/active_job.rb +13 -0
- data/lib/spoom/deadcode/plugins/active_model.rb +46 -0
- data/lib/spoom/deadcode/plugins/active_record.rb +111 -0
- data/lib/spoom/deadcode/plugins/active_support.rb +21 -0
- data/lib/spoom/deadcode/plugins/base.rb +164 -11
- data/lib/spoom/deadcode/plugins/graphql.rb +47 -0
- data/lib/spoom/deadcode/plugins/minitest.rb +28 -0
- data/lib/spoom/deadcode/plugins/namespaces.rb +34 -0
- data/lib/spoom/deadcode/plugins/rails.rb +31 -0
- data/lib/spoom/deadcode/plugins/rake.rb +12 -0
- data/lib/spoom/deadcode/plugins/rspec.rb +19 -0
- data/lib/spoom/deadcode/plugins/rubocop.rb +41 -0
- data/lib/spoom/deadcode/plugins/ruby.rb +3 -2
- data/lib/spoom/deadcode/plugins/sorbet.rb +46 -0
- data/lib/spoom/deadcode/plugins/thor.rb +21 -0
- data/lib/spoom/deadcode/plugins.rb +90 -0
- data/lib/spoom/deadcode/remover.rb +616 -0
- data/lib/spoom/deadcode/send.rb +22 -0
- data/lib/spoom/deadcode.rb +1 -0
- data/lib/spoom/version.rb +1 -1
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23df97e815cc01b35dbc960ec1921bbc1c65ae4c6f0588c690a0d9156877a013
|
4
|
+
data.tar.gz: d82fdb3fb66404b0c2d98ea9206be9d86ec2284bbae2ff24a5653a521ec9155e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67b6209ba61fbc285fc89dcf64adcde27cfecf44bb37d644cfb8aef50b7fca6e53a15e8eec5bc45030e4c838a35d3777c50a2d75fb32461792a1bc5957d7b2e3
|
7
|
+
data.tar.gz: c3e06e5140aac671ff8489243dee9feba3912ec12681332b2abb37ddd5c367246dc180ea80f6207afe28f81f499626f4dcf4b9628baa263854600d19d593f2f5
|
data/README.md
CHANGED
@@ -348,6 +348,16 @@ Find all the symbols for a file:
|
|
348
348
|
puts client.document_symbols("file://path/to/my/file.rb")
|
349
349
|
```
|
350
350
|
|
351
|
+
### Backtrace Filtering
|
352
|
+
|
353
|
+
Spoom provides a backtrace filter for Minitest to remove the Sorbet frames from test failures, giving a more readable output. To enable it:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
# test/test_helper.rb
|
357
|
+
require "spoom/backtrace_filter/minitest"
|
358
|
+
Minitest.backtrace_filter = Spoom::BacktraceFilter::Minitest.new
|
359
|
+
```
|
360
|
+
|
351
361
|
## Development
|
352
362
|
|
353
363
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. Don't forget to run `bin/sanity` before pushing your changes.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "minitest"
|
5
|
+
|
6
|
+
module Spoom
|
7
|
+
module BacktraceFilter
|
8
|
+
class Minitest < ::Minitest::BacktraceFilter
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
SORBET_PATHS = T.let(Gem.loaded_specs["sorbet-runtime"].full_require_paths.freeze, T::Array[String])
|
12
|
+
|
13
|
+
sig { override.params(bt: T.nilable(T::Array[String])).returns(T::Array[String]) }
|
14
|
+
def filter(bt)
|
15
|
+
super.select do |line|
|
16
|
+
SORBET_PATHS.none? { |path| line.include?(path) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/spoom/deadcode/erb.rb
CHANGED
@@ -44,7 +44,7 @@ module Spoom
|
|
44
44
|
|
45
45
|
private
|
46
46
|
|
47
|
-
sig { params(text: T.untyped).void }
|
47
|
+
sig { override.params(text: T.untyped).void }
|
48
48
|
def add_text(text)
|
49
49
|
return if text.empty?
|
50
50
|
|
@@ -62,7 +62,7 @@ module Spoom
|
|
62
62
|
|
63
63
|
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
64
64
|
|
65
|
-
sig { params(indicator: T.untyped, code: T.untyped).void }
|
65
|
+
sig { override.params(indicator: T.untyped, code: T.untyped).void }
|
66
66
|
def add_expression(indicator, code)
|
67
67
|
flush_newline_if_pending(src)
|
68
68
|
|
@@ -79,13 +79,13 @@ module Spoom
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
sig { params(code: T.untyped).void }
|
82
|
+
sig { override.params(code: T.untyped).void }
|
83
83
|
def add_code(code)
|
84
84
|
flush_newline_if_pending(src)
|
85
85
|
super
|
86
86
|
end
|
87
87
|
|
88
|
-
sig { params(_: T.untyped).void }
|
88
|
+
sig { override.params(_: T.untyped).void }
|
89
89
|
def add_postamble(_)
|
90
90
|
flush_newline_if_pending(src)
|
91
91
|
super
|
@@ -157,10 +157,10 @@ module Spoom
|
|
157
157
|
|
158
158
|
sig { override.params(node: SyntaxTree::DefNode).void }
|
159
159
|
def visit_def(node)
|
160
|
-
super
|
161
|
-
|
162
160
|
name = node_string(node.name)
|
163
161
|
define_method(name, [*@names_nesting, name].join("::"), node)
|
162
|
+
|
163
|
+
super
|
164
164
|
end
|
165
165
|
|
166
166
|
sig { override.params(node: SyntaxTree::Field).void }
|
@@ -230,7 +230,7 @@ module Spoom
|
|
230
230
|
end
|
231
231
|
else
|
232
232
|
@plugins.each do |plugin|
|
233
|
-
plugin.
|
233
|
+
plugin.internal_on_send(self, send)
|
234
234
|
end
|
235
235
|
|
236
236
|
reference_method(send.name, send.node)
|
@@ -286,7 +286,7 @@ module Spoom
|
|
286
286
|
location: node_location(node),
|
287
287
|
)
|
288
288
|
@index.define(definition)
|
289
|
-
@plugins.each { |plugin| plugin.
|
289
|
+
@plugins.each { |plugin| plugin.internal_on_define_accessor(self, definition) }
|
290
290
|
end
|
291
291
|
|
292
292
|
sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
|
@@ -298,7 +298,7 @@ module Spoom
|
|
298
298
|
location: node_location(node),
|
299
299
|
)
|
300
300
|
@index.define(definition)
|
301
|
-
@plugins.each { |plugin| plugin.
|
301
|
+
@plugins.each { |plugin| plugin.internal_on_define_accessor(self, definition) }
|
302
302
|
end
|
303
303
|
|
304
304
|
sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
|
@@ -310,7 +310,7 @@ module Spoom
|
|
310
310
|
location: node_location(node),
|
311
311
|
)
|
312
312
|
@index.define(definition)
|
313
|
-
@plugins.each { |plugin| plugin.
|
313
|
+
@plugins.each { |plugin| plugin.internal_on_define_class(self, definition) }
|
314
314
|
end
|
315
315
|
|
316
316
|
sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
|
@@ -322,7 +322,7 @@ module Spoom
|
|
322
322
|
location: node_location(node),
|
323
323
|
)
|
324
324
|
@index.define(definition)
|
325
|
-
@plugins.each { |plugin| plugin.
|
325
|
+
@plugins.each { |plugin| plugin.internal_on_define_constant(self, definition) }
|
326
326
|
end
|
327
327
|
|
328
328
|
sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
|
@@ -334,7 +334,7 @@ module Spoom
|
|
334
334
|
location: node_location(node),
|
335
335
|
)
|
336
336
|
@index.define(definition)
|
337
|
-
@plugins.each { |plugin| plugin.
|
337
|
+
@plugins.each { |plugin| plugin.internal_on_define_method(self, definition) }
|
338
338
|
end
|
339
339
|
|
340
340
|
sig { params(name: String, full_name: String, node: SyntaxTree::Node).void }
|
@@ -346,7 +346,7 @@ module Spoom
|
|
346
346
|
location: node_location(node),
|
347
347
|
)
|
348
348
|
@index.define(definition)
|
349
|
-
@plugins.each { |plugin| plugin.
|
349
|
+
@plugins.each { |plugin| plugin.internal_on_define_module(self, definition) }
|
350
350
|
end
|
351
351
|
|
352
352
|
# Reference indexing
|
@@ -361,6 +361,74 @@ module Spoom
|
|
361
361
|
@index.reference(Reference.new(name: name, kind: Reference::Kind::Method, location: node_location(node)))
|
362
362
|
end
|
363
363
|
|
364
|
+
# Context
|
365
|
+
|
366
|
+
sig { returns(SyntaxTree::Node) }
|
367
|
+
def current_node
|
368
|
+
T.must(@nodes_nesting.last)
|
369
|
+
end
|
370
|
+
|
371
|
+
sig { type_parameters(:N).params(type: T::Class[T.type_parameter(:N)]).returns(T.nilable(T.type_parameter(:N))) }
|
372
|
+
def nesting_node(type)
|
373
|
+
@nodes_nesting.reverse_each do |node|
|
374
|
+
return T.unsafe(node) if node.is_a?(type)
|
375
|
+
end
|
376
|
+
|
377
|
+
nil
|
378
|
+
end
|
379
|
+
|
380
|
+
sig { returns(T.nilable(SyntaxTree::ClassDeclaration)) }
|
381
|
+
def nesting_class
|
382
|
+
nesting_node(SyntaxTree::ClassDeclaration)
|
383
|
+
end
|
384
|
+
|
385
|
+
sig { returns(T.nilable(SyntaxTree::BlockNode)) }
|
386
|
+
def nesting_block
|
387
|
+
nesting_node(SyntaxTree::BlockNode)
|
388
|
+
end
|
389
|
+
|
390
|
+
sig { returns(T.nilable(SyntaxTree::MethodAddBlock)) }
|
391
|
+
def nesting_block_call
|
392
|
+
nesting_node(SyntaxTree::MethodAddBlock)
|
393
|
+
end
|
394
|
+
|
395
|
+
sig { returns(T.nilable(String)) }
|
396
|
+
def nesting_block_call_name
|
397
|
+
block = nesting_block_call
|
398
|
+
return unless block.is_a?(SyntaxTree::MethodAddBlock)
|
399
|
+
|
400
|
+
call = block.call
|
401
|
+
case call
|
402
|
+
when SyntaxTree::ARef
|
403
|
+
node_string(call.collection)
|
404
|
+
when SyntaxTree::CallNode, SyntaxTree::Command, SyntaxTree::CommandCall
|
405
|
+
node_string(call.message)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
sig { returns(T.nilable(String)) }
|
410
|
+
def nesting_class_name
|
411
|
+
nesting_class = self.nesting_class
|
412
|
+
return unless nesting_class
|
413
|
+
|
414
|
+
node_string(nesting_class.constant)
|
415
|
+
end
|
416
|
+
|
417
|
+
sig { returns(T.nilable(String)) }
|
418
|
+
def nesting_class_superclass_name
|
419
|
+
nesting_class_superclass = nesting_class&.superclass
|
420
|
+
return unless nesting_class_superclass
|
421
|
+
|
422
|
+
node_string(nesting_class_superclass).delete_prefix("::")
|
423
|
+
end
|
424
|
+
|
425
|
+
sig { returns(T.nilable(String)) }
|
426
|
+
def last_sig
|
427
|
+
return unless @previous_node.is_a?(SyntaxTree::MethodAddBlock)
|
428
|
+
|
429
|
+
node_string(@previous_node)
|
430
|
+
end
|
431
|
+
|
364
432
|
# Node utils
|
365
433
|
|
366
434
|
sig { params(node: T.any(Symbol, SyntaxTree::Node)).returns(String) }
|
@@ -13,6 +13,23 @@ module Spoom
|
|
13
13
|
class << self
|
14
14
|
extend T::Sig
|
15
15
|
|
16
|
+
sig { params(location_string: String).returns(Location) }
|
17
|
+
def from_string(location_string)
|
18
|
+
file, rest = location_string.split(":", 2)
|
19
|
+
raise LocationError, "Invalid location string: #{location_string}" unless file && rest
|
20
|
+
|
21
|
+
start_line, rest = rest.split(":", 2)
|
22
|
+
raise LocationError, "Invalid location string: #{location_string}" unless start_line && rest
|
23
|
+
|
24
|
+
start_column, rest = rest.split("-", 2)
|
25
|
+
raise LocationError, "Invalid location string: #{location_string}" unless start_column && rest
|
26
|
+
|
27
|
+
end_line, end_column = rest.split(":", 2)
|
28
|
+
raise LocationError, "Invalid location string: #{location_string}" unless end_line && end_column
|
29
|
+
|
30
|
+
new(file, start_line.to_i, start_column.to_i, end_line.to_i, end_column.to_i)
|
31
|
+
end
|
32
|
+
|
16
33
|
sig { params(file: String, location: SyntaxTree::Location).returns(Location) }
|
17
34
|
def from_syntax_tree(file, location)
|
18
35
|
new(file, location.start_line, location.start_column, location.end_line, location.end_column)
|
@@ -42,6 +59,17 @@ module Spoom
|
|
42
59
|
@end_column = end_column
|
43
60
|
end
|
44
61
|
|
62
|
+
sig { params(other: Location).returns(T::Boolean) }
|
63
|
+
def include?(other)
|
64
|
+
return false unless @file == other.file
|
65
|
+
return false if @start_line > other.start_line
|
66
|
+
return false if @start_line == other.start_line && @start_column > other.start_column
|
67
|
+
return false if @end_line < other.end_line
|
68
|
+
return false if @end_line == other.end_line && @end_column < other.end_column
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
45
73
|
sig { override.params(other: BasicObject).returns(T.nilable(Integer)) }
|
46
74
|
def <=>(other)
|
47
75
|
return unless Location === other
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActionMailer < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { override.params(indexer: Indexer, send: Send).void }
|
11
|
+
def on_send(indexer, send)
|
12
|
+
return unless send.recv.nil? && ActionPack::CALLBACKS.include?(send.name)
|
13
|
+
|
14
|
+
send.each_arg(SyntaxTree::SymbolLiteral) do |arg|
|
15
|
+
indexer.reference_method(indexer.node_string(arg.value), send.node)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActionPack < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
CALLBACKS = T.let(
|
11
|
+
[
|
12
|
+
"after_action",
|
13
|
+
"append_after_action",
|
14
|
+
"append_around_action",
|
15
|
+
"append_before_action",
|
16
|
+
"around_action",
|
17
|
+
"before_action",
|
18
|
+
"prepend_after_action",
|
19
|
+
"prepend_around_action",
|
20
|
+
"prepend_before_action",
|
21
|
+
"skip_after_action",
|
22
|
+
"skip_around_action",
|
23
|
+
"skip_before_action",
|
24
|
+
].freeze,
|
25
|
+
T::Array[String],
|
26
|
+
)
|
27
|
+
|
28
|
+
ignore_classes_named(/Controller$/)
|
29
|
+
|
30
|
+
sig { override.params(indexer: Indexer, definition: Definition).void }
|
31
|
+
def on_define_method(indexer, definition)
|
32
|
+
definition.ignored! if ignored_class_name?(indexer.nesting_class_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
sig { override.params(indexer: Indexer, send: Send).void }
|
36
|
+
def on_send(indexer, send)
|
37
|
+
return unless send.recv.nil? && CALLBACKS.include?(send.name)
|
38
|
+
|
39
|
+
arg = send.args.first
|
40
|
+
case arg
|
41
|
+
when SyntaxTree::SymbolLiteral
|
42
|
+
indexer.reference_method(indexer.node_string(arg.value), send.node)
|
43
|
+
when SyntaxTree::VarRef
|
44
|
+
indexer.reference_constant(indexer.node_string(arg), send.node)
|
45
|
+
end
|
46
|
+
|
47
|
+
send.each_arg_assoc do |key, value|
|
48
|
+
key = indexer.node_string(key).delete_suffix(":")
|
49
|
+
|
50
|
+
case key
|
51
|
+
when "if", "unless"
|
52
|
+
indexer.reference_method(indexer.symbol_string(value), send.node) if value
|
53
|
+
else
|
54
|
+
indexer.reference_constant(camelize(key), send.node)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActiveJob < Base
|
8
|
+
ignore_classes_named("ApplicationJob")
|
9
|
+
ignore_methods_named("perform", "build_enumerator", "each_iteration")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActiveModel < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
ignore_classes_inheriting_from(/^(::)?ActiveModel::EachValidator$/)
|
11
|
+
ignore_methods_named("validate_each")
|
12
|
+
|
13
|
+
sig { override.params(indexer: Indexer, send: Send).void }
|
14
|
+
def on_send(indexer, send)
|
15
|
+
return if send.recv
|
16
|
+
|
17
|
+
case send.name
|
18
|
+
when "attribute", "attributes"
|
19
|
+
send.each_arg(SyntaxTree::SymbolLiteral) do |arg|
|
20
|
+
indexer.reference_method(indexer.node_string(arg.value), send.node)
|
21
|
+
end
|
22
|
+
when "validate", "validates", "validates!", "validates_each"
|
23
|
+
send.each_arg(SyntaxTree::SymbolLiteral) do |arg|
|
24
|
+
indexer.reference_method(indexer.node_string(arg.value), send.node)
|
25
|
+
end
|
26
|
+
send.each_arg_assoc do |key, value|
|
27
|
+
key = indexer.node_string(key).delete_suffix(":")
|
28
|
+
|
29
|
+
case key
|
30
|
+
when "if", "unless"
|
31
|
+
indexer.reference_method(indexer.symbol_string(value), send.node) if value
|
32
|
+
else
|
33
|
+
indexer.reference_constant(camelize(key), send.node)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
when "validates_with"
|
37
|
+
arg = send.args.first
|
38
|
+
if arg.is_a?(SyntaxTree::SymbolLiteral)
|
39
|
+
indexer.reference_constant(indexer.node_string(arg.value), send.node)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActiveRecord < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
ignore_classes_inheriting_from(/^(::)?ActiveRecord::Migration/)
|
11
|
+
|
12
|
+
ignore_methods_named(
|
13
|
+
"change",
|
14
|
+
"down",
|
15
|
+
"up",
|
16
|
+
"table_name_prefix",
|
17
|
+
"to_param",
|
18
|
+
)
|
19
|
+
|
20
|
+
CALLBACKS = T.let(
|
21
|
+
[
|
22
|
+
"after_commit",
|
23
|
+
"after_create_commit",
|
24
|
+
"after_create",
|
25
|
+
"after_destroy_commit",
|
26
|
+
"after_destroy",
|
27
|
+
"after_find",
|
28
|
+
"after_initialize",
|
29
|
+
"after_rollback",
|
30
|
+
"after_save_commit",
|
31
|
+
"after_save",
|
32
|
+
"after_touch",
|
33
|
+
"after_update_commit",
|
34
|
+
"after_update",
|
35
|
+
"after_validation",
|
36
|
+
"around_create",
|
37
|
+
"around_destroy",
|
38
|
+
"around_save",
|
39
|
+
"around_update",
|
40
|
+
"before_create",
|
41
|
+
"before_destroy",
|
42
|
+
"before_save",
|
43
|
+
"before_update",
|
44
|
+
"before_validation",
|
45
|
+
].freeze,
|
46
|
+
T::Array[String],
|
47
|
+
)
|
48
|
+
|
49
|
+
CRUD_METHODS = T.let(
|
50
|
+
[
|
51
|
+
"assign_attributes",
|
52
|
+
"create",
|
53
|
+
"create!",
|
54
|
+
"insert",
|
55
|
+
"insert!",
|
56
|
+
"new",
|
57
|
+
"update",
|
58
|
+
"update!",
|
59
|
+
"upsert",
|
60
|
+
].freeze,
|
61
|
+
T::Array[String],
|
62
|
+
)
|
63
|
+
|
64
|
+
ARRAY_METHODS = T.let(
|
65
|
+
[
|
66
|
+
"insert_all",
|
67
|
+
"insert_all!",
|
68
|
+
"upsert_all",
|
69
|
+
].freeze,
|
70
|
+
T::Array[String],
|
71
|
+
)
|
72
|
+
|
73
|
+
sig { override.params(indexer: Indexer, send: Send).void }
|
74
|
+
def on_send(indexer, send)
|
75
|
+
if send.recv.nil? && CALLBACKS.include?(send.name)
|
76
|
+
send.each_arg(SyntaxTree::SymbolLiteral) do |arg|
|
77
|
+
indexer.reference_method(indexer.node_string(arg.value), send.node)
|
78
|
+
end
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
return unless send.recv
|
83
|
+
|
84
|
+
case send.name
|
85
|
+
when *CRUD_METHODS
|
86
|
+
send.each_arg_assoc do |key, _value|
|
87
|
+
key = indexer.symbol_string(key).delete_suffix(":")
|
88
|
+
indexer.reference_method("#{key}=", send.node)
|
89
|
+
end
|
90
|
+
when *ARRAY_METHODS
|
91
|
+
send.each_arg(SyntaxTree::ArrayLiteral) do |arg|
|
92
|
+
args = arg.contents
|
93
|
+
next unless args.is_a?(SyntaxTree::Args)
|
94
|
+
|
95
|
+
args.parts.each do |part|
|
96
|
+
next unless part.is_a?(SyntaxTree::HashLiteral)
|
97
|
+
|
98
|
+
part.assocs.each do |assoc|
|
99
|
+
next unless assoc.is_a?(SyntaxTree::Assoc)
|
100
|
+
|
101
|
+
key = indexer.symbol_string(assoc.key).delete_suffix(":")
|
102
|
+
indexer.reference_method("#{key}=", send.node)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActiveSupport < Base
|
8
|
+
ignore_classes_inheriting_from(/^(::)?ActiveSupport::TestCase$/)
|
9
|
+
|
10
|
+
ignore_methods_named(
|
11
|
+
"after_all",
|
12
|
+
"after_setup",
|
13
|
+
"after_teardown",
|
14
|
+
"before_all",
|
15
|
+
"before_setup",
|
16
|
+
"before_teardown",
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|