rubocop 0.42.0 → 0.43.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.

Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/assets/output.html.erb +21 -10
  4. data/config/default.yml +32 -2
  5. data/config/disabled.yml +8 -1
  6. data/config/enabled.yml +40 -12
  7. data/lib/rubocop.rb +14 -2
  8. data/lib/rubocop/ast_node.rb +2 -0
  9. data/lib/rubocop/cached_data.rb +13 -11
  10. data/lib/rubocop/cli.rb +5 -5
  11. data/lib/rubocop/config.rb +68 -24
  12. data/lib/rubocop/config_loader.rb +13 -11
  13. data/lib/rubocop/config_loader_resolver.rb +4 -2
  14. data/lib/rubocop/cop/cop.rb +16 -5
  15. data/lib/rubocop/cop/lint/assignment_in_condition.rb +21 -20
  16. data/lib/rubocop/cop/lint/block_alignment.rb +3 -4
  17. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -3
  18. data/lib/rubocop/cop/lint/duplicate_methods.rb +16 -6
  19. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  20. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  21. data/lib/rubocop/cop/lint/end_alignment.rb +4 -6
  22. data/lib/rubocop/cop/lint/eval.rb +1 -1
  23. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  24. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
  25. data/lib/rubocop/cop/lint/inherit_exception.rb +22 -7
  26. data/lib/rubocop/cop/lint/literal_in_condition.rb +5 -5
  27. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -5
  28. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  29. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +9 -8
  30. data/lib/rubocop/cop/lint/percent_string_array.rb +17 -6
  31. data/lib/rubocop/cop/lint/percent_symbol_array.rb +4 -4
  32. data/lib/rubocop/cop/lint/rand_one.rb +3 -3
  33. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -3
  34. data/lib/rubocop/cop/lint/shadowed_exception.rb +39 -44
  35. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +2 -2
  36. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +1 -2
  37. data/lib/rubocop/cop/lint/unified_integer.rb +38 -0
  38. data/lib/rubocop/cop/lint/unneeded_disable.rb +51 -38
  39. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +114 -0
  40. data/lib/rubocop/cop/lint/useless_assignment.rb +25 -12
  41. data/lib/rubocop/cop/lint/useless_setter_call.rb +27 -28
  42. data/lib/rubocop/cop/lint/void.rb +2 -4
  43. data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -5
  44. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +19 -17
  45. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +3 -5
  46. data/lib/rubocop/cop/mixin/configurable_naming.rb +4 -5
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +52 -0
  48. data/lib/rubocop/cop/mixin/def_node.rb +28 -0
  49. data/lib/rubocop/cop/mixin/documentation_comment.rb +41 -0
  50. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +18 -13
  51. data/lib/rubocop/cop/mixin/if_node.rb +6 -0
  52. data/lib/rubocop/cop/mixin/match_range.rb +2 -5
  53. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  54. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +40 -28
  55. data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -6
  56. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -5
  57. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +14 -4
  58. data/lib/rubocop/cop/mixin/safe_mode.rb +23 -0
  59. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -4
  60. data/lib/rubocop/cop/mixin/space_inside.rb +1 -3
  61. data/lib/rubocop/cop/mixin/statement_modifier.rb +30 -20
  62. data/lib/rubocop/cop/mixin/trailing_comma.rb +19 -17
  63. data/lib/rubocop/cop/performance/case_when_splat.rb +16 -41
  64. data/lib/rubocop/cop/performance/casecmp.rb +28 -16
  65. data/lib/rubocop/cop/performance/count.rb +58 -34
  66. data/lib/rubocop/cop/performance/detect.rb +3 -7
  67. data/lib/rubocop/cop/performance/double_start_end_with.rb +17 -13
  68. data/lib/rubocop/cop/performance/fixed_size.rb +19 -14
  69. data/lib/rubocop/cop/performance/flat_map.rb +16 -9
  70. data/lib/rubocop/cop/performance/hash_each.rb +2 -3
  71. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +4 -6
  72. data/lib/rubocop/cop/performance/redundant_match.rb +4 -1
  73. data/lib/rubocop/cop/performance/redundant_merge.rb +63 -32
  74. data/lib/rubocop/cop/performance/redundant_sort_by.rb +8 -7
  75. data/lib/rubocop/cop/performance/reverse_each.rb +1 -4
  76. data/lib/rubocop/cop/performance/size.rb +21 -8
  77. data/lib/rubocop/cop/performance/sort_with_block.rb +54 -0
  78. data/lib/rubocop/cop/performance/string_replacement.rb +3 -7
  79. data/lib/rubocop/cop/rails/delegate.rb +2 -3
  80. data/lib/rubocop/cop/rails/find_by.rb +4 -8
  81. data/lib/rubocop/cop/rails/not_null_column.rb +45 -0
  82. data/lib/rubocop/cop/rails/request_referer.rb +3 -3
  83. data/lib/rubocop/cop/rails/safe_navigation.rb +89 -0
  84. data/lib/rubocop/cop/rails/save_bang.rb +78 -9
  85. data/lib/rubocop/cop/rails/scope_args.rb +3 -1
  86. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +2 -3
  87. data/lib/rubocop/cop/rails/validation.rb +1 -1
  88. data/lib/rubocop/cop/security/json_load.rb +36 -0
  89. data/lib/rubocop/cop/style/alias.rb +1 -1
  90. data/lib/rubocop/cop/style/align_hash.rb +25 -14
  91. data/lib/rubocop/cop/style/and_or.rb +13 -3
  92. data/lib/rubocop/cop/style/array_join.rb +3 -3
  93. data/lib/rubocop/cop/style/ascii_comments.rb +1 -2
  94. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -2
  95. data/lib/rubocop/cop/style/attr.rb +1 -3
  96. data/lib/rubocop/cop/style/block_comments.rb +2 -6
  97. data/lib/rubocop/cop/style/block_delimiters.rb +35 -21
  98. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -4
  99. data/lib/rubocop/cop/style/case_indentation.rb +1 -3
  100. data/lib/rubocop/cop/style/class_methods.rb +3 -4
  101. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  102. data/lib/rubocop/cop/style/command_literal.rb +15 -8
  103. data/lib/rubocop/cop/style/comment_annotation.rb +1 -2
  104. data/lib/rubocop/cop/style/conditional_assignment.rb +68 -36
  105. data/lib/rubocop/cop/style/copyright.rb +1 -5
  106. data/lib/rubocop/cop/style/def_with_parentheses.rb +3 -5
  107. data/lib/rubocop/cop/style/documentation.rb +28 -56
  108. data/lib/rubocop/cop/style/documentation_method.rb +80 -0
  109. data/lib/rubocop/cop/style/each_for_simple_loop.rb +6 -5
  110. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  111. data/lib/rubocop/cop/style/else_alignment.rb +10 -9
  112. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -4
  113. data/lib/rubocop/cop/style/empty_else.rb +1 -4
  114. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -3
  115. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +2 -5
  116. data/lib/rubocop/cop/style/encoding.rb +28 -14
  117. data/lib/rubocop/cop/style/even_odd.rb +28 -17
  118. data/lib/rubocop/cop/style/extra_spacing.rb +36 -25
  119. data/lib/rubocop/cop/style/file_name.rb +19 -10
  120. data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -3
  121. data/lib/rubocop/cop/style/for.rb +12 -8
  122. data/lib/rubocop/cop/style/format_string.rb +1 -1
  123. data/lib/rubocop/cop/style/guard_clause.rb +22 -56
  124. data/lib/rubocop/cop/style/hash_syntax.rb +72 -7
  125. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -19
  126. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -3
  127. data/lib/rubocop/cop/style/indentation_width.rb +30 -16
  128. data/lib/rubocop/cop/style/infinite_loop.rb +16 -13
  129. data/lib/rubocop/cop/style/initial_indentation.rb +23 -18
  130. data/lib/rubocop/cop/style/inline_comment.rb +16 -3
  131. data/lib/rubocop/cop/style/lambda.rb +22 -10
  132. data/lib/rubocop/cop/style/leading_comment_space.rb +12 -1
  133. data/lib/rubocop/cop/style/line_end_concatenation.rb +24 -6
  134. data/lib/rubocop/cop/style/method_call_parentheses.rb +18 -9
  135. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  136. data/lib/rubocop/cop/style/method_def_parentheses.rb +3 -4
  137. data/lib/rubocop/cop/style/method_missing.rb +10 -2
  138. data/lib/rubocop/cop/style/module_function.rb +14 -6
  139. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -5
  140. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -5
  141. data/lib/rubocop/cop/style/multiline_block_layout.rb +22 -15
  142. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +9 -0
  143. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +41 -20
  144. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +6 -6
  145. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +3 -5
  146. data/lib/rubocop/cop/style/mutable_constant.rb +21 -13
  147. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  148. data/lib/rubocop/cop/style/negated_while.rb +3 -3
  149. data/lib/rubocop/cop/style/nested_modifier.rb +2 -4
  150. data/lib/rubocop/cop/style/next.rb +4 -4
  151. data/lib/rubocop/cop/style/non_nil_check.rb +18 -10
  152. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +8 -0
  153. data/lib/rubocop/cop/style/numeric_predicate.rb +9 -9
  154. data/lib/rubocop/cop/style/one_line_conditional.rb +11 -1
  155. data/lib/rubocop/cop/style/op_method.rb +1 -1
  156. data/lib/rubocop/cop/style/option_hash.rb +8 -8
  157. data/lib/rubocop/cop/style/optional_arguments.rb +21 -8
  158. data/lib/rubocop/cop/style/parallel_assignment.rb +51 -35
  159. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  160. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  161. data/lib/rubocop/cop/style/raise_args.rb +2 -2
  162. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  163. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -15
  164. data/lib/rubocop/cop/style/redundant_return.rb +5 -5
  165. data/lib/rubocop/cop/style/redundant_self.rb +20 -11
  166. data/lib/rubocop/cop/style/regexp_literal.rb +16 -10
  167. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +8 -6
  168. data/lib/rubocop/cop/style/safe_navigation.rb +125 -0
  169. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  170. data/lib/rubocop/cop/style/semicolon.rb +9 -10
  171. data/lib/rubocop/cop/style/signal_exception.rb +2 -4
  172. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  173. data/lib/rubocop/cop/style/single_line_methods.rb +18 -11
  174. data/lib/rubocop/cop/style/space_after_method_name.rb +2 -3
  175. data/lib/rubocop/cop/style/space_after_not.rb +4 -6
  176. data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -2
  177. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -3
  178. data/lib/rubocop/cop/style/space_around_operators.rb +21 -16
  179. data/lib/rubocop/cop/style/space_before_block_braces.rb +2 -12
  180. data/lib/rubocop/cop/style/space_before_first_arg.rb +1 -3
  181. data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +1 -1
  182. data/lib/rubocop/cop/style/space_inside_block_braces.rb +33 -40
  183. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +38 -23
  184. data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +1 -1
  185. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +26 -12
  186. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -4
  187. data/lib/rubocop/cop/style/symbol_array.rb +10 -10
  188. data/lib/rubocop/cop/style/symbol_proc.rb +28 -13
  189. data/lib/rubocop/cop/style/ternary_parentheses.rb +35 -5
  190. data/lib/rubocop/cop/style/trailing_blank_lines.rb +2 -4
  191. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +29 -17
  192. data/lib/rubocop/cop/style/trivial_accessors.rb +6 -6
  193. data/lib/rubocop/cop/style/unless_else.rb +2 -6
  194. data/lib/rubocop/cop/style/unneeded_capital_w.rb +8 -4
  195. data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -5
  196. data/lib/rubocop/cop/style/unneeded_percent_q.rb +13 -7
  197. data/lib/rubocop/cop/style/variable_number.rb +79 -0
  198. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  199. data/lib/rubocop/cop/style/word_array.rb +25 -15
  200. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -0
  201. data/lib/rubocop/cop/util.rb +23 -4
  202. data/lib/rubocop/cop/variable_force.rb +59 -25
  203. data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
  204. data/lib/rubocop/cop/variable_force/variable.rb +2 -2
  205. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  206. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -11
  207. data/lib/rubocop/formatter/formatter_set.rb +12 -10
  208. data/lib/rubocop/formatter/worst_offenders_formatter.rb +4 -4
  209. data/lib/rubocop/node_pattern.rb +79 -35
  210. data/lib/rubocop/options.rb +4 -4
  211. data/lib/rubocop/processed_source.rb +9 -5
  212. data/lib/rubocop/remote_config.rb +14 -10
  213. data/lib/rubocop/result_cache.rb +14 -6
  214. data/lib/rubocop/runner.rb +55 -34
  215. data/lib/rubocop/string_util.rb +9 -5
  216. data/lib/rubocop/target_finder.rb +1 -1
  217. data/lib/rubocop/token.rb +1 -1
  218. data/lib/rubocop/version.rb +1 -1
  219. metadata +15 -4
  220. data/lib/rubocop/cop/lint/useless_array_splat.rb +0 -56
  221. data/lib/rubocop/cop/performance/push_splat.rb +0 -47
