rubocop 1.90.0 → 1.92.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 (303) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +241 -11
  4. data/config/obsoletion.yml +9 -0
  5. data/lib/rubocop/cached_data.rb +47 -7
  6. data/lib/rubocop/changed_files.rb +134 -0
  7. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  8. data/lib/rubocop/cli/command/execute_runner.rb +23 -3
  9. data/lib/rubocop/cli/command/explain.rb +34 -0
  10. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  11. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  12. data/lib/rubocop/cli.rb +11 -4
  13. data/lib/rubocop/comment_config/directive_range.rb +3 -1
  14. data/lib/rubocop/comment_config/disable_next.rb +49 -3
  15. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  16. data/lib/rubocop/comment_config.rb +32 -53
  17. data/lib/rubocop/config.rb +10 -0
  18. data/lib/rubocop/config_loader.rb +18 -7
  19. data/lib/rubocop/config_loader_resolver.rb +79 -12
  20. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  21. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  22. data/lib/rubocop/config_obsoletion.rb +1 -1
  23. data/lib/rubocop/config_validator.rb +29 -3
  24. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  25. data/lib/rubocop/cop/badge.rb +1 -1
  26. data/lib/rubocop/cop/base.rb +57 -24
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  28. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  29. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  30. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  32. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
  33. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
  35. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  36. data/lib/rubocop/cop/correctors.rb +2 -2
  37. data/lib/rubocop/cop/documentation.rb +1 -1
  38. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  39. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  40. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  41. data/lib/rubocop/cop/generator.rb +1 -1
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  43. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  44. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  45. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  46. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
  48. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  49. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  50. data/lib/rubocop/cop/layout/class_structure.rb +9 -1
  51. data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
  52. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  53. data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
  54. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
  55. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  56. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  57. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  58. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
  59. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  60. data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
  61. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
  62. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  63. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
  64. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
  65. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  66. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  67. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  68. data/lib/rubocop/cop/layout/hash_alignment.rb +15 -10
  69. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
  70. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  71. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  72. data/lib/rubocop/cop/layout/indentation_width.rb +4 -4
  73. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  74. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  75. data/lib/rubocop/cop/layout/line_length.rb +71 -19
  76. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  77. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  78. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
  79. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  80. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
  81. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  82. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  83. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
  84. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  85. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  86. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  87. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  88. data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
  89. data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
  90. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  91. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
  92. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  93. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  94. data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
  95. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
  96. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
  97. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  98. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  99. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  100. data/lib/rubocop/cop/lint/literal_as_condition.rb +23 -2
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  102. data/lib/rubocop/cop/lint/loop.rb +24 -2
  103. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  104. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -4
  105. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  107. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  108. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
  109. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +42 -17
  110. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  111. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  112. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  113. data/lib/rubocop/cop/lint/void.rb +8 -1
  114. data/lib/rubocop/cop/lint.rb +1 -0
  115. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  116. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  117. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  118. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  119. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  120. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  121. data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
  122. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
  123. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  124. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  125. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
  126. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  127. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -2
  128. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +31 -3
  129. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  130. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  131. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  132. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  133. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  134. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  135. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +29 -3
  136. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  137. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  138. data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
  139. data/lib/rubocop/cop/mixin.rb +4 -2
  140. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  141. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  142. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  143. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  144. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  145. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  146. data/lib/rubocop/cop/offense.rb +59 -3
  147. data/lib/rubocop/cop/registry.rb +10 -2
  148. data/lib/rubocop/cop/security/json_load.rb +16 -4
  149. data/lib/rubocop/cop/severity.rb +12 -0
  150. data/lib/rubocop/cop/style/access_modifier_declarations.rb +10 -2
  151. data/lib/rubocop/cop/style/alias.rb +18 -5
  152. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  153. data/lib/rubocop/cop/style/and_or.rb +4 -0
  154. data/lib/rubocop/cop/style/arguments_forwarding.rb +6 -3
  155. data/lib/rubocop/cop/style/attr.rb +3 -4
  156. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  157. data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
  158. data/lib/rubocop/cop/style/case_like_if.rb +9 -6
  159. data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
  160. data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
  161. data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
  162. data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
  163. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  164. data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
  165. data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
  166. data/lib/rubocop/cop/style/directive_scope.rb +154 -21
  167. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +118 -18
  168. data/lib/rubocop/cop/style/documentation_method.rb +1 -9
  169. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  170. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  171. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  172. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  173. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  174. data/lib/rubocop/cop/style/empty_method.rb +15 -3
  175. data/lib/rubocop/cop/style/endless_method.rb +91 -11
  176. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  177. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  178. data/lib/rubocop/cop/style/file_null.rb +2 -2
  179. data/lib/rubocop/cop/style/float_division.rb +28 -14
  180. data/lib/rubocop/cop/style/for.rb +44 -1
  181. data/lib/rubocop/cop/style/format_string.rb +28 -6
  182. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  183. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  184. data/lib/rubocop/cop/style/guard_clause.rb +13 -1
  185. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  186. data/lib/rubocop/cop/style/hash_lookup_method.rb +35 -9
  187. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  188. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  189. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  190. data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
  191. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  192. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  193. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  194. data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
  195. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  196. data/lib/rubocop/cop/style/lambda.rb +18 -0
  197. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  198. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  199. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  200. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
  201. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
  202. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  203. data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
  204. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  205. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  206. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  207. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  208. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  209. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  210. data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
  211. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  212. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  213. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  214. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  215. data/lib/rubocop/cop/style/next.rb +24 -10
  216. data/lib/rubocop/cop/style/nil_comparison.rb +48 -8
  217. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  218. data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
  219. data/lib/rubocop/cop/style/not.rb +10 -3
  220. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  221. data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
  222. data/lib/rubocop/cop/style/one_line_conditional.rb +14 -3
  223. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  224. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  225. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  226. data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
  227. data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
  228. data/lib/rubocop/cop/style/redundant_condition.rb +34 -17
  229. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -1
  230. data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
  231. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
  232. data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
  233. data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -2
  234. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  235. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  236. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +25 -5
  237. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  238. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  239. data/lib/rubocop/cop/style/require_order.rb +9 -0
  240. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
  241. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  242. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  243. data/lib/rubocop/cop/style/sample.rb +9 -8
  244. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  245. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  246. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  247. data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
  248. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  249. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  250. data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
  251. data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
  252. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  253. data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
  254. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  255. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  256. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  257. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  258. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  259. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  260. data/lib/rubocop/cop/style.rb +0 -1
  261. data/lib/rubocop/cop/team.rb +10 -5
  262. data/lib/rubocop/cop/util.rb +1 -1
  263. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  264. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  265. data/lib/rubocop/cops_documentation_generator.rb +23 -2
  266. data/lib/rubocop/directive_comment.rb +37 -8
  267. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  268. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
  269. data/lib/rubocop/formatter/formatter_set.rb +6 -1
  270. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  271. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  272. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  273. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  274. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  275. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  276. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  277. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  278. data/lib/rubocop/formatter.rb +1 -0
  279. data/lib/rubocop/lsp/runtime.rb +47 -11
  280. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  281. data/lib/rubocop/lsp.rb +5 -2
  282. data/lib/rubocop/magic_comment.rb +27 -0
  283. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  284. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  285. data/lib/rubocop/mcp/scope.rb +65 -0
  286. data/lib/rubocop/mcp/server.rb +184 -76
  287. data/lib/rubocop/mcp/source_files.rb +35 -0
  288. data/lib/rubocop/offense_limit.rb +30 -0
  289. data/lib/rubocop/options.rb +97 -4
  290. data/lib/rubocop/path_util.rb +1 -1
  291. data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
  292. data/lib/rubocop/plugin/loader.rb +1 -1
  293. data/lib/rubocop/rake_task.rb +1 -1
  294. data/lib/rubocop/remote_config.rb +8 -5
  295. data/lib/rubocop/result_cache.rb +36 -18
  296. data/lib/rubocop/runner.rb +160 -49
  297. data/lib/rubocop/server/cache.rb +2 -2
  298. data/lib/rubocop/unified_diff.rb +257 -0
  299. data/lib/rubocop/util.rb +69 -0
  300. data/lib/rubocop/version.rb +1 -1
  301. data/lib/rubocop.rb +9 -1
  302. metadata +21 -6
  303. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for magic comments placed where Ruby silently ignores them.
