rubocop 1.50.2 → 1.57.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (232) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -3
  3. data/config/default.yml +110 -14
  4. data/config/obsoletion.yml +5 -0
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
  6. data/lib/rubocop/cli/command/lsp.rb +19 -0
  7. data/lib/rubocop/cli.rb +4 -1
  8. data/lib/rubocop/config.rb +4 -0
  9. data/lib/rubocop/config_finder.rb +2 -2
  10. data/lib/rubocop/config_loader_resolver.rb +4 -3
  11. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  12. data/lib/rubocop/config_obsoletion.rb +2 -2
  13. data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
  14. data/lib/rubocop/cop/base.rb +6 -2
  15. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  16. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  17. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  18. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  19. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  20. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  21. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  22. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  23. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  24. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  25. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  26. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  27. data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
  28. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  29. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  30. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  31. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  32. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  33. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  34. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  35. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  36. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  37. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  38. data/lib/rubocop/cop/layout/end_alignment.rb +7 -1
  39. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  40. data/lib/rubocop/cop/layout/heredoc_indentation.rb +3 -0
  41. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  42. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  43. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  44. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  45. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  46. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  47. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  48. data/lib/rubocop/cop/layout/redundant_line_break.rb +14 -4
  49. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  50. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  51. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  52. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -1
  53. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  54. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  56. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  57. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  58. data/lib/rubocop/cop/lint/debugger.rb +18 -5
  59. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  60. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  61. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  62. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  63. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  64. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  65. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  66. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  67. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  68. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  69. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  70. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  71. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  72. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  73. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  74. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  75. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  76. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  77. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  78. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +20 -4
  79. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  80. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +11 -4
  81. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  82. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  83. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  84. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  85. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  86. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  87. data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
  88. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  89. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  90. data/lib/rubocop/cop/lint/void.rb +78 -10
  91. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  92. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  93. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  94. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  95. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  96. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  97. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  98. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  99. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  100. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  101. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  102. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  103. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
  104. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  105. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +5 -7
  106. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  107. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  108. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  109. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  110. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  111. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  112. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  113. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +25 -10
  114. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  115. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  116. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  117. data/lib/rubocop/cop/style/alias.rb +9 -8
  118. data/lib/rubocop/cop/style/arguments_forwarding.rb +280 -63
  119. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  120. data/lib/rubocop/cop/style/attr.rb +11 -1
  121. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  122. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  123. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  124. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  125. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  126. data/lib/rubocop/cop/style/collection_compact.rb +16 -6
  127. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  128. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  129. data/lib/rubocop/cop/style/combinable_loops.rb +30 -8
  130. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  131. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -3
  132. data/lib/rubocop/cop/style/copyright.rb +5 -2
  133. data/lib/rubocop/cop/style/dir.rb +1 -1
  134. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  135. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  136. data/lib/rubocop/cop/style/documentation.rb +1 -1
  137. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  138. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  139. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  140. data/lib/rubocop/cop/style/file_read.rb +2 -2
  141. data/lib/rubocop/cop/style/for.rb +1 -1
  142. data/lib/rubocop/cop/style/format_string.rb +24 -3
  143. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  144. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  145. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  146. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  147. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  148. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  149. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  150. data/lib/rubocop/cop/style/identical_conditional_branches.rb +31 -5
  151. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  152. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  153. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  154. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
  155. data/lib/rubocop/cop/style/lambda.rb +3 -3
  156. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  157. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  158. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  159. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  160. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  161. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  162. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  163. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  164. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  165. data/lib/rubocop/cop/style/operator_method_call.rb +6 -0
  166. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  167. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  168. data/lib/rubocop/cop/style/redundant_argument.rb +6 -1
  169. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  170. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  171. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  172. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  173. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  174. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  175. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  176. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
  177. data/lib/rubocop/cop/style/redundant_parentheses.rb +42 -16
  178. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  179. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  180. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  181. data/lib/rubocop/cop/style/redundant_return.rb +7 -2
  182. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  183. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  184. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
  185. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  186. data/lib/rubocop/cop/style/require_order.rb +11 -5
  187. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  188. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  189. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  190. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  191. data/lib/rubocop/cop/style/semicolon.rb +12 -4
  192. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  193. data/lib/rubocop/cop/style/single_argument_dig.rb +2 -1
  194. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  195. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  196. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
  197. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  198. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  199. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  200. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  201. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  202. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  203. data/lib/rubocop/cop/team.rb +1 -1
  204. data/lib/rubocop/cop/util.rb +1 -1
  205. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  206. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  207. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  208. data/lib/rubocop/cop/variable_force.rb +1 -0
  209. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  210. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  211. data/lib/rubocop/file_finder.rb +4 -7
  212. data/lib/rubocop/formatter/html_formatter.rb +4 -2
  213. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  214. data/lib/rubocop/lsp/logger.rb +22 -0
  215. data/lib/rubocop/lsp/routes.rb +246 -0
  216. data/lib/rubocop/lsp/runtime.rb +99 -0
  217. data/lib/rubocop/lsp/server.rb +68 -0
  218. data/lib/rubocop/lsp/severity.rb +27 -0
  219. data/lib/rubocop/magic_comment.rb +12 -10
  220. data/lib/rubocop/options.rb +11 -1
  221. data/lib/rubocop/result_cache.rb +5 -1
  222. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  223. data/lib/rubocop/rspec/shared_contexts.rb +2 -3
  224. data/lib/rubocop/runner.rb +5 -3
  225. data/lib/rubocop/server/cache.rb +1 -0
  226. data/lib/rubocop/server/client_command/exec.rb +3 -2
  227. data/lib/rubocop/string_interpreter.rb +3 -3
  228. data/lib/rubocop/target_finder.rb +7 -3
  229. data/lib/rubocop/target_ruby.rb +12 -7
  230. data/lib/rubocop/version.rb +10 -6
  231. data/lib/rubocop.rb +15 -0
  232. metadata +45 -11
