rubocop 1.79.2 → 1.87.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 (376) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +185 -20
  5. data/config/obsoletion.yml +9 -0
  6. data/exe/rubocop +1 -8
  7. data/lib/rubocop/cache_config.rb +29 -0
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +30 -4
  9. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  10. data/lib/rubocop/cli/command/lsp.rb +1 -1
  11. data/lib/rubocop/cli/command/mcp.rb +19 -0
  12. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  13. data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
  14. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  15. data/lib/rubocop/cli.rb +35 -9
  16. data/lib/rubocop/comment_config.rb +59 -17
  17. data/lib/rubocop/config.rb +14 -10
  18. data/lib/rubocop/config_finder.rb +1 -1
  19. data/lib/rubocop/config_loader.rb +37 -23
  20. data/lib/rubocop/config_loader_resolver.rb +20 -10
  21. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  22. data/lib/rubocop/config_store.rb +7 -2
  23. data/lib/rubocop/config_validator.rb +1 -1
  24. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  25. data/lib/rubocop/cop/base.rb +8 -2
  26. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  27. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  28. data/lib/rubocop/cop/correctors/alignment_corrector.rb +26 -7
  29. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  30. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  31. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  32. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
  33. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  34. data/lib/rubocop/cop/correctors.rb +28 -0
  35. data/lib/rubocop/cop/documentation.rb +2 -3
  36. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  37. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  38. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  39. data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
  40. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  41. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  42. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  43. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  44. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  45. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
  46. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  47. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  48. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  49. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  50. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  51. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  52. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  53. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  54. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  55. data/lib/rubocop/cop/layout/class_structure.rb +14 -7
  56. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  57. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +26 -7
  58. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
  59. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
  60. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  61. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  62. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  63. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  64. data/lib/rubocop/cop/layout/end_alignment.rb +10 -3
  65. data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
  66. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  67. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  68. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  69. data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
  70. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  71. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  72. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  73. data/lib/rubocop/cop/layout/indentation_width.rb +123 -7
  74. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  75. data/lib/rubocop/cop/layout/line_length.rb +26 -9
  76. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  77. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  78. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  79. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  80. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  81. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +229 -39
  82. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  83. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  84. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
  85. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  86. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  87. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  88. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  89. data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
  90. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  91. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  92. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  93. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  94. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  95. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  96. data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
  97. data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
  98. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  99. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  100. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  101. data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
  102. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  103. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  104. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
  105. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  106. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  107. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  108. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  109. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  110. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  111. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  112. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  113. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  114. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  115. data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
  116. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  117. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -9
  118. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  119. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  120. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  121. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  122. data/lib/rubocop/cop/lint/number_conversion.rb +6 -6
  123. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  124. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  125. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  126. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -11
  127. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  128. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
  129. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
  130. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
  131. data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
  132. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  133. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  134. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  135. data/lib/rubocop/cop/lint/self_assignment.rb +15 -6
  136. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  137. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  138. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  139. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  140. data/lib/rubocop/cop/lint/to_json.rb +12 -16
  141. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  142. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
  143. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  144. data/lib/rubocop/cop/lint/unreachable_code.rb +7 -5
  145. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  146. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  147. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  148. data/lib/rubocop/cop/lint/useless_assignment.rb +48 -25
  149. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  150. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  151. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  152. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  153. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +37 -11
  154. data/lib/rubocop/cop/lint/void.rb +39 -12
  155. data/lib/rubocop/cop/message_annotator.rb +1 -1
  156. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  157. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  158. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  159. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  160. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  161. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  162. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  163. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
  164. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  165. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  166. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  167. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
  168. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  169. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  170. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  171. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  172. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  173. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  174. data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
  175. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  176. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  177. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  178. data/lib/rubocop/cop/mixin.rb +86 -0
  179. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  180. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  181. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  182. data/lib/rubocop/cop/naming/method_name.rb +5 -3
  183. data/lib/rubocop/cop/naming/predicate_method.rb +32 -8
  184. data/lib/rubocop/cop/naming/predicate_prefix.rb +12 -12
  185. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  186. data/lib/rubocop/cop/offense.rb +17 -1
  187. data/lib/rubocop/cop/registry.rb +62 -38
  188. data/lib/rubocop/cop/security/eval.rb +15 -2
  189. data/lib/rubocop/cop/security/io_methods.rb +1 -1
  190. data/lib/rubocop/cop/security/json_load.rb +33 -11
  191. data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
  192. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  193. data/lib/rubocop/cop/style/alias.rb +14 -2
  194. data/lib/rubocop/cop/style/and_or.rb +1 -0
  195. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  196. data/lib/rubocop/cop/style/array_intersect.rb +46 -12
  197. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  198. data/lib/rubocop/cop/style/array_join.rb +4 -2
  199. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  200. data/lib/rubocop/cop/style/attr.rb +5 -2
  201. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  202. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  203. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  204. data/lib/rubocop/cop/style/block_delimiters.rb +27 -34
  205. data/lib/rubocop/cop/style/case_equality.rb +15 -13
  206. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  207. data/lib/rubocop/cop/style/class_and_module_children.rb +19 -2
  208. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  209. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  210. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  211. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -18
  212. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  213. data/lib/rubocop/cop/style/copyright.rb +22 -11
  214. data/lib/rubocop/cop/style/date_time.rb +2 -2
  215. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  216. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  217. data/lib/rubocop/cop/style/documentation.rb +6 -6
  218. data/lib/rubocop/cop/style/documentation_method.rb +8 -8
  219. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  220. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  221. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  222. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  223. data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
  224. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  225. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  226. data/lib/rubocop/cop/style/encoding.rb +7 -1
  227. data/lib/rubocop/cop/style/end_block.rb +3 -1
  228. data/lib/rubocop/cop/style/endless_method.rb +23 -5
  229. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  230. data/lib/rubocop/cop/style/file_open.rb +84 -0
  231. data/lib/rubocop/cop/style/file_write.rb +18 -16
  232. data/lib/rubocop/cop/style/float_division.rb +15 -1
  233. data/lib/rubocop/cop/style/for.rb +3 -0
  234. data/lib/rubocop/cop/style/format_string.rb +4 -3
  235. data/lib/rubocop/cop/style/format_string_token.rb +49 -5
  236. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  237. data/lib/rubocop/cop/style/guard_clause.rb +27 -22
  238. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  239. data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
  240. data/lib/rubocop/cop/style/hash_lookup_method.rb +106 -0
  241. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  242. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  243. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  244. data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
  245. data/lib/rubocop/cop/style/if_unless_modifier.rb +57 -17
  246. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
  247. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  248. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  249. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  250. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  251. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  252. data/lib/rubocop/cop/style/lambda_call.rb +8 -8
  253. data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
  254. data/lib/rubocop/cop/style/map_join.rb +123 -0
  255. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  256. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  257. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
  258. data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
  259. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  260. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
  261. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  262. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  263. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  264. data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
  265. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  266. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  267. data/lib/rubocop/cop/style/not.rb +2 -0
  268. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  269. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  270. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
  271. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  272. data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
  273. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  274. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  275. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  276. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  277. data/lib/rubocop/cop/style/proc.rb +3 -2
  278. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  279. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  280. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  281. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  282. data/lib/rubocop/cop/style/redundant_begin.rb +37 -3
  283. data/lib/rubocop/cop/style/redundant_condition.rb +6 -3
  284. data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
  285. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  286. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  287. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  288. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  289. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  290. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  291. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  292. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  293. data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -30
  294. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  295. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  296. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
  297. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  298. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  299. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  300. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  301. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  302. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  303. data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
  304. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
  305. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  306. data/lib/rubocop/cop/style/safe_navigation.rb +25 -8
  307. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  308. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  309. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  310. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  311. data/lib/rubocop/cop/style/semicolon.rb +25 -7
  312. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  313. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  314. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  315. data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -3
  316. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  317. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  318. data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
  319. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  320. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  321. data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
  322. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  323. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  324. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  325. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  326. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  327. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  328. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  329. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  330. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  331. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  332. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  333. data/lib/rubocop/cop/team.rb +87 -36
  334. data/lib/rubocop/cop/util.rb +2 -3
  335. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  336. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  337. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  338. data/lib/rubocop/cop/variable_force.rb +9 -7
  339. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  340. data/lib/rubocop/directive_comment.rb +48 -4
  341. data/lib/rubocop/file_patterns.rb +9 -1
  342. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  343. data/lib/rubocop/formatter/disabled_config_formatter.rb +24 -7
  344. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  345. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  346. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  347. data/lib/rubocop/formatter/tap_formatter.rb +5 -2
  348. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  349. data/lib/rubocop/formatter.rb +22 -21
  350. data/lib/rubocop/lsp/diagnostic.rb +18 -33
  351. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  352. data/lib/rubocop/lsp/routes.rb +43 -7
  353. data/lib/rubocop/lsp/runtime.rb +13 -4
  354. data/lib/rubocop/lsp/stdin_runner.rb +8 -17
  355. data/lib/rubocop/magic_comment.rb +20 -0
  356. data/lib/rubocop/mcp/server.rb +200 -0
  357. data/lib/rubocop/options.rb +35 -4
  358. data/lib/rubocop/path_util.rb +14 -2
  359. data/lib/rubocop/plugin/loader.rb +1 -1
  360. data/lib/rubocop/project_index_loader.rb +66 -0
  361. data/lib/rubocop/rake_task.rb +1 -1
  362. data/lib/rubocop/remote_config.rb +10 -8
  363. data/lib/rubocop/result_cache.rb +61 -38
  364. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  365. data/lib/rubocop/rspec/shared_contexts.rb +39 -5
  366. data/lib/rubocop/rspec/support.rb +2 -1
  367. data/lib/rubocop/runner.rb +134 -57
  368. data/lib/rubocop/server/cache.rb +6 -29
  369. data/lib/rubocop/server/core.rb +2 -0
  370. data/lib/rubocop/target_finder.rb +17 -10
  371. data/lib/rubocop/target_ruby.rb +31 -14
  372. data/lib/rubocop/version.rb +21 -3
  373. data/lib/rubocop.rb +28 -96
  374. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  375. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  376. metadata +38 -9
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks that predicate methods end with `?` and non-predicate methods do not.
7
7
  #
