rubocop 0.65.0 → 0.66.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +53 -4
  4. data/lib/rubocop.rb +4 -5
  5. data/lib/rubocop/cli.rb +1 -1
  6. data/lib/rubocop/config.rb +1 -1
  7. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -5
  8. data/lib/rubocop/cop/layout/class_structure.rb +59 -28
  9. data/lib/rubocop/cop/layout/extra_spacing.rb +18 -0
  10. data/lib/rubocop/cop/layout/indentation_width.rb +25 -5
  11. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +33 -17
  12. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +30 -11
  13. data/lib/rubocop/cop/lint/else_layout.rb +1 -0
  14. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  15. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +38 -0
  16. data/lib/rubocop/cop/lint/shadowed_exception.rb +14 -1
  17. data/lib/rubocop/cop/lint/to_json.rb +38 -0
  18. data/lib/rubocop/cop/lint/void.rb +1 -1
  19. data/lib/rubocop/cop/message_annotator.rb +4 -4
  20. data/lib/rubocop/cop/metrics/abc_size.rb +1 -0
  21. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +31 -9
  22. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  23. data/lib/rubocop/cop/mixin/integer_node.rb +1 -1
  24. data/lib/rubocop/cop/mixin/method_preference.rb +2 -1
  25. data/lib/rubocop/cop/naming/constant_name.rb +6 -1
  26. data/lib/rubocop/cop/naming/predicate_name.rb +6 -0
  27. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -1
  28. data/lib/rubocop/cop/rails/output.rb +18 -1
  29. data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
  30. data/lib/rubocop/cop/rails/time_zone.rb +10 -0
  31. data/lib/rubocop/cop/rails/validation.rb +3 -2
  32. data/lib/rubocop/cop/style/block_delimiters.rb +30 -1
  33. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
  34. data/lib/rubocop/cop/style/constant_visibility.rb +66 -0
  35. data/lib/rubocop/cop/style/identical_conditional_branches.rb +8 -12
  36. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -4
  37. data/lib/rubocop/cop/style/numeric_literals.rb +16 -7
  38. data/lib/rubocop/cop/style/option_hash.rb +5 -0
  39. data/lib/rubocop/cop/style/redundant_freeze.rb +13 -1
  40. data/lib/rubocop/cop/style/redundant_self.rb +3 -1
  41. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  42. data/lib/rubocop/cop/style/symbol_array.rb +9 -1
  43. data/lib/rubocop/cop/style/trivial_accessors.rb +5 -0
  44. data/lib/rubocop/cop/style/word_array.rb +0 -4
  45. data/lib/rubocop/cop/util.rb +4 -0
  46. data/lib/rubocop/core_ext/string.rb +47 -0
  47. data/lib/rubocop/node_pattern.rb +76 -55
  48. data/lib/rubocop/processed_source.rb +2 -2
  49. data/lib/rubocop/result_cache.rb +4 -4
  50. data/lib/rubocop/rspec/cop_helper.rb +5 -0
  51. data/lib/rubocop/rspec/expect_offense.rb +5 -5
  52. data/lib/rubocop/runner.rb +6 -13
  53. data/lib/rubocop/version.rb +1 -1
  54. metadata +15 -19
@@ -18,7 +18,7 @@ module RuboCop
18
18
  MSG = 'Specify a `:rel` option containing noopener.'.freeze
19
19
 
20
20
  def_node_matcher :blank_target?, <<-PATTERN
21
- (pair {(sym :target) (str "target")} (str "_blank"))
21
+ (pair {(sym :target) (str "target")} {(str "_blank") (sym :_blank)})
22
22
  PATTERN
23
23
 
24
24
  def_node_matcher :includes_noopener?, <<-PATTERN
@@ -21,11 +21,28 @@ module RuboCop
21
21
  (send nil? {:ap :p :pp :pretty_print :print :puts} ...)
22
22
  PATTERN
23
23
 