@@ -54,7 +54,7 @@ module RuboCop
54
54
  alias on_defs on_def
55
55
 
56
56
  def on_block(node)
57
- return unless node.send_node.method?(:define_method)
57
+ return unless node.method?(:define_method)
58
58
 
59
59
  check_code_length(node)
60
60
  end
@@ -117,8 +117,7 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def capturing_variable?(name)
120
- # TODO: Remove `Symbol#to_s` after supporting only Ruby >= 2.7.
121
- name && !name.to_s.start_with?('_')
120
+ name && !name.start_with?('_')
122
121
  end
123
122
 
124
123
  def branch?(node)
@@ -10,7 +10,7 @@ module RuboCop
10
10
  include Util
11
11
 
12
12
  FOLDABLE_TYPES = %i[array hash heredoc send csend].freeze
13
- CLASSLIKE_TYPES = %i[class module sclass].freeze
13
+ CLASSLIKE_TYPES = %i[class module].freeze
14
14
  private_constant :FOLDABLE_TYPES, :CLASSLIKE_TYPES
15
15
 
16
16
  def initialize(node, processed_source, count_comments: false, foldable_types: [])
@@ -63,7 +63,7 @@ module RuboCop
63
63
  types
64
64
  end
65
65
 
66
- def code_length(node)
66
+ def code_length(node) # rubocop:disable Metrics/MethodLength
67
67
  if classlike_node?(node)
68
68
  classlike_code_length(node)
69
69
  elsif heredoc_node?(node)
@@ -72,7 +72,14 @@ module RuboCop
72
72
  body = extract_body(node)
73
73
  return 0 unless body
74
74
 
75
- body.source.each_line.count { |line| !irrelevant_line?(line) }
75
+ source =
76
+ if node_with_heredoc?(body)
77
+ source_from_node_with_heredoc(body)
78
+ else
79
+ body.source.lines
80
+ end
81
+
82
+ source.count { |line| !irrelevant_line?(line) }
76
83
  end