8
8
  # The names of predicate methods (methods that return a boolean value) should end
9
- # in a question mark. Methods that don't return a boolean, shouldn't
9
+ # in a question mark. Methods that don't return a boolean shouldn't
10
10
  # end in a question mark.
11
11
  #
12
12
  # The cop assesses a predicate method as one that returns boolean values. Likewise,
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # method calls are assumed to return boolean values. The cop does not make an assessment
15
15
  # if the return type is unknown (non-predicate method calls, variables, etc.).
16
16
  #
17
- # NOTE: Operator methods (`def ==`, etc.) are ignored.
17
+ # NOTE: The `initialize` method and operator methods (`def ==`, etc.) are ignored.
18
18
  #
19
19
  # By default, the cop runs in `conservative` mode, which allows a method to be named
20
20
  # with a question mark as long as at least one return value is boolean. In `aggressive`
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # return values are detected.
23
23
  #
24
24
  # The cop also has `AllowedMethods` configuration in order to prevent the cop from
25
- # registering an offense from a method name that does not confirm to the naming
25
+ # registering an offense from a method name that does not conform to the naming
26
26
  # guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
27
27
  # configuration to allow method names by regular expression.
28
28
  #
@@ -113,6 +113,18 @@ module RuboCop
113
113
  # true
