rubocop 1.71.1 → 1.91.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 (661) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +883 -168
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +47 -4
  7. data/exe/rubocop +2 -9
  8. data/lib/rubocop/cache_config.rb +29 -0
  9. data/lib/rubocop/cached_data.rb +7 -2
  10. data/lib/rubocop/changed_files.rb +112 -0
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
  12. data/lib/rubocop/cli/command/execute_runner.rb +52 -1
  13. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  14. data/lib/rubocop/cli/command/lsp.rb +1 -1
  15. data/lib/rubocop/cli/command/mcp.rb +19 -0
  16. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  17. data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
  18. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
  19. data/lib/rubocop/cli.rb +58 -17
  20. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  21. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  22. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  23. data/lib/rubocop/comment_config.rb +92 -48
  24. data/lib/rubocop/config.rb +137 -19
  25. data/lib/rubocop/config_finder.rb +1 -1
  26. data/lib/rubocop/config_loader.rb +72 -49
  27. data/lib/rubocop/config_loader_resolver.rb +94 -28
  28. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  29. data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
  30. data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
  31. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  32. data/lib/rubocop/config_obsoletion.rb +47 -3
  33. data/lib/rubocop/config_store.rb +7 -2
  34. data/lib/rubocop/config_validator.rb +64 -12
  35. data/lib/rubocop/cop/autocorrect_logic.rb +35 -14
  36. data/lib/rubocop/cop/badge.rb +9 -1
  37. data/lib/rubocop/cop/base.rb +93 -21
  38. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -3
  39. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  40. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
  41. data/lib/rubocop/cop/bundler.rb +19 -0
  42. data/lib/rubocop/cop/commissioner.rb +13 -11
  43. data/lib/rubocop/cop/corrector.rb +4 -4
  44. data/lib/rubocop/cop/correctors/alignment_corrector.rb +79 -10
  45. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  46. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
  47. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  48. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -1
  49. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  50. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  51. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +36 -2
  52. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  53. data/lib/rubocop/cop/correctors.rb +28 -0
  54. data/lib/rubocop/cop/documentation.rb +2 -3
  55. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  56. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  57. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  58. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
  59. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -3
  60. data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
  61. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  62. data/lib/rubocop/cop/gemspec.rb +22 -0
  63. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  64. data/lib/rubocop/cop/generator.rb +5 -1
  65. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  66. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  67. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  68. data/lib/rubocop/cop/internal_affairs/location_exists.rb +142 -0
  69. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  70. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +14 -15
  71. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  72. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  73. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  74. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  75. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +2 -2
  76. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  77. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  78. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  79. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  80. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  81. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  82. data/lib/rubocop/cop/internal_affairs.rb +3 -16
  83. data/lib/rubocop/cop/layout/argument_alignment.rb +4 -2
  84. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  85. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  86. data/lib/rubocop/cop/layout/block_alignment.rb +59 -4
  87. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  88. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  89. data/lib/rubocop/cop/layout/class_structure.rb +163 -35
  90. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  91. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  92. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  93. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  94. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  95. data/lib/rubocop/cop/layout/else_alignment.rb +3 -15
  96. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  97. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +27 -9
  98. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  99. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
  100. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  101. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  102. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  103. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  104. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +13 -2
  105. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
  106. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  107. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  108. data/lib/rubocop/cop/layout/end_alignment.rb +9 -3
  109. data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
  110. data/lib/rubocop/cop/layout/first_argument_indentation.rb +56 -3
  111. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  112. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  113. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +20 -15
  114. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  115. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  116. data/lib/rubocop/cop/layout/hash_alignment.rb +11 -13
  117. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +3 -3
  118. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  119. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  120. data/lib/rubocop/cop/layout/indentation_width.rb +157 -10
  121. data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
  122. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +2 -3
  123. data/lib/rubocop/cop/layout/line_length.rb +160 -23
  124. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  125. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  126. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -0
  127. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  128. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  129. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +245 -40
  130. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  131. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  132. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  133. data/lib/rubocop/cop/layout/redundant_line_break.rb +89 -6
  134. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +14 -7
  135. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  136. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  137. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
  138. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -3
  139. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  140. data/lib/rubocop/cop/layout/space_around_operators.rb +30 -4
  141. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  142. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
  143. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  144. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +42 -36
  145. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  146. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  147. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  148. data/lib/rubocop/cop/layout.rb +114 -0
  149. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  150. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  151. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  152. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
  153. data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
  154. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  155. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  156. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  157. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  158. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
  159. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  160. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  161. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  162. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +240 -0
  163. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  164. data/lib/rubocop/cop/lint/debugger.rb +13 -4
  165. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  166. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  167. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  168. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  169. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  170. data/lib/rubocop/cop/lint/duplicate_methods.rb +506 -41
  171. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  172. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  173. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  174. data/lib/rubocop/cop/lint/empty_conditional_body.rb +20 -65
  175. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  176. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  177. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  178. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  179. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  180. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -8
  181. data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
  182. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  183. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  184. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  185. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  186. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  187. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  188. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  189. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  190. data/lib/rubocop/cop/lint/literal_as_condition.rb +137 -11
  191. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  192. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +13 -19
  193. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
  194. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +44 -22
  195. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  196. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  197. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  198. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  199. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  200. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  201. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  202. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  203. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +4 -4
  204. data/lib/rubocop/cop/lint/number_conversion.rb +19 -10
  205. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  206. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +11 -0
  207. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  208. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  209. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  210. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  211. data/lib/rubocop/cop/lint/raise_exception.rb +30 -11
  212. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  213. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +149 -39
  214. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  215. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
  216. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  217. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -25
  218. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -12
  219. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  220. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +267 -0
  221. data/lib/rubocop/cop/lint/redundant_with_index.rb +5 -3
  222. data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -0
  223. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  224. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  225. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  226. data/lib/rubocop/cop/lint/require_range_parentheses.rb +3 -2
  227. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  228. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  229. data/lib/rubocop/cop/lint/rescue_type.rb +2 -2
  230. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  231. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +28 -4
  232. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +9 -5
  233. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  234. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  235. data/lib/rubocop/cop/lint/self_assignment.rb +63 -6
  236. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  237. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  238. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  239. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -1
  240. data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
  241. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  242. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  243. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  244. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +122 -0
  245. data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
  246. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  247. data/lib/rubocop/cop/lint/to_enum_arguments.rb +73 -5
  248. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  249. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  250. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  251. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +36 -10
  252. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  253. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
  254. data/lib/rubocop/cop/lint/unreachable_code.rb +16 -9
  255. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  256. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  257. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  258. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  259. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  260. data/lib/rubocop/cop/lint/useless_access_modifier.rb +31 -6
  261. data/lib/rubocop/cop/lint/useless_assignment.rb +56 -27
  262. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +107 -0
  263. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
  264. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  265. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
  266. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  267. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -3
  268. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +13 -7
  269. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
  270. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  271. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +201 -0
  272. data/lib/rubocop/cop/lint/void.rb +60 -21
  273. data/lib/rubocop/cop/lint.rb +179 -0
  274. data/lib/rubocop/cop/message_annotator.rb +7 -3
  275. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  276. data/lib/rubocop/cop/metrics/block_length.rb +2 -1
  277. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  278. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  279. data/lib/rubocop/cop/metrics/method_length.rb +3 -2
  280. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  281. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  282. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  283. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  284. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  285. data/lib/rubocop/cop/metrics.rb +31 -0
  286. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  287. data/lib/rubocop/cop/migration.rb +13 -0
  288. data/lib/rubocop/cop/mixin/alignment.rb +3 -3
  289. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  290. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
  291. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  292. data/lib/rubocop/cop/mixin/check_line_breakable.rb +27 -9
  293. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -7
  294. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  295. data/lib/rubocop/cop/mixin/comments_help.rb +2 -3
  296. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  297. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  298. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  299. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  300. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  301. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  302. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  303. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
  304. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  305. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  306. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +44 -16
  307. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +29 -26
  308. data/lib/rubocop/cop/mixin/hash_subset.rb +28 -6
  309. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  310. data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
  311. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  312. data/lib/rubocop/cop/mixin/line_length_help.rb +52 -11
  313. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  314. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  315. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  316. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  317. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  318. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
  319. data/lib/rubocop/cop/mixin/project_index_help.rb +188 -0
  320. data/lib/rubocop/cop/mixin/range_help.rb +16 -5
  321. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
  322. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  323. data/lib/rubocop/cop/mixin/statement_modifier.rb +47 -11
  324. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  325. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  326. data/lib/rubocop/cop/mixin/trailing_comma.rb +23 -6
  327. data/lib/rubocop/cop/mixin.rb +91 -0
  328. data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
  329. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  330. data/lib/rubocop/cop/naming/block_forwarding.rb +7 -4
  331. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  332. data/lib/rubocop/cop/naming/file_name.rb +6 -5
  333. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  334. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +13 -6
  335. data/lib/rubocop/cop/naming/method_name.rb +190 -15
  336. data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
  337. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +80 -8
  338. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -6
  339. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  340. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  341. data/lib/rubocop/cop/naming.rb +31 -0
  342. data/lib/rubocop/cop/offense.rb +52 -9
  343. data/lib/rubocop/cop/registry.rb +233 -64
  344. data/lib/rubocop/cop/security/eval.rb +17 -3
  345. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  346. data/lib/rubocop/cop/security/json_load.rb +33 -11
  347. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  348. data/lib/rubocop/cop/security/open.rb +1 -0
  349. data/lib/rubocop/cop/security.rb +19 -0
  350. data/lib/rubocop/cop/severity.rb +12 -0
  351. data/lib/rubocop/cop/style/access_modifier_declarations.rb +47 -13
  352. data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
  353. data/lib/rubocop/cop/style/alias.rb +15 -3
  354. data/lib/rubocop/cop/style/and_or.rb +2 -1
  355. data/lib/rubocop/cop/style/arguments_forwarding.rb +49 -37
  356. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  357. data/lib/rubocop/cop/style/array_intersect.rb +136 -38
  358. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
  359. data/lib/rubocop/cop/style/array_join.rb +4 -2
  360. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  361. data/lib/rubocop/cop/style/attr.rb +5 -2
  362. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  363. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  364. data/lib/rubocop/cop/style/bitwise_predicate.rb +7 -1
  365. data/lib/rubocop/cop/style/block_delimiters.rb +43 -38
  366. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  367. data/lib/rubocop/cop/style/case_like_if.rb +6 -8
  368. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  369. data/lib/rubocop/cop/style/class_and_module_children.rb +135 -21
  370. data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
  371. data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
  372. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  373. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  374. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  375. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  376. data/lib/rubocop/cop/style/combinable_loops.rb +7 -2
  377. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  378. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  379. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  380. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  381. data/lib/rubocop/cop/style/concat_array_literals.rb +8 -3
  382. data/lib/rubocop/cop/style/conditional_assignment.rb +54 -24
  383. data/lib/rubocop/cop/style/constant_visibility.rb +23 -12
  384. data/lib/rubocop/cop/style/copyright.rb +27 -12
  385. data/lib/rubocop/cop/style/data_inheritance.rb +25 -0
  386. data/lib/rubocop/cop/style/date_time.rb +4 -4
  387. data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
  388. data/lib/rubocop/cop/style/dig_chain.rb +6 -1
  389. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  390. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  391. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +122 -14
  392. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  393. data/lib/rubocop/cop/style/documentation.rb +53 -6
  394. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  395. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  396. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  397. data/lib/rubocop/cop/style/each_with_object.rb +4 -3
  398. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  399. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  400. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  401. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  402. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  403. data/lib/rubocop/cop/style/empty_literal.rb +11 -2
  404. data/lib/rubocop/cop/style/empty_method.rb +12 -8
  405. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -0
  406. data/lib/rubocop/cop/style/encoding.rb +7 -1
  407. data/lib/rubocop/cop/style/end_block.rb +3 -1
  408. data/lib/rubocop/cop/style/endless_method.rb +191 -19
  409. data/lib/rubocop/cop/style/env_home.rb +4 -0
  410. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  411. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  412. data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -1
  413. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  414. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  415. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  416. data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
  417. data/lib/rubocop/cop/style/file_null.rb +6 -4
  418. data/lib/rubocop/cop/style/file_open.rb +84 -0
  419. data/lib/rubocop/cop/style/file_write.rb +21 -16
  420. data/lib/rubocop/cop/style/float_division.rb +25 -17
  421. data/lib/rubocop/cop/style/for.rb +9 -0
  422. data/lib/rubocop/cop/style/format_string.rb +17 -4
  423. data/lib/rubocop/cop/style/format_string_token.rb +86 -16
  424. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  425. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  426. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  427. data/lib/rubocop/cop/style/guard_clause.rb +32 -23
  428. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  429. data/lib/rubocop/cop/style/hash_conversion.rb +28 -12
  430. data/lib/rubocop/cop/style/hash_each_methods.rb +4 -4
  431. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  432. data/lib/rubocop/cop/style/hash_lookup_method.rb +105 -0
  433. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  434. data/lib/rubocop/cop/style/hash_syntax.rb +7 -3
  435. data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
  436. data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
  437. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -9
  438. data/lib/rubocop/cop/style/if_inside_else.rb +25 -20
  439. data/lib/rubocop/cop/style/if_unless_modifier.rb +71 -46
  440. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +15 -19
  441. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
  442. data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -6
  443. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  444. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  445. data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
  446. data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
  447. data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
  448. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  449. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  450. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  451. data/lib/rubocop/cop/style/keyword_parameters_order.rb +20 -10
  452. data/lib/rubocop/cop/style/lambda.rb +12 -1
  453. data/lib/rubocop/cop/style/lambda_call.rb +26 -10
  454. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  455. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  456. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  457. data/lib/rubocop/cop/style/map_into_array.rb +5 -2
  458. data/lib/rubocop/cop/style/map_join.rb +123 -0
  459. data/lib/rubocop/cop/style/map_to_hash.rb +13 -5
  460. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  461. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +31 -15
  462. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  463. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +34 -5
  464. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +12 -7
  465. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  466. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -5
  467. data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
  468. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  469. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  470. data/lib/rubocop/cop/style/module_function.rb +4 -2
  471. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  472. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  473. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  474. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  475. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  476. data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -18
  477. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  478. data/lib/rubocop/cop/style/mutable_constant.rb +111 -12
  479. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
  480. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  481. data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
  482. data/lib/rubocop/cop/style/next.rb +44 -0
  483. data/lib/rubocop/cop/style/nil_comparison.rb +41 -13
  484. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  485. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  486. data/lib/rubocop/cop/style/not.rb +5 -1
  487. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  488. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  489. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  490. data/lib/rubocop/cop/style/object_then.rb +1 -0
  491. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  492. data/lib/rubocop/cop/style/one_line_conditional.rb +22 -13
  493. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  494. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  495. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  496. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  497. data/lib/rubocop/cop/style/parallel_assignment.rb +58 -27
  498. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  499. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  500. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +4 -0
  501. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  502. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  503. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  504. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  505. data/lib/rubocop/cop/style/proc.rb +4 -2
  506. data/lib/rubocop/cop/style/raise_args.rb +9 -9
  507. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  508. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  509. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  510. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  511. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  512. data/lib/rubocop/cop/style/redundant_begin.rb +38 -3
  513. data/lib/rubocop/cop/style/redundant_condition.rb +63 -5
  514. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  515. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
  516. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
  517. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  518. data/lib/rubocop/cop/style/redundant_exception.rb +7 -1
  519. data/lib/rubocop/cop/style/redundant_fetch_block.rb +2 -10
  520. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  521. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  522. data/lib/rubocop/cop/style/redundant_format.rb +319 -0
  523. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  524. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  525. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  526. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  527. data/lib/rubocop/cop/style/redundant_line_continuation.rb +83 -119
  528. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  529. data/lib/rubocop/cop/style/redundant_parentheses.rb +164 -82
  530. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  531. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -0
  532. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  533. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +8 -8
  534. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -0
  535. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  536. data/lib/rubocop/cop/style/redundant_self.rb +20 -7
  537. data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -3
  538. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  539. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  540. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  541. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  542. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  543. data/lib/rubocop/cop/style/regexp_literal.rb +32 -3
  544. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
  545. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  546. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  547. data/lib/rubocop/cop/style/safe_navigation.rb +76 -20
  548. data/lib/rubocop/cop/style/sample.rb +11 -6
  549. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  550. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  551. data/lib/rubocop/cop/style/select_by_regexp.rb +54 -22
  552. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  553. data/lib/rubocop/cop/style/semicolon.rb +45 -14
  554. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  555. data/lib/rubocop/cop/style/single_line_do_end_block.rb +22 -8
  556. data/lib/rubocop/cop/style/single_line_methods.rb +13 -8
  557. data/lib/rubocop/cop/style/sole_nested_conditional.rb +96 -104
  558. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  559. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -1
  560. data/lib/rubocop/cop/style/static_class.rb +21 -0
  561. data/lib/rubocop/cop/style/string_concatenation.rb +31 -15
  562. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  563. data/lib/rubocop/cop/style/struct_inheritance.rb +38 -2
  564. data/lib/rubocop/cop/style/super_arguments.rb +4 -6
  565. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  566. data/lib/rubocop/cop/style/symbol_proc.rb +11 -9
  567. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  568. data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
  569. data/lib/rubocop/cop/style/time_now.rb +41 -0
  570. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
  571. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  572. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  573. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
  574. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  575. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  576. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +18 -19
  577. data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
  578. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  579. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  580. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  581. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -1
  582. data/lib/rubocop/cop/style/word_array.rb +1 -0
  583. data/lib/rubocop/cop/style/yoda_condition.rb +2 -3
  584. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  585. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  586. data/lib/rubocop/cop/style.rb +311 -0
  587. data/lib/rubocop/cop/team.rb +163 -45
  588. data/lib/rubocop/cop/util.rb +7 -10
  589. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  590. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  591. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  592. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  593. data/lib/rubocop/cop/variable_force/variable.rb +28 -10
  594. data/lib/rubocop/cop/variable_force.rb +26 -9
  595. data/lib/rubocop/cops_documentation_generator.rb +49 -15
  596. data/lib/rubocop/directive_comment.rb +147 -5
  597. data/lib/rubocop/ext/regexp_node.rb +0 -1
  598. data/lib/rubocop/feature_loader.rb +0 -6
  599. data/lib/rubocop/file_patterns.rb +9 -1
  600. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  601. data/lib/rubocop/formatter/disabled_config_formatter.rb +57 -14
  602. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  603. data/lib/rubocop/formatter/formatter_set.rb +3 -2
  604. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  605. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  606. data/lib/rubocop/formatter/html_formatter.rb +3 -5
  607. data/lib/rubocop/formatter/json_formatter.rb +11 -6
  608. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  609. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  610. data/lib/rubocop/formatter/offense_count_formatter.rb +2 -3
  611. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  612. data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
  613. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  614. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  615. data/lib/rubocop/formatter/worst_offenders_formatter.rb +2 -3
  616. data/lib/rubocop/formatter.rb +23 -21
  617. data/lib/rubocop/lockfile.rb +18 -0
  618. data/lib/rubocop/lsp/diagnostic.rb +22 -41
  619. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  620. data/lib/rubocop/lsp/routes.rb +136 -33
  621. data/lib/rubocop/lsp/runtime.rb +23 -8
  622. data/lib/rubocop/lsp/server.rb +4 -2
  623. data/lib/rubocop/lsp/stdin_runner.rb +31 -18
  624. data/lib/rubocop/magic_comment.rb +55 -0
  625. data/lib/rubocop/mcp/server.rb +199 -0
  626. data/lib/rubocop/options.rb +129 -21
  627. data/lib/rubocop/path_util.rb +20 -5
  628. data/lib/rubocop/pending_cops_reporter.rb +51 -0
  629. data/lib/rubocop/plugin/configuration_integrator.rb +146 -0
  630. data/lib/rubocop/plugin/load_error.rb +26 -0
  631. data/lib/rubocop/plugin/loader.rb +100 -0
  632. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  633. data/lib/rubocop/plugin.rb +46 -0
  634. data/lib/rubocop/project_index_loader.rb +82 -0
  635. data/lib/rubocop/rake_task.rb +6 -4
  636. data/lib/rubocop/remote_config.rb +14 -12
  637. data/lib/rubocop/result_cache.rb +90 -52
  638. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  639. data/lib/rubocop/rspec/expect_offense.rb +11 -7
  640. data/lib/rubocop/rspec/shared_contexts.rb +85 -3
  641. data/lib/rubocop/rspec/support.rb +4 -0
  642. data/lib/rubocop/runner.rb +294 -100
  643. data/lib/rubocop/server/cache.rb +67 -48
  644. data/lib/rubocop/server/cli.rb +2 -4
  645. data/lib/rubocop/server/client_command/base.rb +10 -0
  646. data/lib/rubocop/server/client_command/exec.rb +2 -1
  647. data/lib/rubocop/server/client_command/start.rb +11 -1
  648. data/lib/rubocop/server/core.rb +8 -0
  649. data/lib/rubocop/server.rb +14 -0
  650. data/lib/rubocop/target_finder.rb +25 -11
  651. data/lib/rubocop/target_ruby.rb +31 -14
  652. data/lib/rubocop/todo_audit.rb +111 -0
  653. data/lib/rubocop/unified_diff.rb +257 -0
  654. data/lib/rubocop/version.rb +48 -10
  655. data/lib/rubocop.rb +30 -682
  656. data/lib/ruby_lsp/rubocop/addon.rb +28 -17
  657. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  658. metadata +116 -19
  659. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
  660. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  661. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
