rubocop 0.60.0 → 0.61.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/config/default.yml +573 -560
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/ast/node.rb +1 -1
  6. data/lib/rubocop/ast/sexp.rb +1 -1
  7. data/lib/rubocop/cli.rb +9 -14
  8. data/lib/rubocop/config.rb +4 -3
  9. data/lib/rubocop/config_loader.rb +25 -22
  10. data/lib/rubocop/config_loader_resolver.rb +3 -2
  11. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
  13. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
  15. data/lib/rubocop/cop/generator.rb +13 -17
  16. data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
  17. data/lib/rubocop/cop/layout/align_hash.rb +3 -0
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
  19. data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
  20. data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
  21. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
  22. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
  23. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  24. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  26. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
  27. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
  28. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
  29. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  30. data/lib/rubocop/cop/metrics/line_length.rb +2 -2
  31. data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
  32. data/lib/rubocop/cop/offense.rb +1 -1
  33. data/lib/rubocop/cop/performance/open_struct.rb +46 -0
  34. data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
  35. data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
  36. data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
  37. data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
  38. data/lib/rubocop/cop/rails/http_status.rb +4 -4
  39. data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
  40. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
  41. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
  42. data/lib/rubocop/cop/rails/validation.rb +4 -4
  43. data/lib/rubocop/cop/security/open.rb +31 -11
  44. data/lib/rubocop/cop/style/begin_block.rb +6 -0
  45. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
  47. data/lib/rubocop/cop/style/for.rb +9 -78
  48. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
  49. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  50. data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
  51. data/lib/rubocop/cop/style/lambda.rb +4 -87
  52. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
  53. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  54. data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
  55. data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
  56. data/lib/rubocop/cop/variable_force.rb +4 -2
  57. data/lib/rubocop/cop/variable_force/variable.rb +2 -0
  58. data/lib/rubocop/magic_comment.rb +1 -1
  59. data/lib/rubocop/remote_config.rb +13 -4
  60. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  61. data/lib/rubocop/runner.rb +15 -4
  62. data/lib/rubocop/version.rb +1 -1
  63. metadata +7 -2
@@ -3,11 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop checks presence of parentheses in method calls containing
7
- # parameters. By default, macro methods are ignored. Additional methods
8
- # can be added to the `IgnoredMethods` list.
6
+ # This cop enforces the presence (default) or absence of parentheses in
7
+ # method calls containing parameters.
8
+ #
9
+ # In the default style (require_parentheses), macro methods are ignored.
10
+ # Additional methods can be added to the `IgnoredMethods` list. This
11
+ # option is valid only in the default style.
12
+ #
13
+ # In the alternative style (omit_parentheses), there are two additional
14
+ # options.
15
+ #
16
+ # 1. `AllowParenthesesInChaining` is `false` by default. Setting it to
17
+ # `true` allows the presence of parentheses in the last call during
18
+ # method chaining.
19
+ #
20
+ # 2. `AllowParenthesesInMultilineCall` is `false` by default. Setting it
21
+ # to `true` allows the presence of parentheses in multi-line method
22
+ # calls.
23
+ #
24
+ # @example EnforcedStyle: require_parentheses
9
25
  #
10
- # @example
11
26
  #
12
27
  # # bad
13
28
  # array.delete e
@@ -39,21 +54,114 @@ module RuboCop
39
54
  # class Foo
40
55
  # bar :baz
41
56
  # end
57
+ #
58
+ # @example EnforcedStyle: omit_parentheses
59
+ #
60
+ # # bad
61
+ # array.delete(e)
62
+ #
63
+ # # good
64
+ # array.delete e
65
+ #
66
+ # # bad
67
+ # foo.enforce(strict: true)
68
+ #
69
+ # # good
70
+ # foo.enforce strict: true
71
+ #
72
+ # # AllowParenthesesInMultilineCall: false (default)
73
+ #
74
+ # # bad
75
+ # foo.enforce(
76
+ # strict: true
77
+ # )
78
+ #
79
+ # # good
80
+ # foo.enforce \
81
+ # strict: true
82
+ #
83
+ # # AllowParenthesesInMultilineCall: true
84
+ #
85
+ # # good
86
+ # foo.enforce(
87
+ # strict: true
88
+ # )
89
+ #
90
+ # # good
91
+ # foo.enforce \
92
+ # strict: true
93
+ #
94
+ # # AllowParenthesesInChaining: false (default)
95
+ #
96
+ # # bad
97
+ # foo().bar(1)
98
+ #
99
+ # # good
100
+ # foo().bar 1
101
+ #
102
+ # # AllowParenthesesInChaining: true
103
+ #
104
+ # # good
105
+ # foo().bar(1)
106
+ #
107
+ # # good
108
+ # foo().bar 1
42
109
  class MethodCallWithArgsParentheses < Cop