114
114
  # end
115
115
  #
116
+ # @example AllowedMethods: [call] (default)
117
+ # # good
118
+ # def call
119
+ # foo == bar
120
+ # end
121
+ #
122
+ # @example AllowedPatterns: [\Afoo]
123
+ # # good
124
+ # def foo?
125
+ # 'foo'
126
+ # end
127
+ #
116
128
  # @example AllowBangMethods: false (default)
117
129
  # # bad
118
130
  # def save!
@@ -125,6 +137,17 @@ module RuboCop
125
137
  # true
126
138
  # end
127
139
  #
140
+ # @example WaywardPredicates: ['infinite?', 'nonzero?'] (default)
141
+ # # good
142
+ # def non_predicate_method(num)
143
+ # num.infinite?
144
+ # end
145
+ #
146
+ # # good
147
+ # def non_predicate_method(num)
148
+ # num.nonzero?
149
+ # end
150
+ #
128
151
  class PredicateMethod < Base
129
152
  include AllowedMethods
130
153
  include AllowedPattern
@@ -149,7 +172,8 @@ module RuboCop
149
172
  private
150
173
 
151
174
  def allowed?(node)
152
- allowed_method?(node.method_name) ||
175
+ node.method?(:initialize) ||
176
+ allowed_method?(node.method_name) ||
153
177
  matches_allowed_pattern?(node.method_name) ||
154
178
  allowed_bang_method?(node) ||
155
179
  node.operator_method? ||
@@ -180,8 +204,7 @@ module RuboCop
180
204
  return_values << extract_return_value(return_node)
181
205
  end
182
206
 
183
- last_value = last_value(node)
184
- return_values << last_value if last_value
207
+ return_values << last_value(node)
185
208
 
186
209
  process_return_values(return_values)
187
210
  end
@@ -234,8 +257,9 @@ module RuboCop
234
257
  end
235
258
 
236
259
  def last_value(node)
237
- value = node.begin_type? ? node.children.last : node
238
- value&.return_type? ? extract_return_value(value) : value
260
+ value = node.begin_type? ? node.children.last || s(:nil) : node
261
+
262
+ value.return_type? ? extract_return_value(value) : value
239
263
  end
