rubocop 0.92.0 → 0.93.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +30 -0
  4. data/lib/rubocop.rb +3 -1
  5. data/lib/rubocop/cached_data.rb +2 -1
  6. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  7. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  8. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  9. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -7
  10. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  11. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
  12. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  13. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  14. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
  15. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  16. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  17. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  18. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  19. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
  20. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  21. data/lib/rubocop/cop/metrics/class_length.rb +14 -6
  22. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  23. data/lib/rubocop/cop/offense.rb +15 -2
  24. data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
  25. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  26. data/lib/rubocop/cop/style/case_like_if.rb +20 -4
  27. data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
  28. data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
  29. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  30. data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
  31. data/lib/rubocop/cop/style/for.rb +0 -4
  32. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  33. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  34. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  35. data/lib/rubocop/cop/style/raise_args.rb +0 -3
  36. data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
  37. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  38. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  39. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
  40. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  41. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  42. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  43. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  44. data/lib/rubocop/ext/regexp_node.rb +20 -4
  45. data/lib/rubocop/result_cache.rb +8 -2
  46. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  47. data/lib/rubocop/runner.rb +4 -4
  48. data/lib/rubocop/target_finder.rb +23 -25
  49. data/lib/rubocop/version.rb +1 -1
  50. metadata +11 -9
  51. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 682e17739f5c067f13eb30a3e84b365533bb0e075da92a40529c943e5a67e3b0
4
- data.tar.gz: 2c7e59ef470ad45515bed37249c97419181add1f451379d00b31ff45b21ddd36
3
+ metadata.gz: b8ce11205d6a6bb518654cbe498544aa799fbb8d9c9057afd2f551edfc35bbb8
4
+ data.tar.gz: a1f79001991b28508ca7c9a79d75ed58f39ae0dcf2bad419d6a75919b3a3d539
5
5
  SHA512:
6
- metadata.gz: 0bc3d0c3238795b8563b974c99c20d3cfb34dff97bc33f5231d6ef7497f53ce6f4753923bce17954fe30e69b0a8d4146a3b1377d0489e7f10bc97a0b3c69ae7b
7
- data.tar.gz: 4131b9c8a874e09d8c0581a04e91b44acc76855afa565cd52a324055a0bd7e1a40d37bc532b8b3781c9af9847335c6596ca8ed17fe9bff03d13283171d77c168
6
+ metadata.gz: a32001a91575c41b5ca71b6a148af79f45b2a7b8cbc3909a0dcbb7a652f5e62b6a79a84c14189eda64fd3d2a9e8c40d207c37c0f5a78a156e1f636c5191b995e
7
+ data.tar.gz: 9ac5df57938099031807a96bd87a7fb9c5f7f40c314528b4c3254edb45b1386ce199fa9c394c9e7531655d117df9d3d5215bd66e4a927b9b2b0878e0eac2a1f6
data/README.md CHANGED
@@ -49,7 +49,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
49
49
  might want to use a conservative version lock in your `Gemfile`:
50
50
 
51
51
  ```rb
52
- gem 'rubocop', '~> 0.92.0', require: false
52
+ gem 'rubocop', '~> 0.93.1', require: false
53
53
  ```
54
54
 
55
55
  ## Quickstart
@@ -1546,6 +1546,13 @@ Lint/FormatParameterMismatch:
1546
1546
  Enabled: true
1547
1547
  VersionAdded: '0.33'
1548
1548
 
1549
+ Lint/HashCompareByIdentity:
1550
+ Description: 'Prefer using `Hash#compare_by_identity` than using `object_id` for keys.'
1551
+ StyleGuide: '#identity-comparison'
1552
+ Enabled: pending
1553
+ Safe: false
1554
+ VersionAdded: '0.93'
1555
+
1549
1556
  Lint/HeredocMethodCallPosition:
1550
1557
  Description: >-
1551
1558
  Checks for the ordering of a method call where
@@ -1746,6 +1753,19 @@ Lint/RedundantRequireStatement:
1746
1753
  Enabled: true
1747
1754
  VersionAdded: '0.76'