@@ -9,7 +9,20 @@ module RuboCop
9
9
  # On the other hand, `ENV.fetch` raises `KeyError` or returns the explicitly
10
10
  # specified default value.
11
11
  #
12
- # @example
12
+ # @example DefaultToNil: true (default)
13
+ # # bad
14
+ # ENV['X']
15
+ # x = ENV['X']
16
+ #
17
+ # # good
18
+ # ENV.fetch('X', nil)
19
+ # x = ENV.fetch('X', nil)
20
+ #
21
+ # # also good
22
+ # !ENV['X']
23
+ # ENV['X'].some_method # (e.g. `.nil?`)
24
+ #
25
+ # @example DefaultToNil: false
13
26
  # # bad
14
27
  # ENV['X']
15
28
  # x = ENV['X']
@@ -25,7 +38,8 @@ module RuboCop
25
38
  class FetchEnvVar < Base
26
39
  extend AutoCorrector
27
40
 
28
- MSG = 'Use `ENV.fetch(%<key>s)` or `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
41
+ MSG_WITH_NIL = 'Use `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
42
+ MSG_WITHOUT_NIL = 'Use `ENV.fetch(%<key>s)` instead of `ENV[%<key>s]`.'
29
43
  RESTRICT_ON_SEND = [:[]].freeze