24
+ def_node_matcher :io_output?, <<-PATTERN
25
+ (send
26
+ {
27
+ (gvar #match_gvar?)
28
+ {(const nil? :STDOUT) (const nil? :STDERR)}
29
+ }
30
+ {:binwrite :syswrite :write :write_nonblock}
31
+ ...)
32
+ PATTERN
33
+
24
34
  def on_send(node)
25
- return unless output?(node) && node.arguments?
35
+ return unless (output?(node) || io_output?(node)) &&
36
+ node.arguments?
26
37
 
27
38
  add_offense(node, location: :selector)
28
39
  end
40
+
41
+ private
42
+
43
+ def match_gvar?(sym)
44
+ %i[$stdout $stderr].include?(sym)
45
+ end
29
46
  end
30
47
  end
31
48
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
  PATTERN
22
22
 
23
23
  def_node_search :reflection_class_name, <<-PATTERN
24
- (pair (sym :class_name) !str)
24
+ (pair (sym :class_name) [!str !sym])
25
25
  PATTERN
26
26
 
27
27
  def on_send(node)
@@ -78,6 +78,16 @@ module RuboCop
78
78
  check_time_node(klass, node.parent) if TIMECLASS.include?(klass)
79
79
  end
80
80
 
81
+ def autocorrect(node)
82
+ lambda do |corrector|
83
+ if acceptable?
84
+ corrector.insert_after(node.source_range, '.in_time_zone')
85
+ else
86
+ corrector.insert_after(node.children[0].source_range, '.zone')
87
+ end
88
+ end
89
+ end
90
+
81
91
  private
82
92
 
83
93
  def check_time_node(klass, node)
@@ -87,8 +87,9 @@ module RuboCop
87
87
  "#{validate_type}: #{braced_options(last_argument)}"
88
88
  )
89
89
  else
90
- corrector.insert_after(node.loc.expression,
91
- ", #{validate_type}: true")
90
+ range = last_argument.source_range
91
+
92
+ corrector.insert_after(range, ", #{validate_type}: true")
92
93
  end
93
94
  end
94
95
 
@@ -60,6 +60,30 @@ module RuboCop
60
60
  # x
61
61
  # }.inspect
62
62
  #
63
+ # # The AllowBracesOnProceduralOneLiners option is ignored unless the
64
+ # # EnforcedStyle is set to `semantic`. If so:
65
+ #
66
+ # # If the AllowBracesOnProceduralOneLiners option is unspecified, or
67
+ # # set to `false` or any other falsey value, then semantic purity is
68
+ # # maintained, so one-line procedural blocks must use do-end, not
69
+ # # braces.
70
+ #
71
+ # # bad
72
+ # collection.each { |element| puts element }
73
+ #
74
+ # # good
75
+ # collection.each do |element| puts element end
76
+ #
77
+ # # If the AllowBracesOnProceduralOneLiners option is set to `true`, or
78
+ # # any other truthy value, then one-line procedural blocks may use
79
+ # # either style. (There is no setting for requiring braces on them.)
80
+ #
81
+ # # good
82
+ # collection.each { |element| puts element }
83
+ #
84
+ # # also good
85
+ # collection.each do |element| puts element end
86
+ #
63
87
  # @example EnforcedStyle: braces_for_chaining
64
88
  # # bad
65
89
  # words.each do |word|
@@ -216,7 +240,8 @@ module RuboCop
216
240
  method_name = node.method_name
217
241
 
218
242
  if node.braces?
219
- functional_method?(method_name) || functional_block?(node)
243
+ functional_method?(method_name) || functional_block?(node) ||
244
+ (procedural_oneliners_may_have_braces? && !node.multiline?)
220
245
  else
221
246
  procedural_method?(method_name) || !return_value_used?(node)
222
247
  end
@@ -250,6 +275,10 @@ module RuboCop
250
275
  return_value_used?(node) || return_value_of_scope?(node)
251
276
  end
252
277
 
278
+ def procedural_oneliners_may_have_braces?
279
+ cop_config['AllowBracesOnProceduralOneLiners']
280
+ end
281
+
253
282
  def procedural_method?(method_name)
