rubocop 1.45.1 → 1.50.1

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 (223) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +46 -15
  4. data/lib/rubocop/cli/command/auto_generate_config.rb +7 -0
  5. data/lib/rubocop/cli/command/execute_runner.rb +7 -2
  6. data/lib/rubocop/cli.rb +6 -6
  7. data/lib/rubocop/comment_config.rb +19 -0
  8. data/lib/rubocop/config.rb +3 -3
  9. data/lib/rubocop/config_loader.rb +8 -8
  10. data/lib/rubocop/cop/autocorrect_logic.rb +29 -13
  11. data/lib/rubocop/cop/base.rb +1 -1
  12. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  13. data/lib/rubocop/cop/cop.rb +2 -2
  14. data/lib/rubocop/cop/corrector.rb +1 -1
  15. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
  16. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +3 -3
  17. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +3 -3
  18. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  19. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  20. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -1
  21. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  22. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  23. data/lib/rubocop/cop/gemspec/dependency_version.rb +1 -1
  24. data/lib/rubocop/cop/internal_affairs/cop_description.rb +5 -5
  25. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +3 -3
  26. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/location_expression.rb +37 -0
  28. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  30. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +42 -0
  31. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  32. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  33. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +66 -0
  34. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  35. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -21
  36. data/lib/rubocop/cop/layout/class_structure.rb +6 -3
  37. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/empty_comment.rb +3 -3
  39. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  40. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  41. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
  42. data/lib/rubocop/cop/layout/end_alignment.rb +9 -1
  43. data/lib/rubocop/cop/layout/extra_spacing.rb +6 -1
  44. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  45. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -2
  46. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  47. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  48. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  49. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -3
  50. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -7
  51. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -7
  52. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  53. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  54. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  55. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  56. data/lib/rubocop/cop/layout/space_inside_parens.rb +2 -2
  57. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  58. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  59. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  60. data/lib/rubocop/cop/lint/debugger.rb +3 -0
  61. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  62. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  63. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  64. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  65. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -3
  66. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  67. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  68. data/lib/rubocop/cop/lint/empty_conditional_body.rb +4 -2
  69. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  70. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  71. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +46 -4
  72. data/lib/rubocop/cop/lint/missing_super.rb +31 -2
  73. data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -11
  74. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
  75. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +6 -10
  76. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  77. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  78. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +11 -5
  79. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -5
  80. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -1
  81. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  82. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
  83. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  84. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  85. data/lib/rubocop/cop/lint/refinement_import_methods.rb +2 -1
  86. data/lib/rubocop/cop/lint/rescue_type.rb +3 -3
  87. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +1 -1
  88. data/lib/rubocop/cop/lint/script_permission.rb +1 -1
  89. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  90. data/lib/rubocop/cop/lint/syntax.rb +4 -0
  91. data/lib/rubocop/cop/lint/to_enum_arguments.rb +13 -3
  92. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
  93. data/lib/rubocop/cop/lint/useless_access_modifier.rb +10 -10
  94. data/lib/rubocop/cop/lint/useless_method_definition.rb +10 -2
  95. data/lib/rubocop/cop/lint/useless_rescue.rb +6 -2
  96. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  97. data/lib/rubocop/cop/lint/void.rb +7 -3
  98. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  99. data/lib/rubocop/cop/metrics/class_length.rb +1 -0
  100. data/lib/rubocop/cop/metrics/collection_literal_length.rb +76 -0
  101. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -3
  102. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  103. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  104. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  105. data/lib/rubocop/cop/mixin/comments_help.rb +3 -3
  106. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  107. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +1 -1
  108. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +10 -5
  109. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  110. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  111. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +0 -3
  112. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  113. data/lib/rubocop/cop/mixin/range_help.rb +1 -6
  114. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -3
  115. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  116. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  117. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  118. data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
  119. data/lib/rubocop/cop/naming/method_name.rb +3 -3
  120. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  121. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  122. data/lib/rubocop/cop/registry.rb +3 -1
  123. data/lib/rubocop/cop/style/accessor_grouping.rb +39 -17
  124. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  125. data/lib/rubocop/cop/style/array_intersect.rb +1 -1
  126. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  127. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +1 -1
  128. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  129. data/lib/rubocop/cop/style/block_delimiters.rb +11 -2
  130. data/lib/rubocop/cop/style/case_like_if.rb +20 -3
  131. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  132. data/lib/rubocop/cop/style/class_equality_comparison.rb +42 -9
  133. data/lib/rubocop/cop/style/collection_compact.rb +1 -1
  134. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  135. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  136. data/lib/rubocop/cop/style/concat_array_literals.rb +10 -2
  137. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -6
  138. data/lib/rubocop/cop/style/copyright.rb +1 -1
  139. data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
  140. data/lib/rubocop/cop/style/dir_empty.rb +60 -0
  141. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  142. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +2 -2
  143. data/lib/rubocop/cop/style/documentation.rb +10 -4
  144. data/lib/rubocop/cop/style/documentation_method.rb +4 -4
  145. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  146. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  147. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  148. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  149. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  150. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  151. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  152. data/lib/rubocop/cop/style/file_read.rb +1 -1
  153. data/lib/rubocop/cop/style/file_write.rb +1 -1
  154. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  155. data/lib/rubocop/cop/style/guard_clause.rb +1 -1
  156. data/lib/rubocop/cop/style/hash_except.rb +4 -4
  157. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  158. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  159. data/lib/rubocop/cop/style/if_unless_modifier.rb +108 -15
  160. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  161. data/lib/rubocop/cop/style/inverse_methods.rb +5 -5
  162. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +2 -2
  163. data/lib/rubocop/cop/style/map_to_hash.rb +4 -1
  164. data/lib/rubocop/cop/style/map_to_set.rb +4 -1
  165. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -7
  166. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +44 -37
  167. data/lib/rubocop/cop/style/min_max.rb +3 -3
  168. data/lib/rubocop/cop/style/mixin_grouping.rb +4 -4
  169. data/lib/rubocop/cop/style/multiline_method_signature.rb +7 -4
  170. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  171. data/lib/rubocop/cop/style/negated_if_else_condition.rb +12 -7
  172. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  173. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -18
  174. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
  175. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  176. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  177. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +2 -2
  178. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  179. data/lib/rubocop/cop/style/redundant_line_continuation.rb +179 -0
  180. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -2
  181. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  182. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -8
  183. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +11 -4
  184. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  185. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -4
  186. data/lib/rubocop/cop/style/require_order.rb +1 -3
  187. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  188. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  189. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  190. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -3
  191. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  192. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  193. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  194. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -1
  195. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  196. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  197. data/lib/rubocop/cop/style/unpack_first.rb +3 -3
  198. data/lib/rubocop/cop/style/word_array.rb +17 -5
  199. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  200. data/lib/rubocop/cop/style/zero_length_predicate.rb +9 -5
  201. data/lib/rubocop/cop/team.rb +11 -8
  202. data/lib/rubocop/cop/util.rb +13 -4
  203. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  204. data/lib/rubocop/cops_documentation_generator.rb +10 -3
  205. data/lib/rubocop/directive_comment.rb +3 -3
  206. data/lib/rubocop/ext/comment.rb +18 -0
  207. data/lib/rubocop/ext/regexp_node.rb +1 -1
  208. data/lib/rubocop/ext/regexp_parser.rb +1 -1
  209. data/lib/rubocop/formatter/junit_formatter.rb +4 -1
  210. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  211. data/lib/rubocop/options.rb +4 -1
  212. data/lib/rubocop/result_cache.rb +1 -1
  213. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  214. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  215. data/lib/rubocop/rspec/support.rb +1 -0
  216. data/lib/rubocop/server/cache.rb +1 -1
  217. data/lib/rubocop/server/core.rb +1 -1
  218. data/lib/rubocop/server/helper.rb +1 -1
  219. data/lib/rubocop/server/server_command/exec.rb +1 -1
  220. data/lib/rubocop/target_ruby.rb +1 -1
  221. data/lib/rubocop/version.rb +1 -1
  222. data/lib/rubocop.rb +8 -0
  223. metadata +20 -9
