rubocop 0.37.2 → 0.38.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/assets/output.html.erb +3 -0
- data/config/default.yml +14 -1
- data/config/disabled.yml +0 -4
- data/lib/rubocop.rb +0 -1
- data/lib/rubocop/ast_node.rb +6 -0
- data/lib/rubocop/ast_node/traversal.rb +1 -1
- data/lib/rubocop/cached_data.rb +6 -2
- data/lib/rubocop/config_loader.rb +7 -3
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/lint/block_alignment.rb +91 -17
- data/lib/rubocop/cop/lint/else_layout.rb +24 -14
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +6 -12
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +16 -10
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/unneeded_disable.rb +36 -23
- data/lib/rubocop/cop/lint/unused_block_argument.rb +0 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
- data/lib/rubocop/cop/metrics/line_length.rb +25 -18
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/if_node.rb +0 -4
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +6 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +26 -24
- data/lib/rubocop/cop/mixin/unused_argument.rb +9 -1
- data/lib/rubocop/cop/offense.rb +16 -0
- data/lib/rubocop/cop/performance/casecmp.rb +15 -10
- data/lib/rubocop/cop/performance/count.rb +3 -2
- data/lib/rubocop/cop/performance/fixed_size.rb +13 -12
- data/lib/rubocop/cop/performance/reverse_each.rb +15 -14
- data/lib/rubocop/cop/rails/date.rb +13 -1
- data/lib/rubocop/cop/rails/output.rb +2 -1
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -1
- data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +41 -48
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +3 -3
- data/lib/rubocop/cop/style/comment_annotation.rb +8 -10
- data/lib/rubocop/cop/style/conditional_assignment.rb +7 -2
- data/lib/rubocop/cop/style/encoding.rb +15 -10
- data/lib/rubocop/cop/style/extra_spacing.rb +14 -12
- data/lib/rubocop/cop/style/file_name.rb +3 -7
- data/lib/rubocop/cop/style/lambda.rb +17 -6
- data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
- data/lib/rubocop/cop/style/nested_modifier.rb +7 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +0 -4
- data/lib/rubocop/cop/style/not.rb +27 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +21 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -1
- data/lib/rubocop/cop/style/signal_exception.rb +28 -26
- data/lib/rubocop/cop/style/space_around_keyword.rb +10 -6
- data/lib/rubocop/cop/style/string_literals.rb +1 -0
- data/lib/rubocop/cop/style/unless_else.rb +24 -0
- data/lib/rubocop/cop/style/unneeded_interpolation.rb +26 -13
- data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -3
- data/lib/rubocop/cop/team.rb +6 -1
- data/lib/rubocop/cop/util.rb +13 -6
- data/lib/rubocop/formatter/clang_style_formatter.rb +18 -14
- data/lib/rubocop/formatter/html_formatter.rb +9 -10
- data/lib/rubocop/rake_task.rb +4 -4
- data/lib/rubocop/remote_config.rb +4 -2
- data/lib/rubocop/result_cache.rb +14 -8
- data/lib/rubocop/runner.rb +9 -0
- data/lib/rubocop/version.rb +1 -1
- data/spec/support/cop_helper.rb +81 -0
- metadata +13 -7
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +0 -57
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
# Rails time zone. You must use Time.zone.today instead.
|
12
12
|
#
|
13
13
|
# The cop also reports warnings when you are using 'to_time' method,
|
14
|
-
# because it doesn't know about Rails time zone
|
14
|
+
# because it doesn't know about Rails time zone either.
|
15
15
|
#
|
16
16
|
# Two styles are supported for this cop. When EnforcedStyle is 'strict'
|
17
17
|
# then the Date methods (today, current, yesterday, tomorrow)
|
@@ -57,6 +57,10 @@ module RuboCop
|
|
57
57
|
def on_send(node)
|
58
58
|
receiver, method_name, *args = *node
|
59
59
|
return unless receiver && bad_methods.include?(method_name)
|
60
|
+
|
61
|
+
chain = extract_method_chain(node)
|
62
|
+
return if safe_chain?(chain)
|
63
|
+
|
60
64
|
return if method_name == :to_time && args.length == 1
|
61
65
|
|
62
66
|
add_offense(node, :selector,
|
@@ -105,6 +109,10 @@ module RuboCop
|
|
105
109
|
receiver == node
|
106
110
|
end
|
107
111
|
|
112
|
+
def safe_chain?(chain)
|
113
|
+
(chain & bad_methods).empty? || !(chain & good_methods).empty?
|
114
|
+
end
|
115
|
+
|
108
116
|
def good_days
|
109
117
|
style == :strict ? [] : [:current, :yesterday, :tomorrow]
|
110
118
|
end
|
@@ -116,6 +124,10 @@ module RuboCop
|
|
116
124
|
def bad_methods
|
117
125
|
style == :strict ? [:to_time, :to_time_in_current_zone] : [:to_time]
|
118
126
|
end
|
127
|
+
|
128
|
+
def good_methods
|
129
|
+
style == :strict ? [] : TimeZone::ACCEPTED_METHODS
|
130
|
+
end
|
119
131
|
end
|
120
132
|
end
|
121
133
|
end
|
@@ -6,7 +6,6 @@ module RuboCop
|
|
6
6
|
module Style
|
7
7
|
# This cop checks for uses of *and* and *or*.
|
8
8
|
class AndOr < Cop
|
9
|
-
include AutocorrectUnlessChangingAST
|
10
9
|
include ConfigurableEnforcedStyle
|
11
10
|
|
12
11
|
MSG = 'Use `%s` instead of `%s`.'.freeze
|
@@ -59,7 +58,7 @@ module RuboCop
|
|
59
58
|
add_offense(node, :operator, format(MSG, OPS[op], op))
|
60
59
|
end
|
61
60
|
|
62
|
-
def
|
61
|
+
def autocorrect(node)
|
63
62
|
expr1, expr2 = *node
|
64
63
|
replacement = (node.type == :and ? '&&' : '||')
|
65
64
|
lambda do |corrector|
|
@@ -8,24 +8,24 @@ module RuboCop
|
|
8
8
|
# multi-line blocks.
|
9
9
|
class BlockDelimiters < Cop
|
10
10
|
include ConfigurableEnforcedStyle
|
11
|
-
|
11
|
+
|
12
|
+
def_node_matcher :block_method_name, '(block (send _ $_ ...) ...)'
|
12
13
|
|
13
14
|
def on_send(node)
|
14
15
|
_receiver, method_name, *args = *node
|
15
|
-
return
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
return if args.empty?
|
17
|
+
return if parentheses?(node) || operator?(method_name)
|
18
|
+
|
19
|
+
get_blocks(args.last) do |block|
|
20
|
+
# If there are no parentheses around the arguments, then braces and
|
21
|
+
# do-end have different meaning due to how they bind, so we allow
|
22
|
+
# either.
|
23
|
+
ignore_node(block)
|
24
|
+
end
|
24
25
|
end
|
25
26
|
|
26
27
|
def on_block(node)
|
27
28
|
return if ignored_node?(node)
|
28
|
-
|
29
29
|
return if proper_block_style?(node)
|
30
30
|
|
31
31
|
add_offense(node, :begin)
|
@@ -34,9 +34,7 @@ module RuboCop
|
|
34
34
|
private
|
35
35
|
|
36
36
|
def line_count_based_message(node)
|
37
|
-
|
38
|
-
|
39
|
-
if block_length > 0
|
37
|
+
if block_length(node) > 0
|
40
38
|
'Avoid using `{...}` for multi-line blocks.'
|
41
39
|
else
|
42
40
|
'Prefer `{...}` over `do...end` for single-line blocks.'
|
@@ -54,9 +52,7 @@ module RuboCop
|
|
54
52
|
end
|
55
53
|
|
56
54
|
def braces_for_chaining_message(node)
|
57
|
-
|
58
|
-
|
59
|
-
if block_length > 0
|
55
|
+
if block_length(node) > 0
|
60
56
|
if return_value_chaining?(node)
|
61
57
|
'Prefer `{...}` over `do...end` for multi-line chained blocks.'
|
62
58
|
else
|
@@ -78,7 +74,9 @@ module RuboCop
|
|
78
74
|
end
|
79
75
|
end
|
80
76
|
|
81
|
-
def
|
77
|
+
def autocorrect(node)
|
78
|
+
return if correction_would_break_code?(node)
|
79
|
+
|
82
80
|
lambda do |corrector|
|
83
81
|
b = node.loc.begin
|
84
82
|
e = node.loc.end
|
@@ -98,14 +96,23 @@ module RuboCop
|
|
98
96
|
node.source_buffer.source[node.begin_pos - 1, 1] =~ /\s/
|
99
97
|
end
|
100
98
|
|
101
|
-
def
|
99
|
+
def get_blocks(node, &block)
|
102
100
|
case node.type
|
103
101
|
when :block
|
104
|
-
node
|
102
|
+
yield node
|
105
103
|
when :send
|
106
104
|
receiver, _method_name, *_args = *node
|
107
|
-
|
105
|
+
get_blocks(receiver, &block) if receiver
|
106
|
+
when :hash
|
107
|
+
# A hash which is passed as method argument may have no braces
|
108
|
+
# In that case, one of the K/V pairs could contain a block node
|
109
|
+
# which could change in meaning if do...end replaced {...}
|
110
|
+
return if node.loc.begin
|
111
|
+
node.children.each { |child| get_blocks(child, &block) }
|
112
|
+
when :pair
|
113
|
+
node.children.each { |child| get_blocks(child, &block) }
|
108
114
|
end
|
115
|
+
nil
|
109
116
|
end
|
110
117
|
|
111
118
|
def proper_block_style?(node)
|
@@ -120,18 +127,13 @@ module RuboCop
|
|
120
127
|
end
|
121
128
|
|
122
129
|
def line_count_based_block_style?(node)
|
123
|
-
block_length = block_length(node)
|
124
130
|
block_begin = node.loc.begin.source
|
125
131
|
|
126
|
-
|
127
|
-
block_begin != '{'
|
128
|
-
else
|
129
|
-
block_begin == '{'
|
130
|
-
end
|
132
|
+
(block_length(node) > 0) ^ (block_begin == '{')
|
131
133
|
end
|
132
134
|
|
133
135
|
def semantic_block_style?(node)
|
134
|
-
method_name =
|
136
|
+
method_name = block_method_name(node)
|
135
137
|
return true if ignored_method?(method_name)
|
136
138
|
|
137
139
|
block_begin = node.loc.begin.source
|
@@ -158,19 +160,22 @@ module RuboCop
|
|
158
160
|
node.parent && node.parent.send_type? && node.parent.loc.dot
|
159
161
|
end
|
160
162
|
|
161
|
-
def
|
162
|
-
node
|
163
|
-
|
164
|
-
|
165
|
-
|
163
|
+
def correction_would_break_code?(node)
|
164
|
+
if node.loc.begin.is?('do')
|
165
|
+
# Converting `obj.method arg do |x| end` to use `{}` would cause
|
166
|
+
# a syntax error.
|
167
|
+
send = node.children.first
|
168
|
+
_receiver, _method_name, *args = *send
|
169
|
+
!args.empty? && !parentheses?(send)
|
170
|
+
end
|
166
171
|
end
|
167
172
|
|
168
173
|
def ignored_method?(method_name)
|
169
|
-
|
174
|
+
cop_config['IgnoredMethods'].map(&:to_sym).include?(method_name)
|
170
175
|
end
|
171
176
|
|
172
177
|
def functional_method?(method_name)
|
173
|
-
|
178
|
+
cop_config['FunctionalMethods'].map(&:to_sym).include?(method_name)
|
174
179
|
end
|
175
180
|
|
176
181
|
def functional_block?(node)
|
@@ -178,7 +183,7 @@ module RuboCop
|
|
178
183
|
end
|
179
184
|
|
180
185
|
def procedural_method?(method_name)
|
181
|
-
|
186
|
+
cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name)
|
182
187
|
end
|
183
188
|
|
184
189
|
def return_value_used?(node)
|
@@ -200,18 +205,6 @@ module RuboCop
|
|
200
205
|
node.parent.children.last == node
|
201
206
|
end
|
202
207
|
|
203
|
-
def procedural_methods
|
204
|
-
cop_config['ProceduralMethods'].map(&:to_sym)
|
205
|
-
end
|
206
|
-
|
207
|
-
def functional_methods
|
208
|
-
cop_config['FunctionalMethods'].map(&:to_sym)
|
209
|
-
end
|
210
|
-
|
211
|
-
def ignored_methods
|
212
|
-
cop_config['IgnoredMethods'].map(&:to_sym)
|
213
|
-
end
|
214
|
-
|
215
208
|
def conditional?(node)
|
216
209
|
node.if_type? || node.or_type? || node.and_type?
|
217
210
|
end
|
@@ -8,7 +8,6 @@ module RuboCop
|
|
8
8
|
# if the last parameter is a hash.
|
9
9
|
class BracesAroundHashParameters < Cop
|
10
10
|
include ConfigurableEnforcedStyle
|
11
|
-
include AutocorrectUnlessChangingAST
|
12
11
|
|
13
12
|
MSG = '%s curly braces around a hash parameter.'.freeze
|
14
13
|
|
@@ -55,7 +54,7 @@ module RuboCop
|
|
55
54
|
# node, because that context is needed. When parsing the code to see if
|
56
55
|
# the AST has changed, a braceless hash would not be parsed as a hash
|
57
56
|
# otherwise.
|
58
|
-
def
|
57
|
+
def autocorrect(send_node)
|
59
58
|
_receiver, _method_name, *args = *send_node
|
60
59
|
node = args.last
|
61
60
|
lambda do |corrector|
|
@@ -71,6 +70,9 @@ module RuboCop
|
|
71
70
|
comments = processed_source.comments
|
72
71
|
right_brace_and_space = range_with_surrounding_space(node.loc.end,
|
73
72
|
:left)
|
73
|
+
right_brace_and_space =
|
74
|
+
range_with_surrounding_comma(right_brace_and_space, :left)
|
75
|
+
|
74
76
|
if comments.any? { |c| c.loc.line == right_brace_and_space.line }
|
75
77
|
# Removing a line break between a comment and the closing
|
76
78
|
# parenthesis would cause a syntax error, so we only remove the
|
@@ -17,18 +17,18 @@ module RuboCop
|
|
17
17
|
# class Foo::Bar
|
18
18
|
# end
|
19
19
|
#
|
20
|
-
# The compact style is only forced
|
20
|
+
# The compact style is only forced for classes/modules with one child.
|
21
21
|
class ClassAndModuleChildren < Cop
|
22
22
|
include ConfigurableEnforcedStyle
|
23
23
|
|
24
24
|
NESTED_MSG = 'Use nested module/class definitions instead of ' \
|
25
25
|
'compact style.'.freeze
|
26
|
-
|
27
26
|
COMPACT_MSG = 'Use compact module/class definition instead of ' \
|
28
27
|
'nested style.'.freeze
|
29
28
|
|
30
29
|
def on_class(node)
|
31
|
-
_name,
|
30
|
+
_name, superclass, body = *node
|
31
|
+
return if superclass
|
32
32
|
check_style(node, body)
|
33
33
|
end
|
34
34
|
|
@@ -23,17 +23,9 @@ module RuboCop
|
|
23
23
|
next unless annotation?(comment) &&
|
24
24
|
!correct_annotation?(first_word, colon, space, note)
|
25
25
|
|
26
|
-
start = comment.loc.expression.begin_pos + margin.length
|
27
26
|
length = first_word.length + colon.to_s.length + space.to_s.length
|
28
|
-
|
29
|
-
|
30
|
-
start,
|
31
|
-
start + length)
|
32
|
-
if note
|
33
|
-
add_offense(comment, range, format(MSG, first_word))
|
34
|
-
else
|
35
|
-
add_offense(comment, range, format(MISSING_NOTE, first_word))
|
36
|
-
end
|
27
|
+
add_offense(comment, annotation_range(comment, margin, length),
|
28
|
+
format(note ? MSG : MISSING_NOTE, first_word))
|
37
29
|
end
|
38
30
|
end
|
39
31
|
|
@@ -43,6 +35,12 @@ module RuboCop
|
|
43
35
|
ix == 0 || comments[ix - 1].loc.line < comments[ix].loc.line - 1
|
44
36
|
end
|
45
37
|
|
38
|
+
def annotation_range(comment, margin, length)
|
39
|
+
start = comment.loc.expression.begin_pos + margin.length
|
40
|
+
source_buffer = comment.loc.expression.source_buffer
|
41
|
+
Parser::Source::Range.new(source_buffer, start, start + length)
|
42
|
+
end
|
43
|
+
|
46
44
|
def autocorrect(comment)
|
47
45
|
margin, first_word, colon, space, note = split_comment(comment)
|
48
46
|
start = comment.loc.expression.begin_pos + margin.length
|
@@ -252,16 +252,21 @@ module RuboCop
|
|
252
252
|
def correction_exceeds_line_limit?(node, branches)
|
253
253
|
return false unless config.for_cop(LINE_LENGTH)[ENABLED]
|
254
254
|
assignment = lhs(tail(branches[0]))
|
255
|
-
assignment_regex = /#{assignment.gsub(' ', '\s*')}/
|
256
255
|
max_line_length = config.for_cop(LINE_LENGTH)[MAX]
|
257
256
|
indentation_width = config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2
|
258
257
|
return true if longest_rhs(branches) + indentation_width +
|
259
258
|
assignment.length > max_line_length
|
259
|
+
|
260
|
+
longest_line(node, assignment).length > max_line_length
|
261
|
+
end
|
262
|
+
|
263
|
+
def longest_line(node, assignment)
|
264
|
+
assignment_regex = /#{Regexp.escape(assignment).gsub(' ', '\s*')}/
|
260
265
|
lines = node.source.lines.map do |line|
|
261
266
|
line.chomp.sub(assignment_regex, '')
|
262
267
|
end
|
263
268
|
longest_line = lines.max_by(&:length)
|
264
|
-
|
269
|
+
longest_line + assignment
|
265
270
|
end
|
266
271
|
|
267
272
|
def longest_rhs(branches)
|
@@ -25,22 +25,27 @@ module RuboCop
|
|
25
25
|
return if processed_source.buffer.source.empty?
|
26
26
|
|
27
27
|
line_number = encoding_line_number(processed_source)
|
28
|
-
message = offense(processed_source, line_number)
|
28
|
+
return unless (@message = offense(processed_source, line_number))
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
range = source_range(processed_source.buffer, line_number + 1, 0)
|
33
|
-
add_offense(range, range, message)
|
30
|
+
range = processed_source.buffer.line_range(line_number + 1)
|
31
|
+
add_offense(range, range, @message)
|
34
32
|
end
|
35
33
|
|
36
34
|
def autocorrect(range)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
corrector
|
35
|
+
if @message == MSG_MISSING
|
36
|
+
encoding = cop_config[AUTO_CORRECT_ENCODING_COMMENT]
|
37
|
+
if encoding && encoding =~ ENCODING_PATTERN
|
38
|
+
lambda do |corrector|
|
39
|
+
corrector.insert_before(range, "#{encoding}\n")
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise "#{encoding} does not match #{ENCODING_PATTERN}"
|
41
43
|
end
|
42
44
|
else
|
43
|
-
|
45
|
+
# Need to remove unnecessary encoding comment
|
46
|
+
lambda do |corrector|
|
47
|
+
corrector.remove(range_with_surrounding_space(range, :right))
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
@@ -27,8 +27,6 @@ module RuboCop
|
|
27
27
|
MSG_UNALIGNED_ASGN = '`=` is not aligned with the %s assignment.'.freeze
|
28
28
|
|
29
29
|
def investigate(processed_source)
|
30
|
-
ast = processed_source.ast
|
31
|
-
|
32
30
|
if force_equal_sign_alignment?
|
33
31
|
@asgn_tokens = processed_source.tokens.select { |t| equal_sign?(t) }
|
34
32
|
# Only attempt to align the first = on each line
|
@@ -39,16 +37,7 @@ module RuboCop
|
|
39
37
|
end
|
40
38
|
|
41
39
|
processed_source.tokens.each_cons(2) do |t1, t2|
|
42
|
-
|
43
|
-
|
44
|
-
if force_equal_sign_alignment? &&
|
45
|
-
@asgn_tokens.include?(t2) &&
|
46
|
-
(@asgn_lines.include?(t2.pos.line - 1) ||
|
47
|
-
@asgn_lines.include?(t2.pos.line + 1))
|
48
|
-
check_assignment(t2)
|
49
|
-
else
|
50
|
-
check_other(t1, t2, ast)
|
51
|
-
end
|
40
|
+
check_tokens(processed_source.ast, t1, t2)
|
52
41
|
end
|
53
42
|
end
|
54
43
|
|
@@ -64,6 +53,19 @@ module RuboCop
|
|
64
53
|
|
65
54
|
private
|
66
55
|
|
56
|
+
def check_tokens(ast, t1, t2)
|
57
|
+
return if t2.type == :tNL
|
58
|
+
|
59
|
+
if force_equal_sign_alignment? &&
|
60
|
+
@asgn_tokens.include?(t2) &&
|
61
|
+
(@asgn_lines.include?(t2.pos.line - 1) ||
|
62
|
+
@asgn_lines.include?(t2.pos.line + 1))
|
63
|
+
check_assignment(t2)
|
64
|
+
else
|
65
|
+
check_other(t1, t2, ast)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
67
69
|
def check_assignment(token)
|
68
70
|
# minus 2 is because pos.line is zero-based
|
69
71
|
line = processed_source.lines[token.pos.line - 2]
|