254
283
  cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name)
255
284
  end
@@ -350,6 +350,8 @@ module RuboCop
350
350
  end
351
351
 
352
352
  def lhs_all_match?(branches)
353
+ return true if branches.empty?
354
+
353
355
  first_lhs = lhs(branches.first)
354
356
  branches.all? { |branch| lhs(branch) == first_lhs }
355
357
  end
@@ -372,7 +374,7 @@ module RuboCop
372
374
  def allowed_statements?(branches)
373
375
  return false unless branches.all?
374
376
 
375
- statements = branches.map { |branch| tail(branch) }
377
+ statements = branches.map { |branch| tail(branch) }.compact
376
378
 
377
379
  lhs_all_match?(statements) && statements.none?(&:masgn_type?) &&
378
380
  assignment_types_match?(*statements)
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks that constants defined in classes and modules have
7
+ # an explicit visibility declaration. By default, Ruby makes all class-
8
+ # and module constants public, which litters the public API of the
9
+ # class or module. Explicitly declaring a visibility makes intent more
10
+ # clear, and prevents outside actors from touching private state.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # class Foo
16
+ # BAR = 42
17
+ # BAZ = 43
18
+ # end
19
+ #
20
+ # # good
21
+ # class Foo
22
+ # BAR = 42
23
+ # private_constant :BAR
24
+ #
25
+ # BAZ = 43
26
+ # public_constant :BAZ
27
+ # end
28
+ #
29
+ class ConstantVisibility < Cop
30
+ MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
31
+ 'either `#public_constant` or `#private_constant`.'.freeze
32
+
33
+ def on_casgn(node)
34
+ return unless class_or_module_scope?(node)
35
+ return if visibility_declaration?(node)
36
+
37
+ add_offense(node)
38
+ end
39
+
40
+ private
41
+
42
+ def message(node)
43
+ _namespace, constant_name, _value = *node
44
+
45
+ format(MSG, constant_name: constant_name)
46
+ end
47
+
48
+ def class_or_module_scope?(node)
49
+ node.parent && %i[class module].include?(node.parent.type)
50
+ end
51
+
52
+ def visibility_declaration?(node)
53
+ _namespace, constant_name, _value = *node
54
+
55
+ node.parent.each_child_node(:send).any? do |child|
56
+ visibility_declaration_for?(child, constant_name)
57
+ end
58
+ end
59
+
60
+ def_node_matcher :visibility_declaration_for?, <<-PATTERN
61
+ (send nil? {:public_constant :private_constant} ({sym str} %1))
62
+ PATTERN
63
+ end
64
+ end
65
+ end
66
+ end
@@ -69,11 +69,6 @@ module RuboCop
69
69
  return if node.elsif?
70
70
 
71
71
  branches = expand_elses(node.else_branch).unshift(node.if_branch)
72
-
73
- # return if any branch is empty. An empty branch can be an `if`
74
- # without an `else` or a branch that contains only comments.
75
- return if branches.any?(&:nil?)
76
-
77
72
  check_branches(branches)
78
73
  end
79
74
 
@@ -81,19 +76,20 @@ module RuboCop
81
76
  return unless node.else? && node.else_branch
82
77
 
83
78
  branches = node.when_branches.map(&:body).push(node.else_branch)
84
-
85
- return if branches.any?(&:nil?)
86
-
87
79
  check_branches(branches)
88
80
  end
89
81
 
90
82
  private
91
83
 
92
84
  def check_branches(branches)
93
- tails = branches.compact.map { |branch| tail(branch) }
94
- check_expressions(tails)
95
- heads = branches.compact.map { |branch| head(branch) }
96
- check_expressions(heads)
85
+ # return if any branch is empty. An empty branch can be an `if`
86
+ # without an `else` or a branch that contains only comments.
87
+ return if branches.any?(&:nil?)
88
+
89
+ tails = branches.map { |branch| tail(branch) }
90
+ check_expressions(tails) if tails.none?(&:nil?)
91
+ heads = branches.map { |branch| head(branch) }
92
+ check_expressions(heads) if tails.none?(&:nil?)
97
93
  end