@@ -23,10 +23,10 @@ module RuboCop
23
23
  end
24
24
 
25
25
  def file_finished(file, offenses)
26
- unless offenses.empty?
27
- path = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
28
- @offense_counts[path] = offenses.size
29
- end
26
+ return if offenses.empty?
27
+
28
+ path = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
29
+ @offense_counts[path] = offenses.size
30
30
  end
31
31
 
32
32
  def finished(_inspected_files)
@@ -171,11 +171,11 @@ module RuboCop
171
171
  # but we don't know how expensive it is
172
172
  # to be safe, cache the node in a temp variable and then use the
173
173
  # temp variable as 'cur_node'
174
- init = "temp#{@temps += 1} = #{cur_node}"
175
- cur_node = "temp#{@temps}"
176
- terms = compile_seq_terms(tokens, cur_node)
174
+ with_temp_node(cur_node) do |init, temp_node|
175
+ terms = compile_seq_terms(tokens, temp_node)
177
176
 
178
- join_terms(init, terms, ' && ')
177
+ join_terms(init, terms, ' && ')
178
+ end
179
179
  end
180
180
 
181
181
  def compile_seq_terms(tokens, cur_node)
@@ -255,43 +255,60 @@ module RuboCop
255
255
  def compile_union(tokens, cur_node, seq_head)
