rubocop 1.50.2 → 1.53.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +76 -6
  4. data/lib/rubocop/cli/command/lsp.rb +19 -0
  5. data/lib/rubocop/cli.rb +3 -0
  6. data/lib/rubocop/config.rb +4 -0
  7. data/lib/rubocop/config_loader_resolver.rb +4 -3
  8. data/lib/rubocop/config_obsoletion.rb +2 -2
  9. data/lib/rubocop/cop/base.rb +5 -1
  10. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  13. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  14. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  16. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  17. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  18. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  19. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  21. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  22. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  23. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  24. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  25. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  26. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  27. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  28. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  29. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  30. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  31. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  32. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  33. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  34. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  35. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  36. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  37. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  38. data/lib/rubocop/cop/lint/mixed_case_range.rb +109 -0
  39. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  40. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  41. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  42. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  43. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +120 -0
  44. data/lib/rubocop/cop/lint/redundant_require_statement.rb +8 -3
  45. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  46. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  47. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  48. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  49. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  50. data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
  51. data/lib/rubocop/cop/lint/void.rb +63 -7
  52. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  53. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  54. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  55. data/lib/rubocop/cop/mixin/comments_help.rb +7 -3
  56. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  57. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  58. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  59. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  60. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  61. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +25 -10
  62. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  63. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  64. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  65. data/lib/rubocop/cop/style/attr.rb +11 -1
  66. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  67. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  68. data/lib/rubocop/cop/style/block_delimiters.rb +3 -3
  69. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  70. data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
  71. data/lib/rubocop/cop/style/collection_compact.rb +16 -6
  72. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  73. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  74. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -3
  75. data/lib/rubocop/cop/style/copyright.rb +5 -2
  76. data/lib/rubocop/cop/style/dir.rb +1 -1
  77. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  78. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  79. data/lib/rubocop/cop/style/documentation.rb +1 -1
  80. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  81. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  82. data/lib/rubocop/cop/style/file_read.rb +2 -2
  83. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  84. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  85. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  86. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  87. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  88. data/lib/rubocop/cop/style/identical_conditional_branches.rb +6 -2
  89. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  90. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  91. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -4
  93. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  94. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  95. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  96. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  97. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  98. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  99. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  100. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  101. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  102. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
  103. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  104. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +86 -0
  105. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  106. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  107. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +3 -1
  108. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  109. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
  110. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  111. data/lib/rubocop/cop/style/require_order.rb +11 -5
  112. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  113. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +81 -0
  114. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  115. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  116. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  117. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  118. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  119. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  120. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  121. data/lib/rubocop/cop/team.rb +1 -1
  122. data/lib/rubocop/cop/util.rb +1 -1
  123. data/lib/rubocop/cop/utils/regexp_ranges.rb +100 -0
  124. data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
  125. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  126. data/lib/rubocop/cop/variable_force.rb +1 -0
  127. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  128. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  129. data/lib/rubocop/lsp/logger.rb +22 -0
  130. data/lib/rubocop/lsp/routes.rb +223 -0
  131. data/lib/rubocop/lsp/runtime.rb +79 -0
  132. data/lib/rubocop/lsp/server.rb +62 -0
  133. data/lib/rubocop/lsp/severity.rb +27 -0
  134. data/lib/rubocop/options.rb +11 -1
  135. data/lib/rubocop/result_cache.rb +1 -1
  136. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  137. data/lib/rubocop/server/client_command/exec.rb +2 -1
  138. data/lib/rubocop/target_ruby.rb +3 -2
  139. data/lib/rubocop/version.rb +10 -6
  140. data/lib/rubocop.rb +13 -0
  141. metadata +38 -6
@@ -88,10 +88,7 @@ module RuboCop
88
88
  return unless previous_older_sibling
89
89
 
90
90
  add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
91
- corrector.swap(
92
- range_with_comments_and_lines(previous_older_sibling),
93
- range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
94
- )
91
+ autocorrect(corrector, node, previous_older_sibling)
95
92
  end
96
93
  end
97
94
 
@@ -109,11 +106,20 @@ module RuboCop
109
106
  break unless sibling&.send_type? && sibling&.method?(node.method_name)
110
107
  break unless sibling.arguments? && !sibling.receiver
111
108
  break unless in_same_section?(sibling, node)
109
+ break unless node.first_argument.str_type? && sibling.first_argument.str_type?
112
110
 
113
- node.first_argument.source < sibling.first_argument.source
111
+ node.first_argument.value < sibling.first_argument.value
114
112
  end
115
113
  end
116
114
 