30
44
 
31
45
  # @!method env_with_bracket?(node)
@@ -37,7 +51,7 @@ module RuboCop
37
51
  env_with_bracket?(node) do |name_node|
38
52
  break unless offensive?(node)
39
53
 
40
- message = format(MSG, key: name_node.source)
54
+ message = format(offense_message, key: name_node.source)
41
55
  add_offense(node, message: message) do |corrector|
42
56
  corrector.replace(node, new_code(name_node))
43
57
  end
@@ -46,19 +60,27 @@ module RuboCop
46
60
 
47
61
  private
48
62
 
63
+ def default_to_nil?
64
+ cop_config.fetch('DefaultToNil', true)
65
+ end
66
+
67
+ def offense_message
68
+ default_to_nil? ? MSG_WITH_NIL : MSG_WITHOUT_NIL
69
+ end
70
+
49
71
  def allowed_var?(node)
50
72
  env_key_node = node.children.last
51
- env_key_node.str_type? && cop_config['AllowedVars'].include?(env_key_node.value)
73
+ env_key_node.str_type? && cop_config['AllowedVariables'].include?(env_key_node.value)
52
74
  end
53
75
 
54
76
  def used_as_flag?(node)
55
77
  return false if node.root?
56
- return true if used_if_condition_in_body(node)
78
+ return true if used_if_condition_in_body?(node)
57
79
 