110
+ include ConfigurableEnforcedStyle
43
111
  include IgnoredMethods
44
112
 
45
- MSG = 'Use parentheses for method calls with arguments.'.freeze
113
+ TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
46
114
 
47
115
  def on_send(node)
48
- return if ignored_method?(node)
49
- return unless node.arguments? && !node.parenthesized?
50
-
51
- add_offense(node)
116
+ case style
117
+ when :require_parentheses
118
+ add_offense_for_require_parentheses(node)
119
+ when :omit_parentheses
120
+ add_offense_for_omit_parentheses(node)
121
+ end
52
122
  end
53
123
  alias on_super on_send
54
124
  alias on_yield on_send
55
125
 
56
126
  def autocorrect(node)
127
+ case style
128
+ when :require_parentheses
129
+ autocorrect_for_require_parentheses(node)
130
+ when :omit_parentheses
131
+ autocorrect_for_omit_parentheses(node)
132
+ end
133
+ end
134
+
135
+ def message(_node = nil)
136
+ case style
137
+ when :require_parentheses
138
+ 'Use parentheses for method calls with arguments.'.freeze
139
+ when :omit_parentheses
140
+ 'Omit parentheses for method calls with arguments.'.freeze
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def add_offense_for_require_parentheses(node)
147
+ return if ignored_method?(node.method_name)
148
+ return if eligible_for_parentheses_omission?(node)
149
+ return unless node.arguments? && !node.parenthesized?
150
+
151
+ add_offense(node)
152
+ end
153
+
154
+ def add_offense_for_omit_parentheses(node)
155
+ return unless node.parenthesized?
156
+ return if node.implicit_call?
157
+ return if super_call_without_arguments?(node)
158
+ return if camel_case_method_call_without_arguments?(node)
159
+ return if eligible_for_parentheses_presence?(node)
160
+
161
+ add_offense(node, location: node.loc.begin.join(node.loc.end))
162
+ end
163
+
164
+ def autocorrect_for_require_parentheses(node)
57
165
  lambda do |corrector|
58
166
  corrector.replace(args_begin(node), '(')
59
167
 
@@ -63,16 +171,23 @@ module RuboCop
63
171
  end
64
172
  end
65
173
 
66
- private
174
+ def autocorrect_for_omit_parentheses(node)
175
+ lambda do |corrector|
176
+ if parentheses_at_the_end_of_multiline_call?(node)
177
+ corrector.replace(args_begin(node), ' \\')
178
+ else
179
+ corrector.replace(args_begin(node), ' ')
180
+ end
181
+ corrector.remove(node.loc.end)
182
+ end
183
+ end
67
184
 
68
- def ignored_method?(node)
69
- node.operator_method? || node.setter_method? ||
70
- ignore_macros? && node.macro? ||
71
- super(node.method_name)
185
+ def eligible_for_parentheses_omission?(node)
186
+ node.operator_method? || node.setter_method? || ignore_macros?(node)
72
187
  end
73
188
 
74
- def ignore_macros?
75
- cop_config['IgnoreMacros']
189
+ def ignore_macros?(node)
190
+ cop_config['IgnoreMacros'] && node.macro?
76
191
  end
77
192
 
78
193
  def args_begin(node)
@@ -94,6 +209,96 @@ module RuboCop
94
209
  first_node = node.arguments.first
95
210
  first_node.begin_type? && first_node.parenthesized_call?
96
211
  end