256
256
  fail_due_to('empty union') if tokens.first == '}'
257
257
 
258
- init = "temp#{@temps += 1} = #{cur_node}"
259
- cur_node = "temp#{@temps}"
258
+ with_temp_node(cur_node) do |init, temp_node|
259
+ terms = union_terms(tokens, temp_node, seq_head)
260
+ join_terms(init, terms, ' || ')
261
+ end
262
+ end
260
263
 
261
- terms = []
264
+ def union_terms(tokens, temp_node, seq_head)
262
265
  # we need to ensure that each branch of the {} contains the same
263
266
  # number of captures (since only one branch of the {} can actually
264
267
  # match, the same variables are used to hold the captures for each
265
268
  # branch)
266
- captures_before = @captures
267
- terms << compile_expr(tokens, cur_node, seq_head)
268
- captures_after = @captures
269
-
270
- until tokens.first == '}'
271
- @captures = captures_before
272
- terms << compile_expr(tokens, cur_node, seq_head)
273
- if @captures != captures_after
274
- fail_due_to('each branch of {} must have same # of captures')
269
+ compile_expr_with_captures(tokens,
270
+ temp_node, seq_head) do |term, before, after|
271
+ terms = [term]
272
+ until tokens.first == '}'
273
+ terms << compile_expr_with_capture_check(tokens, temp_node,
274
+ seq_head, before, after)
275
275
  end