1748
1755
 
1756
+ Lint/RedundantSafeNavigation:
1757
+ Description: 'Checks for redundant safe navigation calls.'
1758
+ Enabled: pending
1759
+ VersionAdded: '0.93'
1760
+ AllowedMethods:
1761
+ - instance_of?
1762
+ - kind_of?
1763
+ - is_a?
1764
+ - eql?
1765
+ - respond_to?
1766
+ - equal?
1767
+ Safe: false
1768
+
1749
1769
  Lint/RedundantSplatExpansion:
1750
1770
  Description: 'Checks for splat unnecessarily being called on literals.'
1751
1771
  Enabled: true
@@ -2702,6 +2722,16 @@ Style/ClassCheck:
2702
2722
  - is_a?
2703
2723
  - kind_of?
2704
2724
 
2725
+ Style/ClassEqualityComparison:
2726
+ Description: 'Enforces the use of `Object#instance_of?` instead of class comparison for equality.'
2727
+ StyleGuide: '#instance-of-vs-class-comparison'
2728
+ Enabled: pending
2729
+ VersionAdded: '0.93'
2730
+ IgnoredMethods:
2731
+ - ==
2732
+ - equal?
2733
+ - eql?
2734
+
2705
2735
  Style/ClassMethods:
2706
2736
  Description: 'Use self when defining module/class methods.'
2707
2737
  StyleGuide: '#def-self-class-methods'
@@ -105,7 +105,6 @@ require_relative 'rubocop/cop/mixin/percent_literal'
105
105
  require_relative 'rubocop/cop/mixin/preceding_following_alignment'
106
106
  require_relative 'rubocop/cop/mixin/preferred_delimiters'
107
107
  require_relative 'rubocop/cop/mixin/rational_literal'
108
- require_relative 'rubocop/cop/mixin/regexp_literal_help'
109
108
  require_relative 'rubocop/cop/mixin/rescue_node'
110
109
  require_relative 'rubocop/cop/mixin/safe_assignment'
111
110
  require_relative 'rubocop/cop/mixin/space_after_punctuation'
@@ -279,6 +278,7 @@ require_relative 'rubocop/cop/lint/flip_flop'
279
278
  require_relative 'rubocop/cop/lint/float_comparison'
280
279
  require_relative 'rubocop/cop/lint/float_out_of_range'
281
280
  require_relative 'rubocop/cop/lint/format_parameter_mismatch'
281
+ require_relative 'rubocop/cop/lint/hash_compare_by_identity'
282
282
  require_relative 'rubocop/cop/lint/heredoc_method_call_position'
283
283
  require_relative 'rubocop/cop/lint/identity_comparison'
284
284
  require_relative 'rubocop/cop/lint/implicit_string_concatenation'
@@ -308,6 +308,7 @@ require_relative 'rubocop/cop/lint/rand_one'
308
308
  require_relative 'rubocop/cop/lint/redundant_cop_disable_directive'
309
309
  require_relative 'rubocop/cop/lint/redundant_cop_enable_directive'
310
310
  require_relative 'rubocop/cop/lint/redundant_require_statement'
311
+ require_relative 'rubocop/cop/lint/redundant_safe_navigation'
311
312
  require_relative 'rubocop/cop/lint/redundant_splat_expansion'
312
313
  require_relative 'rubocop/cop/lint/redundant_string_coercion'
313
314
  require_relative 'rubocop/cop/lint/redundant_with_index'
@@ -398,6 +399,7 @@ require_relative 'rubocop/cop/style/case_like_if'
398
399
  require_relative 'rubocop/cop/style/character_literal'
399
400
  require_relative 'rubocop/cop/style/class_and_module_children'
400
401
  require_relative 'rubocop/cop/style/class_check'
402
+ require_relative 'rubocop/cop/style/class_equality_comparison'
401
403
  require_relative 'rubocop/cop/style/class_methods'
402
404
  require_relative 'rubocop/cop/style/class_methods_definitions'
403
405
  require_relative 'rubocop/cop/style/class_vars'