77
84
  end
78
85
 
@@ -138,7 +145,7 @@ module RuboCop
138
145
 
139
146
  def extract_body(node)
140
147
  case node.type
141
- when :class, :module, :block, :numblock, :def, :defs
148
+ when :class, :module, :sclass, :block, :numblock, :def, :defs
142
149
  node.body
143
150
  when :casgn
144
151
  _scope, _name, value = *node
@@ -175,6 +182,27 @@ module RuboCop
175
182
  def another_args?(node)
176
183
  node.call_type? && node.arguments.count > 1
177
184
  end
185
+
186
+ def node_with_heredoc?(node)
187
+ node.each_descendant(:str, :dstr).any? { |descendant| heredoc_node?(descendant) }
188
+ end
189
+
190
+ def source_from_node_with_heredoc(node)
191
+ last_line = -1
192
+ node.each_descendant do |descendant|
193
+ next unless descendant.source
194
+
195
+ descendant_last_line =
196
+ if heredoc_node?(descendant)
197
+ descendant.loc.heredoc_end.line
198
+ else
199
+ descendant.last_line
200
+ end
201
+
202
+ last_line = [last_line, descendant_last_line].max
203
+ end
204
+ @processed_source[(node.first_line - 1)..(last_line - 1)]
205
+ end
178
206
  end
179
207
  end
180
208
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # The token that makes up a disable comment.
17
17
  # The allowed specification for comments after `# rubocop: disable` is
18
18
  # `DepartmentName/CopName` or` all`.
19
- DISABLING_COPS_CONTENT_TOKEN = %r{[A-z]+/[A-z]+|all}.freeze
19
+ DISABLING_COPS_CONTENT_TOKEN = %r{[A-Za-z]+/[A-Za-z]+|all}.freeze
20
20
 
21
21
  def on_new_investigation
22
22
  processed_source.comments.each do |comment|
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def contain_unexpected_character_for_department_name?(name)
70
- name.match?(%r{[^A-z/, ]})
70
+ name.match?(%r{[^A-Za-z/, ]})
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to allow certain receivers in a cop.
6
+ module AllowedReceivers
7
+ def allowed_receiver?(receiver)
8
+ receiver_name = receiver_name(receiver)
9
+
10
+ allowed_receivers.include?(receiver_name)
11
+ end
12
+
13
+ def receiver_name(receiver)
14
+ if receiver.receiver && !receiver.receiver.const_type?
15
+ return receiver_name(receiver.receiver)
16
+ end
17
+
18
+ if receiver.send_type?
19
+ if receiver.receiver
20
+ "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
21
+ else
22
+ receiver.method_name.to_s
23
+ end
24
+ else
25
+ receiver.source
26
+ end
27
+ end
28
+
29
+ def allowed_receivers
30
+ cop_config.fetch('AllowedReceivers', [])
31
+ end
32
+ end
33
+ end
34
+ end
@@ -25,7 +25,7 @@ module RuboCop
25
25
  def comments_contain_disables?(node, cop_name)
26
26
  disabled_ranges = processed_source.disabled_line_ranges[cop_name]
27
27
 
28
- return unless disabled_ranges
28
+ return false unless disabled_ranges
29
29
 
30
30
  node_range = node.source_range.line...find_end_line(node)
31
31
 
@@ -62,21 +62,29 @@ module RuboCop
62
62
  # Returns the end line of a node, which might be a comment and not part of the AST
63
63
  # End line is considered either the line at which another node starts, or
64
64
  # the line at which the parent node ends.
65
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
65
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
66
66
  def find_end_line(node)
67
- if node.if_type? && node.else?
68
- node.loc.else.line
69
- elsif node.if_type? && node.ternary?
70
- node.else_branch.loc.line
67
+ if node.if_type?
68
+ if node.else?
69
+ node.loc.else.line
70
+ elsif node.ternary?
71
+ node.else_branch.loc.line
72
+ elsif node.elsif?
73
+ node.each_ancestor(:if).find(&:if?).loc.end.line
74
+ end
75
+ elsif node.block_type? || node.numblock_type?
76
+ node.loc.end.line
71
77
  elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node)