7
+ #
8
+ # The `encoding` magic comment is only honored on the first line of a file,
9
+ # or on the second line when the first line is a shebang. Anywhere else it
10
+ # is silently ignored - even directly below another comment or a blank line.
11
+ #
12
+ # Other magic comments (such as `frozen_string_literal`) are honored
13
+ # anywhere before the first token of code, but are ignored after any code,
14
+ # with a warning emitted only when running Ruby with `-w`.
15
+ #
16
+ # A magic comment misplaced ahead of a shebang also renders the shebang
17
+ # ineffective, since a shebang is only recognized on the first line.
18
+ #
19
+ # NOTE: An `encoding` comment that is only preceded by other magic
20
+ # comments is not flagged by this cop; that case is handled by
21
+ # `Lint/OrderedMagicComments`. `shareable_constant_value` is never
22
+ # flagged, as Ruby intentionally allows it mid-file with block scoping.
23
+ #
24
+ # @safety
25
+ # This cop's autocorrection is unsafe because moving the magic comment
26
+ # to its effective position activates it, which changes runtime
27
+ # behavior (e.g. the source encoding or string mutability).
28
+ #
29
+ # @example
30
+ # # bad
31
+ # # Documentation comment
32
+ # # encoding: ascii-8bit
33
+ # puts 'hello'
34
+ #
35
+ # # good
36
+ # # encoding: ascii-8bit
37
+ # # Documentation comment
38
+ # puts 'hello'
39
+ #
40
+ # # bad
41
+ # require 'foo'
42
+ # # frozen_string_literal: true
43
+ #
44
+ # # good
45
+ # # frozen_string_literal: true
46
+ # require 'foo'
47
+ #
48
+ # # bad
49
+ # # frozen_string_literal: true
50
+ # #!/usr/bin/env ruby
51
+ # puts 'hello'
52
+ #
53
+ # # good
54
+ # #!/usr/bin/env ruby
55
+ # # frozen_string_literal: true
56
+ # puts 'hello'
57
+ class MisplacedMagicComment < Base
58
+ include RangeHelp
59
+ extend AutoCorrector
60
+
61
+ MSG_ENCODING = 'The `encoding` magic comment is ignored unless placed on the first ' \
62
+ 'line (or below a shebang on the first line).'
63
+ MSG_AFTER_CODE = 'The `%<directive>s` magic comment is ignored after any code.'
64
+ MSG_ABOVE_SHEBANG = 'A magic comment above a shebang renders the shebang ineffective.'
65
+
66
+ def on_new_investigation
67
+ return if processed_source.buffer.source.empty?
68
+
69
+ check_magic_comment_above_shebang
70
+ processed_source.comments.each { |comment| check_comment(comment) }
71
+ end
72
+
73
+ private
74
+
75
+ def check_comment(comment)
76
+ return unless magic_comment_shaped?(comment.text)
77
+
78
+ magic_comment = MagicComment.parse(comment.text)
79
+ return unless magic_comment.valid?
80
+
81
+ if magic_comment.encoding_specified?
82
+ return unless known_encoding?(magic_comment.encoding)
83
+
84
+ check_encoding_comment(comment)
85
+ elsif magic_comment.frozen_string_literal_specified?
86
+ check_top_block_comment(comment, 'frozen_string_literal')
87
+ end
88
+ end
89
+
90
+ # The Emacs and Vim regexps in `MagicComment` match anywhere inside a
91
+ # comment, which would flag documentation that merely quotes a magic
92
+ # comment (e.g. `# # -*- coding: UTF-8 -*-`). Require the magic
93
+ # comment to start right after the `#`.
94
+ def magic_comment_shaped?(text)
95
+ /\A#(?![^#]*#)/.match?(text)
96
+ end
97
+
98
+ # Prose that happens to open with `Encoding:` parses as an encoding
99
+ # comment (`# Encoding: force given encoding` yields `force`). Ruby
100
+ # ignores a misplaced encoding comment entirely, so a name no encoding
101
+ # answers to means the line is a comment, not a directive.
102
+ def known_encoding?(name)
103
+ Encoding.find(name)
104
+ true
105
+ rescue ArgumentError
106
+ false
107
+ end
108
+
109
+ def shebang?
110
+ processed_source.lines.first.to_s.start_with?('#!')
111
+ end
112
+
113
+ # First line that may carry an effective encoding comment.
114
+ def effective_encoding_line
115
+ shebang? ? 2 : 1
116
+ end
117
+
118
+ def first_code_token
119
+ processed_source.sorted_tokens.find { |token| !token.comment? }
120
+ end
121
+
122
+ def check_encoding_comment(comment)
123
+ return unless misplaced_encoding_position?(comment)
124
+
125
+ add_offense(comment, message: MSG_ENCODING) do |corrector|
126
+ correct_encoding_comment(corrector, comment)
127
+ end
128
+ end
129
+
130
+ def misplaced_encoding_position?(comment)
131
+ line = comment.source_range.line
132
+ return false if line == effective_encoding_line && comment_starts_line?(comment)
133
+
134
+ # Leave `# frozen_string_literal: true` + `# encoding: x` runs at the
135
+ # very top to Lint/OrderedMagicComments, which already reorders them.
136
+ !preceded_only_by_magic_comments?(comment)
137
+ end
138
+
139
+ # With an effective encoding comment already in place, moving another
140
+ # one in would override it. Drop an identical duplicate and leave a
141
+ # conflicting one for a human to resolve.
142
+ def correct_encoding_comment(corrector, comment)
143
+ effective_comment = effective_encoding_comment
144
+
145
+ if effective_comment.nil?
146
+ move_comment(corrector, comment, effective_encoding_line)
147
+ elsif comment_encoding(effective_comment) == comment_encoding(comment)
148
+ corrector.remove(comment_removal_range(comment))
149
+ end
150
+ end
151
+
152
+ def comment_encoding(comment)
153
+ Encoding.find(MagicComment.parse(comment.text).encoding)
154
+ rescue ArgumentError
155
+ nil
156
+ end
157
+
158
+ def check_top_block_comment(comment, directive)
159
+ return unless first_code_token
160
+ return unless comment.source_range.begin_pos > first_code_token.begin_pos
161
+
162
+ message = format(MSG_AFTER_CODE, directive: directive)
163
+ add_offense(comment, message: message) do |corrector|
164
+ # Both would be inserted at the top, in no reliable order. Leave
165
+ # this one to the next pass, once the encoding comment is in place.
166
+ next if encoding_comment_moving_in?
167
+
168
+ move_comment(corrector, comment, top_block_insertion_line)
169
+ end
170
+ end
171
+
172
+ def encoding_comment_moving_in?
173
+ return false if effective_encoding_comment
174
+
175
+ processed_source.comments.any? do |comment|
176
+ known_encoding_comment?(comment) && misplaced_encoding_position?(comment)
177
+ end
178
+ end
179
+
180
+ def effective_encoding_comment
181
+ processed_source.comments.find do |comment|
182
+ comment.source_range.line == effective_encoding_line &&
183
+ comment_starts_line?(comment) &&
184
+ MagicComment.parse(comment.text).encoding_specified?
185
+ end
186
+ end
187
+
188
+ def known_encoding_comment?(comment)
189
+ return false unless magic_comment_shaped?(comment.text)
190
+
191
+ magic_comment = MagicComment.parse(comment.text)
192
+ magic_comment.encoding_specified? && known_encoding?(magic_comment.encoding)
193
+ end
194
+
195
+ # Insert below an effective encoding comment rather than above it,
196
+ # which would push it off the only lines where Ruby honors it.
197
+ def top_block_insertion_line
198
+ effective_encoding_comment ? effective_encoding_line + 1 : effective_encoding_line
199
+ end
200
+
201
+ def check_magic_comment_above_shebang
202
+ shebang_comment = processed_source.comments.find do |comment|
203
+ comment.source_range.line > 1 && comment.text.start_with?('#!') &&
204
+ comment.source_range.column.zero?
205
+ end
206
+ return unless shebang_comment
207
+ # Only flag when what precedes the shebang is magic comments -
208
+ # a `#!` comment deep inside a file is not an intended shebang.
209
+ return unless preceded_only_by_magic_comments?(shebang_comment)
210
+
211
+ add_offense(shebang_comment, message: MSG_ABOVE_SHEBANG)
212
+ end
213
+
214
+ def preceded_only_by_magic_comments?(comment)
215
+ (1...comment.source_range.line).all? do |line_number|
216
+ text = processed_source.lines[line_number - 1]
217
+ (line_number == 1 && text.start_with?('#!')) || MagicComment.parse(text).valid?
218
+ end
219
+ end
220
+
221
+ def comment_starts_line?(comment)
222
+ processed_source.lines[comment.source_range.line - 1].lstrip.start_with?('#')
223
+ end
224
+
225
+ def move_comment(corrector, comment, target_line)
226
+ corrector.remove(comment_removal_range(comment))
227
+ target_range = processed_source.buffer.line_range(target_line)
228
+ if comment.source_range.line < target_line
229
+ corrector.insert_after(target_range, "\n#{comment.text}")
230
+ else
231
+ corrector.insert_before(target_range, "#{comment.text}\n")
232
+ end
233
+ end
234
+
235
+ def comment_removal_range(comment)
236
+ if comment_starts_line?(comment)
237
+ range_by_whole_lines(comment.source_range, include_final_newline: true)
238
+ else
239
+ range_with_surrounding_space(comment.source_range, side: :left)
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable-next Lint/RedundantCopDisableDirective
3
+ # rubocop:disable-next Lint/RedundantCopDisableDirective -- the examples below read as real directives
4
4
  module RuboCop