240
264
 
241
265
  def process_return_values(return_values)
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # they end with a `?`. These methods should be changed to remove the
18
18
  # prefix.
19
19
  #
20
- # When `UseSorbetSigs` set to true (optional), the cop will only report
20
+ # When `UseSorbetSigs` is set to true (optional), the cop will only report
21
21
  # offenses if the method has a Sorbet `sig` with a return type of
22
22
  # `T::Boolean`. Dynamic methods are not supported with this configuration.
23
23
  #
@@ -63,17 +63,17 @@ module RuboCop
63
63
  # end
64
64
  #
65
65
  # @example UseSorbetSigs: false (default)
66
- # # bad
67
- # sig { returns(String) }
68
- # def is_this_thing_on
69
- # "yes"
70
- # end
71
- #
72
- # # good - Sorbet signature is not evaluated
73
- # sig { returns(String) }
74
- # def is_this_thing_on?
75
- # "yes"
76
- # end
66
+ # # bad
67
+ # sig { returns(String) }
68
+ # def is_this_thing_on
69
+ # "yes"
70
+ # end
71
+ #
72
+ # # good - Sorbet signature is not evaluated
73
+ # sig { returns(String) }
74
+ # def is_this_thing_on?
75
+ # "yes"
76
+ # end
77
77
  #
78
78
  # @example UseSorbetSigs: true
79
79
  # # bad
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # Makes sure that rescued exceptions variables are named as
6
+ # Makes sure that rescued exception variables are named as
7
7
  # expected.
8
8
  #
9
9
  # The `PreferredName` config option takes a `String`. It represents
@@ -66,6 +66,13 @@ module RuboCop
66
66
  alias_method :last_line, :line
67
67
  alias_method :last_column, :column
68
68
 
69
+ attr_reader :source_buffer
70
+
71
+ def initialize(line, column, source_line, begin_pos, end_pos)
72
+ super
73
+ @source_buffer = Parser::Source::Buffer.new('(pseudo)', source: source_line)
74
+ end
75
+
69
76
  def column_range
70
77
  column...last_column
71
78
  end
@@ -91,6 +98,14 @@ module RuboCop
91
98
  freeze
92
99
  end
93
100
 
101
+ def marshal_dump
102
+ [@severity, @location, @message, @cop_name, @status]
103
+ end
104
+
105
+ def marshal_load(array)
106
+ @severity, @location, @message, @cop_name, @status = array
107
+ end
108
+
94
109
  # @api public
95
110
  #
96
111
  # @!attribute [r] correctable?
@@ -139,7 +154,8 @@ module RuboCop
139
154
  # @return [Parser::Source::Range]
140
155
  # the range of the code that is highlighted
141
156
  def highlighted_area
142
- Parser::Source::Range.new(source_line, column, column + column_length)
157
+ source_buffer = Parser::Source::Buffer.new(location.source_buffer.name, source: source_line)
158
+ Parser::Source::Range.new(source_buffer, column, column + column_length)
143
159
  end
144
160
 
145
161
  # @api private
@@ -16,7 +16,7 @@ module RuboCop
16
16
  end
17
17
 
18
18
  # Registry that tracks all cops by their badge and department.
19
- class Registry
19
+ class Registry # rubocop:disable Metrics/ClassLength
20
20
  include Enumerable
21
21
 
22
22
  def self.all
@@ -46,18 +46,25 @@ module RuboCop
46
46
  global.qualify_badge(badge).first == badge
47
47
  end
48
48
 
49
- attr_reader :options
49
+ attr_reader :options, :warnings
50
50
 
51
51
  def initialize(cops = [], options = {})
52
- @registry = {}
53
- @departments = {}
54
- @cops_by_cop_name = Hash.new { |hash, key| hash[key] = [] }
52
+ @departments = Set.new
53
+ @cops_by_badge = {}
54
+ @lazy_loaded_cops_by_badge = {}
55
55
 
56
56
  @enrollment_queue = cops
57
57
  @options = options
58
58
 
59
59
  @enabled_cache = {}.compare_by_identity
60
60
  @disabled_cache = {}.compare_by_identity
61
+ @warnings = {}
62
+ end
63
+
64
+ def lazy_load(cop_name, constant_name)
65
+ badge = Badge.parse(cop_name)
66
+ @departments << badge.department
67
+ @lazy_loaded_cops_by_badge[badge] = constant_name
61
68
  end
62
69
 
63
70
  def enlist(cop)
@@ -71,22 +78,17 @@ module RuboCop
71
78
  # @return [Array<Symbol>] list of departments for current cops.
72
79
  def departments