@@ -31,22 +31,26 @@ module RuboCop
31
31
  def on_masgn(node)
32
32
  lhs, rhs = *node
33
33
  lhs_elements = *lhs
34
+ rhs = rhs.body if rhs.rescue_type?
34
35
  rhs_elements = Array(rhs).compact # edge case for one constant
35
36
 
36
37
  return if allowed_lhs?(lhs) || allowed_rhs?(rhs) ||
37
38
  allowed_masign?(lhs_elements, rhs_elements)
38
39
 
39
- add_offense(node) { |corrector| autocorrect(corrector, node) }
40
+ range = node.source_range.begin.join(rhs.source_range.end)
41
+
42
+ add_offense(range) do |corrector|
43
+ autocorrect(corrector, node, lhs, rhs)
44
+ end
40
45
  end
41
46
 
42
47
  private
43
48
 
44
- def autocorrect(corrector, node)
45
- left, right = *node
46
- left_elements = *left
47
- right_elements = Array(right).compact
49
+ def autocorrect(corrector, node, lhs, rhs)
50
+ left_elements = *lhs
51
+ right_elements = Array(rhs).compact
48
52
  order = find_valid_order(left_elements, right_elements)
49
- correction = assignment_corrector(node, order)
53
+ correction = assignment_corrector(node, rhs, order)
50
54
 