5
5
  module Cop
6
6
  module Lint
@@ -62,7 +62,7 @@ module RuboCop
62
62
  each_missing_enable do |cop, line_range|
63
63
  next if acceptable_range?(cop, line_range)
64
64
 
65
- comment = processed_source.comment_at_line(line_range.begin)
65
+ comment = opening_comment(line_range)
66
66
 
67
67
  add_offense(comment, message: message(cop, comment))
68
68
  end
@@ -73,14 +73,29 @@ module RuboCop
73
73
  def each_missing_enable
74
74
  processed_source.disabled_line_ranges.each do |cop, line_ranges|
75
75
  line_ranges.each do |line_range|
76
- # A `disable-next` scope closes itself with its statement.
77
- next if line_range.respond_to?(:directive) && line_range.directive.disable_next?
76
+ # A `disable-next` or `next` scope closes itself with its statement.
77
+ next if statement_scoped?(line_range)
78
78
 
79
79
  yield cop, line_range
80
80
  end
81
81
  end
82
82
  end
83
83
 
84
+ def statement_scoped?(line_range)
85
+ directive = line_range.respond_to?(:directive) && line_range.directive
86
+ directive && (directive.disable_next? || directive.next?)
87
+ end
88
+
89
+ # A disable suspended by `enable-next` or `next +Cop` reopens below the
90
+ # statement, on a code line, so the comment that opened it has to come
91
+ # from the range rather than from its first line.
92
+ def opening_comment(line_range)
93
+ directive = line_range.respond_to?(:directive) && line_range.directive
94
+ return directive.comment if directive
95
+
96
+ processed_source.comment_at_line(line_range.begin)
97
+ end
98
+
84
99
  def acceptable_range?(cop, line_range)