276
+ tokens.shift
277
+
278
+ terms
276
279
  end
277
- tokens.shift
280
+ end
278
281
 
279
- join_terms(init, terms, ' || ')
282
+ def compile_expr_with_captures(tokens, temp_node, seq_head)
283
+ captures_before = @captures
284
+ expr = compile_expr(tokens, temp_node, seq_head)
285
+
286
+ yield expr, captures_before, @captures
287
+ end
288
+
289
+ def compile_expr_with_capture_check(tokens, temp_node, seq_head, before,
290
+ after)
291
+ @captures = before
292
+ expr = compile_expr(tokens, temp_node, seq_head)
293
+ if @captures != after
294
+ fail_due_to('each branch of {} must have same # of captures')
295
+ end
296
+
297
+ expr
280
298
  end
281
299
 
282
300
  def compile_intersect(tokens, cur_node, seq_head)
283
301
  fail_due_to('empty intersection') if tokens.first == ']'
284
302
 
285
- init = "temp#{@temps += 1} = #{cur_node}"
286
- cur_node = "temp#{@temps}"
303
+ with_temp_node(cur_node) do |init, temp_node|
304
+ terms = []
305
+ until tokens.first == ']'
306
+ terms << compile_expr(tokens, temp_node, seq_head)
307
+ end
308
+ tokens.shift
287
309
 