98
94
 
99
95
  def check_expressions(expressions)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Metrics/ClassLength
3
4
  module RuboCop
4
5
  module Cop
5
6
  module Style
@@ -8,7 +9,11 @@ module RuboCop
8
9
  #
9
10
  # In the default style (require_parentheses), macro methods are ignored.
10
11
  # Additional methods can be added to the `IgnoredMethods` list. This
11
- # option is valid only in the default style.
12
+ # option is valid only in the default style. Macros can be included by
13
+ # either setting `IgnoreMacros` to false or adding specific macros to
14
+ # the `IncludedMacros` list. If a method is listed in both
15
+ # `IncludedMacros` and `IgnoredMethods`, then the latter takes
16
+ # precedence (that is, the method is ignored).
12
17
  #
13
18
  # In the alternative style (omit_parentheses), there are three additional
14
19
  # options.
@@ -206,11 +211,17 @@ module RuboCop
206
211
  end
207
212
 
208
213
  def eligible_for_parentheses_omission?(node)
209
- node.operator_method? || node.setter_method? || ignore_macros?(node)
214
+ node.operator_method? || node.setter_method? || ignored_macro?(node)
210
215
  end
211
216
 
212
- def ignore_macros?(node)
213
- cop_config['IgnoreMacros'] && node.macro?
217
+ def included_macros_list
218
+ cop_config.fetch('IncludedMacros', []).map(&:to_sym)
219
+ end
220
+
221
+ def ignored_macro?(node)
222
+ cop_config['IgnoreMacros'] &&
223
+ node.macro? &&
224
+ !included_macros_list.include?(node.method_name)
214
225
  end
215
226
 
216
227
  def args_begin(node)
@@ -354,3 +365,4 @@ module RuboCop
354
365
  end
355
366
  end
356
367
  end
368
+ # rubocop:enable Metrics/ClassLength
@@ -32,6 +32,7 @@ module RuboCop
32
32
 
33
33
  MSG = 'Use underscores(_) as thousands separator and ' \
34
34
  'separate every 3 digits with them.'.freeze
35
+ DELIMITER_REGEXP = /[eE.]/.freeze
35
36
 
36
37
  def on_int(node)
37
38
  check(node)
@@ -75,7 +76,20 @@ module RuboCop
75
76
  end
76
77
 
77
78
  def format_number(node)
78
- int_part, float_part = node.source.split('.')
79
+ source = node.source.gsub(/\s+/, '')
80
+ int_part, additional_part = source.split(DELIMITER_REGEXP, 2)
81
+ formatted_int = format_int_part(int_part)
82
+ delimiter = source[DELIMITER_REGEXP]
83
+
84
+ if additional_part
85
+ formatted_int + delimiter + additional_part
86
+ else
87
+ formatted_int
88
+ end
89
+ end
90
+
91
+ # @param int_part [String]
92
+ def format_int_part(int_part)
79
93
  int_part = Integer(int_part)
80
94
  formatted_int = int_part
81
95
  .abs
@@ -84,12 +98,7 @@ module RuboCop
84
98
  .gsub(/...(?=.)/, '\&_')
85
99
  .reverse
86
100
  formatted_int.insert(0, '-') if int_part < 0
87
-
88
- if float_part
89
- format('%<int>s.%<float>s', int: formatted_int, float: float_part)
90
- else
91
- formatted_int
92
- end
101
+ formatted_int
93
102
  end
94
103
 
95
104
  def min_digits
@@ -28,6 +28,7 @@ module RuboCop
28
28
 
29
29
  def on_args(node)
30
30
  return if super_used?(node)
31
+ return if whitelist.include?(node.parent.method_name.to_s)
31
32
 
32
33
  option_hash(node) do |options|
33
34
  add_offense(options)
@@ -36,6 +37,10 @@ module RuboCop
36
37
 