72
78
  next_sibling.loc.line
73
79
  elsif (parent = node.parent)
74
- parent.loc.respond_to?(:end) && parent.loc.end ? parent.loc.end.line : parent.loc.line
75
- else
76
- node.loc.end.line
77
- end
80
+ if parent.loc.respond_to?(:end) && parent.loc.end
81
+ parent.loc.end.line
82
+ else
83
+ parent.loc.line
84
+ end
85
+ end || node.loc.end.line
78
86
  end
79
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
80
88
  end
81
89
  end
82
90
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  # @!method non_public_modifier?(node)
21
21
  def_node_matcher :non_public_modifier?, <<~PATTERN
22
- (send nil? {:private :protected} ({def defs} ...))
22
+ (send nil? {:private :protected :private_class_method} ({def defs} ...))
23
23
  PATTERN
24
24
  end
25
25
  end
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def variable_alignment?(whole_expression, rhs, end_alignment_style)
70
- return if end_alignment_style == :keyword
70
+ return false if end_alignment_style == :keyword
71
71
 
72
72
  !line_break_before_keyword?(whole_expression, rhs)
73
73
  end
@@ -48,18 +48,21 @@ module RuboCop
48
48
 
49
49
  def register_offense(node, message, replacement) # rubocop:disable Metrics/AbcSize
50
50
  add_offense(node.value, message: message) do |corrector|
51
- if (def_node = def_node_that_require_parentheses(node))
52
- last_argument = def_node.last_argument
53
- if last_argument.nil? || !last_argument.hash_type?
54
- next corrector.replace(node, replacement)
55
- end
56
-
57
- white_spaces = range_between(def_node.selector.end_pos,
58
- def_node.first_argument.source_range.begin_pos)
59
- corrector.replace(white_spaces, '(')
60
- corrector.insert_after(last_argument, ')') if node == last_argument.pairs.last
61
- end
62
51
  corrector.replace(node, replacement)
52
+
53
+ next unless (def_node = def_node_that_require_parentheses(node))
54
+
55
+ last_argument = def_node.last_argument
56
+ if last_argument.nil? || !last_argument.hash_type?
57
+ next corrector.replace(node, replacement)
58
+ end
59
+
60
+ white_spaces = range_between(def_node.selector.end_pos,
61
+ def_node.first_argument.source_range.begin_pos)
62
+ next if node.parent.braces?
63
+
64
+ corrector.replace(white_spaces, '(')
65
+ corrector.insert_after(last_argument, ')') if node == last_argument.pairs.last
63
66
  end
64
67
  end
65
68
 
@@ -26,11 +26,15 @@ module RuboCop
26
26
  end
27
27
 
28
28
  def delimiter_string(node)
29
- node.source.match(OPENING_DELIMITER).captures[1]
29
+ return '' unless (match = node.source.match(OPENING_DELIMITER))
30
+
31
+ match.captures[1]
30
32
  end
31
33
 
32
34
  def heredoc_type(node)
33
- node.source.match(OPENING_DELIMITER).captures[0]
35
+ return '' unless (match = node.source.match(OPENING_DELIMITER))
36
+
37
+ match.captures[0]
34
38
  end
35
39
  end
36
40
  end
@@ -20,16 +20,17 @@ module RuboCop
20
20
  range = offending_range(node, lhs, rhs, style)
21
21
  check(range, node, lhs, rhs)
22
22
  end
23
+ alias on_csend on_send
23
24
 
24
25
  private
25
26
 
26
- # In a chain of method calls, we regard the top send node as the base
27
+ # In a chain of method calls, we regard the top call node as the base
27
28
  # for indentation of all lines following the first. For example:
28
29
  # a.
29
30
  # b c { block }. <-- b is indented relative to a