288
- terms = []
289
- until tokens.first == ']'
290
- terms << compile_expr(tokens, cur_node, seq_head)
310
+ join_terms(init, terms, ' && ')
291
311
  end
292
- tokens.shift
293
-
294
- join_terms(init, terms, ' && ')
295
312
  end
296
313
 
297
314
  def compile_capture(tokens, cur_node, seq_head)
@@ -317,7 +334,7 @@ module RuboCop
317
334
  # in a temp. check if this value matches the one stored in the temp
318
335
  "(#{cur_node}#{'.type' if seq_head} == temp#{@unify[name]})"
319
336
  else
320
- n = @unify[name] = (@temps += 1)
337
+ n = @unify[name] = next_temp_value
321
338
  "(temp#{n} = #{cur_node}#{'.type' if seq_head}; true)"
322
339
  end
323
340
  end
@@ -425,6 +442,20 @@ module RuboCop
425
442
  def fail_due_to(message)
426
443
  raise Invalid, "Couldn't compile due to #{message}. Pattern: #{@string}"
427
444
  end
445
+
446
+ def with_temp_node(cur_node)
447
+ with_temp_variable do |temp_var|
448
+ yield "#{temp_var} = #{cur_node}", temp_var
449
+ end
450
+ end
451
+
452
+ def with_temp_variable
453
+ yield "temp#{next_temp_value}"
454
+ end
455
+
456
+ def next_temp_value
457
+ @temps += 1
458
+ end
428
459
  end
429
460
 
430
461
  # Helpers for defining methods based on a pattern string
@@ -454,20 +485,33 @@ module RuboCop
454
485
  # yield all descendants which match.
455
486
  def def_node_search(method_name, pattern_str)
456
487
  compiler = RuboCop::NodePattern::Compiler.new(pattern_str, 'node')
488
+ called_from = caller.first.split(':')
489
+
457
490
  if method_name.to_s.end_with?('?')
458
- on_match = 'return true'
459
- prelude = ''
491
+ node_search_first(method_name, compiler, called_from)
460
492
  else
461
- yieldval = compiler.emit_capture_list
462
- yieldval = 'node' if yieldval.empty?
463
- on_match = "yield(#{yieldval})"
464
- prelude = "return enum_for(:#{method_name}, node0" \
465
- "#{compiler.emit_trailing_params}) unless block_given?"
493
+ node_search_all(method_name, compiler, called_from)
466
494
  end
495
+ end
496
+
497
+ def node_search_first(method_name, compiler, called_from)
498
+ node_search(method_name, compiler, 'return true', '', called_from)
499
+ end
500
+
501
+ def node_search_all(method_name, compiler, called_from)
502
+ yieldval = compiler.emit_capture_list
503
+ yieldval = 'node' if yieldval.empty?
504
+ prelude = "return enum_for(:#{method_name}, node0" \
505
+ "#{compiler.emit_trailing_params}) unless block_given?"
506
+
507
+ node_search(method_name, compiler, "yield(#{yieldval})", prelude,
508
+ called_from)
509
+ end
467
510
 