85
100
  # This has to remain a strict inequality to handle
86
101
  # the case when max_range is Float::INFINITY
@@ -95,7 +95,7 @@ module RuboCop
95
95
  MSG = 'Method definitions must not be nested. Use `lambda` instead.'
96
96
 
97
97
  def on_def(node)
98
- subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
98
+ subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring -- the first child differs between `def` and `defs`
99
99
  return if node.defs_type? && allowed_subject_type?(subject)
100
100
 
101
101
  def_ancestor = node.each_ancestor(:any_def).first
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  # NOTE: itblock is not handled because this cop is limited to Ruby <= 2.7
69
69
  # via `maximum_target_ruby_version`, so itblock nodes (Ruby 3.4+) are never encountered.
70
- def on_block(node) # rubocop:disable InternalAffairs/ItblockHandler
70
+ def on_block(node) # rubocop:disable InternalAffairs/ItblockHandler -- limited to Ruby <= 2.7, where `it` blocks do not exist
71
71
  return unless node.body
72
72
  return unless unsorted_dir_loop?(node.send_node)
73
73
 
@@ -132,7 +132,7 @@ module RuboCop
132
132
 
133
133
  def handle_as_symbol(node)
134
134
  to_method_symbol(node) do |receiver, sym_node, to_method|