@@ -21,6 +21,7 @@ module RuboCop
21
21
  private
22
22
 
23
23
  def serialize_offense(offense)
24
+ status = :uncorrected if %i[corrected corrected_with_todo].include?(offense.status)
24
25
  {
25
26
  # Calling #to_s here ensures that the serialization works when using
26
27
  # other json serializers such as Oj. Some of these gems do not call
@@ -32,7 +33,7 @@ module RuboCop
32
33
  },
33
34
  message: message(offense),
34
35
  cop_name: offense.cop_name,
35
- status: :uncorrected
36
+ status: status || offense.status
36
37
  }
37
38
  end
38
39
 
@@ -52,8 +52,8 @@ module RuboCop
52
52
  end
53
53
 
54
54
  def semicolon(node)
55
- @semicolon ||= {}
56
- @semicolon[node.object_id] ||= processed_source.tokens_within(node).find(&:semicolon?)
55
+ @semicolon ||= {}.compare_by_identity
56
+ @semicolon[node] ||= processed_source.tokens_within(node).find(&:semicolon?)
57
57
  end
58
58
  end
59
59
  end
@@ -58,24 +58,22 @@ module RuboCop
58
58
  (send _ :required_ruby_version= $_)
59
59
  PATTERN
60
60
 
61
- def_node_matcher :string_version?, <<~PATTERN
62
- {(str _) (array (str _))}
61
+ def_node_matcher :defined_ruby_version, <<~PATTERN
62
+ {$(str _) $(array (str _) (str _))
63
+ (send (const (const nil? :Gem) :Requirement) :new $(str _))}
63
64
  PATTERN
64
65
 
65
66
  # rubocop:disable Metrics/AbcSize
66
67
  def investigate(processed_source)
67
- version = required_ruby_version(processed_source.ast).first
68
+ version_def = required_ruby_version(processed_source.ast).first
68
69
 
69
- if version
70
- return unless string_version?(version)
71
-
72
- ruby_version = extract_ruby_version(version)
73
-
74
- return if ruby_version == target_ruby_version.to_s
70
+ if version_def
71
+ ruby_version = extract_ruby_version(defined_ruby_version(version_def))
72
+ return if !ruby_version || ruby_version == target_ruby_version.to_s
75
73
 
76
74
  add_offense(
77
75
  processed_source.ast,
78
- location: version.loc.expression,
76
+ location: version_def.loc.expression,
79
77
  message: not_equal_message(ruby_version, target_ruby_version)
80
78
  )
81
79
  else
@@ -88,6 +86,8 @@ module RuboCop
88
86
  private
89
87
 
90
88
  def extract_ruby_version(required_ruby_version)
89
+ return unless required_ruby_version
90
+
91
91
  if required_ruby_version.array_type?
92
92
  required_ruby_version = required_ruby_version.children.detect do |v|
93
93
  /[>=]/.match?(v.str_content)
@@ -29,17 +29,14 @@ module RuboCop
29
29
  def on_send(node)
30
30
  return unless node.dot? || ampersand_dot?(node)
31
31
 
32
- if proper_dot_position?(node)
33
- correct_style_detected
34
- else
35
- return unless opposite_style_detected
32
+ return correct_style_detected if proper_dot_position?(node)
36
33
 
37
- dot = node.loc.dot
38
- message = message(dot)
34
+ opposite_style_detected
35
+ dot = node.loc.dot
36
+ message = message(dot)
39
37
 
40
- add_offense(dot, message: message) do |corrector|
41
- autocorrect(corrector, dot, node)
42
- end
38
+ add_offense(dot, message: message) do |corrector|
39
+ autocorrect(corrector, dot, node)
43
40
  end
44
41
  end
45
42
  alias on_csend on_send
@@ -84,7 +84,8 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def on_send(node)
87
- return unless register_offense?(node)
87
+ return unless node.bare_access_modifier? && !node.parent&.block_type?
88
+ return if expected_empty_lines?(node)
88
89
 
89
90
  message = message(node)
90
91
  add_offense(node, message: message) do |corrector|