511
+ def node_search(method_name, compiler, on_match, prelude, called_from)
468
512
  src = node_search_body(method_name, compiler.emit_trailing_params,
469
513
  prelude, compiler.match_code, on_match)
470
- filename, lineno = *caller.first.split(':')
514
+ filename, lineno = *called_from
471
515
  class_eval(src, filename, lineno.to_i)
472
516
  end
473
517
 
@@ -34,7 +34,7 @@ module RuboCop
34
34
  private
35
35
 
36
36
  def args_from_file
37
- if File.exist?('.rubocop')
37
+ if File.exist?('.rubocop') && !File.directory?('.rubocop')
38
38
  IO.readlines('.rubocop').map(&:strip)
39
39
  else
40
40
  []
@@ -127,7 +127,7 @@ module RuboCop
127
127
  end
128
128
  end
129
129
 
130
- def add_boolean_flags(opts)
130
+ def add_boolean_flags(opts) # rubocop:disable Metrics/MethodLength
131
131
  option(opts, '-F', '--fail-fast')
132
132
  option(opts, '-C', '--cache FLAG')
133
133
  option(opts, '-d', '--debug')
@@ -145,7 +145,7 @@ module RuboCop
145
145
 
146
146
  option(opts, '-v', '--version')
147
147
  option(opts, '-V', '--verbose-version')
148
- option(opts, '-s', '--stdin') { @options[:stdin] = $stdin.read }
148
+ option(opts, '-s', '--stdin') { @options[:stdin] = $stdin.binmode.read }
149
149
  end
150
150
 
151
151
  def add_list_options(opts)
@@ -192,7 +192,7 @@ module RuboCop
192
192
  @options = options
193
193
  end
194
194
 
195
- def validate_compatibility
195
+ def validate_compatibility # rubocop:disable Metrics/MethodLength
196
196
  if only_includes_unneeded_disable?
197
197
  raise ArgumentError, 'Lint/UnneededDisable can not be used with --only.'
198
198
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  :parser_error, :raw_source, :ruby_version
15
15
 
16
16
  def self.from_file(path, ruby_version)
17
- file = File.read(path)
17
+ file = File.read(path, mode: 'rb')
18
18
  new(file, ruby_version, path)
19
19
  rescue Errno::ENOENT
20
20
  raise RuboCop::Error, "No such file or directory: #{path}"
@@ -91,16 +91,20 @@ module RuboCop
91
91
  return
92
92
  end
93
93
 
94
- parser = create_parser(ruby_version)
94
+ @ast, @comments, @tokens = tokenize(create_parser(ruby_version))
95
+ end
95
96
 
97
+ def tokenize(parser)
96
98
  begin
97
- @ast, @comments, tokens = parser.tokenize(@buffer)
98
- @ast.complete! if @ast
99
+ ast, comments, tokens = parser.tokenize(@buffer)
100
+ ast.complete! if ast
99
101
  rescue Parser::SyntaxError # rubocop:disable Lint/HandleExceptions
100
102
  # All errors are in diagnostics. No need to handle exception.
101
103
  end
102
104
 
103
- @tokens = tokens.map { |t| Token.from_parser_token(t) } if tokens
105
+ tokens = tokens.map { |t| Token.from_parser_token(t) } if tokens
106
+
107
+ [ast, comments, tokens]
104
108
  end
105
109
 
106
110
  def parser_class(ruby_version) # rubocop:disable Metrics/MethodLength
@@ -17,6 +17,18 @@ module RuboCop
17
17
  def file
18
18
  return cache_path unless cache_path_expired?
19
19
 
20
+ request do |response|
21
+ open cache_path, 'w' do |io|
22
+ io.write response.body
23
+ end
24
+ end
25
+
26
+ cache_path
27
+ end
28
+
29
+ private
30
+
31
+ def request
20
32
  http = Net::HTTP.new(@uri.hostname, @uri.port)
21
33
  http.use_ssl = true if @uri.instance_of? URI::HTTPS