135
- next if receiver.nil? || !node.arguments.one?
135
+ next if receiver.nil? || !node.arguments.one? || node.operator_method?
136
136
 
137
137
  message = format(
138
138
  MSG,
@@ -46,13 +46,29 @@ module RuboCop
46
46
 
47
47
  def valid_first_argument?(first_arg)
48
48
  first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg) ||
49
- compound_range?(first_arg)
49
+ compound_range?(first_arg) || invalid_bare_argument?(first_arg)
50
50
  end
51
51
 
52
52
  def compound_range?(first_arg)
53
53
  first_arg.range_type? && first_arg.parenthesized_call?
54
54
  end
55
55
 
56
+ def invalid_bare_argument?(node)
57
+ node = node.children.first while node&.begin_type? && node.children.one?
58
+ return false unless node
59
+
60
+ keyword_operator?(node) || modifier_expression?(node)
61
+ end
62
+
63
+ def keyword_operator?(node)
64
+ (node.operator_keyword? && node.semantic_operator?) ||
65
+ node.rescue_type? || (node.send_type? && node.prefix_not?)
66
+ end
67
+
68
+ def modifier_expression?(node)
69
+ node.type?(:if, :while, :until) && node.modifier_form?
70
+ end
71
+
56
72
  def chained_calls?(node)
57
73
  first_argument = node.first_argument
58
74
  first_argument.call_type? && (node.children.last&.children&.count || 0) > 1
@@ -2,7 +2,7 @@
2
2
 
3
3
  # The Lint/RedundantCopDisableDirective cop needs to be disabled so as
4
4
  # to be able to provide a (bad) example of a redundant disable.