51
55
  corrector.replace(correction.correction_range, correction.correction)
52
56
  end
@@ -77,14 +81,19 @@ module RuboCop
77
81
  node.block_type? || node.send_type?
78
82
  end
79
83
 
80
- def assignment_corrector(node, order)
81
- _assignment, modifier = *node.parent
84
+ def assignment_corrector(node, rhs, order)
85
+ if node.parent&.rescue_type?
86
+ _assignment, modifier = *node.parent
87
+ else
88
+ _assignment, modifier = *rhs.parent
89
+ end
90
+
82
91
  if modifier_statement?(node.parent)
83
- ModifierCorrector.new(node, config, order)
92
+ ModifierCorrector.new(node, rhs, modifier, config, order)
84
93
  elsif rescue_modifier?(modifier)
85
- RescueCorrector.new(node, config, order)
94
+ RescueCorrector.new(node, rhs, modifier, config, order)
86
95
  else
87
- GenericCorrector.new(node, config, order)
96
+ GenericCorrector.new(node, rhs, modifier, config, order)
88
97
  end
89
98
  end
90
99
 
@@ -181,10 +190,12 @@ module RuboCop
181
190
  class GenericCorrector
182
191
  include Alignment
183
192
 
184
- attr_reader :config, :node
193
+ attr_reader :node, :rhs, :rescue_result, :config
185
194
 
186
- def initialize(node, config, new_elements)
195
+ def initialize(node, rhs, modifier, config, new_elements)
187
196
  @node = node
197
+ @rhs = rhs
198
+ _, _, @rescue_result = *modifier
188
199
  @config = config
189
200
  @new_elements = new_elements
190
201
  end
@@ -228,13 +239,10 @@ module RuboCop
228
239
  # protected by rescue
229
240
  class RescueCorrector < GenericCorrector
230
241
  def correction
231
- _node, rescue_clause = *node.parent
232
- _, _, rescue_result = *rescue_clause
233
-
234
242
  # If the parallel assignment uses a rescue modifier and it is the
235
243
  # only contents of a method, then we want to make use of the
236
244
  # implicit begin
237
- if node.parent.parent&.def_type?
245
+ if rhs.parent.parent.parent&.def_type?
238
246
  super + def_correction(rescue_result)
239
247
  else
240
248
  begin_correction(rescue_result)
@@ -242,7 +250,7 @@ module RuboCop
242
250
  end
243
251
 
244
252
  def correction_range
245
- node.parent.source_range
253
+ rhs.parent.parent.source_range
246
254
  end
247
255
 
248
256
  private
@@ -92,9 +92,8 @@ module RuboCop
92
92
 