212
+
213
+ def parentheses_at_the_end_of_multiline_call?(node)
214
+ node.multiline? &&
215
+ node.loc.begin.source_line
216
+ .gsub(TRAILING_WHITESPACE_REGEX, '')
217
+ .end_with?('(')
218
+ end
219
+
220
+ def super_call_without_arguments?(node)
221
+ node.super_type? && node.arguments.none?
222
+ end
223
+
224
+ def camel_case_method_call_without_arguments?(node)
225
+ node.camel_case_method? && node.arguments.none?
226
+ end
227
+
228
+ def eligible_for_parentheses_presence?(node)
229
+ call_in_literals?(node) ||
230
+ call_with_ambiguous_arguments?(node) ||
231
+ call_in_logical_operators?(node) ||
232
+ allowed_multiline_call_with_parentheses?(node) ||
233
+ allowed_chained_call_with_parentheses?(node)
234
+ end
235
+
236
+ def call_in_literals?(node)
237
+ node.parent &&
238
+ (node.parent.pair_type? ||
239
+ node.parent.array_type? ||
240
+ ternary_if?(node.parent))
241
+ end
242
+
243
+ def call_in_logical_operators?(node)
244
+ node.parent &&
245
+ (logical_operator?(node.parent) ||
246
+ node.parent.descendants.any?(&method(:logical_operator?)))
247
+ end
248
+
249
+ def call_with_ambiguous_arguments?(node)
250
+ call_with_braced_block?(node) ||
251
+ call_as_argument?(node) ||
252
+ hash_literal_in_arguments?(node) ||
253
+ node.descendants.any? do |n|
254
+ splat?(n) || ternary_if?(n) || logical_operator?(n)
255
+ end
256
+ end
257
+
258
+ def call_with_braced_block?(node)
259
+ node.block_node && node.block_node.braces?
260
+ end
261
+
262
+ def call_as_argument?(node)
263
+ node.parent && node.parent.send_type?
264
+ end
265
+
266
+ def hash_literal_in_arguments?(node)
267
+ node.arguments.any? do |n|
268
+ hash_literal?(n) ||
269
+ n.send_type? && node.descendants.any?(&method(:hash_literal?))
270
+ end
271
+ end
272
+
273
+ def allowed_multiline_call_with_parentheses?(node)
274
+ cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
275
+ end
276
+
277
+ def allowed_chained_call_with_parentheses?(node)
278
+ return unless cop_config['AllowParenthesesInChaining']
279
+
280
+ previous = node.descendants.first
281
+ return false unless previous && previous.send_type?
282
+
283
+ previous.parenthesized? ||
284
+ allowed_chained_call_with_parentheses?(previous)
285
+ end
286
+
287
+ def splat?(node)
288
+ node.splat_type? || node.kwsplat_type? || node.block_pass_type?
289
+ end
290
+
291
+ def ternary_if?(node)
292
+ node.if_type? && node.ternary?
293
+ end
294
+
295
+ def logical_operator?(node)
296
+ (node.and_type? || node.or_type?) && node.logical_operator?
297
+ end
298
+
299
+ def hash_literal?(node)
300
+ node.hash_type? && node.braces?
301
+ end
97
302
  end
98
303
  end
99
304
  end
@@ -68,7 +68,7 @@ module RuboCop
68
68
 
69
69
  message = message_node && message_node.source
70
70
 
71
- correction = exception_node.const_name.to_s
71
+ correction = exception_node.source
72
72
  correction = "#{correction}, #{message}" if message
73
73
 
74
74
  "#{node.method_name} #{correction}"
@@ -83,6 +83,7 @@ module RuboCop
83
83
  # x =~ /home\//
84
84
  class RegexpLiteral < Cop
85
85
  include ConfigurableEnforcedStyle
86
+ include RangeHelp
86
87
 
87
88
  MSG_USE_SLASHES = 'Use `//` around regular expression.'.freeze
88
89
  MSG_USE_PERCENT_R = 'Use `%r` around regular expression.'.freeze
@@ -96,17 +97,9 @@ module RuboCop
96
97
  end
97
98
 
98
99
  def autocorrect(node)
99
- return if contains_slash?(node)
100
-
101
- replacement = if slash_literal?(node)
102
- ['%r', ''].zip(preferred_delimiters).map(&:join)
103
- else
104
- %w[/ /]
105
- end
106
-
107
100
  lambda do |corrector|
108
- corrector.replace(node.loc.begin, replacement.first)
109
- corrector.replace(node.loc.end, replacement.last)
101
+ correct_delimiters(node, corrector)
102
+ correct_inner_slashes(node, corrector)
110
103
  end
111
104
  end
112
105
 
@@ -169,6 +162,65 @@ module RuboCop
169
162
  config.for_cop('Style/PercentLiteralDelimiters') \