5
- # rubocop:disable-next Lint/RedundantCopDisableDirective
5
+ # rubocop:disable-next Lint/RedundantCopDisableDirective -- the examples below read as real directives
6
6
  module RuboCop
7
7
  module Cop
8
8
  module Lint
@@ -110,7 +110,7 @@ module RuboCop
110
110
  # A pending cop that is not enabled in this run produces no
111
111
  # offenses, so its directives cannot be judged - they typically
112
112
  # prepare the code for the moment the cop gets enabled.
113
- next if pending_cop_not_run?(cop)
113
+ next if pending_cop_not_run?(cop) || disabled_by_preview?(cop)
114
114
 
115
115
  each_already_disabled(cop, line_ranges, &block)
116
116
  each_line_range(cop, line_ranges, &block)
@@ -128,6 +128,17 @@ module RuboCop
128
128
  !processed_source.registry.enabled_pending_cop?(cop_cfg, config, cop)
129
129
  end
130
130
 
131
+ # A cop that only the `Preview` defaults disable runs again as soon as
132
+ # preview is turned off, so its directives are still needed.
133
+ def disabled_by_preview?(cop)
134
+ return false unless preview? && all_cop_names.include?(cop)
135
+
136
+ preview_defaults = ConfigLoader.default_configuration[cop]&.fetch('Preview', nil)
137
+ return false unless preview_defaults.is_a?(Hash) && preview_defaults['Enabled'] == false
138
+
139
+ !config.cop_enabled?(cop)
140
+ end
141
+
131
142
  def each_line_range(cop, line_ranges)
132
143
  line_ranges.each_with_index do |line_range, line_range_index|
133
144
  next if should_skip_line_range?(cop, line_range)
@@ -155,17 +166,29 @@ module RuboCop
155
166
  end
156
167
  end
157
168
 
158
- # A `disable-next` with no statement attached (or misplaced at the end
159
- # of a code line) suppresses nothing, so it is redundant by definition.
169
+ # A next-statement directive with no statement attached (or misplaced
170
+ # at the end of a code line) affects nothing, so it is redundant by
171
+ # definition.
160
172
  def each_detached_next_directive
161
173
  processed_source.comment_config.detached_next_directives.each do |directive|
162
- directive.raw_cop_names.each { |cop| yield directive.comment, cop }
174
+ names = if directive.next?
175
+ directive.signed_args.values.flatten
176
+ else
177
+ directive.raw_cop_names
178
+ end
179
+ names.each { |cop| yield directive.comment, cop }
163
180
  end
164
181
  end
165
182
 
166
183
  def skip_directive?(comment)
184
+ # A cop disabled in the configuration is represented by a synthetic directive that
185
+ # has no comment in the source, so there is nothing to report or to remove.
186
+ # Its range starts at `CONFIG_DISABLED_LINE_RANGE_MIN` and runs to the end of the file,
187
+ # but a `pop` splits it, and the pieces in between are bounded on both sides.
188
+ return true if comment.is_a?(CommentConfig::ConfigDisabledCopDirectiveComment)
189
+
167
190
  directive = DirectiveComment.new(comment)
168
- directive.push? || directive.pop?
191
+ directive.push? || directive.pop? || directive.next?
169
192
  end
170
193
 
171
194
  def find_redundant_directive(cop, comment, line_range, next_range)
@@ -190,11 +213,11 @@ module RuboCop
190
213
 
191
214
  comment = directive_comment(range)
192
215
 
193
- next unless comment
194
- # Comments disabling all cops don't count since it's reasonable
195
- # to disable a few select cops first and then all cops further
196
- # down in the code.
197
- next if all_disabled?(comment)
216
+ # `push`/`next` signed arguments are not analyzed for redundancy
217
+ # (yet), and comments disabling all cops don't count since it's
218
+ # reasonable to disable a few select cops first and then all cops
219
+ # further down in the code.
220
+ next if comment.nil? || skip_directive?(comment) || all_disabled?(comment)
198
221
 
199
222
  redundant =
200
223
  if department_disabled?(cop, comment)
@@ -280,18 +303,20 @@ module RuboCop
280
303
  end
281
304
 
282
305
  def add_offense_for_entire_comment(comment, cops)
283
- location = DirectiveComment.new(comment).range
306
+ directive = DirectiveComment.new(comment)
307
+ location = directive.range
284
308
  cop_names = cops.sort.map { |c| describe(c) }.join(', ')
285
309
 
286
310
  # An unknown cop may just not be loaded in this run (e.g. a custom
287
311
  # cop whose configuration failed to load) - removing its directive
288
312
  # would destroy something that cannot be restored, so only report.
289
313
  # A misplaced EOL `disable-next` should be moved, not deleted.