73
80
  clear_enrollment_queue
74
- @departments.keys
81
+ @departments.to_a
75
82
  end
76
83
 
77
84
  # @return [Registry] Cops for that specific department.
78
85
  def with_department(department)
79
- clear_enrollment_queue
80
- with(@departments.fetch(department, []))
86
+ with(cops.select { |cop| cop.department == department })
81
87
  end
82
88
 
83
89
  # @return [Registry] Cops not for a specific department.
84
90
  def without_department(department)
85
- clear_enrollment_queue
86
- without_department = @departments.dup
87
- without_department.delete(department)
88
-
89
- with(without_department.values.flatten)
91
+ with(cops.reject { |cop| cop.department == department })
90
92
  end
91
93
 
92
94
  # @return [Boolean] Checks if given name is department
@@ -132,7 +134,7 @@ module RuboCop
132
134
  # @return [String] Qualified cop name
133
135
  def qualified_cop_name(name, path, warn: true)
134
136
  badge = Badge.parse(name)
135
- print_warning(name, path) if warn && department_missing?(badge, name)
137
+ print_department_missing_warning(name, path) if warn && department_missing?(badge, name)
136
138
  return name if registered?(badge)
137
139
 
138
140
  potential_badges = qualify_badge(badge)
@@ -148,42 +150,44 @@ module RuboCop
148
150
  !badge.qualified? && unqualified_cop_names.include?(name)
149
151
  end
150
152
 
151
- def print_warning(name, path)
152
- message = "#{path}: Warning: no department given for #{name}."
153
+ def print_department_missing_warning(name, path)
154
+ message = "no department given for #{name}."
153
155
  if path.end_with?('.rb')
154
156
  message += ' Run `rubocop -a --only Migration/DepartmentName` to fix.'
155
157
  end
156
- warn message
158
+ emit_warning(path, message)
157
159
  end
158
160
 
159
161
  def unqualified_cop_names
160
162
  clear_enrollment_queue
161
163
  @unqualified_cop_names ||=
162
- Set.new(@cops_by_cop_name.keys.map { |qn| File.basename(qn) }) <<
163
- 'RedundantCopDisableDirective'
164
+ (@cops_by_badge.keys | @lazy_loaded_cops_by_badge.keys)
165
+ .to_set { |badge| File.basename(badge.to_s) } << 'RedundantCopDisableDirective'
164
166
  end
165
167
 
166
168
  def qualify_badge(badge)
167
169
  clear_enrollment_queue
168
170
  @departments
169
- .map { |department, _| badge.with_department(department) }
171
+ .map { |department| badge.with_department(department) }
170
172
  .select { |potential_badge| registered?(potential_badge) }
171
173
  end
172
174
 
173
175
  # @return [Hash{String => Array<Class>}]
174
176
  def to_h
175
177
  clear_enrollment_queue
176
- @cops_by_cop_name
178
+ load_all_lazy_cops
179
+ @cops_by_badge.to_h { |_badge, cop| [cop.cop_name, [cop]] }
177
180
  end
178
181
 
179
182
  def cops
180
183
  clear_enrollment_queue
181
- @registry.values
184
+ load_all_lazy_cops
185
+ @cops_by_badge.values
182
186
  end
183
187
 
184
188
  def length
185
189
  clear_enrollment_queue
186
- @registry.size
190
+ @cops_by_badge.size + @lazy_loaded_cops_by_badge.size
187
191
  end
188
192
 
189
193
  def enabled(config)
@@ -218,7 +222,8 @@ module RuboCop
218
222
  end
219
223
 
220
224
  def names
221
- cops.map(&:cop_name)
225
+ clear_enrollment_queue
226
+ @cops_by_badge.keys.map(&:to_s) | @lazy_loaded_cops_by_badge.keys.map(&:to_s)
222
227
  end
223
228
 
224
229
  def cops_for_department(department)
@@ -235,7 +240,8 @@ module RuboCop
235
240
 
236
241
  def sort!
237
242
  clear_enrollment_queue
238
- @registry = @registry.sort_by { |badge, _| badge.cop_name }.to_h
243
+ load_all_lazy_cops
244
+ @cops_by_badge = @cops_by_badge.sort_by { |badge, _cop| badge.cop_name }.to_h
239
245
 
240
246
  self
241
247
  end
@@ -251,7 +257,9 @@ module RuboCop
251
257
  # @param [String] cop_name
252
258
  # @return [Class, nil]
253
259
  def find_by_cop_name(cop_name)
254
- to_h[cop_name].first
260
+ clear_enrollment_queue
261
+ badge = Badge.parse(cop_name)
262
+ @cops_by_badge[badge] || load_lazy_cop(badge)
255
263
  end