30
31
  # d <-- d is indented relative to a
31
32
  def left_hand_side(lhs)
32
- while lhs.parent&.send_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method?
33
+ while lhs.parent&.call_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method?
33
34
  lhs = lhs.parent
34
35
  end
35
36
  lhs
@@ -9,7 +9,7 @@ module RuboCop
9
9
  private
10
10
 
11
11
  def percent_literal?(node)
12
- return unless (begin_source = begin_source(node))
12
+ return false unless (begin_source = begin_source(node))
13
13
 
14
14
  begin_source.start_with?('%')
15
15
  end
@@ -75,9 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def aligned_token?(range, line)
78
- aligned_words?(range, line) ||
79
- aligned_char?(range, line) ||
80
- aligned_assignment?(range, line)
78
+ aligned_words?(range, line) || aligned_assignment?(range, line)
81
79
  end
82
80
 
83
81
  def aligned_operator?(range, line)
@@ -85,11 +83,11 @@ module RuboCop
85
83
  end
86
84
 
87
85
  def aligned_words?(range, line)
88
- /\s\S/.match?(line[range.column - 1, 2])
89
- end
86
+ left_edge = range.column
87
+ return true if /\s\S/.match?(line[left_edge - 1, 2])
90
88
 
91
- def aligned_char?(range, line)
92
- line[range.column] == range.source[0]
89
+ token = range.source
90
+ token == line[left_edge, token.length]
93
91
  end
94
92
 
95
93
  def aligned_assignment?(range, line)
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def allowed_type?(token)
39
- %i[tRPAREN tRBRACK tPIPE].include?(token.type)
39
+ %i[tRPAREN tRBRACK tPIPE tSTRING_DEND].include?(token.type)
40
40
  end
41
41
 
42
42
  def space_forbidden_before_rcurly?
@@ -30,8 +30,10 @@ module RuboCop
30
30
  private
31
31
 
32
32
  def inside_interpolation?(node)
33
- # A :begin node inside a :dstr node is an interpolation.
34
- node.ancestors.drop_while { |a| !a.begin_type? }.any?(&:dstr_type?)
33
+ # A :begin node inside a :dstr, :dsym, or :regexp node is an interpolation.
34
+ node.ancestors
35
+ .drop_while { |a| !a.begin_type? }
36
+ .any? { |a| a.dstr_type? || a.dsym_type? || a.regexp_type? }
35
37
  end
36
38
  end
37
39
  end
@@ -106,7 +106,7 @@ module RuboCop
106
106
  end
107
107
 
108
108
  def elements(node)
109
- return node.children unless %i[csend send].include?(node.type)
109
+ return node.children unless node.call_type?
110
110
 
111
111
  node.arguments.flat_map do |argument|
112
112
  # For each argument, if it is a multi-line hash without braces,
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def use_block_argument_as_local_variable?(node, last_argument)
112
- return if node.body.nil?
112
+ return false if node.body.nil?
113
113
 
114
114
  node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
115
115
  !lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
@@ -76,7 +76,7 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def contains_constant?(node)
79
- node.branches.any?(&:const_type?)
79
+ node.branches.compact.any?(&:const_type?)
80
80
  end
81
81
  end
82
82
  end
@@ -136,7 +136,7 @@ module RuboCop
136
136
  end
137
137
 
138
138
  def filename_good?(basename)
139
- basename = basename.sub(/^\./, '')
139
+ basename = basename.delete_prefix('.')
140
140
  basename = basename.sub(/\.[^.]+$/, '')
141
141
  # special handling for Action Pack Variants file names like
142
142
  # some_file.xlsx+mobile.axlsx
@@ -31,7 +31,9 @@ module RuboCop
31
31
  def on_heredoc(node)
32
32
  return if meaningful_delimiters?(node)
33
33
 
34
- add_offense(node.loc.heredoc_end)
34
+ range = node.children.empty? ? node : node.loc.heredoc_end
35
+
36
+ add_offense(range)
35
37
  end
