rubocop 1.69.1 → 1.70.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 +19 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/config.rb +13 -4
  7. data/lib/rubocop/config_loader.rb +4 -0
  8. data/lib/rubocop/config_loader_resolver.rb +14 -3
  9. data/lib/rubocop/config_validator.rb +18 -8
  10. data/lib/rubocop/cop/autocorrect_logic.rb +31 -34
  11. data/lib/rubocop/cop/base.rb +6 -0
  12. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  13. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  15. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  16. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +4 -2
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -7
  19. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  20. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  21. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
  23. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  24. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -6
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  27. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  28. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  29. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  31. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +24 -0
  32. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  33. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  34. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  35. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  36. data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
  37. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  38. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +11 -3
  39. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  40. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -2
  41. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +6 -14
  42. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  43. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  44. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  45. data/lib/rubocop/cop/lint/void.rb +3 -2
  46. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  47. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
  49. data/lib/rubocop/cop/mixin/comments_help.rb +6 -1
  50. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  51. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  52. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +46 -22
  53. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  54. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  55. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  56. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  57. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  58. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
  59. data/lib/rubocop/cop/style/and_or.rb +1 -1
  60. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
  61. data/lib/rubocop/cop/style/block_delimiters.rb +8 -1
  62. data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
  63. data/lib/rubocop/cop/style/each_for_simple_loop.rb +3 -6
  64. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  65. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  66. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  67. data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -2
  68. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  69. data/lib/rubocop/cop/style/file_null.rb +20 -4
  70. data/lib/rubocop/cop/style/float_division.rb +8 -4
  71. data/lib/rubocop/cop/style/hash_except.rb +54 -67
  72. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  73. data/lib/rubocop/cop/style/if_with_semicolon.rb +6 -4
  74. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  75. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
  76. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  77. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -1
  78. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  79. data/lib/rubocop/cop/style/multiple_comparison.rb +34 -22
  80. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  81. data/lib/rubocop/cop/style/object_then.rb +13 -15
  82. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  83. data/lib/rubocop/cop/style/raise_args.rb +5 -3
  84. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  85. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  86. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  87. data/lib/rubocop/cop/style/redundant_line_continuation.rb +12 -9
  88. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -4
  89. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  90. data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
  91. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  92. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  93. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  94. data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
  95. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  96. data/lib/rubocop/cop/style/super_arguments.rb +63 -15
  97. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  98. data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
  99. data/lib/rubocop/cop/util.rb +9 -2
  100. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  101. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  102. data/lib/rubocop/lsp/logger.rb +2 -2
  103. data/lib/rubocop/lsp/routes.rb +7 -23
  104. data/lib/rubocop/lsp/runtime.rb +15 -49
  105. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  106. data/lib/rubocop/magic_comment.rb +3 -3
  107. data/lib/rubocop/path_util.rb +11 -8
  108. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  109. data/lib/rubocop/runner.rb +5 -6
  110. data/lib/rubocop/target_ruby.rb +15 -0
  111. data/lib/rubocop/version.rb +1 -1
  112. data/lib/rubocop.rb +3 -0
  113. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  114. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  115. metadata +16 -8
@@ -55,12 +55,9 @@ module RuboCop
55
55
  return if node.each_descendant(:dstr).any?
56
56
 
57
57
  regexp_constructor(node) do |text|
58
- Regexp::Parser.parse(text.value)&.each_expression do |expr|
58
+ parse_regexp(text.value)&.each_expression do |expr|
59
59
  detect_offenses(text, expr)
60
60
  end
61
- rescue Regexp::Parser::ParserError
62
- # Upon encountering an invalid regular expression,
63
- # we aim to proceed and identify any remaining potential offenses.
64
61
  end
65
62
  end
66
63
 
@@ -113,7 +113,8 @@ module RuboCop
113
113
  end
114
114
 
115
115
  def check_expression(expr)
116
- expr = expr.body if expr.if_type? && expr.modifier_form?
116
+ expr = expr.body if expr.if_type?
117
+ return unless expr
117
118
 
118
119
  check_literal(expr)
119
120
  check_var(expr)