@@ -98,17 +99,15 @@ module RuboCop
98
99
 
99
100
  private
100
101
 
101
- def register_offense?(node)
102
- return false unless node.bare_access_modifier? && !node.parent.block_type?
103
-
102
+ def expected_empty_lines?(node)
104
103
  case style
105
104
  when :around
106
- return false if empty_lines_around?(node)
105
+ return true if empty_lines_around?(node)
107
106
  when :only_before
108
- return false if allowed_only_before_style?(node)
107
+ return true if allowed_only_before_style?(node)
109
108
  end
110
109
 
111
- true
110
+ false
112
111
  end
113
112
 
114
113
  def allowed_only_before_style?(node)
@@ -88,7 +88,7 @@ module RuboCop
88
88
  end
89
89
 
90
90
  def require_empty_line?(node)
91
- return false unless node&.respond_to?(:type)
91
+ return false unless node.respond_to?(:type)
92
92
 
93
93
  !allow_alias?(node) && !attribute_or_allowed_method?(node)
94
94
  end
@@ -51,22 +51,13 @@ module RuboCop
51
51
  style == :no_space && no_surrounding_space
52
52
  correct_style_detected
53
53
  else
54
- incorrect_style_detected(arg, value, space_on_both_sides,
55
- no_surrounding_space)
54
+ incorrect_style_detected(arg, value)
56
55
  end
57
56
  end
58
57
 
59
- def incorrect_style_detected(arg, value, space_on_both_sides,
60
- no_surrounding_space)
58
+ def incorrect_style_detected(arg, value)
61
59
  range = range_between(arg.end_pos, value.begin_pos)
62
60
 
63
- if style == :space && no_surrounding_space ||
64
- style == :no_space && space_on_both_sides
65
- return unless opposite_style_detected
66
- else
67
- return unless unrecognized_style_detected
68
- end
69
-
70
61
  add_offense(range) do |corrector|
71
62
  autocorrect(corrector, range)
72
63
  end
@@ -206,8 +206,6 @@ module RuboCop
206
206
 
207
207
  def no_space(begin_pos, end_pos, msg)
208
208
  if style == :space
209
- return unless opposite_style_detected
210
-
211
209
  offense(begin_pos, end_pos, msg)
212
210
  else
213
211
  correct_style_detected
@@ -216,8 +214,6 @@ module RuboCop
216
214
 
217
215
  def space(begin_pos, end_pos, msg)
218
216
  if style == :no_space
219
- return unless opposite_style_detected
220
-
221
217
  offense(begin_pos, end_pos, msg)
222
218
  else
223
219
  correct_style_detected
@@ -15,6 +15,8 @@ module RuboCop
15
15
  #
16
16
  # # good
17
17
  # # With parentheses, there's no ambiguity.
18
+ # some_method(a { |val| puts val })
19
+ # # or (different meaning)
18
20
  # some_method(a) { |val| puts val }
19
21
  #
20
22
  # # good
@@ -47,7 +47,24 @@ module RuboCop
47
47
  regexp_node.source_range.begin_pos == diagnostic.location.begin_pos
48
48
  end
49
49
 
50
- node.parent
50
+ find_offense_node(node.parent, node)
51
+ end
52
+
53
+ def find_offense_node(node, regexp_receiver)
54
+ return node unless node.parent
55
+
56
+ if node.parent.send_type? || method_chain_to_regexp_receiver?(node, regexp_receiver)
57
+ node = find_offense_node(node.parent, regexp_receiver)
58
+ end
59
+
60
+ node
61
+ end
62
+
63
+ def method_chain_to_regexp_receiver?(node, regexp_receiver)
64
+ return false unless (parent = node.parent)
65
+ return false unless (parent_receiver = parent.receiver)
66
+
67
+ parent.parent && parent_receiver.receiver == regexp_receiver
51
68
  end
52
69
  end
53
70
  end
@@ -32,6 +32,9 @@ module RuboCop
32
32
  def on_sym(node)
33
33
  return unless boolean_symbol?(node)
34
34
 