36
38
 
37
39
  private
@@ -17,7 +17,8 @@ module RuboCop
17
17
  # @safety
18
18
  # This cop relies on the pattern `@instance_var ||= ...`,
19
19
  # but this is sometimes used for other purposes than memoization
20
- # so this cop is considered unsafe.
20
+ # so this cop is considered unsafe. Also, its autocorrection is unsafe
21
+ # because it may conflict with instance variable names already in use.
21
22
  #
22
23
  # @example EnforcedStyleForLeadingUnderscores: disallowed (default)
23
24
  # # bad
@@ -145,6 +146,8 @@ module RuboCop
145
146
  # @_foo ||= calculate_expensive_thing
146
147
  # end
147
148
  class MemoizedInstanceVariableName < Base
149
+ extend AutoCorrector
150
+
148
151
  include ConfigurableEnforcedStyle
149
152
 
150
153
  MSG = 'Memoized variable `%<var>s` does not match ' \
@@ -163,6 +166,7 @@ module RuboCop
163
166
  PATTERN
164
167
 
165
168
  # rubocop:disable Metrics/AbcSize
169
+ # rubocop:disable Metrics/MethodLength
166
170
  def on_or_asgn(node)
167
171
  lhs, _value = *node
168
172
  return unless lhs.ivasgn_type?
@@ -175,14 +179,18 @@ module RuboCop
175
179
 
176
180
  return if matches?(method_name, lhs)
177
181
 
182
+ suggested_var = suggested_var(method_name)
178
183
  msg = format(
179
184
  message(lhs.children.first.to_s),
180
185
  var: lhs.children.first.to_s,
181
- suggested_var: suggested_var(method_name),
186
+ suggested_var: suggested_var,
182
187
  method: method_name
183
188
  )
184
- add_offense(lhs, message: msg)
189
+ add_offense(lhs, message: msg) do |corrector|
190
+ corrector.replace(lhs.loc.name, "@#{suggested_var}")
191
+ end
185
192
  end
193
+ # rubocop:enable Metrics/MethodLength
186
194
  # rubocop:enable Metrics/AbcSize
187
195
 
188
196
  # @!method defined_memoized?(node, ivar)
@@ -196,24 +204,31 @@ module RuboCop
196
204
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
197
205
  def on_defined?(node)
198
206
  arg = node.arguments.first
199
- return unless arg.ivar_type?
207
+ return false unless arg.ivar_type?
200
208
 
201
209
  method_node, method_name = find_definition(node)
202
- return unless method_node
210
+ return false unless method_node
203
211
 
204
212
  var_name = arg.children.first
205
213
  defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
206
- return if matches?(method_name, ivar_assign)
214
+ return false if matches?(method_name, ivar_assign)
207
215
 
216
+ suggested_var = suggested_var(method_name)
208
217
  msg = format(
209
218
  message(var_name.to_s),
210
219
  var: var_name.to_s,
211
- suggested_var: suggested_var(method_name),
220
+ suggested_var: suggested_var,
212
221
  method: method_name
213
222
  )
214
- add_offense(defined_ivar, message: msg)
215
- add_offense(return_ivar, message: msg)
216
- add_offense(ivar_assign.loc.name, message: msg)
223
+ add_offense(defined_ivar, message: msg) do |corrector|
224
+ corrector.replace(defined_ivar, "@#{suggested_var}")
225
+ end
226
+ add_offense(return_ivar, message: msg) do |corrector|
227
+ corrector.replace(return_ivar, "@#{suggested_var}")
228
+ end
229
+ add_offense(ivar_assign.loc.name, message: msg) do |corrector|
230
+ corrector.replace(ivar_assign.loc.name, "@#{suggested_var}")
231
+ end
217
232
  end
218
233
  end
219
234
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
@@ -82,9 +82,7 @@ module RuboCop
82
82
  message = message(node)
83
83
 
84
84
  add_offense(range, message: message) do |corrector|