314
+ message = message(cop_names, enabling: directive.enable_next?)
290
315
  if any_unknown_cop?(cops) || misplaced_next_directive?(comment)
291
- return add_offense(location, message: message(cop_names))
316
+ return add_offense(location, message: message)
292
317
  end
293
318
 
294
- add_offense(location, message: message(cop_names)) do |corrector|
319
+ add_offense(location, message: message) do |corrector|
295
320
  remove_entire_comment(corrector, comment)
296
321
  end
297
322
  end
@@ -333,7 +358,7 @@ module RuboCop
333
358
 
334
359
  def misplaced_next_directive?(comment)
335
360
  directive = DirectiveComment.new(comment)
336
- directive.disable_next? &&
361
+ (directive.disable_next? || directive.next? || directive.enable_next?) &&
337
362
  !processed_source.comment_config.comment_only_line?(directive.line_number)
338
363
  end
339
364
 
@@ -396,8 +421,8 @@ module RuboCop
396
421
  similar ? "`#{cop}` (did you mean `#{similar}`?)" : "`#{cop}` (unknown cop)"
397
422
  end
398
423
 
399
- def message(cop_names)
400
- "Unnecessary disabling of #{cop_names}."
424
+ def message(cop_names, enabling: false)
425
+ "Unnecessary #{enabling ? 'enabling' : 'disabling'} of #{cop_names}."
401
426
  end
402
427
 
403
428
  def all_cop_names
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # end
29
29
  #
30
30
  class RedundantDirGlobSort < Base
31
+ include RangeHelp
31
32
  extend AutoCorrector
32
33
  extend TargetRubyVersion
33
34
 
@@ -46,8 +47,7 @@ module RuboCop
46
47
  selector = node.loc.selector
47
48
 
48
49
  add_offense(selector) do |corrector|
49
- corrector.remove(selector)
50
- corrector.remove(node.loc.dot)
50
+ autocorrect(corrector, node.loc.dot, selector)
51
51
  end
52
52
  end
53
53
 
@@ -67,6 +67,17 @@ module RuboCop
67
67
  def sort_with_comparator?(node)
68
68
  node.parent&.any_block_type? || node.last_argument&.block_pass_type?
69
69
  end
70
+
71
+ def autocorrect(corrector, dot, selector)
72
+ range = dot.join(selector)
73
+
74
+ if processed_source.contains_comment?(range)
75
+ corrector.remove(dot)
76
+ corrector.remove(selector)
77
+ else
78
+ corrector.remove(range_with_surrounding_space(range, side: :left))
79
+ end
80
+ end
70
81
  end
71
82
  end
72
83
  end
@@ -53,12 +53,22 @@ module RuboCop
53
53
  return if node.each_descendant(:dstr).any?
54
54
 
55
55
  regexp_constructor(node) do |text|
56
+ next unless verbatim_string?(text)
57
+
56
58
  detect_offenses_in_tree(text, parse_regexp(text.value))
57
59
  end
58
60
  end
59
61
 
60
62
  private
61
63
 
64
+ # Offsets into the string's value only point at the right place in the source
65
+ # when the string has no escape sequences, so anything else is left alone.
66
+ def verbatim_string?(node)
67
+ return false unless node.loc?(:begin) && node.loc?(:end)
68
+
69
+ node.loc.begin.end.join(node.loc.end.begin).source == node.value
70
+ end
71
+
62
72
  # When a character class opens with a bare `]` (e.g. `[^]]`), `regexp_parser` parses
63
73
  # `[^]` / `[]` as an empty set and reports the closing `]` as a separate literal.
64
74
  # Ruby treats that `]` as the end of the class, not as an unescaped bracket,
@@ -97,7 +107,7 @@ module RuboCop
97
107
  location = range_at_index(node, expr.ts, pos)
98
108
 
99
109
  add_offense(location) do |corrector|
100
- corrector.replace(location, '\]')
110
+ corrector.replace(location, escaped_bracket(node))
101
111
  end
102
112
  end
103
113
 
@@ -108,6 +118,13 @@ module RuboCop
108
118
  adjustment = index + offset
109
119
  node.loc.begin.end.adjust(begin_pos: adjustment, end_pos: adjustment + 1)
110
120
  end
121
+
122
+ # A double-quoted string turns `\]` into `]`, so its backslash needs escaping too.
123
+ def escaped_bracket(node)
124
+ return '\]' if node.regexp_type? || node.single_quoted? || node.percent_literal?(:q)
125
+
126
+ '\\\\]'
127
+ end
111
128
  end
112
129
  end
113
130
  end