@@ -229,7 +230,7 @@ module RuboCop
229
230
  end
230
231
 
231
232
  def autocorrect_void_expression(corrector, node)
232
- return if node.parent.if_type? && node.parent.modifier_form?
233
+ return if node.parent.if_type?
233
234
 
234
235
  corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
235
236
  end
@@ -51,15 +51,7 @@ module RuboCop
51
51
  end
52
52
 
53
53
  def on_casgn(node)
54
- parent = node.parent
55
-
56
- block_node = if parent&.assignment?
57
- parent.expression
58
- elsif parent&.parent&.masgn_type?
59
- parent.parent.expression
60
- else
61
- node.expression
62
- end
54
+ block_node = node.expression || find_expression_within_parent(node.parent)
63
55
 
64
56
  return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
65
57
 
@@ -71,6 +63,14 @@ module RuboCop
71
63
  def message(length, max_length)
72
64
  format('Class has too many lines. [%<length>d/%<max>d]', length: length, max: max_length)
73
65
  end
66
+
67
+ def find_expression_within_parent(parent)
68
+ if parent&.assignment?
69
+ parent.expression
70
+ elsif parent&.parent&.masgn_type?
71
+ parent.parent.expression
72
+ end
73
+ end
74
74
  end
75
75
  end
76
76
  end
@@ -48,7 +48,7 @@ module RuboCop
48
48
  LABEL = 'Method'
49
49
 
50
50
  def on_def(node)
51
- return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
51
+ return if allowed?(node.method_name)
52
52
 
53
53
  check_code_length(node)
54
54
  end
@@ -57,6 +57,9 @@ module RuboCop
57
57
  def on_block(node)
58
58
  return unless node.method?(:define_method)
59
59
 
60
+ method_name = node.send_node.first_argument
61
+ return if method_name.basic_literal? && allowed?(method_name.value)
62
+
60
63
  check_code_length(node)
61
64
  end
62
65
  alias on_numblock on_block
@@ -66,6 +69,10 @@ module RuboCop
66
69
  def cop_label
67
70
  LABEL
68
71
  end
72
+
73
+ def allowed?(method_name)
74
+ allowed_method?(method_name) || matches_allowed_pattern?(method_name)
75
+ end
69
76
  end
70
77
  end
71
78
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  # (Note: Passes may not happen exactly in this sequence.)
44
44
  module CheckLineBreakable
45
45
  def extract_breakable_node(node, max)
46
- if node.send_type?
46
+ if node.call_type?
47
47
  return if chained_to_heredoc?(node)
48
48
 
49
49
  args = process_args(node.arguments)
@@ -74,9 +74,9 @@ module RuboCop
74
74
  def extract_first_element_over_column_limit(node, elements, max)
75
75
  line = node.first_line
76
76
 
77
- # If a `send` node is not parenthesized, don't move the first element, because it
77
+ # If a `send` or `csend` node is not parenthesized, don't move the first element, because it
78
78
  # can result in changed behavior or a syntax error.
79
- if node.send_type? && !node.parenthesized? && !first_argument_is_heredoc?(node)
79
+ if node.call_type? && !node.parenthesized? && !first_argument_is_heredoc?(node)
80
80
  elements = elements.drop(1)
81
81
  end
82
82
 
@@ -98,10 +98,10 @@ module RuboCop
98
98
  end
99
99
 
100
100
  # @api private
101
- # If a send node contains a heredoc argument, splitting cannot happen
101
+ # If a `send` or `csend` node contains a heredoc argument, splitting cannot happen
102
102
  # after the heredoc or else it will cause a syntax error.
103
103
  def shift_elements_for_heredoc_arg(node, elements, index)
104
- return index unless node.send_type? || node.array_type?
104
+ return index unless node.call_type? || node.array_type?
105
105
 
106
106
  heredoc_index = elements.index { |arg| arg.respond_to?(:heredoc?) && arg.heredoc? }
107
107
  return index unless heredoc_index
@@ -156,7 +156,7 @@ module RuboCop
156
156
 
157
157
  if ancestor.hash_type? || ancestor.array_type?
