rubocop 1.40.0 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +44 -1
  5. data/lib/rubocop/cli.rb +1 -1
  6. data/lib/rubocop/config.rb +34 -11
  7. data/lib/rubocop/config_loader.rb +9 -0
  8. data/lib/rubocop/config_loader_resolver.rb +5 -1
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/badge.rb +9 -4
  11. data/lib/rubocop/cop/base.rb +83 -66
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +29 -29
  14. data/lib/rubocop/cop/corrector.rb +23 -11
  15. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  16. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  17. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  19. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  20. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  21. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  22. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  23. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  24. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  25. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  26. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  27. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  28. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  29. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  30. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  31. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  32. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  33. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  34. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  35. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  36. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  38. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  39. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  40. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  41. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  42. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  43. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
  45. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  46. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  47. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  48. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -19
  49. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  50. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
  51. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  52. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  53. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  54. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
  55. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  56. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  57. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  58. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  59. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  60. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  61. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -1
  62. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  63. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  64. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  65. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  66. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  67. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  68. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  69. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  70. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  71. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  72. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  73. data/lib/rubocop/cop/registry.rb +28 -25
  74. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  75. data/lib/rubocop/cop/style/alias.rb +9 -1
  76. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  77. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  78. data/lib/rubocop/cop/style/documentation.rb +11 -5
  79. data/lib/rubocop/cop/style/guard_clause.rb +17 -9
  80. data/lib/rubocop/cop/style/hash_syntax.rb +10 -7
  81. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  82. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -3
  83. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  84. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  85. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  86. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  87. data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
  88. data/lib/rubocop/cop/style/redundant_constant_base.rb +13 -0
  89. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  90. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  91. data/lib/rubocop/cop/style/require_order.rb +63 -9
  92. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
  93. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  94. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  95. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  96. data/lib/rubocop/cop/style/word_array.rb +41 -0
  97. data/lib/rubocop/cop/style/yoda_expression.rb +74 -0
  98. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  99. data/lib/rubocop/cop/team.rb +29 -29
  100. data/lib/rubocop/cop/util.rb +31 -4
  101. data/lib/rubocop/cop/variable_force.rb +0 -3
  102. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  103. data/lib/rubocop/directive_comment.rb +1 -1
  104. data/lib/rubocop/file_patterns.rb +43 -0
  105. data/lib/rubocop/formatter.rb +2 -0
  106. data/lib/rubocop/options.rb +1 -1
  107. data/lib/rubocop/path_util.rb +26 -15
  108. data/lib/rubocop/result_cache.rb +1 -1
  109. data/lib/rubocop/runner.rb +10 -3
  110. data/lib/rubocop/target_finder.rb +1 -1
  111. data/lib/rubocop/target_ruby.rb +0 -1
  112. data/lib/rubocop/version.rb +1 -1
  113. data/lib/rubocop.rb +6 -1
  114. metadata +15 -10
  115. data/lib/rubocop/optimized_patterns.rb +0 -38
@@ -36,6 +36,33 @@ module RuboCop
36
36
  # require 'b'
37
37
  # require_relative 'c'
38
38
  # require 'a'
39
+ #
40
+ # # bad
41
+ # require 'a'
42
+ # require 'c' if foo
43
+ # require 'b'
44
+ #
45
+ # # good
46
+ # require 'a'
47
+ # require 'b'
48
+ # require 'c' if foo
49
+ #
50
+ # # bad
51
+ # require 'c'
52
+ # if foo
53
+ # require 'd'
54
+ # require 'b'
55
+ # end
56
+ # require 'a'
57
+ #
58
+ # # good
59
+ # require 'c'
60
+ # if foo
61
+ # require 'b'
62
+ # require 'd'
63
+ # end
64
+ # require 'a'
65
+ #
39
66
  class RequireOrder < Base
40
67
  extend AutoCorrector
41
68
 
@@ -43,17 +70,27 @@ module RuboCop
43
70
 
44
71
  RESTRICT_ON_SEND = %i[require require_relative].freeze
45
72
 