115
+ def autocorrect(corrector, node, previous_older_sibling)
116
+ range1 = range_with_comments_and_lines(previous_older_sibling)
117
+ range2 = range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
118
+
119
+ corrector.remove(range2)
120
+ corrector.insert_before(range1, range2.source)
121
+ end
122
+
117
123
  def search_node(node)
118
124
  node.parent.if_type? ? node.parent : node
119
125
  end
@@ -3,9 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of rescue in its modifier form.
7
- #
8
- # The cop to check `rescue` in its modifier form is added for following
6
+ # Checks for uses of `rescue` in its modifier form is added for following
9
7
  # reasons:
10
8
  #
11
9
  # * The syntax of modifier form `rescue` can be misleading because it
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks if `return` or `return nil` is used in predicate method definitions.
7
+ #
8
+ # @safety
9
+ # Autocorrection is marked as unsafe because the change of the return value
10
+ # from `nil` to `false` could potentially lead to incompatibility issues.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # def foo?
15
+ # return if condition
16
+ #
17
+ # do_something?
18
+ # end
19
+ #
20
+ # # bad
21
+ # def foo?
22
+ # return nil if condition
23
+ #
24
+ # do_something?
25
+ # end
26
+ #
27
+ # # good
28
+ # def foo?
29
+ # return false if condition
30
+ #
31
+ # do_something?
32
+ # end
33
+ #
34
+ # @example AllowedMethod: ['foo?']
35
+ # # good
36
+ # def foo?
37
+ # return if condition
38
+ #
39
+ # do_something?
40
+ # end
41
+ #
42
+ # @example AllowedPattern: [/foo/]
43
+ # # good
44
+ # def foo?
45
+ # return if condition
46
+ #
47
+ # do_something?
48
+ # end
49
+ #
50
+ class ReturnNilInPredicateMethodDefinition < Base
51
+ extend AutoCorrector
52
+ include AllowedMethods
53
+ include AllowedPattern
54
+
55
+ MSG = 'Use `return false` instead of `%<prefer>s` in the predicate method.'
56
+
57
+ # @!method return_nil?(node)
58
+ def_node_matcher :return_nil?, <<~PATTERN
59
+ {(return) (return (nil))}
60
+ PATTERN
61
+
62
+ def on_def(node)
63
+ return unless node.predicate_method?
64
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
65
+ return unless (body = node.body)
66
+
67
+ body.each_descendant(:return) do |return_node|
68
+ next unless return_nil?(return_node)
69
+
70
+ message = format(MSG, prefer: return_node.source)
71
+
72
+ add_offense(return_node, message: message) do |corrector|
73
+ corrector.replace(return_node, 'return false')
74
+ end
75
+ end
76
+ end
77
+ alias on_defs on_def
78
+ end
79
+ end
80
+ end
81
+ end
@@ -84,6 +84,7 @@ module RuboCop
84
84
  }
85
85
  PATTERN
86
86
 
87
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
88
  def on_send(node)
88
89
  return unless (block_node = node.block_node)
89
90
  return if block_node.body&.begin_type?
@@ -91,11 +92,14 @@ module RuboCop
91
92
  return unless (regexp_method_send_node = extract_send_node(block_node))
92
93
  return if match_predicate_without_receiver?(regexp_method_send_node)
93
94
 
94
- opposite = opposite?(regexp_method_send_node)
95
+ replacement = replacement(regexp_method_send_node, node)
96
+ return if target_ruby_version <= 2.2 && replacement == 'grep_v'
97
+
95
98
  regexp = find_regexp(regexp_method_send_node, block_node)
96
99
 
97
- register_offense(node, block_node, regexp, opposite)
100
+ register_offense(node, block_node, regexp, replacement)
98
101
  end
102
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
103
 
100
104
  private
101
105
 
@@ -105,9 +109,15 @@ module RuboCop
105
109
  node.hash_type? || creates_hash?(node) || env_const?(node)
106
110
  end
107
111
 
108
- def register_offense(node, block_node, regexp, opposite)
109
- method_name = node.method_name.to_sym
110
- replacement = opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
112
+ def replacement(regexp_method_send_node, node)
113
+ opposite = opposite?(regexp_method_send_node)
114
+
115
+ method_name = node.method_name
116
+
117
+ opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
118
+ end
119
+
120
+ def register_offense(node, block_node, regexp, replacement)
111
121
  message = format(MSG, replacement: replacement, original_method: node.method_name)
112
122
 
113
123
  add_offense(block_node, message: message) do |corrector|
@@ -90,8 +90,11 @@ module RuboCop
90
90
  0