58
80
  node.parent.send_type? && (node.parent.prefix_bang? || node.parent.comparison_method?)
59
81
  end
60
82
 
61
- def used_if_condition_in_body(node)
83
+ def used_if_condition_in_body?(node)
62
84
  if_node = node.ancestors.find(&:if_type?)
63
85
 
64
86
  return false unless (condition = if_node&.condition)
@@ -125,7 +147,11 @@ module RuboCop
125
147
  end
126
148
 
127
149
  def new_code(name_node)
128
- "ENV.fetch(#{name_node.source}, nil)"
150
+ if default_to_nil?
151
+ "ENV.fetch(#{name_node.source}, nil)"
152
+ else
153
+ "ENV.fetch(#{name_node.source})"
154
+ end
129
155
  end
130
156
  end
131
157
  end
@@ -54,7 +54,7 @@ module RuboCop
54
54
  @contain_dev_null_string_in_file = ast.each_descendant(:str).any? do |str|
55
55
  content = str.str_content
56
56
 
57
- valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull
57
+ valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull -- the cop needs the literal it is matching
58
58
  end
59
59
  end
60
60
 
@@ -62,7 +62,7 @@ module RuboCop
62
62
  value = node.value
63
63
  return unless valid_string?(value)
64
64
  return if acceptable?(node)