256
264
 
257
265
  # When a cop name is given returns a single-element array with the cop class.
@@ -264,6 +272,7 @@ module RuboCop
264
272
 
265
273
  def freeze
266
274
  clear_enrollment_queue
275
+ load_all_lazy_cops
267
276
  unqualified_cop_names # build cache
268
277
  super
269
278
  end
@@ -274,6 +283,10 @@ module RuboCop
274
283
  attr_reader :global
275
284
  end
276
285
 
286
+ def warnings?(path)
287
+ @warnings[path]
288
+ end
289
+
277
290
  private
278
291
 
279
292
  def initialize_copy(reg)
@@ -284,34 +297,45 @@ module RuboCop
284
297
  return if @enrollment_queue.empty?
285
298
 
286
299
  @enrollment_queue.each do |cop|
287
- @registry[cop.badge] = cop
288
- @departments[cop.department] ||= []
289
- @departments[cop.department] << cop
290
- @cops_by_cop_name[cop.cop_name] << cop
300
+ @cops_by_badge[cop.badge] = cop
301
+ @departments << cop.department
291
302
  end
292
303
  @enrollment_queue = []
293
304
  end
294
305
 
306
+ def load_all_lazy_cops
307
+ @lazy_loaded_cops_by_badge.each_key { |badge| load_lazy_cop(badge) }
308
+ end
309
+
310
+ def load_lazy_cop(badge)
311
+ constant_name = @lazy_loaded_cops_by_badge.delete(badge)
312
+ return unless constant_name
313
+
314
+ @cops_by_badge[badge] = Kernel.const_get(constant_name)
315
+ end
316
+
295
317
  def with(cops)
296
318
  self.class.new(cops)
297
319
  end
298
320
 
299
321
  def resolve_badge(given_badge, real_badge, source_path, warn: true)
300
- unless given_badge.match?(real_badge)
301
- path = PathUtil.smart_path(source_path)
302
-
303
- if warn
304
- warn("#{path}: #{given_badge} has the wrong namespace - " \
305
- "replace it with #{given_badge.with_department(real_badge.department)}")
306
- end
322
+ if warn && !given_badge.match?(real_badge)
323
+ emit_warning(source_path,
324
+ "#{given_badge} has the wrong namespace - " \
325
+ "replace it with #{given_badge.with_department(real_badge.department)}")
307
326
  end
308
327
 
309
328
  real_badge.to_s
310
329
  end
311
330
 
331
+ def emit_warning(path, message)
332
+ Registry.global.warnings[path] = true
333
+ warn "#{PathUtil.smart_path(path)}: Warning: #{message}"
334
+ end
335
+
312
336
  def registered?(badge)
313
337
  clear_enrollment_queue
314
- @registry.key?(badge)
338
+ @cops_by_badge.key?(badge) || @lazy_loaded_cops_by_badge.key?(badge)
315
339
  end
316
340
  end
317
341
  end
@@ -3,15 +3,28 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Security
6
- # Checks for the use of `Kernel#eval` and `Binding#eval`.
6
+ # Checks for the use of `Kernel#eval` and `Binding#eval` with
7
+ # dynamic strings as arguments. Evaluating non-literal strings
8
+ # can enable code injection attacks and makes it difficult to
9
+ # reason about what code will actually be executed.
10
+ #
11
+ # Calls to `eval` with literal strings are not flagged by this cop,
12
+ # as they do not pose the same injection risk.
7
13
  #
8
14
  # @example
9
15
  #
10
16
  # # bad
11
- #
12
17
  # eval(something)
13
18
  # binding.eval(something)
14
19
  # Kernel.eval(something)
20
+ #
21
+ # # good - use safer alternatives
22
+ # obj.public_send(method_name)
23
+ # obj.send(method_name, *args)
24
+ #
25
+ # # good - literal strings are allowed
26
+ # eval("1 + 1")
27
+ # binding.eval("foo")
15
28
  class Eval < Base
16
29
  MSG = 'The use of `eval` is a serious security risk.'
17
30
  RESTRICT_ON_SEND = %i[eval].freeze
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # a subprocess is created in the same way as `Kernel#open`, and its output is returned.
11
11
  # `Kernel#open` may allow unintentional command injection, which is the reason these
12
12
  # `IO` methods are a security risk.
13
- # Consider to use `File.read` to disable the behavior of subprocess invocation.
13
+ # Consider using `File.read` to disable the behavior of subprocess invocation.
14
14
  #
15
15
  # @safety
16
16
  # This cop is unsafe because false positive will occur if the variable passed as