22
34
 
@@ -24,19 +36,11 @@ module RuboCop
24
36
  if cache_path_exists?
25
37
  request['If-Modified-Since'] = File.stat(cache_path).mtime.rfc2822
26
38
  end
27
- response = http.request(request)
28
39
 
29
- cache_path.tap do |f|
30
- if response.is_a?(Net::HTTPSuccess)
31
- open f, 'w' do |io|
32
- io.write response.body
33
- end
34
- end
35
- end
40
+ response = http.request(request)
41
+ yield response if response.is_a?(Net::HTTPSuccess)
36
42
  end
37
43
 
38
- private
39
-
40
44
  def cache_path
41
45
  File.expand_path(".rubocop-#{cache_name_from_uri}", @base_dir)
42
46
  end
@@ -24,8 +24,20 @@ module RuboCop
24
24
  return unless File.exist?(cache_root)
25
25
 
26
26
  files, dirs = Find.find(cache_root).partition { |path| File.file?(path) }
27
- if files.length > config_store.for('.').for_all_cops['MaxFilesInCache'] &&
28
- files.length > 1
27
+ return unless requires_file_removal?(files.length, config_store)
28
+
29
+ remove_oldest_files(files, dirs, cache_root, verbose)
30
+ end
31
+
32
+ class << self
33
+ private
34
+
35
+ def requires_file_removal?(file_count, config_store)
36
+ file_count > 1 &&
37
+ file_count > config_store.for('.').for_all_cops['MaxFilesInCache']
38
+ end
39
+
40
+ def remove_oldest_files(files, dirs, cache_root, verbose)
29
41
  # Add 1 to half the number of files, so that we remove the file if
30
42
  # there's only 1 left.
31
43
  remove_count = 1 + files.length / 2
@@ -35,10 +47,6 @@ module RuboCop
35
47
  sorted = files.sort_by { |path| File.mtime(path) }
36
48
  remove_files(sorted, dirs, remove_count, verbose)
37
49
  end
38
- end
39
-
40
- class << self
41
- private
42
50
 
43
51
  def remove_files(files, dirs, remove_count, verbose)
44
52
  # Batch file deletions, deleting over 130,000+ files will crash
@@ -16,6 +16,8 @@ module RuboCop
16
16
  end
17
17
  end
18
18
 
19
+ MAX_ITERATIONS = 200
20
+
19
21
  attr_reader :errors, :warnings, :aborting
20
22
  alias aborting? aborting
21
23
 
@@ -50,25 +52,32 @@ module RuboCop
50
52
 
51
53
  def inspect_files(files)
52
54
  inspected_files = []
53
- all_passed = true
54
55
 
55
56
  formatter_set.started(files)
56
57
 
57
- files.each do |file|
58
- break if aborting?
59
- offenses = process_file(file)
60
- all_passed = false if offenses.any? { |o| considered_failure?(o) }
61
- inspected_files << file
62
- break if @options[:fail_fast] && !all_passed
63
- end
64
-
65
- all_passed
58
+ each_inspected_file(files) { |file| inspected_files << file }
66
59
  ensure
67
60
  ResultCache.cleanup(@config_store, @options[:debug]) if cached_run?
68
61
  formatter_set.finished(inspected_files.freeze)
69
62
  formatter_set.close_output_files
70
63
  end
71
64
 
65
+ def each_inspected_file(files)
66
+ files.reduce(true) do |all_passed, file|
67
+ break false if aborting?
68
+
69
+ offenses = process_file(file)
70
+ yield file
71
+
72
+ if offenses.any? { |o| considered_failure?(o) }
73
+ break false if @options[:fail_fast]
74
+ next false
75
+ end
76
+
77
+ all_passed
78
+ end
79
+ end
80
+
72
81
  def list_files(paths)
73
82
  paths.each do |path|
74
83
  puts PathUtil.relative_path(path)
@@ -108,10 +117,7 @@ module RuboCop
108
117
  end
109
118
 
110
119
  def add_unneeded_disables(file, offenses, source)