37
38
  private
38
39
 
40
+ def whitelist
41
+ cop_config['Whitelist'] || []
42
+ end
43
+
39
44
  def suspicious_name?(arg_name)
40
45
  cop_config.key?('SuspiciousParamNames') &&
41
46
  cop_config['SuspiciousParamNames'].include?(arg_name.to_s)
@@ -19,7 +19,8 @@ module RuboCop
19
19
 
20
20
  def on_send(node)
21
21
  return unless node.receiver && node.method?(:freeze) &&
22
- immutable_literal?(node.receiver)
22
+ (immutable_literal?(node.receiver) ||
23
+ operation_produces_immutable_object?(node.receiver))
23
24
 
24
25
  add_offense(node)
25
26
  end
@@ -49,6 +50,17 @@ module RuboCop
49
50
  node
50
51
  end
51
52
  end
53
+
54
+ def_node_matcher :operation_produces_immutable_object?, <<-PATTERN
55
+ {
56
+ (begin (send {float int} {:+ :- :* :** :/ :% :<<} _))
57
+ (begin (send _ {:+ :- :* :** :/ :%} {float int}))
58
+ (begin (send _ {:== :=== :!= :<= :>= :< :>} _))
59
+ (send (const nil? :ENV) :[] _)
60
+ (send _ {:count :length :size} ...)
61
+ (block (send _ {:count :length :size} ...) ...)
62
+ }
63
+ PATTERN
52
64
  end
53
65
  end
54
66
  end
@@ -43,6 +43,7 @@ module RuboCop
43
43
  # end
44
44
  class RedundantSelf < Cop
45
45
  MSG = 'Redundant `self` detected.'.freeze
46
+ KERNEL_METHODS = Kernel.methods(false)
46
47
 
47
48
  def self.autocorrect_incompatible_with
48
49
  [ColonMethodCall]
@@ -117,7 +118,8 @@ module RuboCop
117
118
 
118
119
  def allowed_send_node?(node)
119
120
  @allowed_send_nodes.include?(node) ||
120
- @local_variables_scopes[node].include?(node.method_name)
121
+ @local_variables_scopes[node].include?(node.method_name) ||
122
+ KERNEL_METHODS.include?(node.method_name)
121
123
  end
122
124
 
123
125
  def regular_method_call?(node)
@@ -22,7 +22,7 @@ module RuboCop
22
22
 
23
23
  def_node_matcher :stderr_puts?, <<-PATTERN
24
24
  (send
25
- (gvar #stderr_gvar?) :puts
25
+ (gvar #stderr_gvar?) :puts $_
26
26
  ...)
27
27
  PATTERN
28
28
 
@@ -70,7 +70,15 @@ module RuboCop
70
70
  end
71
71
 
72
72
  def correct_bracketed(node)
73
- syms = node.children.map { |c| to_symbol_literal(c.value.to_s) }
73
+ syms = node.children.map do |c|
74
+ if c.dsym_type?
75
+ string_literal = to_string_literal(c.source)
76
+
77
+ ':' + trim_string_interporation_escape_character(string_literal)
78
+ else
79
+ to_symbol_literal(c.value.to_s)
80
+ end
81
+ end
74
82
 
75
83
  lambda do |corrector|
76
84
  corrector.replace(node.source_range, "[#{syms.join(', ')}]")
@@ -31,6 +31,7 @@ module RuboCop
31
31
  MSG = 'Use `attr_%<kind>s` to define trivial %<kind>s methods.'.freeze
32
32
 
33
33
  def on_def(node)
34
+ return if top_level_node?(node)
34
35
  return if in_module_or_instance_eval?(node)
35
36
  return if ignore_class_methods? && node.defs_type?
36
37
 
@@ -180,6 +181,10 @@ module RuboCop
180
181
  )
181
182
  end
182
183
  end
184
+
185
+ def top_level_node?(node)
186
+ node.parent.nil?
187
+ end
183
188
  end
184
189
  end
185
190
  end