/
unused_block_argument.rb
172 lines (146 loc) · 4.58 KB
/
unused_block_argument.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
module RuboCop
module Cop
module Lint
# This cop checks for unused block arguments.
#
# @example
# # bad
# do_something do |used, unused|
# puts used
# end
#
# do_something do |bar|
# puts :foo
# end
#
# define_method(:foo) do |bar|
# puts :baz
# end
#
# # good
# do_something do |used, _unused|
# puts used
# end
#
# do_something do
# puts :foo
# end
#
# define_method(:foo) do |_bar|
# puts :baz
# end
#
# @example IgnoreEmptyBlocks: true (default)
# # good
# do_something { |unused| }
#
# @example IgnoreEmptyBlocks: false
# # bad
# do_something { |unused| }
#
# @example AllowUnusedKeywordArguments: false (default)
# # bad
# do_something do |unused: 42|
# foo
# end
#
# @example AllowUnusedKeywordArguments: true
# # good
# do_something do |unused: 42|
# foo
# end
#
class UnusedBlockArgument < Base
include UnusedArgument
extend AutoCorrector
def self.joining_forces
VariableForce
end
private
def autocorrect(corrector, node)
UnusedArgCorrector.correct(corrector, processed_source, node)
end
def check_argument(variable)
return if allowed_block?(variable) ||
allowed_keyword_argument?(variable) ||
used_block_local?(variable)
super
end
def used_block_local?(variable)
variable.explicit_block_local_variable? && !variable.assignments.empty?
end
def allowed_block?(variable)
!variable.block_argument? || (ignore_empty_blocks? && empty_block?(variable))
end
def allowed_keyword_argument?(variable)
variable.keyword_argument? && allow_unused_keyword_arguments?
end
def message(variable)
message = "Unused #{variable_type(variable)} - `#{variable.name}`."
if variable.explicit_block_local_variable?
message
else
augment_message(message, variable)
end
end
def augment_message(message, variable)
scope = variable.scope
all_arguments = scope.variables.each_value.select(&:block_argument?)
augmentation = if scope.node.lambda?
message_for_lambda(variable, all_arguments)
else
message_for_normal_block(variable, all_arguments)
end
[message, augmentation].join(' ')
end
def variable_type(variable)
if variable.explicit_block_local_variable?
'block local variable'
else
'block argument'
end
end
def message_for_normal_block(variable, all_arguments)
if all_arguments.none?(&:referenced?) && !define_method_call?(variable)
if all_arguments.count > 1
"You can omit all the arguments if you don't care about them."
else
"You can omit the argument if you don't care about it."
end
else
message_for_underscore_prefix(variable)
end
end
def message_for_lambda(variable, all_arguments)
message = message_for_underscore_prefix(variable)
if all_arguments.none?(&:referenced?)
proc_message = 'Also consider using a proc without arguments ' \
'instead of a lambda if you want it ' \
"to accept any arguments but don't care about them."
end
[message, proc_message].compact.join(' ')
end
def message_for_underscore_prefix(variable)
"If it's necessary, use `_` or `_#{variable.name}` " \
"as an argument name to indicate that it won't be used."
end
def define_method_call?(variable)
call, = *variable.scope.node
_, method, = *call
method == :define_method
end
def empty_block?(variable)
_send, _args, body = *variable.scope.node
body.nil?
end
def allow_unused_keyword_arguments?
cop_config['AllowUnusedKeywordArguments']
end
def ignore_empty_blocks?
cop_config['IgnoreEmptyBlocks']
end
end
end
end
end