158
158
  elements = ancestor.children
159
- elsif ancestor.send_type?
159
+ elsif ancestor.call_type?
160
160
  elements = process_args(ancestor.arguments)
161
161
  else
162
162
  next
@@ -176,7 +176,7 @@ module RuboCop
176
176
  return children_could_be_broken_up?(ancestor.children)
177
177
  end
178
178
 
179
- next unless ancestor.send_type?
179
+ next unless ancestor.call_type?
180
180
 
181
181
  args = process_args(ancestor.arguments)
182
182
  return children_could_be_broken_up?(args) if breakable_collection?(ancestor, args)
@@ -16,6 +16,8 @@ module RuboCop
16
16
  end
17
17
 
18
18
  def comments_in_range(node)
19
+ return [] unless node.source_range
20
+
19
21
  start_line = node.source_range.line
20
22
  end_line = find_end_line(node)
21
23
 
@@ -71,10 +73,13 @@ module RuboCop
71
73
  node.else_branch.loc.line
72
74
  elsif node.elsif?
73
75
  node.each_ancestor(:if).find(&:if?).loc.end.line
76
+ elsif node.if? && node.parent && parentheses?(node.parent)
77
+ node.parent.loc.end.line
74
78
  end
75
79
  elsif node.block_type? || node.numblock_type?
76
80
  node.loc.end.line
77
- elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node)
81
+ elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node) &&
82
+ next_sibling.source_range
78
83
  next_sibling.loc.line
79
84
  elsif (parent = node.parent)
80
85
  if parent.loc.respond_to?(:end) && parent.loc.end
@@ -20,7 +20,7 @@ module RuboCop
20
20
  private
21
21
 
22
22
  def dig_chain_enabled?
23
- @config.for_cop('Style/DigChain')['Enabled']
23
+ @config.cop_enabled?('Style/DigChain')
24
24
  end
25
25
  end
26
26
  end
@@ -37,12 +37,13 @@ module RuboCop
37
37
  last_uri_match = match_uris(line).last
38
38
  return nil unless last_uri_match
39
39
 
40
- begin_position, end_position = last_uri_match.offset(0).map do |pos|
41
- pos + indentation_difference(line)
42
- end
43
-
40
+ begin_position, end_position = last_uri_match.offset(0)
44
41
  end_position = extend_uri_end_position(line, end_position)
45
42
 
43
+ line_indentation_difference = indentation_difference(line)
44
+ begin_position += line_indentation_difference
45
+ end_position += line_indentation_difference
46
+
46
47
  return nil if begin_position < max_line_length && end_position < max_line_length
47
48
 
48
49
  begin_position...end_position
@@ -5,6 +5,10 @@ module RuboCop
5
5
  # Common functionality for checking whether an AST node/token is aligned
6
6
  # with something on a preceding or following line
7
7
  module PrecedingFollowingAlignment
8
+ # Tokens that end with an `=`, as well as `<<`, that can be aligned together:
9
+ # `=`, `==`, `===`, `!=`, `<=`, `>=`, `<<` and operator assignment (`+=`, etc).
10
+ ASSIGNMENT_OR_COMPARISON_TOKENS = %i[tEQL tEQ tEQQ tNEQ tLEQ tGEQ tOP_ASGN tLSHFT].freeze
11
+
8
12
  private
9
13
 
10
14
  def allow_for_alignment?
@@ -19,16 +23,20 @@ module RuboCop
19
23
  aligned_with_adjacent_line?(range, method(:aligned_operator?))
20
24
  end
21
25
 
22
- def aligned_with_preceding_assignment(token)
26
+ # Allows alignment with a preceding operator that ends with an `=`,
27
+ # including assignment and comparison operators.
28
+ def aligned_with_preceding_equals_operator(token)
23
29
  preceding_line_range = token.line.downto(1)
24
30
 
25
- aligned_with_assignment(token, preceding_line_range)
31
+ aligned_with_equals_sign(token, preceding_line_range)
26
32
  end
27
33
 