65
- return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull
65
+ return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull -- the cop needs the literal it is matching
66
66
  return unless REGEXP.match?(value)
67
67
 
68
68
  add_offense(node, message: format(MSG, source: value)) do |corrector|
@@ -78,10 +78,12 @@ module RuboCop
78
78
 
79
79
  def acceptable?(node)
80
80
  # Using a hardcoded null device is acceptable when inside an array or
81
- # inside a hash to ensure behavior doesn't change.
81
+ # inside a hash to ensure behavior doesn't change. A `str` that is part of
82
+ # an interpolated or concatenated string (`dstr`) is not a standalone null
83
+ # device either, and replacing it would corrupt the surrounding string.
82
84
  return false unless node.parent
83
85
 
84
- node.parent.type?(:array, :pair)
86
+ node.parent.type?(:array, :pair, :dstr)
85
87
  end
86
88
  end
87
89
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for `File.open` without a block, which can leak file descriptors.
7
+ #
8
+ # When `File.open` is called without a block, the caller is responsible
9
+ # for closing the file descriptor. If it is not explicitly closed, it
10
+ # will only be closed when the garbage collector runs, which may lead
11
+ # to resource exhaustion. Using the block form ensures the file is
12
+ # automatically closed when the block exits.
13
+ #
14
+ # This cop only registers an offense when the result of `File.open` is
15
+ # assigned to a variable or has a method chained on it, as those are the
16
+ # clearest indicators that the block form should be used instead. When
17
+ # `File.open` is used as a return value or passed as an argument, the
18
+ # caller is likely managing the file descriptor intentionally.
19
+ #
20
+ # @safety
21
+ # This cop is unsafe because it relies on syntax heuristics and cannot
22
+ # verify whether the file descriptor is safely managed. For example, it
23
+ # still flags intentional one-shot reads (`File.open("f").read`) where
24
+ # the file descriptor is closed by the garbage collector.
25
+ #
26
+ # @example
27
+ # # bad
28
+ # f = File.open('file')
29
+ #
30
+ # # bad
31
+ # File.open('file').read
32
+ #
33
+ # # good
34
+ # File.open('file') do |f|
35
+ # f.read
36
+ # end
37
+ #
38
+ # # good
39
+ # File.open('file', &:read)
40
+ #
41
+ # # good - pass an open file object to an API that manages its lifecycle
42
+ # process(io: File.open('file'))
43
+ #
44
+ # # good - return an open file object for the caller to manage
45
+ # def json_key_io
46
+ # File.open('file')
47
+ # end
48
+ #
49
+ # # good - use File.read for one-shot reads
50
+ # File.read('file')
51
+ #
52
+ class FileOpen < Base
53
+ MSG = '`File.open` without a block may leak a file descriptor; use the block form.'
54
+ RESTRICT_ON_SEND = %i[open].freeze
55
+
56
+ # @!method file_open?(node)
57
+ def_node_matcher :file_open?, <<~PATTERN
58
+ (send (const {nil? cbase} :File) :open ...)
59
+ PATTERN
60
+
61
+ def on_send(node)
62
+ return unless file_open?(node)
63
+ return if node.block_argument?
64
+ return unless offensive_usage?(node)
65
+
66
+ add_offense(node)
67
+ end
68
+ alias on_csend on_send
69
+
70
+ private
71
+
72
+ def offensive_usage?(node)
73
+ return true unless node.value_used?
74
+
75
+ node.parent.lvasgn_type? || receiver_of_chained_call?(node)
76
+ end
77
+
78
+ def receiver_of_chained_call?(node)
79
+ node.parent.receiver == node
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -104,28 +104,33 @@ module RuboCop
104
104
 
105
105
  def replacement(mode, filename, content, write_node)
106
106
  replacement = "#{write_method(mode)}(#{filename.source}, #{content.source})"
107
+ heredocs = removed_heredocs(filename, content, write_node)
108
+ return replacement if heredocs.empty?
107
109
 
108
- if heredoc?(write_node)
109
- first_argument = write_node.body.first_argument
110
+ [replacement, *heredocs.map { |heredoc| heredoc_range(heredoc).source }].join("\n")
111
+ end
110
112
 