85
- corrector.replace(range, preferred_name)
86
-
87
- correct_node(corrector, node.body, offending_name, preferred_name)
85
+ autocorrect(corrector, node, range, offending_name, preferred_name)
88
86
  end
89
87
  end
90
88
 
@@ -95,6 +93,16 @@ module RuboCop
95
93
  variable.source_range
96
94
  end
97
95
 
96
+ def autocorrect(corrector, node, range, offending_name, preferred_name)
97
+ corrector.replace(range, preferred_name)
98
+ correct_node(corrector, node.body, offending_name, preferred_name)
99
+ return unless (kwbegin_node = node.parent.each_ancestor(:kwbegin).first)
100
+
101
+ kwbegin_node.right_siblings.each do |child_node|
102
+ correct_node(corrector, child_node, offending_name, preferred_name)
103
+ end
104
+ end
105
+
98
106
  def variable_name_matches?(node, name)
99
107
  if node.masgn_type?
100
108
  node.each_descendant(:lvasgn).any? do |lvasgn_node|
@@ -20,9 +20,14 @@ module RuboCop
20
20
  # # good
21
21
  # fooBar = 1
22
22
  #
23
+ # @example AllowedIdentifiers: ['fooBar']
24
+ # # good (with EnforcedStyle: snake_case)
25
+ # fooBar = 1
26
+ #
23
27
  # @example AllowedPatterns: ['_v\d+\z']
24
- # # good
28
+ # # good (with EnforcedStyle: camelCase)
25
29
  # :release_v1
30
+ #
26
31
  class VariableName < Base
27
32
  include AllowedIdentifiers
28
33
  include ConfigurableNaming
@@ -92,6 +92,7 @@ module RuboCop
92
92
  comment_line?(processed_source[node.first_line - 2])
93
93
  end
94
94
 
95
+ # rubocop:disable Metrics/CyclomaticComplexity
95
96
  def groupable_accessor?(node)
96
97
  return true unless (previous_expression = node.left_siblings.last)
97
98
 
@@ -104,8 +105,11 @@ module RuboCop
104
105
 
105
106
  return true unless previous_expression.send_type?
106
107
 
107
- previous_expression.attribute_accessor? || previous_expression.access_modifier?
108
+ previous_expression.attribute_accessor? ||
109
+ previous_expression.access_modifier? ||
110
+ node.first_line - previous_expression.last_line > 1 # there is a space between nodes
108
111
  end
112
+ # rubocop:enable Metrics/CyclomaticComplexity
109
113
 
110
114
  def class_send_elements(class_node)
111
115
  class_def = class_node.body
@@ -122,7 +122,7 @@ module RuboCop
122
122
  end
123
123
 
124
124
  def bareword?(sym_node)
125
- !sym_node.source.start_with?(':')
125
+ !sym_node.source.start_with?(':') || sym_node.dsym_type?
126
126
  end
127
127
 
128
128
  def correct_alias_method_to_alias(corrector, send_node)
@@ -134,9 +134,7 @@ module RuboCop
134
134
 
135
135
  def correct_alias_to_alias_method(corrector, node)
136
136
  replacement =
137
- 'alias_method ' \
138
- ":#{identifier(node.new_identifier)}, " \
139
- ":#{identifier(node.old_identifier)}"
137
+ "alias_method #{identifier(node.new_identifier)}, #{identifier(node.old_identifier)}"
140
138
 
141
139
  corrector.replace(node, replacement)
142
140
  end
@@ -146,10 +144,13 @@ module RuboCop
146
144
  corrector.replace(node.old_identifier, node.old_identifier.source[1..])
147
145
  end
148
146
 
149
- # @!method identifier(node)
150
- def_node_matcher :identifier, <<~PATTERN
151
- (sym $_)
152
- PATTERN
147
+ def identifier(node)
148
+ if node.sym_type?
149
+ ":#{node.children.first}"
150
+ else
151
+ node.source
152
+ end
153
+ end
153
154
  end
154
155
  end
155
156
  end