28
- def aligned_with_subsequent_assignment(token)
34
+ # Allows alignment with a subsequent operator that ends with an `=`,
35
+ # including assignment and comparison operators.
36
+ def aligned_with_subsequent_equals_operator(token)
29
37
  subsequent_line_range = token.line.upto(processed_source.lines.length)
30
38
 
31
- aligned_with_assignment(token, subsequent_line_range)
39
+ aligned_with_equals_sign(token, subsequent_line_range)
32
40
  end
33
41
 
34
42
  def aligned_with_adjacent_line?(range, predicate)
@@ -62,7 +70,7 @@ module RuboCop
62
70
  next unless index
63
71
  next if indent && indent != index
64
72
 
65
- return yield(range, line)
73
+ return yield(range, line, lineno + 1)
66
74
  end
67
75
  false
68
76
  end
@@ -74,12 +82,12 @@ module RuboCop
74
82
  end.map(&:line)
75
83
  end
76
84
 
77
- def aligned_token?(range, line)
78
- aligned_words?(range, line) || aligned_assignment?(range, line)
85
+ def aligned_token?(range, line, lineno)
86
+ aligned_words?(range, line) || aligned_equals_operator?(range, lineno)
79
87
  end
80
88
 
81
- def aligned_operator?(range, line)
82
- aligned_identical?(range, line) || aligned_assignment?(range, line)
89
+ def aligned_operator?(range, line, lineno)
90
+ aligned_identical?(range, line) || aligned_equals_operator?(range, lineno)
83
91
  end
84
92
 
85
93
  def aligned_words?(range, line)
@@ -90,23 +98,42 @@ module RuboCop
90
98
  token == line[left_edge, token.length]
91
99
  end
92
100
 
93
- def aligned_assignment?(range, line)
94
- (range.source[-1] == '=' && line[range.last_column - 1] == '=') ||
95
- aligned_with_append_operator?(range, line)
101
+ def aligned_equals_operator?(range, lineno)
102
+ # Check that the operator is aligned with a previous assignment or comparison operator
103
+ # ie. an equals sign, an operator assignment (eg. `+=`), a comparison (`==`, `<=`, etc.).
104
+ # Since append operators (`<<`) are a type of assignment, they are allowed as well,
105
+ # despite not ending with a literal equals character.
106
+ line_range = processed_source.buffer.line_range(lineno)
107
+ return false unless line_range
108
+
109
+ # Find the specific token to avoid matching up to operators inside strings
110
+ operator_token = processed_source.tokens_within(line_range).detect do |token|
111
+ ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
112
+ end
113
+
114
+ aligned_with_preceding_equals?(range, operator_token) ||
115
+ aligned_with_append_operator?(range, operator_token)
96
116
  end
97
117
 
98
- def aligned_with_append_operator?(range, line)
99
- last_column = range.last_column
118
+ def aligned_with_preceding_equals?(range, token)
119
+ return false unless token
100
120
 
101
- (range.source == '<<' && line[last_column - 1] == '=') ||
102
- (range.source[-1] == '=' && line[(last_column - 2)..(last_column - 1)] == '<<')
121
+ range.source[-1] == '=' && range.last_column == token.pos.last_column
122
+ end
123
+
124
+ def aligned_with_append_operator?(range, token)
125
+ return false unless token
126
+
127
+ ((range.source == '<<' && token.equal_sign?) ||
128
+ (range.source[-1] == '=' && token.type == :tLSHFT)) &&
129
+ token && range.last_column == token.pos.last_column
103
130
  end
104
131
 
105
132
  def aligned_identical?(range, line)
106
133
  range.source == line[range.column, range.size]
107
134
  end
108
135
 
109
- def aligned_with_assignment(token, line_range)
136
+ def aligned_with_equals_sign(token, line_range)
110
137
  token_line_indent = processed_source.line_indentation(token.line)
111
138
  assignment_lines = relevant_assignment_lines(line_range)
112
139
  relevant_line_number = assignment_lines[1]
@@ -116,12 +143,9 @@ module RuboCop
116
143
  relevant_indent = processed_source.line_indentation(relevant_line_number)
117
144
 