111
- <<~REPLACEMENT.chomp
112
- #{replacement}
113
- #{heredoc_range(first_argument).source}
114
- REPLACEMENT
115
- else
116
- replacement
117
- end
113
+ # Heredocs opened in the arguments keep working in the replacement, but their
114
+ # bodies are lost when they lie within the replaced range, so they need to be
115
+ # restored after the replacement.
116
+ def removed_heredocs(filename, content, write_node)
117
+ [filename, content].flat_map { |argument| find_heredocs(argument) }
118
+ .select { |heredoc| removed?(heredoc, write_node) }
119
+ .sort_by { |heredoc| heredoc.loc.heredoc_body.begin_pos }
118
120
  end
119
121
 
120
- def heredoc?(write_node)
121
- write_node.block_type? && (first_argument = write_node.body.first_argument) &&
122
- first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
122
+ def heredoc_range(heredoc)
123
+ range_between(heredoc.loc.heredoc_body.begin_pos, heredoc.loc.heredoc_end.end_pos)
123
124
  end
124
125
 
125
- def heredoc_range(first_argument)
126
- range_between(
127
- first_argument.loc.heredoc_body.begin_pos, first_argument.loc.heredoc_end.end_pos
128
- )
126
+ def find_heredocs(node)
127
+ [node, *node.each_descendant(:any_str)].select do |child|
128
+ child.respond_to?(:heredoc?) && child.heredoc?
129
+ end
130
+ end
131
+
132
+ def removed?(heredoc, write_node)
133
+ heredoc.loc.heredoc_end.end_pos <= write_node.source_range.end_pos
129
134
  end
130
135
  end
131
136
  end
@@ -7,9 +7,12 @@ module RuboCop
7
7
  # It is recommended to either always use `fdiv` or coerce one side only.
8
8
  # This cop also provides other options for code consistency.
9
9
  #
10
+ # For `Regexp.last_match` and nth reference (e.g., `$1`), it assumes that the value
11
+ # is a string matched by a regular expression, and allows conversion with `#to_f`.
12
+ #
10
13
  # @safety
11
14
  # This cop is unsafe, because if the operand variable is a string object
12
- # then `.to_f` will be removed and an error will occur.
15
+ # then `#to_f` will be removed and an error will occur.
13
16
  #
14
17
  # [source,ruby]
15
18
  # ----
@@ -84,6 +87,14 @@ module RuboCop
84
87
  (send !nil? :to_f)
85
88
  PATTERN
86
89
 
90
+ # @!method regexp_last_match?(node)
91
+ def_node_matcher :regexp_last_match?, <<~PATTERN
92
+ {
93
+ (send (const {nil? cbase} :Regexp) :last_match int)
94
+ (:nth_ref _)
95
+ }
96
+ PATTERN
97
+
87
98
  def on_send(node)
88
99
  return unless offense_condition?(node)
89
100
 
@@ -96,7 +107,7 @@ module RuboCop
96
107
  remove_to_f_method(corrector, node.receiver)
97
108
  add_to_f_method(corrector, node.first_argument)
98
109
  when :fdiv
99
- correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
110
+ correct_from_slash_to_fdiv(corrector, node.receiver, node.first_argument)
100
111
  end
101
112
  end
102
113
  end
@@ -104,6 +115,9 @@ module RuboCop
104
115
  private
105
116
 
106
117
  def offense_condition?(node)
118
+ return false if regexp_last_match?(node.receiver.receiver) ||
119
+ regexp_last_match?(node.first_argument.receiver)
120
+
107
121
  case style
108
122
  when :left_coerce
109
123
  right_coerce?(node)
@@ -131,23 +145,17 @@ module RuboCop
131
145
  corrector.remove(send_node.loc.selector)
132
146
  end
133
147
 
134
- def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
135
- receiver_source = extract_receiver_source(receiver)
136
- argument_source = extract_receiver_source(argument)
148
+ def correct_from_slash_to_fdiv(corrector, receiver, argument)
149
+ remove_to_f_method(corrector, receiver) if to_f_method?(receiver)
137
150
 
138
- if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
139
- argument_source = "(#{argument_source})"
140
- end
151
+ argument_parenthesized = argument.begin_type?
152
+ corrector.replace(
153
+ receiver.source_range.end.join(argument.source_range.begin),
154
+ argument_parenthesized ? '.fdiv' : '.fdiv('
155
+ )
141
156
 
142
- corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
143
- end
144
-
145
- def extract_receiver_source(node)
146
- if node.send_type? && node.method?(:to_f)
147
- node.receiver.source
148
- else
149
- node.source
150
- end
157
+ remove_to_f_method(corrector, argument) if to_f_method?(argument)
158
+ corrector.insert_after(argument, ')') unless argument_parenthesized
151
159
  end
152
160
  end
153
161
  end
@@ -8,6 +8,9 @@ module RuboCop
8
8
  # parameter. An `each` call with a block on a single line is always
9
9
  # allowed.
10
10
  #
11
+ # NOTE: `each` is preferred in idiomatic Ruby because `for` leaks
12
+ # its loop variable into the surrounding scope.
13
+ #
11
14
  # @example EnforcedStyle: each (default)
12
15
  # # bad
13
16
  # def foo
@@ -66,6 +69,7 @@ module RuboCop
66
69
 
67
70
  if style == :for
68
71
  return unless node.receiver
72
+ return if rescue_or_ensure_body?(node)
69
73
 
70
74
  add_offense(node, message: PREFER_FOR) do |corrector|
71
75
  EachToForCorrector.new(node).call(corrector)
@@ -77,12 +81,17 @@ module RuboCop
77
81
  end
78
82
 
79
83
  alias on_numblock on_block
84
+ alias on_itblock on_block
80
85
 
81
86
  private
82
87
 
83
88
  def suspect_enumerable?(node)
84
89
  node.multiline? && node.method?(:each) && !node.send_node.arguments?
85
90
  end