91
91
  elsif exist_semicolon_before_right_curly_brace?(tokens)
92
92
  -3
93
- elsif exist_semicolon_after_left_curly_brace?(tokens)
93
+ elsif exist_semicolon_after_left_curly_brace?(tokens) ||
94
+ exist_semicolon_after_left_string_interpolation_brace?(tokens)
94
95
  2
96
+ elsif exist_semicolon_before_right_string_interpolation_brace?(tokens)
97
+ -4
95
98
  end
96
99
  end
97
100
 
@@ -103,6 +106,14 @@ module RuboCop
103
106
  tokens[1]&.left_curly_brace? && tokens[2]&.semicolon?
104
107
  end
105
108
 
109
+ def exist_semicolon_before_right_string_interpolation_brace?(tokens)
110
+ tokens[-3]&.type == :tSTRING_DEND && tokens[-4]&.semicolon?
111
+ end
112
+
113
+ def exist_semicolon_after_left_string_interpolation_brace?(tokens)
114
+ tokens[1]&.type == :tSTRING_DBEG && tokens[2]&.semicolon?
115
+ end
116
+
106
117
  def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
107
118
  range = source_range(processed_source.buffer, line, column)
108
119
 
@@ -198,7 +198,7 @@ module RuboCop
198
198
  end
199
199
 
200
200
  def command_or_kernel_call?(name, node)
201
- return unless node.method?(name)
201
+ return false unless node.method?(name)
202
202
 
203
203
  node.command?(name) || kernel_call?(node, name)
204
204
  end
@@ -135,7 +135,7 @@ module RuboCop
135
135
 
136
136
  def disallow_endless_method_style?
137
137
  endless_method_config = config.for_cop('Style/EndlessMethod')
138
- return false unless endless_method_config['Enabled']
138
+ return true unless endless_method_config['Enabled']
139
139
 
140
140
  endless_method_config['EnforcedStyle'] == 'disallow'
141
141
  end
@@ -186,7 +186,9 @@ module RuboCop
186
186
  begin_pos = condition.first_argument.source_range.begin_pos
187
187
  return if end_pos > begin_pos
188
188
 
189
- corrector.replace(range_between(end_pos, begin_pos), '(')
189
+ range = range_between(end_pos, begin_pos)
190
+ corrector.remove(range)
191
+ corrector.insert_after(range, '(')
190
192
  corrector.insert_after(condition.last_argument, ')')
191
193
  end
192
194
 
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- #
7
- # This cop looks for uses of Perl-style global variables.
6
+ # Looks for uses of Perl-style global variables.
8
7
  # Correcting to global variables in the 'English' library
9
8
  # will add a require statement to the top of the file if
10
9
  # enabled by RequireEnglish config.
@@ -234,9 +233,9 @@ module RuboCop
234
233
  end
235
234
 
236
235
  def matching_styles(global)
237
- STYLE_VARS_MAP.map do |style, vars|
236
+ STYLE_VARS_MAP.filter_map do |style, vars|
238
237
  style if vars.values.flatten(1).include? global
239
- end.compact
238
+ end
240
239
  end
241
240
 
242
241
  def english_name_replacement(preferred_name, node)
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the use of `YAML.load`, `YAML.safe_load`, and `YAML.parse` with
7
+ # `File.read` argument.
8
+ #
9
+ # NOTE: `YAML.safe_load_file` was introduced in Ruby 3.0.
10
+ #
11
+ # @example
12
+ #
13
+ # # bad
14
+ # YAML.load(File.read(path))
15
+ # YAML.parse(File.read(path))
16
+ #
17
+ # # good
18
+ # YAML.load_file(path)
19
+ # YAML.parse_file(path)
20
+ #
21
+ # # bad
22
+ # YAML.safe_load(File.read(path)) # Ruby 3.0 and newer
23
+ #
24
+ # # good
25
+ # YAML.safe_load_file(path) # Ruby 3.0 and newer
26
+ #
27
+ class YAMLFileRead < Base
28
+ extend AutoCorrector
29
+
30
+ MSG = 'Use `%<prefer>s` instead.'
31
+ RESTRICT_ON_SEND = %i[load safe_load parse].freeze
32
+
33
+ # @!method yaml_file_read?(node)
34
+ def_node_matcher :yaml_file_read?, <<~PATTERN
35
+ (send
36
+ (const {cbase nil?} :YAML) _
37
+ (send
38
+ (const {cbase nil?} :File) :read $_) $...)
39
+ PATTERN
40
+
41
+ def on_send(node)
42
+ return if node.method?(:safe_load) && target_ruby_version <= 2.7
43
+ return unless (file_path, rest_arguments = yaml_file_read?(node))
44
+
45
+ range = offense_range(node)
46
+ rest_arguments = if rest_arguments.empty?
47
+ ''
48
+ else
49
+ ", #{rest_arguments.map(&:source).join(', ')}"
50
+ end
51
+ prefer = "#{node.method_name}_file(#{file_path.source}#{rest_arguments})"
52
+
53
+ add_offense(range, message: format(MSG, prefer: prefer)) do |corrector|
54
+ corrector.replace(range, prefer)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def offense_range(node)
61
+ node.loc.selector.join(node.source_range.end)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -112,7 +112,7 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def external_dependency_checksum
115
- keys = cops.map(&:external_dependency_checksum).compact
115
+ keys = cops.filter_map(&:external_dependency_checksum)
116
116
  Digest::SHA1.hexdigest(keys.join)