93
93
  def contains_delimiter?(node, delimiters)
94
94
  delimiters_regexp = Regexp.union(delimiters)
95
- node
96
- .children.map { |n| string_source(n) }.compact
97
- .any? { |s| delimiters_regexp.match?(s) }
95
+
96
+ node.children.map { |n| string_source(n) }.compact.any?(delimiters_regexp)
98
97
  end
99
98
 
100
99
  def string_source(node)
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  # Report offense only if changing case doesn't change semantics,
46
46
  # i.e., if the string would become dynamic or has special characters.
47
- ast = ProcessedSource.new(corrected(node.source), target_ruby_version).ast
47
+ ast = parse(corrected(node.source)).ast
48
48
  return if node.children != ast.children
49
49
 
50
50
  add_offense(node.loc.begin) do |corrector|
@@ -70,8 +70,8 @@ module RuboCop
70
70
  end
71
71
 
72
72
  def range_of_offense(node)
73
- return node.loc.expression unless node.ternary?
74
- return node.loc.expression if node.ternary? && branches_have_method?(node)
73
+ return node.source_range unless node.ternary?
74
+ return node.source_range if node.ternary? && branches_have_method?(node)
75
75
 
76
76
  range_between(node.loc.question.begin_pos, node.loc.colon.end_pos)
77
77
  end
@@ -33,11 +33,11 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def opening_brace(node)
36
- node.loc.begin.join(node.children.first.loc.expression.begin)
36
+ node.loc.begin.join(node.children.first.source_range.begin)
37
37
  end
38
38
 
39
39
  def closing_brace(node)
40
- node.children.last.loc.expression.end.join(node.loc.end)
40
+ node.children.last.source_range.end.join(node.loc.end)
41
41
  end
42
42
  end
43
43
  end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def autocorrect_variable_interpolation(corrector, embedded_node, node)
100
- replacement = "#{embedded_node.loc.expression.source}.to_s"
100
+ replacement = "#{embedded_node.source}.to_s"
101
101
 
102
102
  corrector.replace(node, replacement)
103
103
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
 
108
108
  source = if require_parentheses?(embedded_var)
109
109
  receiver = range_between(
110
- embedded_var.loc.expression.begin_pos, embedded_var.loc.selector.end_pos
110
+ embedded_var.source_range.begin_pos, embedded_var.loc.selector.end_pos
111
111
  )
112
112
  arguments = embedded_var.arguments.map(&:source).join(', ')