73
+ MSG = 'Sort `%<name>s` in alphabetical order.'
74
+
75
+ # @!method if_inside_only_require(node)
76
+ def_node_matcher :if_inside_only_require, <<~PATTERN
77
+ {
78
+ (if _ _ $(send nil? {:require :require_relative} _))
79
+ (if _ $(send nil? {:require :require_relative} _) _)
80
+ }
81
+ PATTERN
82
+
46
83
  def on_send(node)
84
+ return unless node.parent && node.arguments?
85
+ return if not_modifier_form?(node.parent)
86
+
47
87
  previous_older_sibling = find_previous_older_sibling(node)
48
88
  return unless previous_older_sibling
49
89
 
50
- add_offense(
51
- node,
52
- message: "Sort `#{node.method_name}` in alphabetical order."
53
- ) do |corrector|
90
+ add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
54
91
  swap(
55
92
  range_with_comments_and_lines(previous_older_sibling),
56
- range_with_comments_and_lines(node),
93
+ range_with_comments_and_lines(node.parent.if_type? ? node.parent : node),
57
94
  corrector: corrector
58
95
  )
59
96
  end
@@ -61,16 +98,33 @@ module RuboCop
61
98
 
62
99
  private
63
100
 
64
- def find_previous_older_sibling(node)
65
- node.left_siblings.reverse.find do |sibling|
66
- break unless sibling.send_type?
67
- break unless sibling.method?(node.method_name)
101
+ def not_modifier_form?(node)
102
+ node.if_type? && !node.modifier_form?
103
+ end
104
+
105
+ def find_previous_older_sibling(node) # rubocop:disable Metrics
106
+ search_node(node).left_siblings.reverse.find do |sibling|
107
+ next unless sibling.is_a?(AST::Node)
108
+
109
+ sibling = sibling_node(sibling)
110
+ break unless sibling&.send_type? && sibling&.method?(node.method_name)
111
+ break unless sibling.arguments? && !sibling.receiver
68
112
  break unless in_same_section?(sibling, node)
69
113
 
70
114
  node.first_argument.source < sibling.first_argument.source
71
115
  end
72
116
  end
73
117
 
118
+ def search_node(node)
119
+ node.parent.if_type? ? node.parent : node
120
+ end
121
+
122
+ def sibling_node(node)
123
+ return if not_modifier_form?(node)
124
+
125
+ node.if_type? ? if_inside_only_require(node) : node
126
+ end
127
+
74
128
  def in_same_section?(node1, node2)
75
129
  !node1.location.expression.with(
76
130
  end_pos: node2.location.expression.end_pos
@@ -86,12 +86,12 @@ module RuboCop
86
86
 
87
87
  def on_send(node)
88
88
  return unless (block_node = node.block_node)
89
- return if block_node.body.begin_type?
89
+ return if block_node.body&.begin_type?
90
90
  return if receiver_allowed?(block_node.receiver)
91
91
  return unless (regexp_method_send_node = extract_send_node(block_node))
92
92
  return if match_predicate_without_receiver?(regexp_method_send_node)
93
93
 
94
- opposite = regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
94
+ opposite = opposite?(regexp_method_send_node)
95
95
  regexp = find_regexp(regexp_method_send_node, block_node)
96
96
 
97
97
  register_offense(node, block_node, regexp, opposite)
@@ -128,6 +128,10 @@ module RuboCop
128
128
  regexp_method_send_node
129
129
  end
130
130
 
131
+ def opposite?(regexp_method_send_node)
132
+ regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
133
+ end
134
+
131
135
  def find_regexp(node, block)
132
136
  return node.child_nodes.first if node.match_with_lvasgn_type?
133
137
 
@@ -37,13 +37,14 @@ module RuboCop
37
37
  end
38
38
 
39
39
  def on_new_investigation
40
- return if processed_source.blank?
40
+ return if processed_source.blank? || !processed_source.raw_source.include?(';')
41
41
 
42
42
  check_for_line_terminator_or_opener
43
43
  end
44
44
 
45
45
  def on_begin(node)
46
46
  return if cop_config['AllowAsExpressionSeparator']
47
+ return unless node.source.include?(';')
47
48
 
48
49
  exprs = node.children
49
50
 
@@ -119,11 +119,6 @@ module RuboCop
119
119
  # @!method custom_fail_methods(node)
120
120
  def_node_search :custom_fail_methods, '{(def :fail ...) (defs _ :fail ...)}'
121
121
 
122
- def on_new_investigation
123
- ast = processed_source.ast
124
- @custom_fail_defined = ast && custom_fail_methods(ast).any?
125
- end
126
-
127
122
  def on_rescue(node)
128
123
  return unless style == :semantic
129
124
 
@@ -141,7 +136,7 @@ module RuboCop
141
136
  when :semantic
142
137
  check_send(:raise, node) unless ignored_node?(node)
143
138
  when :only_raise
144
- return if @custom_fail_defined
139
+ return if custom_fail_defined?
145
140
 
146
141
  check_send(:fail, node)
147
142
  when :only_fail
@@ -151,6 +146,13 @@ module RuboCop
151
146
 
152
147
  private
153
148
 
149
+ def custom_fail_defined?
150
+ return @custom_fail_defined if defined?(@custom_fail_defined)
151
+
152
+ ast = processed_source.ast
153
+ @custom_fail_defined = ast && custom_fail_methods(ast).any?
154
+ end
155
+
154
156
  def message(method_name)
155
157
  case style
156
158
  when :semantic
@@ -88,6 +88,10 @@ module RuboCop
88
88
  include TrailingComma
89
89
  extend AutoCorrector
90
90
 
91
+ def self.autocorrect_incompatible_with
92
+ [Layout::HeredocArgumentClosingParenthesis]
93
+ end
94
+
91
95
  def on_send(node)
92
96
  return unless node.arguments? && node.parenthesized?
93
97
 
@@ -96,10 +100,6 @@ module RuboCop
96
100
  node.source_range.end_pos)