@@ -212,16 +212,23 @@ module RuboCop
212
212
  end
213
213
 
214
214
  def remove_local_variable_assignment_part(corrector, node)
215
- corrector.remove(node.loc.name.begin.join(node.expression.source_range.begin))
216
- end
217
-
218
- def variable_in_loop_condition?(assignment_node, variable)
219
- return false if assignment_node.each_ancestor(:any_def).any?
215
+ expression = node.expression
216
+ assignment_part = node.loc.name.begin.join(expression.source_range.begin)
220
217
 
221
- loop_node = assignment_node.each_ancestor.find do |ancestor|
222
- ancestor.type?(*VariableForce::LOOP_TYPES)
218
+ # `x = 1, 2` cannot become `1, 2`, so the values become an array literal.
219
+ if expression.array_type? && !expression.bracketed?
220
+ corrector.replace(assignment_part, '[')
221
+ corrector.insert_after(expression, ']')
222
+ else
223
+ corrector.remove(assignment_part)
223
224
  end
225
+ end
224
226
 
227
+ def variable_in_loop_condition?(assignment_node, variable)
228
+ # A method defined inside the loop has its own scope, so the loop condition
229
+ # can only read the variable if the loop is nearer than any method definition.
230
+ loop_node = assignment_node.each_ancestor(*VariableForce::LOOP_TYPES, :any_def).first
231
+ return false if !loop_node || loop_node.any_def_type?
225
232
  return false unless loop_node.respond_to?(:condition)
226
233
 
227
234
  condition_node = loop_node.condition
@@ -271,7 +271,14 @@ module RuboCop
271
271
  return if node.parent.type?(:if, :case, :when, :case_match, :in_pattern)
272
272
  return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
273
273
 
274
- corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
274
+ range = range_with_surrounding_space(range: void_expression_range(node), side: :left)
275
+ corrector.remove(range)
276
+ end
277
+
278
+ def void_expression_range(node)
279
+ return node.source_range unless node.respond_to?(:heredoc?) && node.heredoc?
280
+
281
+ node.source_range.join(node.loc.heredoc_end)
275
282
  end
276
283
 
277
284
  def autocorrect_nonmutating_send(corrector, node, suggestion)
@@ -76,6 +76,7 @@ module RuboCop
76
76
  register_cop :LiteralAssignmentInCondition, "#{__dir__}/lint/literal_assignment_in_condition"
77
77
  register_cop :LiteralInInterpolation, "#{__dir__}/lint/literal_in_interpolation"
78
78
  register_cop :Loop, "#{__dir__}/lint/loop"
79
+ register_cop :MisplacedMagicComment, "#{__dir__}/lint/misplaced_magic_comment"
79
80
  register_cop :MissingCopEnableDirective, "#{__dir__}/lint/missing_cop_enable_directive"
80
81
  register_cop :MissingSuper, "#{__dir__}/lint/missing_super"
81
82
  register_cop :MixedCaseRange, "#{__dir__}/lint/mixed_case_range"
@@ -40,6 +40,8 @@ module RuboCop
40
40
  class ClassLength < Base
41
41
  include CodeLength
42
42
 
43
+ LABEL = 'Class'
44
+
43
45
  def on_class(node)
44
46
  check_code_length(node)
45
47
  end
@@ -60,8 +62,8 @@ module RuboCop
60
62
 
61
63
  private
62
64
 
63
- def message(length, max_length)
64
- format('Class has too many lines. [%<length>d/%<max>d]', length: length, max: max_length)
65
+ def cop_label
66
+ LABEL
65
67
  end
66
68
 
67
69
  def find_expression_within_parent(parent)
@@ -48,10 +48,6 @@ module RuboCop
48
48
 
49
49
  1
50
50
  end
51
-
52
- def count_block?(block)
53
- KNOWN_ITERATING_METHODS.include? block.method_name
54
- end
55
51
  end
56
52
  end
57
53
  end
@@ -38,6 +38,8 @@ module RuboCop
38
38
  class ModuleLength < Base
39
39
  include CodeLength
40
40
 
41
+ LABEL = 'Module'
42
+
41
43
  def on_module(node)
42
44
  check_code_length(node)
43
45
  end
@@ -53,8 +55,8 @@ module RuboCop
53
55
  (casgn nil? _ (any_block (send (const {nil? cbase} :Module) :new) ...))
54
56
  PATTERN
55
57
 
56
- def message(length, max_length)
57
- format('Module has too many lines. [%<length>d/%<max>d]', length: length, max: max_length)
58
+ def cop_label
59
+ LABEL
58
60
  end
59
61
  end
60
62
  end