113
113
 
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Check for redundant line continuation.
7
+ #
8
+ # This cop marks a line continuation as redundant if removing the backslash
9
+ # does not result in a syntax error.
10
+ # However, a backslash at the end of a comment or
11
+ # for string concatenation is not redundant and is not considered an offense.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # foo. \
16
+ # bar
17
+ # foo \
18
+ # &.bar \
19
+ # .baz
20
+ #
21
+ # # good
22
+ # foo.
23
+ # bar
24
+ # foo
25
+ # &.bar
26
+ # .baz
27
+ #
28
+ # # bad
29
+ # [foo, \
30
+ # bar]
31
+ # {foo: \
32
+ # bar}
33
+ #
34
+ # # good
35
+ # [foo,
36
+ # bar]
37
+ # {foo:
38
+ # bar}
39
+ #
40
+ # # bad
41
+ # foo(bar, \
42
+ # baz)
43
+ #
44
+ # # good
45
+ # foo(bar,
46
+ # baz)
47
+ #
48
+ # # also good - backslash in string concatenation is not redundant
49
+ # foo('bar' \
50
+ # 'baz')
51
+ #
52
+ # # also good - backslash at the end of a comment is not redundant
53
+ # foo(bar, # \
54
+ # baz)
55
+ #
56
+ # # also good - backslash at the line following the newline begins with a + or -,
57
+ # # it is not redundant
58
+ # 1 \
59
+ # + 2 \
60
+ # - 3
61
+ #
62
+ # # also good - backslash with newline between the method name and its arguments,
63
+ # # it is not redundant.
64
+ # some_method \
65
+ # (argument)
66
+ #
67
+ class RedundantLineContinuation < Base
68
+ include MatchRange
69
+ extend AutoCorrector
70
+
71
+ MSG = 'Redundant line continuation.'
72
+ ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
73
+
74
+ def on_new_investigation
75
+ return unless processed_source.ast
76
+
77
+ each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
78
+ next if require_line_continuation?(range)
79
+ next unless redundant_line_continuation?(range)
80
+
81
+ add_offense(range) do |corrector|
82
+ corrector.remove_leading(range, 1)
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def require_line_continuation?(range)
90
+ !ends_with_backslash_without_comment?(range.source_line) ||
91
+ string_concatenation?(range.source_line) ||
92
+ start_with_arithmetic_operator?(processed_source[range.line]) ||
93
+ inside_string_literal_or_method_with_argument?(range)
94
+ end
95
+
96
+ def ends_with_backslash_without_comment?(source_line)
97
+ source_line.gsub(/#.+/, '').end_with?('\\')
98
+ end
99
+
100
+ def string_concatenation?(source_line)
101
+ /["']\s*\\\z/.match?(source_line)
102
+ end
103
+
104
+ def inside_string_literal_or_method_with_argument?(range)
105
+ processed_source.tokens.each_cons(2).any? do |token, next_token|
106
+ inside_string_literal?(range, token) || method_with_argument?(token, next_token)
107
+ end
108
+ end
109
+
110
+ def redundant_line_continuation?(range)
111
+ return true unless (node = find_node_for_line(range.line))
112
+ return false if argument_newline?(node)
113
+
114
+ source = node.parent ? node.parent.source : node.source
115
+ parse(source.gsub(/\\\n/, "\n")).valid_syntax?
116
+ end
117
+
118
+ def inside_string_literal?(range, token)
119
+ ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
120
+ end
121
+
122
+ # A method call without parentheses such as the following cannot remove `\`:
123
+ #
124
+ # do_something \
125
+ # argument
126
+ def method_with_argument?(current_token, next_token)
127
+ current_token.type == :tIDENTIFIER && next_token.type == :tIDENTIFIER
128
+ end
129
+
130
+ def argument_newline?(node)
131
+ node = node.children.first if node.root? && node.begin_type?
132
+
133
+ if argument_is_method?(node)
134
+ argument_newline?(node.first_argument)
135
+ else
136
+ return false unless method_call_with_arguments?(node)
137
+
138
+ node.loc.selector.line != node.first_argument.loc.line
139
+ end
140
+ end
141
+
142
+ def find_node_for_line(line)
143
+ processed_source.ast.each_node do |node|
144
+ return node if same_line?(node, line)
145
+ end
146
+ end
147
+
148
+ def same_line?(node, line)
149
+ return unless (source_range = node.source_range)
150
+
151
+ if node.is_a?(AST::StrNode)
152
+ if node.heredoc?
153
+ (node.loc.heredoc_body.line..node.loc.heredoc_body.last_line).cover?(line)
154
+ else
155
+ (source_range.line..source_range.last_line).cover?(line)
156
+ end
157
+ else
158
+ source_range.line == line
159
+ end
160
+ end
161
+
162
+ def argument_is_method?(node)
163
+ return false unless node.send_type?
164
+ return false unless (first_argument = node.first_argument)
165
+
166
+ method_call_with_arguments?(first_argument)
167
+ end
168
+
169
+ def method_call_with_arguments?(node)
170
+ node.call_type? && !node.arguments.empty?
171
+ end
172
+
173
+ def start_with_arithmetic_operator?(source_line)
174
+ %r{\A\s*[+\-*/%]}.match?(source_line)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -98,7 +98,7 @@ module RuboCop
98
98
  end
99
99
 
100
100
  def like_method_argument_parentheses?(node)
101
- node.send_type? && node.arguments.one? &&
101
+ node.send_type? && node.arguments.one? && !node.parenthesized? &&
102
102
  !node.arithmetic_operation? && node.first_argument.begin_type?
103
103
  end
104
104
 
@@ -153,7 +153,7 @@ module RuboCop
153
153
 
154
154
  return if node.send_type? && !method_call_with_redundant_parentheses?(node)
155
155
 
156
- offense(begin_node, 'an unary operation')
156
+ offense(begin_node, 'a unary operation')
157
157
  end
158
158
 
159
159
  def offense(node, msg)
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  return true if STRING_INTERPOLATION_REGEXP.match?(src)
95
95
 
96
- src.scan(/\\./).any? { |s| ESCAPED_NON_BACKSLASH.match?(s) }
96
+ src.scan(/\\./).any?(ESCAPED_NON_BACKSLASH)
97
97
  end
98
98
 
99
99
  def acceptable_capital_q?(node)
@@ -63,7 +63,7 @@ module RuboCop
63
63
  next if expr.type != :set || expr.expressions.size != 1
64
64
  next if expr.negative?
65
65
  next if %i[set posixclass nonposixclass].include?(expr.expressions.first.type)
66
- next if multiple_codepoins?(expr.expressions.first)
66
+ next if multiple_codepoints?(expr.expressions.first)
67
67
 
68
68
  yield expr
69
69
  end
@@ -74,13 +74,13 @@ module RuboCop
74
74
 
75
75
  non_redundant =
76
76
  whitespace_in_free_space_mode?(node, class_elem) ||
77
- backslash_b?(class_elem) || backslash_zero?(class_elem) ||
77
+ backslash_b?(class_elem) || octal_requiring_char_class?(class_elem) ||
78
78
  requires_escape_outside_char_class?(class_elem)
79
79
 
80
80
  !non_redundant
81
81
  end
82
82
 
83
- def multiple_codepoins?(expression)
83
+ def multiple_codepoints?(expression)
84
84
  expression.respond_to?(:codepoints) && expression.codepoints.count >= 2
85
85
  end
86
86
 
@@ -104,11 +104,10 @@ module RuboCop
104
104
  elem == '\b'
105
105
  end
106
106
 
107
- def backslash_zero?(elem)
108
- # See https://github.com/rubocop/rubocop/issues/11067 for details - in short "\0" != "0" -
109
- # the former means an Unicode code point `"\u0000"`, the latter a number character `"0"`.
110
- # Similarly "\032" means "\u001A". Other numbers starting with "\0" can also be mentioned.
111
- elem == '\0'
107
+ def octal_requiring_char_class?(elem)
108
+ # The octal escapes \1 to \7 only work inside a character class
109
+ # because they would be a backreference outside it.
110
+ elem.match?(/\A\\[1-7]\z/)
112
111
  end
113
112
 
114
113
  def requires_escape_outside_char_class?(elem)
@@ -74,11 +74,18 @@ module RuboCop
74
74
 
75
75
  def char_class_begins_or_ends_with_escaped_hyphen?(node, index)
76
76
  # The hyphen character is allowed to be escaped within a character class
77
- # but it's not necessry to escape hyphen if it's the first or last character
77
+ # but it's not necessary to escape hyphen if it's the first or last character
78
78
  # within the character class. This method checks if that's the case.
79
79
  # e.g. "[0-9\\-]" or "[\\-0-9]" would return true
80
- contents_range(node).source[index - 1] == '[' ||
81
- contents_range(node).source[index + 2] == ']'
80
+ content = contents_range(node).source
81
+
82
+ if content[index + 2] == ']'
83
+ true
84
+ elsif content[index - 1] == '['
85
+ index < 2 || content[index - 2] != '\\'
86
+ else
87
+ false
88
+ end
82
89
  end
83
90
 
84
91
  def delimiter?(node, char)
@@ -100,7 +107,7 @@ module RuboCop
100
107
  end
101
108
  end
102
109
  # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
103
- # It's for compatibility with regexp_arser 1.8 and will never be maintained.
110
+ # It's for compatibility with regexp_parser 1.8 and will never be maintained.
104
111
  else
105
112
  def each_escape(node)
106
113
  node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
@@ -129,13 +129,13 @@ module RuboCop
129
129
  end
130
130
 
131
131
  def offense_range(sort_node, node)
132
- range_between(sort_node.loc.selector.begin_pos, node.loc.expression.end_pos)
132
+ range_between(sort_node.loc.selector.begin_pos, node.source_range.end_pos)
133
133
  end
134
134
 
135
135
  def message(node, sorter, accessor)
136
136
  accessor_source = range_between(
137
137
  node.loc.selector.begin_pos,
138
- node.loc.expression.end_pos
138
+ node.source_range.end_pos
139
139
  ).source
140
140
 
141
141
  format(MSG,
@@ -146,7 +146,7 @@ module RuboCop
146
146
 
147
147
  def autocorrect(corrector, node, sort_node, sorter, accessor)
148
148
  # Remove accessor, e.g. `first` or `[-1]`.
149
- corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
149
+ corrector.remove(range_between(accessor_start(node), node.source_range.end_pos))
150
150
  # Replace "sort" or "sort_by" with the appropriate min/max method.
151
151
  corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
152
152
  # Replace to avoid syntax errors when followed by a logical operator.
@@ -36,7 +36,6 @@ module RuboCop
36
36
  # STR
37
37
  class RedundantStringEscape < Base
38
38
  include MatchRange
39
- include RangeHelp
40
39
  extend AutoCorrector
41
40
 
42
41
  MSG = 'Redundant escape of %<char>s inside string literal.'
@@ -64,10 +63,10 @@ module RuboCop
64
63
  def str_contents_range(node)
65
64
  if heredoc?(node)
66
65
  node.loc.heredoc_body
66
+ elsif node.str_type?
67
+ node.source_range
67
68
  elsif begin_loc_present?(node)
68
69
  contents_range(node)
69
- else
70
- node.loc.expression
71
70
  end
72
71
  end
73
72
 
@@ -139,7 +138,7 @@ module RuboCop
139
138
 
140
139
  def heredoc_with_disabled_interpolation?(node)
141
140
  if heredoc?(node)
142
- node.loc.expression.source.end_with?("'")
141
+ node.source.end_with?("'")
143
142
  elsif node.parent&.dstr_type?
144
143
  heredoc_with_disabled_interpolation?(node.parent)
145
144
  else
@@ -125,9 +125,7 @@ module RuboCop
125
125
  end
126
126
 
127
127
  def in_same_section?(node1, node2)
128
- !node1.location.expression.with(
129
- end_pos: node2.location.expression.end_pos
130
- ).source.include?("\n\n")
128
+ !node1.source_range.with(end_pos: node2.source_range.end_pos).source.include?("\n\n")
131
129
  end
132
130
  end
133
131
  end
@@ -105,11 +105,11 @@ module RuboCop
105
105
  private
106
106
 
107
107
  def offense_for_implicit_enforced_style(node, error)
108
- range = node.loc.keyword.join(error.loc.expression)
108
+ range = node.loc.keyword.join(error.source_range)
109
109
 
110
110
  add_offense(range, message: MSG_IMPLICIT) do |corrector|
111
111
  error = rescue_standard_error?(node)
112
- range = range_between(node.loc.keyword.end_pos, error.loc.expression.end_pos)
112
+ range = range_between(node.loc.keyword.end_pos, error.source_range.end_pos)
113
113
 
114
114
  corrector.remove(range)
115
115
  end
@@ -297,11 +297,11 @@ module RuboCop
297
297
  end
298
298
 
299
299
  def begin_range(node, method_call)
300
- range_between(node.loc.expression.begin_pos, method_call.loc.expression.begin_pos)
300
+ range_between(node.source_range.begin_pos, method_call.source_range.begin_pos)
301
301
  end
302
302
 
303
303
  def end_range(node, method_call)
304
- range_between(method_call.loc.expression.end_pos, node.loc.expression.end_pos)
304
+ range_between(method_call.source_range.end_pos, node.source_range.end_pos)
305
305
  end
306
306
 
307
307
  def add_safe_nav_to_all_methods_in_chain(corrector,
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # @safety
10
10
  # This cop is unsafe because `x..-1` and `x..` are only guaranteed to
11
- # be equivalent for `Array#[]`, and the cop cannot determine what class
11
+ # be equivalent for `Array#[]`, `String#[]`, and the cop cannot determine what class
12
12
  # the receiver is.
13
13
  #
14
14
  # For example:
@@ -167,7 +167,7 @@ module RuboCop
167
167
  corrector.insert_before(condition,
168
168
  "#{'!' if node.unless?}#{replace_condition(node.condition)} && ")
169
169
 
170
- corrector.remove(node.condition.loc.expression)
170
+ corrector.remove(node.condition)
171
171
  corrector.remove(range_with_surrounding_space(node.loc.keyword, newlines: false))
172
172
  corrector.replace(if_branch.loc.keyword, 'if')
173
173
  end
@@ -187,7 +187,7 @@ module RuboCop
187
187
  return if end_pos > begin_pos
188
188
 
189
189
  corrector.replace(range_between(end_pos, begin_pos), '(')
190
- corrector.insert_after(condition.last_argument.source_range, ')')
190
+ corrector.insert_after(condition.last_argument, ')')
191
191
  end
192
192
 
193
193
  def insert_bang(corrector, node, is_modify_form)
@@ -240,7 +240,7 @@ module RuboCop
240
240
  end
241
241
 
242
242
  def outer_condition_modify_form?(node, if_branch)
243
- node.condition.loc.expression.begin_pos > if_branch.condition.loc.expression.begin_pos
243
+ node.condition.source_range.begin_pos > if_branch.condition.source_range.begin_pos
244
244
  end
245
245
  end
246
246
  end
@@ -49,7 +49,7 @@ module RuboCop
49
49
  end
50
50
 
51
51
  def stderr_puts_range(send)
52
- range_between(send.loc.expression.begin_pos, send.loc.selector.end_pos)
52
+ range_between(send.source_range.begin_pos, send.loc.selector.end_pos)
53
53
  end
54
54
  end
55
55
  end
@@ -55,7 +55,7 @@ module RuboCop
55
55
  elsif (class_node = parent.parent).body.nil?
56
56
  corrector.remove(range_for_empty_class_body(class_node, parent))
57
57
  else
58
- corrector.insert_after(parent.loc.expression, ' do')
58
+ corrector.insert_after(parent, ' do')
59
59
  end
60
60
  end
61
61
 
@@ -34,6 +34,7 @@ module RuboCop
34
34
  )
35
35
  end
36
36
  end
37
+ alias on_sclass on_class
37
38
  end
38
39
  end
39
40
  end
@@ -144,7 +144,7 @@ module RuboCop
144
144
  end
145
145
 
146
146
  def range_for_parentheses(offense, left)
147
- range_between(offense.source_range.begin_pos - 1, left.loc.expression.end_pos - 1)
147
+ range_between(offense.source_range.begin_pos - 1, left.source_range.end_pos - 1)
148
148
  end
149
149
  end
150
150
  end
@@ -238,7 +238,7 @@ module RuboCop
238
238
 
239
239
  indent = ' ' * node.loc.column
240
240
  corrector.replace(
241
- node.source_range,
241
+ node,
242
242
  ['class << self',
243
243
  "#{indent} #{accessor(kind, node.method_name)}",
244
244
  "#{indent}end"].join("\n")
@@ -8,6 +8,7 @@ module RuboCop
8
8
  # to read and understand.
9
9
  #
10
10
  # This cop supports two styles:
11
+ #
11
12
  # - `forbid_mixed_logical_operators` (default)
12
13
  # - `forbid_logical_operators`
13
14
  #
@@ -52,9 +52,9 @@ module RuboCop
52
52
  private
53
53
 
54
54
  def first_element_range(node, unpack_call)
55
- Parser::Source::Range.new(node.loc.expression.source_buffer,
56
- unpack_call.loc.expression.end_pos,
57
- node.loc.expression.end_pos)
55
+ Parser::Source::Range.new(node.source_range.source_buffer,
56
+ unpack_call.source_range.end_pos,
57
+ node.source_range.end_pos)
58
58
  end
59
59
  end
60
60
  end