@@ -6,22 +6,40 @@ module RuboCop
6
6
  # Checks for the use of JSON class methods which have potential
7
7
  # security issues.
8
8
  #
9
+ # `JSON.load` and similar methods allow deserialization of arbitrary ruby objects:
10
+ #
11
+ # [source,ruby]
12
+ # ----
13
+ # require 'json/add/string'
14
+ # result = JSON.load('{ "json_class": "String", "raw": [72, 101, 108, 108, 111] }')
15
+ # pp result # => "Hello"
16
+ # ----
17
+ #
18
+ # Never use `JSON.load` for untrusted user input. Prefer `JSON.parse` unless you have
19
+ # a concrete use-case for `JSON.load`.
20
+ #
21
+ # NOTE: Starting with `json` gem version 2.8.0, triggering this behavior without explicitly
22
+ # passing the `create_additions` keyword argument emits a deprecation warning, with the
23
+ # goal of being secure by default in the next major version 3.0.0.
24
+ #
9
25
  # @safety
10
26
  # This cop's autocorrection is unsafe because it's potentially dangerous.
11
- # If using a stream, like `JSON.load(open('file'))`, it will need to call
27
+ # If using a stream, like `JSON.load(open('file'))`, you will need to call
12
28
  # `#read` manually, like `JSON.parse(open('file').read)`.
13
- # If reading single values (rather than proper JSON objects), like
14
- # `JSON.load('false')`, it will need to pass the `quirks_mode: true`
15
- # option, like `JSON.parse('false', quirks_mode: true)`.
16
29
  # Other similar issues may apply.
17
30
  #
18
31
  # @example
19
32
  # # bad
20
- # JSON.load("{}")
21
- # JSON.restore("{}")
33
+ # JSON.load('{}')
34
+ # JSON.restore('{}')
22
35
  #
23
36
  # # good
24
- # JSON.parse("{}")
37
+ # JSON.parse('{}')
38
+ # JSON.unsafe_load('{}')
39
+ #
40
+ # # good - explicit use of `create_additions` option
41
+ # JSON.load('{}', create_additions: true)
42
+ # JSON.load('{}', create_additions: false)
25
43
  #
26
44
  class JSONLoad < Base
27
45
  extend AutoCorrector
@@ -29,13 +47,17 @@ module RuboCop
29
47
  MSG = 'Prefer `JSON.parse` over `JSON.%<method>s`.'
30
48
  RESTRICT_ON_SEND = %i[load restore].freeze
31
49
 