97
101
  end
98
102
  alias on_csend on_send
99
-
100
- def self.autocorrect_incompatible_with
101
- [Layout::HeredocArgumentClosingParenthesis]
102
- end
103
103
  end
104
104
  end
105
105
  end
@@ -27,6 +27,25 @@ module RuboCop
27
27
  # # bad (contains spaces)
28
28
  # %w[foo\ bar baz\ quux]
29
29
  #
30
+ # # bad
31
+ # [
32
+ # ['one', 'One'],
33
+ # ['two', 'Two']
34
+ # ]
35
+ #
36
+ # # good
37
+ # [
38
+ # %w[one One],
39
+ # %w[two Two]
40
+ # ]
41
+ #
42
+ # # good (2d array containing spaces)
43
+ # [
44
+ # ['one', 'One'],
45
+ # ['two', 'Two'],
46
+ # ['forty two', 'Forty Two']
47
+ # ]
48
+ #
30
49
  # @example EnforcedStyle: brackets
31
50
  # # good
32
51
  # ['foo', 'bar', 'baz']
@@ -36,6 +55,19 @@ module RuboCop
36
55
  #
37
56
  # # good (contains spaces)
38
57
  # ['foo bar', 'baz quux']
58
+ #
59
+ # # good
60
+ # [
61
+ # ['one', 'One'],
62
+ # ['two', 'Two']
63
+ # ]
64
+ #
65
+ # # bad
66
+ # [
67
+ # %w[one One],
68
+ # %w[two Two]
69
+ # ]
70
+ #
39
71
  class WordArray < Base
40
72
  include ArrayMinSize
41
73
  include ArraySyntax
@@ -53,6 +85,7 @@ module RuboCop
53
85
  def on_array(node)
54
86
  if bracketed_array_of?(:str, node)
55
87
  return if complex_content?(node.values)
88
+ return if within_2d_array_of_complex_content?(node)
56
89
 
57
90
  check_bracketed_array(node, 'w')
58
91
  elsif node.percent_literal?(:string)
@@ -62,6 +95,14 @@ module RuboCop
62
95
 
63
96
  private
64
97
 
98
+ def within_2d_array_of_complex_content?(node)
99
+ return false unless (parent = node.parent)
100
+
101
+ parent.array_type? &&
102
+ parent.values.all?(&:array_type?) &&
103
+ parent.values.any? { |subarray| complex_content?(subarray.values) }
104
+ end
105
+
65
106
  def complex_content?(strings, complex_regex: word_regex)