118
145
  return :none if relevant_indent < token_line_indent
146
+ return :none unless processed_source.lines[relevant_line_number - 1]
119
147
 
120
- assignment_line = processed_source.lines[relevant_line_number - 1]
121
-
122
- return :none unless assignment_line
123
-
124
- aligned_assignment?(token.pos, assignment_line) ? :yes : :no
148
+ aligned_equals_operator?(token.pos, relevant_line_number) ? :yes : :no
125
149
  end
126
150
 
127
151
  def assignment_lines
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def space_required_after?(token)
39
- (token.left_curly_brace? || token.type == :tLAMBEG) && space_required_after_lcurly?
39
+ token.left_curly_brace? && space_required_after_lcurly?
40
40
  end
41
41
 
42
42
  def space_required_after_lcurly?
@@ -96,7 +96,7 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def max_line_length
99
- return unless config.for_cop('Layout/LineLength')['Enabled']
99
+ return unless config.cop_enabled?('Layout/LineLength')
100
100
 
101
101
  config.for_cop('Layout/LineLength')['Max']
102
102
  end
@@ -26,7 +26,7 @@ module RuboCop
26
26
  end
27
27
 
28
28
  def string_literals_config
29
- config.for_cop('Style/StringLiterals')
29
+ config.for_enabled_cop('Style/StringLiterals')
30
30
  end
31
31
  end
32
32
  end
@@ -138,7 +138,7 @@ module RuboCop
138
138
  def use_block_argument_as_local_variable?(node, last_argument)
139
139
  return false if node.body.nil?
140
140
 
141
- node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
141
+ node.body.each_node(:lvar, :lvasgn).any? do |lvar|
142
142
  !lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
143
143
  end
144
144
  end
@@ -154,7 +154,7 @@ module RuboCop
154
154
  end
155
155
 
156
156
  def variable_name(node)
157
- node.exception_variable&.name
157
+ node.exception_variable.name if node.exception_variable.respond_to?(:name)
158
158
  end
159
159
 
160
160
  def message(node)
@@ -112,6 +112,26 @@ module RuboCop
112
112
  # private attr :quux
113
113
  #
114
114
  # end
115
+ #
116
+ # @example AllowModifiersOnAliasMethod: true (default)
117
+ # # good
118
+ # class Foo
119
+ #
120
+ # public alias_method :bar, :foo
121
+ # protected alias_method :baz, :foo
122
+ # private alias_method :qux, :foo
123
+ #
124
+ # end
125
+ #
126
+ # @example AllowModifiersOnAliasMethod: false
127
+ # # bad
128
+ # class Foo
129
+ #
130
+ # public alias_method :bar, :foo
131
+ # protected alias_method :baz, :foo
132
+ # private alias_method :qux, :foo
133
+ #
134
+ # end
115
135
  class AccessModifierDeclarations < Base
116
136
  extend AutoCorrector
117
137
 
@@ -145,6 +165,12 @@ module RuboCop
145
165
  (send nil? {:attr :attr_reader :attr_writer :attr_accessor} _+))
146
166
  PATTERN
147
167
 
168
+ # @!method access_modifier_with_alias_method?, <<~PATTERN
169
+ def_node_matcher :access_modifier_with_alias_method?, <<~PATTERN
170
+ (send nil? {:private :protected :public :module_function}
171
+ (send nil? :alias_method _ _))
172
+ PATTERN
173
+
148
174
  def on_send(node)
149
175
  return if allowed?(node)
150
176
 
@@ -164,7 +190,8 @@ module RuboCop
164
190
  !node.access_modifier? ||
165
191
  ALLOWED_NODE_TYPES.include?(node.parent&.type) ||
166
192
  allow_modifiers_on_symbols?(node) ||
167
- allow_modifiers_on_attrs?(node)
193
+ allow_modifiers_on_attrs?(node) ||
194
+ allow_modifiers_on_alias_method?(node)
168
195
  end
169
196
 
170
197
  def autocorrect(corrector, node)
@@ -194,6 +221,10 @@ module RuboCop
194
221
  cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node)
195
222
  end
196
223
 