91
+
92
+ def rescue_or_ensure_body?(node)
93
+ node.body&.type?(:rescue, :ensure)
94
+ end
86
95
  end
87
96
  end
88
97
  end
@@ -11,9 +11,10 @@ module RuboCop
11
11
  # if the first argument is a string literal and if the second
12
12
  # argument is an array literal.
13
13
  #
14
- # Autocorrection will be applied when using argument is a literal or known built-in conversion
15
- # methods such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`, and `to_sym` on variables,
16
- # provided that their return value is not an array. For example, when using `to_s`,
14
+ # Autocorrection will be applied when the argument is a literal or uses a known
15
+ # built-in conversion method such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`,
16
+ # and `to_sym` on variables, provided that their return value is not an array.
17
+ # For example, when using `to_s`,
17
18
  # `'%s' % [1, 2, 3].to_s` can be autocorrected without any incompatibility:
18
19
  #
19
20
  # [source,ruby]
@@ -143,10 +144,22 @@ module RuboCop
143
144
  end
144
145
 
145
146
  def format_single_parameter(arg)
147
+ # `format(fmt, *args)` is equivalent to `fmt % args`, so unwrap the splat
148
+ # and render the argument it splats.
149
+ return format_single_parameter(arg.children.first) if arg.splat_type?
150
+
146
151
  source = arg.source
147
152
  return "{ #{source} }" if arg.hash_type?
148
153
 
149
- arg.send_type? && arg.operator_method? && !arg.parenthesized? ? "(#{source})" : source
154
+ requires_parentheses?(arg) ? "(#{source})" : source
155
+ end
156
+
157
+ # An argument that binds looser than `%` (a ternary, range, assignment, or
158
+ # operator call) must be parenthesized to keep its meaning.
159
+ def requires_parentheses?(arg)
160
+ return true if arg.assignment? || arg.type?(:if, :and, :or, :range)
161
+
162
+ arg.send_type? && arg.operator_method? && !arg.parenthesized?
150
163
  end
151
164
  end
152
165
  end
@@ -3,16 +3,29 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Use a consistent style for named format string tokens.
6
+ # Use a consistent style for tokens within a format string.
7
7
  #
8
- # NOTE: `unannotated` style cop only works for strings
9
- # which are passed as arguments to those methods:
10
- # `printf`, `sprintf`, `format`, `%`.
11
- # The reason is that _unannotated_ format is very similar
12
- # to encoded URLs or Date/Time formatting strings.
8
+ # By default, all strings are evaluated. In some cases, this may be undesirable,
9
+ # as they could be used as arguments to a method that does not consider
10
+ # them to be tokens, but rather other identifiers or just part of the string.
13
11
  #
14
- # This cop's allowed methods can be customized with `AllowedMethods`.
15
- # By default, there are no allowed methods.
12
+ # `AllowedMethods` or `AllowedPatterns` can be configured with in order to mark specific
13
+ # methods as always allowed, thereby avoiding an offense from the cop. By default, there
14
+ # are no allowed methods.
15
+ #
16
+ # Additionally, the cop can be made conservative by configuring it with
17
+ # `Mode: conservative` (default `aggressive`). In this mode, tokens (regardless
18
+ # of `EnforcedStyle`) are only considered if used in the format string argument to the
19
+ # methods `printf`, `sprintf`, `format` and `%`.
20
+ #
21
+ # NOTE: In `aggressive` mode, offenses are registered for all strings containing tokens,
22
+ # but autocorrection is only applied when the string appears in a known formatting context
23
+ # (`format`, `sprintf`, `printf`, or `%`). This is done in order to prevent false
24
+ # autocorrections for strings that are not actually format strings.
25
+ #
26
+ # NOTE: Tokens in the `unannotated` style (eg. `%s`) are always treated as if
27
+ # configured with `Conservative: true`. This is done in order to prevent false positives,
28
+ # because this format is very similar to encoded URLs or Date/Time formatting strings.
16
29
  #
17
30
  # @example EnforcedStyle: annotated (default)
18
31
  #
@@ -82,6 +95,42 @@ module RuboCop
82
95
  # # good
83
96
  # redirect('foo/%{bar_id}')
84
97
  #
98
+ # @example Mode: aggressive (default), EnforcedStyle: annotated
99
+ #
100
+ # # bad
101
+ # "%{greeting}"
102
+ # foo("%{greeting}")
103
+ #
104
+ # # bad
105
+ # format("%{greeting}", greeting: 'Hello')
106
+ # printf("%{greeting}", greeting: 'Hello')
107
+ # sprintf("%{greeting}", greeting: 'Hello')
108
+ # "%{greeting}" % { greeting: 'Hello' }
109
+ #
110
+ # # good
111
+ # format("%<greeting>s", greeting: 'Hello')
112
+ # printf("%<greeting>s", greeting: 'Hello')
113
+ # sprintf("%<greeting>s", greeting: 'Hello')
114
+ # "%<greeting>s" % { greeting: 'Hello' }
115
+ #
116
+ # @example Mode: conservative, EnforcedStyle: annotated
117
+ #
118
+ # # good
119
+ # "%{greeting}"
120
+ # foo("%{greeting}")
121
+ #
122
+ # # bad
123
+ # format("%{greeting}", greeting: 'Hello')
124
+ # printf("%{greeting}", greeting: 'Hello')
125
+ # sprintf("%{greeting}", greeting: 'Hello')
126
+ # "%{greeting}" % { greeting: 'Hello' }
127
+ #
128
+ # # good
129
+ # format("%<greeting>s", greeting: 'Hello')
130
+ # printf("%<greeting>s", greeting: 'Hello')
131
+ # sprintf("%<greeting>s", greeting: 'Hello')
132
+ # "%<greeting>s" % { greeting: 'Hello' }
133
+ #
85
134
  class FormatStringToken < Base
86
135
  include ConfigurableEnforcedStyle
87
136
  include AllowedMethods
@@ -96,7 +145,7 @@ module RuboCop
96
145
  return if allowed_unannotated?(detections)
97
146
 
98
147
  detections.each do |detected_sequence, token_range|