32
- # @!method json_load(node)
33
- def_node_matcher :json_load, <<~PATTERN
34
- (send (const {nil? cbase} :JSON) ${:load :restore} ...)
50
+ # @!method insecure_json_load(node)
51
+ def_node_matcher :insecure_json_load, <<~PATTERN
52
+ (
53
+ send (const {nil? cbase} :JSON) ${:load :restore}
54
+ ...
55
+ !`(pair (sym :create_additions) _)
56
+ )
35
57
  PATTERN
36
58
 
37
59
  def on_send(node)
38
- json_load(node) do |method|
60
+ insecure_json_load(node) do |method|
39
61
  add_offense(node.loc.selector, message: format(MSG, method: method)) do |corrector|
40
62
  corrector.replace(node.loc.selector, 'parse')
41
63
  end
@@ -326,8 +326,7 @@ module RuboCop
326
326
  argument_less_modifier_node = find_argument_less_modifier_node(node)
327
327
  if argument_less_modifier_node
328
328
  corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
329
- elsif (ancestor = node.each_ancestor(:class, :module).first)
330
-
329
+ elsif (ancestor = node.each_ancestor(:class, :module, :sclass).first)
331
330
  corrector.insert_before(ancestor.loc.end, "#{node.method_name}\n\n#{source}\n")
332
331
  else
333
332
  corrector.replace(node, "#{node.method_name}\n\n#{source}")
@@ -349,8 +348,20 @@ module RuboCop
349
348
 
350
349
  def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
351
350
  def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
352
- range = modifier_node.source_range.begin.join(def_node.source_range.begin)
353
- corrector.remove(range)
351
+ # Stop the removal range at the first comment that precedes the def, if
352
+ # any exist. Without this, comments between the modifier and the def are
353
+ # dropped because they fall inside the removed range.
354
+ end_pos = first_comment_or_node_start(def_node)
355
+ corrector.remove(modifier_node.source_range.begin.join(end_pos))
356
+ end
357
+
358
+ def first_comment_or_node_start(node)
359
+ preceding = processed_source.ast_with_comments[node].select do |comment|
360
+ comment.loc.line < node.loc.line
361
+ end
362
+ return node.source_range.begin if preceding.empty?
363
+
364
+ preceding.first.source_range.begin
354
365
  end
355
366
 
356
367
  def def_source(node, def_nodes)
@@ -4,8 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for grouping of accessors in `class` and `module` bodies.
7
- # By default it enforces accessors to be placed in grouped declarations,
8
- # but it can be configured to enforce separating them in multiple declarations.
7
+ # By default it enforces accessors to be placed in grouped
8
+ # declarations, reducing boilerplate. It can also be configured
9
+ # to enforce separating them into individual declarations for
10
+ # easier diffing and per-attribute documentation.
9
11
  #
10
12
  # NOTE: If there is a method call before the accessor method it is always allowed
11
13
  # as it might be intended like Sorbet.
@@ -4,10 +4,13 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Enforces the use of either `#alias` or `#alias_method`
7
- # depending on configuration.
7
+ # depending on configuration. Consistent use of one or the
8
+ # other prevents confusion about their different semantics
9
+ # (e.g., `alias` is resolved at parse time, while `alias_method`
10
+ # is resolved at runtime).
8
11
  # It also flags uses of `alias :symbol` rather than `alias bareword`.
9
12
  #
10
- # However, it will always enforce `method_alias` when used `alias`
13
+ # However, it will always enforce `alias_method` when `alias` is used
11
14
  # in an instance method definition and in a singleton method definition.
12
15
  # If used in a block, always enforce `alias_method`
13
16
  # unless it is an `instance_eval` block.
@@ -42,6 +45,7 @@ module RuboCop
42
45
  return unless node.command?(:alias_method)
43
46
  return unless style == :prefer_alias && alias_keyword_possible?(node)
44
47
  return unless node.arguments.count == 2
48
+ return if alias_method_value_used?(node)
45
49
 
46
50
  msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
47
51
  add_offense(node.loc.selector, message: msg) do |corrector|
@@ -77,6 +81,14 @@ module RuboCop
77
81
  scope_type(node) != :dynamic && node.arguments.all?(&:sym_type?)
78
82
  end
79
83
 
84
+ # `alias_method` is a method call whose return value can be used
85
+ # (e.g., as an argument to `public`/`module_function`, or as an assignment),
86
+ # but `alias` is a keyword statement that cannot appear in such positions.
87
+ # Detect these positions so the conversion does not produce a syntax error.
88
+ def alias_method_value_used?(node)
89
+ node.argument? || node.parent&.assignment?
90
+ end
91
+
80
92
  def alias_method_possible?(node)
81
93
  scope_type(node) != :instance_eval &&
82
94
  node.children.none?(&:gvar_type?) &&
@@ -128,6 +128,7 @@ module RuboCop
128
128
 
129
129
  def correct_other(node, corrector)
130
130
  return if node.parenthesized_call?
131
+ return if node.children.empty? && node.equal?(node.parent.children.last)
131
132
 
132
133
  corrector.wrap(node, '(', ')')
133
134
  end
@@ -424,21 +424,39 @@ module RuboCop
424
424
  end
425
425
 
426
426
  def forwarded_rest_arg
427
- return nil if referenced_rest_arg?
427
+ return @forwarded_rest_arg if defined?(@forwarded_rest_arg)
428
428
 
429
- arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
429
+ @forwarded_rest_arg = if referenced_rest_arg?
430
+ nil
431
+ else
432
+ arguments.find do |arg|
433
+ forwarded_rest_arg?(arg, @rest_arg_name)
434
+ end
435
+ end
430
436
  end
431
437
 
432
438
  def forwarded_kwrest_arg
433
- return nil if referenced_kwrest_arg?
439
+ return @forwarded_kwrest_arg if defined?(@forwarded_kwrest_arg)
434
440
 
435
- arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
441
+ @forwarded_kwrest_arg = if referenced_kwrest_arg?
442
+ nil
443
+ else
444
+ arguments.filter_map do |arg|
445
+ extract_forwarded_kwrest_arg(arg, @kwrest_arg_name)
446
+ end.first
447
+ end
436
448
  end
437
449
 
438
450
  def forwarded_block_arg
439
- return nil if referenced_block_arg?
440
-
441
- arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
451
+ return @forwarded_block_arg if defined?(@forwarded_block_arg)
452
+
453
+ @forwarded_block_arg = if referenced_block_arg?
454
+ nil
455
+ else
456
+ arguments.find do |arg|
457
+ forwarded_block_arg?(arg, @block_arg_name)
458
+ end
459
+ end
442
460
  end
443
461
 
444
462
  def classification