224
+ def allow_modifiers_on_alias_method?(node)
225
+ cop_config['AllowModifiersOnAliasMethod'] && access_modifier_with_alias_method?(node)
226
+ end
227
+
197
228
  def offense?(node)
198
229
  (group_style? && access_modifier_is_inlined?(node) &&
199
230
  !node.parent&.if_type? && !right_siblings_same_inline_method?(node)) ||
@@ -127,7 +127,7 @@ module RuboCop
127
127
  end
128
128
 
129
129
  def correct_other(node, corrector)
130
- return if node.source_range.begin.is?('(')
130
+ return if node.parenthesized_call?
131
131
 
132
132
  corrector.wrap(node, '(', ')')
133
133
  end
@@ -540,10 +540,7 @@ module RuboCop
540
540
  end
541
541
 
542
542
  def explicit_block_name?
543
- block_forwarding_config = config.for_cop('Naming/BlockForwarding')
544
- return false unless block_forwarding_config['Enabled']
545
-
546
- block_forwarding_config['EnforcedStyle'] == 'explicit'
543
+ config.for_enabled_cop('Naming/BlockForwarding')['EnforcedStyle'] == 'explicit'
547
544
  end
548
545
  end
549
546
  end
@@ -183,7 +183,8 @@ module RuboCop
183
183
  def on_send(node)
184
184
  return unless node.arguments?
185
185
  return if node.parenthesized?
186
- return if node.operator_method? || node.assignment_method?
186
+ return if node.assignment_method?
187
+ return if single_argument_operator_method?(node)
187
188
 
188
189
  node.arguments.each do |arg|
189
190
  get_blocks(arg) do |block|
@@ -501,6 +502,12 @@ module RuboCop
501
502
  # `begin`...`end` when changing `do-end` to `{}`.
502
503
  block_node.each_child_node(:rescue, :ensure).any? && !block_node.single_line?
503
504
  end
505
+
506
+ def single_argument_operator_method?(node)
507
+ return false unless node.operator_method?
508
+
509
+ node.arguments.one? && node.first_argument.block_type?
510
+ end
504
511
  end
505
512
  end
506
513
  end
@@ -126,9 +126,12 @@ module RuboCop
126
126
  end
127
127
 
128
128
  def unindent(corrector, node)
129
- return if node.body.children.last.nil?
129
+ return unless node.body.children.last
130
130
 
131
- column_delta = configured_indentation_width - leading_spaces(node.body.children.last).size
131
+ last_child_leading_spaces = leading_spaces(node.body.children.last)
132
+ return if leading_spaces(node).size == last_child_leading_spaces.size
133
+
134
+ column_delta = configured_indentation_width - last_child_leading_spaces.size
132
135
  return if column_delta.zero?
133
136
 
134
137
  AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
@@ -53,8 +53,7 @@ module RuboCop
53
53
  (block
54
54
  (call
55
55
  (begin
56
- (${irange erange}
57
- (int $_) (int $_)))
56
+ ($range (int $_) (int $_)))
58
57
  :each)
59
58
  (args ...)
60
59
  ...)
@@ -65,8 +64,7 @@ module RuboCop
65
64
  (block
66
65
  (call
67
66
  (begin
68
- ({irange erange}
69
- (int 0) (int _)))
67
+ (range (int 0) (int _)))
70
68
  :each)
71
69
  (args ...)
72
70
  ...)
@@ -77,8 +75,7 @@ module RuboCop
77
75
  (block
78
76
  (call
79
77
  (begin
80
- ({irange erange}
81
- (int _) (int _)))
78
+ (range (int _) (int _)))
82
79
  :each)
83
80
  (args)
84
81
  ...)
@@ -131,6 +131,8 @@ module RuboCop
131
131
  extend AutoCorrector
132
132
 
133
133
  MSG = 'Redundant `else`-clause.'
134
+ NIL_STYLES = %i[nil both].freeze
135
+ EMPTY_STYLES = %i[empty both].freeze
134
136
 
135
137
  def on_normal_if_unless(node)
136
138
  check(node)
@@ -150,11 +152,11 @@ module RuboCop
150
152
  end