170
163
  ['PreferredDelimiters']['%r'].split(//)
171
164
  end
165
+
166
+ def correct_delimiters(node, corrector)
167
+ replacement = calculate_replacement(node)
168
+ corrector.replace(node.loc.begin, replacement.first)
169
+ corrector.replace(node.loc.end, replacement.last)
170
+ end
171
+
172
+ def correct_inner_slashes(node, corrector)
173
+ regexp_begin = node.loc.begin.end_pos
174
+
175
+ inner_slash_indices(node).each do |index|
176
+ start = regexp_begin + index
177
+
178
+ corrector.replace(
179
+ range_between(
180
+ start,
181
+ start + inner_slash_before_correction(node).length
182
+ ),
183
+ inner_slash_after_correction(node)
184
+ )
185
+ end
186
+ end
187
+
188
+ def inner_slash_indices(node)
189
+ text = node_body(node)
190
+ pattern = inner_slash_before_correction(node)
191
+ index = -1
192
+ indices = []
193
+
194
+ while (index = text.index(pattern, index + 1))
195
+ indices << index
196
+ end
197
+
198
+ indices
199
+ end
200
+
201
+ def inner_slash_before_correction(node)
202
+ inner_slash_for(node.loc.begin.source)
203
+ end
204
+
205
+ def inner_slash_after_correction(node)
206
+ inner_slash_for(calculate_replacement(node).first)
207
+ end
208
+
209
+ def inner_slash_for(opening_delimiter)
210
+ if ['/', '%r/'].include?(opening_delimiter)
211
+ '\/'
212
+ else
213
+ '/'
214
+ end
215
+ end
216
+
217
+ def calculate_replacement(node)
218
+ if slash_literal?(node)
219
+ ['%r', ''].zip(preferred_delimiters).map(&:join)
220
+ else
221
+ %w[/ /]
222
+ end
223
+ end
172
224
  end
173
225
  end
174
226
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  lambda do |corrector|
48
48
  if node.ternary?
49
49
  corrector.replace(range_of_offense(node), '||')
50
- elsif node.modifier_form?
50
+ elsif node.modifier_form? || !node.else_branch
51
51
  corrector.replace(node.source_range, node.if_branch.source)
52
52
  else
53
53
  corrected = make_ternary_form(node)
@@ -60,7 +60,7 @@ module RuboCop
60
60
  private
61
61
 
62
62
  def message(node)
63
- if node.modifier_form?
63
+ if node.modifier_form? || !node.else_branch
64
64
  UNNEEDED_CONDITION
65
65
  else
66
66
  MSG
@@ -50,8 +50,8 @@ module RuboCop
50
50
 
51
51
  ZERO_ARITY_SUPER_TYPE = :zsuper
52
52
 
53
- TWISTED_SCOPE_TYPES = %i[block class sclass defs].freeze
54
- SCOPE_TYPES = (TWISTED_SCOPE_TYPES + %i[module def]).freeze
53
+ TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
54
+ SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
55
55
 
56
56
  SEND_TYPE = :send
57
57
 
@@ -196,6 +196,7 @@ module RuboCop
196
196
  regexp.named_captures.keys
197
197
  end
198
198
 
199
+ # rubocop:disable Metrics/AbcSize
199
200
  def process_variable_operator_assignment(node)
200
201
  if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
201
202
  asgn_node, rhs_node = *node
@@ -232,6 +233,7 @@ module RuboCop
232
233
 
233
234
  skip_children!
234
235
  end
236
+ # rubocop:enable Metrics/AbcSize
235
237
 
236
238
  def process_variable_multiple_assignment(node)
237
239
  lhs_node, rhs_node = *node
@@ -37,6 +37,7 @@ module RuboCop
37
37
  !@references.empty?
38
38
  end
39
39
 
40
+ # rubocop:disable Metrics/AbcSize
40
41
  def reference!(node)
41
42
  reference = Reference.new(node, @scope)
42
43
  @references << reference
@@ -56,6 +57,7 @@ module RuboCop
56
57
  end
57
58
  end
58
59
  end
60
+ # rubocop:enable Metrics/AbcSize
59
61
 
60
62
  def capture_with_block!
61
63
  @captured_by_block = true
@@ -134,7 +134,7 @@ module RuboCop
134
134
  OPERATOR = ':'.freeze
135
135
 
136
136
  def encoding
137
- match('encoding')
137
+ match('(?:en)?coding')
138
138
  end
139
139
 
140
140
  private