111
- if source.disabled_line_ranges.any? &&
112
- # Don't check unneeded disable if --only or --except option is
113
- # given, because these options override configuration.
114
- (@options[:except] || []).empty? && (@options[:only] || []).empty?
120
+ if check_for_unneded_disables?(source)
115
121
  config = @config_store.for(file)
116
122
  if config.cop_enabled?(Cop::Lint::UnneededDisable)
117
123
  cop = Cop::Lint::UnneededDisable.new(config, @options)
@@ -127,6 +133,14 @@ module RuboCop
127
133
  offenses.sort.reject(&:disabled?).freeze
128
134
  end
129
135
 
136
+ def check_for_unneded_disables?(source)
137
+ !source.disabled_line_ranges.empty? && !filtered_run?
138
+ end
139
+
140
+ def filtered_run?
141
+ @options[:except] || @options[:only]
142
+ end
143
+
130
144
  def autocorrect_unneeded_disables(source, cop)
131
145
  cop.processed_source = source
132
146
  Cop::Team.new([], nil, @options).autocorrect(source.buffer, [cop])
@@ -166,27 +180,11 @@ module RuboCop
166
180
  def do_inspection_loop(file, processed_source)
167
181
  offenses = []
168
182
 
169
- # Keep track of the state of the source. If a cop modifies the source
170
- # and another cop undoes it producing identical source we have an
171
- # infinite loop.
172
- @processed_sources = []
173
-
174
- # It is also possible for a cop to keep adding indefinitely to a file,
175
- # making it bigger and bigger. If the inspection loop runs for an
176
- # excessively high number of iterations, this is likely happening.
177
- @iterations = 0
178
-
179
183
  # When running with --auto-correct, we need to inspect the file (which
180
184
  # includes writing a corrected version of it) until no more corrections
181
185
  # are made. This is because automatic corrections can introduce new
182
186
  # offenses. In the normal case the loop is only executed once.
183
- loop do
184
- check_for_infinite_loop(processed_source, offenses)
185
-
186
- if (@iterations += 1) > 200
187
- raise InfiniteCorrectionLoop.new(processed_source.path, offenses)
188
- end
189
-
187
+ iterate_until_no_changes(processed_source, offenses) do
190
188
  # The offenses that couldn't be corrected will be found again so we
191
189
  # only keep the corrected ones in order to avoid duplicate reporting.
192
190
  offenses.select!(&:corrected?)
@@ -204,6 +202,29 @@ module RuboCop
204
202
  [processed_source, offenses]
205
203
  end
206
204
 
205
+ def iterate_until_no_changes(source, offenses)
206
+ # Keep track of the state of the source. If a cop modifies the source
207
+ # and another cop undoes it producing identical source we have an
208
+ # infinite loop.
209
+ @processed_sources = []
210
+
211
+ # It is also possible for a cop to keep adding indefinitely to a file,
212
+ # making it bigger and bigger. If the inspection loop runs for an
213
+ # excessively high number of iterations, this is likely happening.
214
+ iterations = 0
215
+
216
+ loop do
217
+ check_for_infinite_loop(source, offenses)
218
+
219
+ if (iterations += 1) > MAX_ITERATIONS
220
+ raise InfiniteCorrectionLoop.new(source.path, offenses)
221
+ end
222
+
223
+ source = yield
224
+ break unless source
225
+ end
226
+ end
227
+
207
228
  # Check whether a run created source identical to a previous run, which
208
229
  # means that we definitely have an infinite loop.
209
230
  def check_for_infinite_loop(processed_source, offenses)
@@ -254,9 +275,9 @@ module RuboCop
254
275
 
255
276
  def filter_cop_classes(cop_classes, config)
256
277
  # use only cops that link to a style guide if requested
257
- if style_guide_cops_only?(config)
258
- cop_classes.select! { |cop| config.for_cop(cop)['StyleGuide'] }
259
- end
278
+ return unless style_guide_cops_only?(config)
279
+
280
+ cop_classes.select! { |cop| config.for_cop(cop)['StyleGuide'] }
260
281
  end
261
282
 
262
283
  def style_guide_cops_only?(config)