151
153
 
152
154
  def nil_style?
153
- style == :nil || style == :both
155
+ NIL_STYLES.include?(style)
154
156
  end
155
157
 
156
158
  def empty_style?
157
- style == :empty || style == :both
159
+ EMPTY_STYLES.include?(style)
158
160
  end
159
161
 
160
162
  def empty_check(node)
@@ -136,7 +136,7 @@ module RuboCop
136
136
  def frozen_strings?
137
137
  return true if frozen_string_literals_enabled?
138
138
 
139
- frozen_string_cop_enabled = config.for_cop('Style/FrozenStringLiteralComment')['Enabled']
139
+ frozen_string_cop_enabled = config.cop_enabled?('Style/FrozenStringLiteralComment')
140
140
  frozen_string_cop_enabled &&
141
141
  !frozen_string_literals_disabled? &&
142
142
  string_literals_frozen_by_default?.nil?
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def max_line_length
112
- return unless config.for_cop('Layout/LineLength')['Enabled']
112
+ return unless config.cop_enabled?('Layout/LineLength')
113
113
 
114
114
  config.for_cop('Layout/LineLength')['Max']
115
115
  end
@@ -40,8 +40,7 @@ module RuboCop
40
40
  def on_send(node)
41
41
  return unless (receiver = node.receiver)
42
42
  return unless (regexp = exact_regexp_match(node))
43
-
44
- parsed_regexp = Regexp::Parser.parse(regexp)
43
+ return unless (parsed_regexp = parse_regexp(regexp))
45
44
  return unless exact_match_pattern?(parsed_regexp)
46
45
 
47
46
  prefer = "#{receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # * `scientific` which enforces a mantissa between 1 (inclusive) and 10 (exclusive).
10
10
  # * `engineering` which enforces the exponent to be a multiple of 3 and the mantissa
11
- # to be between 0.1 (inclusive) and 10 (exclusive).
11
+ # to be between 0.1 (inclusive) and 1000 (exclusive).
12
12
  # * `integral` which enforces the mantissa to always be a whole number without
13
13
  # trailing zeroes.
14
14
  #
@@ -8,6 +8,12 @@ module RuboCop
8
8
  # Only looks for full string matches, substrings within a longer string are not
9
9
  # considered.
10
10
  #
11
+ # However, only files that use the string `'/dev/null'` are targeted for detection.
12
+ # This is because the string `'NUL'` is not limited to the null device.
13
+ # This behavior results in false negatives when the `'/dev/null'` string is not used,
14
+ # but it is a trade-off to avoid false positives. `NULL:`
15
+ # Unlike `'NUL'`, `'NUL:'` is regarded as something like `C:` and is always detected.
16
+ #
11
17
  # NOTE: Uses inside arrays and hashes are ignored.
12
18
  #
13
19
  # @safety
@@ -42,11 +48,21 @@ module RuboCop
42
48
  REGEXP = %r{\A(/dev/null|NUL:?)\z}i.freeze
43
49
  MSG = 'Use `File::NULL` instead of `%<source>s`.'
44
50
 
51
+ def on_new_investigation
52
+ return unless (ast = processed_source.ast)
53
+
54
+ @contain_dev_null_string_in_file = ast.each_descendant(:str).any? do |str|
55
+ content = str.str_content
56
+
57
+ valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull
58
+ end
59
+ end
60
+
45
61
  def on_str(node)
46
62
  value = node.value
47
-
48
- return if invalid_string?(value)
63
+ return unless valid_string?(value)
49
64
  return if acceptable?(node)
65
+ return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull
50
66
  return unless REGEXP.match?(value)
51
67
 
52
68
  add_offense(node, message: format(MSG, source: value)) do |corrector|
@@ -56,8 +72,8 @@ module RuboCop
56
72
 
57
73
  private
58
74
 
59
- def invalid_string?(value)
60
- value.empty? || !value.valid_encoding?
75
+ def valid_string?(value)
76
+ !value.empty? && value.valid_encoding?
61
77
  end
62
78
 
63
79
  def acceptable?(node)