117
117
  end
118
118
 
@@ -142,7 +142,7 @@ module RuboCop
142
142
  end
143
143
 
144
144
  def escape_string(string)
145
- string.inspect[1..-2].tap { |s| s.gsub!(/\\"/, '"') }
145
+ string.inspect[1..-2].tap { |s| s.gsub!('\\"', '"') }
146
146
  end
147
147
 
148
148
  def to_string_literal(string)
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Utils
6
+ # Helper to abstract complexity of building range pairs
7
+ # with octal escape reconstruction (needed for regexp_parser < 2.7).
8
+ class RegexpRanges
9
+ attr_reader :compound_token, :root
10
+
11
+ def initialize(root)
12
+ @root = root
13
+ @compound_token = []
14
+ end
15
+
16
+ def pairs
17
+ unless @pairs
18
+ @pairs = []
19
+ populate(root)
20
+ end
21
+
22
+ # If either bound is a compound the first one is an escape
23
+ # and that's all we need to work with.
24
+ # If there are any cops that wanted to operate on the compound
25
+ # expression we could wrap it with a facade class.
26
+ @pairs.map { |pair| pair.map(&:first) }
27
+ end
28
+
29
+ private
30
+
31
+ def populate(expr)
32
+ expressions = expr.expressions.to_a
33
+
34
+ until expressions.empty?
35
+ current = expressions.shift
36
+
37
+ if escaped_octal?(current)
38
+ compound_token << current
39
+ compound_token.concat(pop_octal_digits(expressions))
40
+ # If we have all the digits we can discard.
41
+ end
42
+
43
+ next unless current.type == :set
44
+
45
+ process_set(expressions, current)
46
+ compound_token.clear
47
+ end
48
+ end
49
+
50
+ def process_set(expressions, current)
51
+ case current.token
52
+ when :range
53
+ @pairs << compose_range(expressions, current)
54
+ when :character
55
+ # Child expressions may include the range we are looking for.
56
+ populate(current)
57
+ when :intersection
58
+ # Each child expression could have child expressions that lead to ranges.
59
+ current.expressions.each do |intersected|
60
+ populate(intersected)
61
+ end
62
+ end
63
+ end
64
+
65
+ def compose_range(expressions, current)
66
+ range_start, range_end = current.expressions
67
+ range_start = if compound_token.size.between?(1, 2) && octal_digit?(range_start.text)
68
+ compound_token.dup << range_start
69
+ else
70
+ [range_start]
71
+ end
72
+ range_end = [range_end]
73
+ range_end.concat(pop_octal_digits(expressions)) if escaped_octal?(range_end.first)
74
+ [range_start, range_end]
75
+ end
76
+
77
+ def escaped_octal?(expr)
78
+ expr.text =~ /^\\[0-7]$/
79
+ end
80
+
81
+ def octal_digit?(char)
82
+ ('0'..'7').cover?(char)
83
+ end
84
+
85
+ def pop_octal_digits(expressions)
86
+ digits = []
87
+
88
+ 2.times do
89
+ next unless (next_child = expressions.first)
90
+ next unless next_child.type == :literal && next_child.text =~ /^[0-7]$/
91
+
92
+ digits << expressions.shift
93
+ end
94
+
95
+ digits
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -47,6 +47,10 @@ module RuboCop
47
47
  @node.type == REGEXP_NAMED_CAPTURE_TYPE
48
48
  end
49
49
 
50
+ def exception_assignment?
51
+ node.parent&.resbody_type? && node.parent.exception_variable == node
52
+ end
53
+
50
54
  def operator_assignment?
51
55
  return false unless meta_assignment_node
52
56
 
@@ -59,6 +63,18 @@ module RuboCop
59
63
  meta_assignment_node.type == MULTIPLE_ASSIGNMENT_TYPE
60
64
  end
61
65
 
66
+ def rest_assignment?
67
+ return false unless meta_assignment_node
68
+
69
+ meta_assignment_node.type == REST_ASSIGNMENT_TYPE
70
+ end
71
+
72
+ def for_assignment?
73
+ return false unless meta_assignment_node
74
+
75
+ meta_assignment_node.for_type?
76
+ end
77
+
62
78
  def operator
63
79
  assignment_node = meta_assignment_node || @node
64
80
  assignment_node.loc.operator.source
@@ -66,7 +82,10 @@ module RuboCop
66
82
 
67
83
  def meta_assignment_node
68
84
  unless instance_variable_defined?(:@meta_assignment_node)
69
- @meta_assignment_node = operator_assignment_node || multiple_assignment_node
85
+ @meta_assignment_node = operator_assignment_node ||
86
+ multiple_assignment_node ||
87
+ rest_assignment_node ||
88
+ for_assignment_node
70
89
  end
71
90
 
72
91
  @meta_assignment_node
@@ -90,6 +109,19 @@ module RuboCop
90
109
 
91
110
  grandparent_node
92
111
  end
112
+
113
+ def rest_assignment_node
114
+ return nil unless node.parent
115
+ return nil unless node.parent.type == REST_ASSIGNMENT_TYPE
116
+
117
+ node.parent
118
+ end
119
+
120
+ def for_assignment_node
121
+ return nil unless node.parent&.for_type?
122
+
123
+ node.parent
124
+ end
93
125
  end
94
126
  end
95
127
  end
@@ -113,14 +113,14 @@ module RuboCop
113
113
  def accessible_variables
114
114
  scope_stack.reverse_each.with_object([]) do |scope, variables|
115
115
  variables.concat(scope.variables.values)
116
- break variables unless scope.node.block_type?
116
+ break variables unless scope.node.block_type? || scope.node.numblock_type?
117
117
  end
118
118
  end
119
119
 
120
120
  private
121
121
 
122
122
  def mark_variable_as_captured_by_block_if_so(variable)
123
- return unless current_scope.node.block_type?
123
+ return unless current_scope.node.block_type? || current_scope.node.numblock_type?
124
124
  return if variable.scope == current_scope
125
125
 
126
126
  variable.capture_with_block!
@@ -40,6 +40,7 @@ module RuboCop
40
40
  OPERATOR_ASSIGNMENT_TYPES = (LOGICAL_OPERATOR_ASSIGNMENT_TYPES + [:op_asgn]).freeze
41
41
 
42
42
  MULTIPLE_ASSIGNMENT_TYPE = :masgn
43
+ REST_ASSIGNMENT_TYPE = :splat
43
44
 
44
45
  VARIABLE_REFERENCE_TYPE = :lvar
45
46
 
@@ -198,7 +198,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
198
198
  table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n")
199
199
  marked_contents = content.map do |plain_content|
200
200
  # Escape `|` with backslash to prevent the regexp `|` is not used as a table separator.
201
- plain_content.map { |c| "| #{c.gsub(/\|/, '\|')}" }.join("\n")
201
+ plain_content.map { |c| "| #{c.gsub('|', '\|')}" }.join("\n")
202
202
  end
203
203
  table << marked_contents.join("\n\n")
204
204
  table << "\n|===\n"
@@ -68,7 +68,9 @@ module RuboCop
68
68
  return { body: expression } unless (q = quantifier)
69
69
 
70
70
  body = expression.adjust(end_pos: -q.text.length)
71
- q_loc = expression.with(begin_pos: body.end_pos)
71
+ q.origin = origin
72
+ q.source = source if q.respond_to?(:source=) # for regexp_parser 1.8
73
+ q_loc = q.expression
72
74
  { body: body, quantifier: q_loc }
73
75
  end
74
76
  end
@@ -86,6 +88,7 @@ module RuboCop
86
88
  end
87
89
  end
88
90
  ::Regexp::Expression::Base.include Expression::Base
91
+ ::Regexp::Expression::Quantifier.include Expression::Base
89
92
  ::Regexp::Expression::CharacterSet.include Expression::CharacterSet
90
93
  end
91
94
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/standardrb/standard.
5
+ #
6
+ # Copyright (c) 2023 Test Double, Inc.
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Lsp
14
+ # Log for Language Server Protocol of RuboCop.
15
+ # @api private
16
+ class Logger
17
+ def self.log(message)
18
+ warn("[server] #{message}")
19
+ end
20
+ end
21
+ end
22
+ end