66
107
  strings.any? do |s|
67
108
  next unless s.str_content
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Forbids Yoda expressions, i.e. binary operations (using `*`, `+`, `&`, `|`,
7
+ # and `^` operators) where the order of expression is reversed, eg. `1 + x`.
8
+ # This cop complements `Style/YodaCondition` cop, which has a similar purpose.
9
+ #
10
+ # @safety
11
+ # This cop is unsafe because binary operators can be defined
12
+ # differently on different classes, and are not guaranteed to
13
+ # have the same result if reversed.
14
+ #
15
+ # @example SupportedOperators: ['*', '+', '&'']
16
+ # # bad
17
+ # 1 + x
18
+ # 10 * y
19
+ # 1 & z
20
+ #
21
+ # # good
22
+ # 60 * 24
23
+ # x + 1
24
+ # y * 10
25
+ # z & 1
26
+ #
27
+ # # good
28
+ # 1 | x
29
+ #
30
+ class YodaExpression < Base
31
+ extend AutoCorrector
32
+
33
+ MSG = 'Non-literal operand (`%<source>s`) should be first.'
34
+
35
+ RESTRICT_ON_SEND = %i[* + & | ^].freeze
36
+
37
+ def on_new_investigation
38
+ @offended_nodes = nil
39
+ end
40
+
41
+ def on_send(node)
42
+ return unless supported_operators.include?(node.method_name.to_s)
43
+
44
+ lhs = node.receiver
45
+ rhs = node.first_argument
46
+ return if !lhs.numeric_type? || rhs.numeric_type?
47
+
48
+ return if offended_ancestor?(node)
49
+
50
+ message = format(MSG, source: rhs.source)
51
+ add_offense(node, message: message) do |corrector|
52
+ corrector.swap(lhs, rhs)
53
+ end
54
+
55
+ offended_nodes.add(node)
56
+ end
57
+
58
+ private
59
+
60
+ def supported_operators
61
+ Array(cop_config['SupportedOperators'])
62
+ end
63
+
64
+ def offended_ancestor?(node)
65
+ node.each_ancestor(:send).any? { |ancestor| @offended_nodes&.include?(ancestor) }
66
+ end
67
+
68
+ def offended_nodes
69
+ @offended_nodes ||= Set.new.compare_by_identity
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -34,43 +34,55 @@ module RuboCop
34
34
  class ZeroLengthPredicate < Base
35
35
  extend AutoCorrector
36
36
 
37
- ZERO_MSG = 'Use `empty?` instead of `%<lhs>s %<opr>s %<rhs>s`.'
38
- NONZERO_MSG = 'Use `!empty?` instead of `%<lhs>s %<opr>s %<rhs>s`.'
37
+ ZERO_MSG = 'Use `empty?` instead of `%<current>s`.'
38
+ NONZERO_MSG = 'Use `!empty?` instead of `%<current>s`.'
39
39
 
40
40
  RESTRICT_ON_SEND = %i[size length].freeze
41
41
 
42
42
  def on_send(node)
43
43
  check_zero_length_predicate(node)
44
- check_nonzero_length_predicate(node)
44
+ check_zero_length_comparison(node)
45
+ check_nonzero_length_comparison(node)
45
46
  end
46
47
 
47
48
  private
48
49
 
49
50
  def check_zero_length_predicate(node)
50
- zero_length_predicate = zero_length_predicate(node.parent)
51
- return unless zero_length_predicate
51
+ return unless (length_method = zero_length_predicate(node.parent))
52
52
 
53
- lhs, opr, rhs = zero_length_predicate
53
+ offense = node.loc.selector.join(node.parent.source_range.end)
54
+ message = format(ZERO_MSG, current: "#{length_method}.zero?")
55
+
56
+ add_offense(offense, message: message) do |corrector|
57
+ corrector.replace(offense, 'empty?')
58
+ end
59
+ end
60
+
61
+ def check_zero_length_comparison(node)
62
+ zero_length_comparison = zero_length_comparison(node.parent)
63
+ return unless zero_length_comparison
64
+
65
+ lhs, opr, rhs = zero_length_comparison
54
66
 
55
67
  return if non_polymorphic_collection?(node.parent)
56
68
 
57
69
  add_offense(
58
- node.parent, message: format(ZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
70
+ node.parent, message: format(ZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
59
71
  ) do |corrector|
60
72
  corrector.replace(node.parent, replacement(node.parent))
61
73
  end
62
74
  end
63
75
 
64
- def check_nonzero_length_predicate(node)
65
- nonzero_length_predicate = nonzero_length_predicate(node.parent)
66
- return unless nonzero_length_predicate
76
+ def check_nonzero_length_comparison(node)
77
+ nonzero_length_comparison = nonzero_length_comparison(node.parent)
78
+ return unless nonzero_length_comparison
67
79
 
68
- lhs, opr, rhs = nonzero_length_predicate
80
+ lhs, opr, rhs = nonzero_length_comparison
69
81
 
70
82
  return if non_polymorphic_collection?(node.parent)
71
83
 
72
84
  add_offense(
73
- node.parent, message: format(NONZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
85
+ node.parent, message: format(NONZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
74
86
  ) do |corrector|
75
87
  corrector.replace(node.parent, replacement(node.parent))
76
88
  end
@@ -78,14 +90,19 @@ module RuboCop
78
90
 
79
91
  # @!method zero_length_predicate(node)
80
92
  def_node_matcher :zero_length_predicate, <<~PATTERN
93
+ (send (send (...) ${:length :size}) :zero?)
94
+ PATTERN
95
+
96
+ # @!method zero_length_comparison(node)
97
+ def_node_matcher :zero_length_comparison, <<~PATTERN
81
98
  {(send (send (...) ${:length :size}) $:== (int $0))
82
99
  (send (int $0) $:== (send (...) ${:length :size}))
83
100
  (send (send (...) ${:length :size}) $:< (int $1))
84
101
  (send (int $1) $:> (send (...) ${:length :size}))}
85
102
  PATTERN
86
103
 
87
- # @!method nonzero_length_predicate(node)
88
- def_node_matcher :nonzero_length_predicate, <<~PATTERN
104
+ # @!method nonzero_length_comparison(node)
105
+ def_node_matcher :nonzero_length_comparison, <<~PATTERN
89
106
  {(send (send (...) ${:length :size}) ${:> :!=} (int $0))
90
107
  (send (int $0) ${:< :!=} (send (...) ${:length :size}))}
91
108
  PATTERN
@@ -10,20 +10,6 @@ module RuboCop
10
10
  # first the ones needed for autocorrection (if any), then the rest
11
11
  # (unless autocorrections happened).
12
12
  class Team
13
- attr_reader :errors, :warnings, :updated_source_file, :cops
14
-
15
- alias updated_source_file? updated_source_file
16
-
17
- def initialize(cops, config = nil, options = {})
18
- @cops = cops
19
- @config = config
20
- @options = options
21
- reset
22
- @ready = true
23
-
24
- validate_config
25
- end
26
-
27
13
  # @return [Team]
28
14
  def self.new(cop_or_classes, config, options = {})
29
15
  # Support v0 api:
@@ -47,6 +33,35 @@ module RuboCop
47
33
  end
48
34
  end
49
35
 
36
+ # @return [Array<Force>] needed for the given cops
37
+ def self.forces_for(cops)
38
+ needed = Hash.new { |h, k| h[k] = [] }
39
+ cops.each do |cop|
40
+ forces = cop.class.joining_forces
41
+ if forces.is_a?(Array)
42
+ forces.each { |force| needed[force] << cop }
43
+ elsif forces
44
+ needed[forces] << cop
45
+ end
46
+ end
47
+
48
+ needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
49
+ end
50
+
51
+ attr_reader :errors, :warnings, :updated_source_file, :cops
52
+
53
+ alias updated_source_file? updated_source_file
54
+
55
+ def initialize(cops, config = nil, options = {})
56
+ @cops = cops
57
+ @config = config
58
+ @options = options
59
+ reset
60
+ @ready = true
61
+
62
+ validate_config
63
+ end
64
+
50
65
  def autocorrect?
51
66
  @options[:autocorrect]
52
67
  end
@@ -94,21 +109,6 @@ module RuboCop
94
109
  @forces ||= self.class.forces_for(cops)
95
110
  end
96
111
 
97
- # @return [Array<Force>] needed for the given cops
98
- def self.forces_for(cops)
99
- needed = Hash.new { |h, k| h[k] = [] }
100
- cops.each do |cop|
101
- forces = cop.class.joining_forces
102
- if forces.is_a?(Array)
103
- forces.each { |force| needed[force] << cop }
104
- elsif forces
105
- needed[forces] << cop
106
- end
107
- end
108
-
109
- needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
110
- end
111
-
112
112
  def external_dependency_checksum
113
113
  keys = cops.map(&:external_dependency_checksum).compact
114
114
  Digest::SHA1.hexdigest(keys.join)
@@ -52,6 +52,21 @@ module RuboCop
52
52
  end
53
53
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
54
54
 
55
+ def any_descendant?(node, *types)
56
+ if block_given?
57
+ node.each_descendant(*types) do |descendant|
58
+ return true if yield(descendant)
59
+ end
60
+ else
61
+ # Use a block version to avoid allocating enumerators.
62
+ node.each_descendant do # rubocop:disable Lint/UnreachableLoop
63
+ return true
64
+ end
65
+ end
66
+
67
+ false
68
+ end
69
+
55
70
  def args_begin(node)
56
71
  loc = node.loc
57
72
  selector = if node.super_type? || node.yield_type?
@@ -71,14 +86,19 @@ module RuboCop
71
86
  def on_node(syms, sexp, excludes = [], &block)
72
87
  return to_enum(:on_node, syms, sexp, excludes) unless block
73
88
 
74
- yield sexp if Array(syms).include?(sexp.type)
75
- return if Array(excludes).include?(sexp.type)
89
+ yield sexp if include_or_equal?(syms, sexp.type)
90
+ return if include_or_equal?(excludes, sexp.type)
76
91
 
77
92
  sexp.each_child_node { |elem| on_node(syms, elem, excludes, &block) }
78
93
  end
79
94
 
95
+ LINE_BEGINS_REGEX_CACHE = Hash.new do |hash, index|
96
+ hash[index] = /^\s{#{index}}\S/
97
+ end
98
+ private_constant :LINE_BEGINS_REGEX_CACHE
99
+
80
100
  def begins_its_line?(range)
81
- range.source_line.index(/\S/) == range.column
101
+ range.source_line.match?(LINE_BEGINS_REGEX_CACHE[range.column])
82
102
  end
83
103
 
84
104
  # Returns, for example, a bare `if` node if the given node is an `if`
@@ -152,8 +172,11 @@ module RuboCop
152
172
  ' ' * (node.loc.column + offset)
153
173
  end
154
174
 
175
+ @to_supported_styles_cache = {}
176
+
155
177
  def to_supported_styles(enforced_style)
156
- enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
178
+ @to_supported_styles_cache[enforced_style] ||=
179
+ enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
157
180
  end
158
181
 
159
182
  private
@@ -162,6 +185,10 @@ module RuboCop
162
185
  src = src.dup if RUBY_ENGINE == 'jruby'
163
186
  src.force_encoding(Encoding.default_external).valid_encoding?
164
187
  end
188
+
189
+ def include_or_equal?(source, target)
190
+ source == target || (source.is_a?(Array) && source.include?(target))
191
+ end
165
192
  end
166
193
  end
167
194
  end
@@ -108,7 +108,6 @@ module RuboCop
108
108
  :skip_children
109
109
  end
110
110
 
111
- # rubocop:disable Layout/ClassStructure
112
111
  NODE_HANDLER_METHOD_NAMES = [
113
112
  [VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment],
114
113
  [REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures],
@@ -123,8 +122,6 @@ module RuboCop
123
122
  *SCOPE_TYPES.product([:process_scope])
124
123
  ].to_h.freeze
125
124
  private_constant :NODE_HANDLER_METHOD_NAMES
126
- # rubocop:enable Layout/ClassStructure
127
-
128
125
  def node_handler_method_name(node)
129
126
  NODE_HANDLER_METHOD_NAMES[node.type]
130
127
  end