35
+ parent = node.parent
36
+ return if parent&.array_type? && parent&.percent_literal?(:symbol)
37
+
35
38
  add_offense(node, message: format(MSG, boolean: node.value)) do |corrector|
36
39
  autocorrect(corrector, node)
37
40
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Prefer using `Hash#compare_by_identity` than using `object_id` for hash keys.
7
+ #
8
+ # This cop is marked as unsafe as a hash possibly can contain other keys
9
+ # besides `object_id`s.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # hash = {}
14
+ # hash[foo.object_id] = :bar
15
+ # hash.key?(baz.object_id)
16
+ #
17
+ # # good
18
+ # hash = {}.compare_by_identity
19
+ # hash[foo] = :bar
20
+ # hash.key?(baz)
21
+ #
22
+ class HashCompareByIdentity < Base
23
+ RESTRICT_ON_SEND = %i[key? has_key? fetch [] []=].freeze
24
+
25
+ MSG = 'Use `Hash#compare_by_identity` instead of using `object_id` for keys.'
26
+
27
+ def_node_matcher :id_as_hash_key?, <<~PATTERN
28
+ (send _ {:key? :has_key? :fetch :[] :[]=} (send _ :object_id) ...)
29
+ PATTERN
30
+
31
+ def on_send(node)
32
+ add_offense(node) if id_as_hash_key?(node)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -25,6 +25,7 @@ module RuboCop
25
25
  'in a Regexp literal.'
26
26
 
27
27
  def on_regexp(node)
28
+ return if node.interpolation?
28
29
  return if node.each_capture(named: false).none?
29
30
  return if node.each_capture(named: true).none?
30
31
 
@@ -43,7 +43,7 @@ module RuboCop
43
43
  end
44
44
 
45
45
  node.operator_method? || node.setter_method? || chained_calls?(node) ||
46
- operator_keyword?(node)
46
+ operator_keyword?(node) || node.first_argument.hash_type?
47
47
  end
48
48
 
49
49
  def first_argument_starts_with_left_parenthesis?(node)
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for redundant safe navigation calls.
7
+ # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
+ # are checked by default. These are customizable with `AllowedMethods` option.
9
+ #
10
+ # This cop is marked as unsafe, because auto-correction can change the
11
+ # return type of the expression. An offending expression that previously
12
+ # could return `nil` will be auto-corrected to never return `nil`.
13
+ #
14
+ # In the example below, the safe navigation operator (`&.`) is unnecessary
15
+ # because `NilClass` has methods like `respond_to?` and `is_a?`.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # do_something if attrs&.respond_to?(:[])
20
+ #
21
+ # # good
22
+ # do_something if attrs.respond_to?(:[])
23
+ #
24
+ # # bad
25
+ # while node&.is_a?(BeginNode)
26
+ # node = node.parent
27
+ # end
28
+ #
29
+ # # good
30
+ # while node.is_a?(BeginNode)
31
+ # node = node.parent
32
+ # end
33
+ #
34
+ # # good - without `&.` this will always return `true`
35
+ # foo&.respond_to?(:to_a)
36
+ #
37
+ class RedundantSafeNavigation < Base
38
+ include AllowedMethods
39
+ include RangeHelp
40
+ extend AutoCorrector
41
+
42
+ MSG = 'Redundant safe navigation detected.'
43
+
44
+ NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
45
+
46
+ def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
47
+ (csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
48
+ PATTERN
49
+
50
+ def on_csend(node)
51
+ return unless check?(node) && allowed_method?(node.method_name)
52
+ return if respond_to_nil_specific_method?(node)
53
+
54
+ range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
55
+ add_offense(range) do |corrector|
56
+ corrector.replace(node.loc.dot, '.')
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def check?(node)
63
+ parent = node.parent
64
+ return false unless parent
65
+
66
+ condition?(parent, node) ||
67
+ parent.and_type? ||
68
+ parent.or_type? ||
69
+ (parent.send_type? && parent.negation_method?)
70
+ end
71
+
72
+ def condition?(parent, node)
73
+ (parent.conditional? || parent.post_condition_loop?) && parent.condition == node
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end