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