99
- check_sequence(detected_sequence, token_range)
148
+ check_sequence(node, detected_sequence, token_range)
100
149
  end
101
150
  end
102
151
 
@@ -121,17 +170,34 @@ module RuboCop
121
170
  matches_allowed_pattern?(send_parent.method_name))
122
171
  end
123
172
 
124
- def check_sequence(detected_sequence, token_range)
173
+ def check_sequence(node, detected_sequence, token_range)
125
174
  if detected_sequence.style == style
126
175
  correct_style_detected
127
176
  elsif correctable_sequence?(detected_sequence.type)
128
177
  style_detected(detected_sequence.style)
129
- add_offense(token_range, message: message(detected_sequence.style)) do |corrector|
178
+ register_offense(node, detected_sequence, token_range)
179
+ end
180
+ end
181
+
182
+ def register_offense(node, detected_sequence, token_range)
183
+ msg = message(detected_sequence.style)
184
+
185
+ if format_string_context?(node)
186
+ add_offense(token_range, message: msg) do |corrector|
130
187
  autocorrect_sequence(corrector, detected_sequence, token_range)
131
188
  end
189
+ else
190
+ add_offense(token_range, message: msg)
132
191
  end
133
192
  end
134
193
 
194
+ def format_string_context?(node)
195
+ format_string_in_typical_context?(node) ||
196
+ node.each_ancestor(:dstr).any? do |dstr_node|
197
+ format_string_in_typical_context?(dstr_node)
198
+ end
199
+ end
200
+
135
201
  def correctable_sequence?(detected_type)
136
202
  detected_type == 's' || style == :annotated || style == :unannotated
137
203
  end
@@ -153,15 +219,16 @@ module RuboCop
153
219
  corrector.replace(token_range, correction)
154
220
  end
155
221
 
156
- def unannotated_format?(node, detected_style)
157
- detected_style == :unannotated && !format_string_in_typical_context?(node)
222
+ def allowed_string?(node, detected_style)
223
+ (detected_style == :unannotated || conservative?) &&
224
+ !format_string_in_typical_context?(node)
158
225
  end
159
226
 
160
227
  def message(detected_style)
161
228
  "Prefer #{message_text(style)} over #{message_text(detected_style)}."
162
229
  end
163
230
 
164
- # rubocop:disable Style/FormatStringToken
231
+ # rubocop:disable-next Style/FormatStringToken -- the cop needs the token style it is matching
165
232
  def message_text(style)
166
233
  {
167
234
  annotated: 'annotated tokens (like `%<foo>s`)',
@@ -169,7 +236,6 @@ module RuboCop
169
236
  unannotated: 'unannotated tokens (like `%s`)'
170
237
  }[style]
171
238
  end
172
- # rubocop:enable Style/FormatStringToken
173
239
 
174
240
  def tokens(str_node, &block)
175
241
  return if str_node.source == '__FILE__'
@@ -203,7 +269,7 @@ module RuboCop
203
269
  def collect_detections(node)
204
270
  detections = []
205
271
  tokens(node) do |detected_sequence, token_range|
206
- unless unannotated_format?(node, detected_sequence.style)
272
+ unless allowed_string?(node, detected_sequence.style)
207
273
  detections << [detected_sequence, token_range]
208
274
  end
209
275
  end
@@ -222,6 +288,10 @@ module RuboCop
222
288
  def max_unannotated_placeholders_allowed
223
289
  cop_config['MaxUnannotatedPlaceholdersAllowed']
224
290
  end
291
+
292
+ def conservative?
293
+ cop_config.fetch('Mode', :aggressive).to_sym == :conservative
294
+ end
225
295
  end
226
296
  end
227
297
  end
@@ -151,7 +151,7 @@ module RuboCop
151
151
 
152
152
  def frozen_string_literal_comment(processed_source)
153
153
  processed_source.tokens.find do |token|
154
- token.text.start_with?(FROZEN_STRING_LITERAL_REGEXP)
154
+ MagicComment.parse(token.text).frozen_string_literal_specified?
155
155
  end
156
156
  end
157
157
 
@@ -189,8 +189,9 @@ module RuboCop
189
189
 
190
190
  def enable_comment(corrector)
191
191
  comment = frozen_string_literal_comment(processed_source)
192
+ replacement = MagicComment.parse(comment.text).new_frozen_string_literal(true)
192
193
 
193
- corrector.replace(line_range(comment.line), FROZEN_STRING_LITERAL_ENABLED)
194
+ corrector.replace(line_range(comment.line), replacement)
194
195
  end
195
196
 
196
197
  def insert_comment(corrector)
@@ -8,6 +8,9 @@ module RuboCop
8
8
  # reassign (possibly to redirect some stream) constants in Ruby, you'll get
9
9
  # an interpreter warning if you do so.
10
10
  #
11
+ # Additionally, `$stdout/$stderr/$stdin` can safely be accessed in a Ractor because they
12
+ # are ractor-local, while `STDOUT/STDERR/STDIN` will raise `Ractor::IsolationError`.
13
+ #
11
14
  # @safety
12
15
  # Autocorrection is unsafe because `STDOUT` and `$stdout` may point to different
13
16
  # objects, for example.
@@ -3,7 +3,10 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Looks for uses of global variables.
6
+ # Looks for uses of global variables. Global variables introduce
7
+ # shared mutable state that makes code harder to test, debug,
8
+ # and reason about, since any part of the program can read or modify them.
9
+ #
7
10
  # It does not report offenses for built-in global variables.
8
11
  # Built-in global variables are allowed by default. Additionally
9
12
  # users can allow additional variables via the AllowedVariables option.
@@ -54,7 +57,7 @@ module RuboCop
54
57
  ].map(&:to_sym)
55
58
 
56
59
  def user_vars
57
- cop_config['AllowedVariables'].map(&:to_sym)
60
+ @user_vars ||= cop_config['AllowedVariables'].map(&:to_sym).freeze
58
61
  end
59
62
 
60
63
  def allowed_var?(global_var)