rubocop 1.71.1 → 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (705) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +885 -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 +50 -5
  10. data/lib/rubocop/changed_files.rb +134 -0
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
  12. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  13. data/lib/rubocop/cli/command/execute_runner.rb +54 -3
  14. data/lib/rubocop/cli/command/explain.rb +34 -0
  15. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  16. data/lib/rubocop/cli/command/lsp.rb +1 -1
  17. data/lib/rubocop/cli/command/mcp.rb +19 -0
  18. data/lib/rubocop/cli/command/show_cops.rb +8 -2
  19. data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
  20. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
  21. data/lib/rubocop/cli.rb +59 -17
  22. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  23. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  24. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  25. data/lib/rubocop/comment_config.rb +98 -45
  26. data/lib/rubocop/config.rb +137 -19
  27. data/lib/rubocop/config_finder.rb +1 -1
  28. data/lib/rubocop/config_loader.rb +75 -49
  29. data/lib/rubocop/config_loader_resolver.rb +124 -33
  30. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  31. data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
  32. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  33. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  34. data/lib/rubocop/config_obsoletion.rb +47 -3
  35. data/lib/rubocop/config_store.rb +7 -2
  36. data/lib/rubocop/config_validator.rb +75 -12
  37. data/lib/rubocop/cop/autocorrect_logic.rb +43 -17
  38. data/lib/rubocop/cop/badge.rb +9 -1
  39. data/lib/rubocop/cop/base.rb +128 -35
  40. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
  41. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  42. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -11
  43. data/lib/rubocop/cop/bundler.rb +19 -0
  44. data/lib/rubocop/cop/commissioner.rb +13 -11
  45. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  46. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  47. data/lib/rubocop/cop/corrector.rb +4 -4
  48. data/lib/rubocop/cop/correctors/alignment_corrector.rb +92 -11
  49. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  50. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
  51. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  52. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  53. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +29 -2
  54. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  55. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  56. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +73 -2
  57. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  58. data/lib/rubocop/cop/correctors.rb +28 -0
  59. data/lib/rubocop/cop/documentation.rb +3 -4
  60. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  61. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  62. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  63. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  64. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
  65. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -9
  66. data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
  67. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  68. data/lib/rubocop/cop/gemspec.rb +22 -0
  69. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  70. data/lib/rubocop/cop/generator.rb +5 -1
  71. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  72. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  73. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  74. data/lib/rubocop/cop/internal_affairs/location_exists.rb +142 -0
  75. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  76. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +16 -20
  77. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  78. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  79. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  80. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +85 -0
  81. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +2 -2
  82. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  83. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  84. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  85. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  86. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  87. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  88. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  89. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  90. data/lib/rubocop/cop/internal_affairs.rb +3 -16
  91. data/lib/rubocop/cop/layout/argument_alignment.rb +4 -2
  92. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  93. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  94. data/lib/rubocop/cop/layout/block_alignment.rb +86 -4
  95. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  96. data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
  97. data/lib/rubocop/cop/layout/class_structure.rb +172 -36
  98. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  99. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  100. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  101. data/lib/rubocop/cop/layout/def_end_alignment.rb +5 -1
  102. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  103. data/lib/rubocop/cop/layout/else_alignment.rb +3 -15
  104. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  105. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +27 -9
  106. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  107. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
  108. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
  109. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  110. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  111. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  112. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  113. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
  114. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +14 -3
  115. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
  116. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  117. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  118. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  119. data/lib/rubocop/cop/layout/end_alignment.rb +20 -8
  120. data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
  121. data/lib/rubocop/cop/layout/first_argument_indentation.rb +57 -3
  122. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  123. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  124. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +25 -18
  125. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  126. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  127. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  128. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  129. data/lib/rubocop/cop/layout/hash_alignment.rb +20 -18
  130. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -3
  131. data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
  132. data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
  133. data/lib/rubocop/cop/layout/indentation_width.rb +159 -12
  134. data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
  135. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
  136. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  137. data/lib/rubocop/cop/layout/line_length.rb +201 -30
  138. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
  139. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  140. data/lib/rubocop/cop/layout/multiline_block_layout.rb +11 -1
  141. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +63 -56
  142. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
  143. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +259 -40
  144. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  145. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  146. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  147. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  148. data/lib/rubocop/cop/layout/redundant_line_break.rb +111 -7
  149. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +29 -9
  150. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  151. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  152. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  153. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  154. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  155. data/lib/rubocop/cop/layout/space_around_keyword.rb +20 -3
  156. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  157. data/lib/rubocop/cop/layout/space_around_operators.rb +30 -4
  158. data/lib/rubocop/cop/layout/space_before_block_braces.rb +5 -1
  159. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
  160. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  161. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +55 -36
  162. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -8
  163. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  164. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  165. data/lib/rubocop/cop/layout.rb +114 -0
  166. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  167. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  168. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  169. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  170. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
  171. data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
  172. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  173. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  174. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  175. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  176. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
  177. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  178. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  179. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  180. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +240 -0
  181. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  182. data/lib/rubocop/cop/lint/debugger.rb +13 -4
  183. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  184. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  185. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  186. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  187. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  188. data/lib/rubocop/cop/lint/duplicate_methods.rb +506 -41
  189. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  190. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  191. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  192. data/lib/rubocop/cop/lint/empty_conditional_body.rb +22 -65
  193. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  194. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  195. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  196. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  197. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  198. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -8
  199. data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
  200. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  201. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  202. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  203. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  204. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  205. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  206. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  207. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  208. data/lib/rubocop/cop/lint/literal_as_condition.rb +152 -11
  209. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  210. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
  211. data/lib/rubocop/cop/lint/loop.rb +24 -2
  212. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  213. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +60 -23
  214. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  215. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  216. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  217. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  218. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  219. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  220. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  221. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  222. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +4 -4
  223. data/lib/rubocop/cop/lint/number_conversion.rb +20 -11
  224. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  225. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +11 -0
  226. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  227. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  228. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  229. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  230. data/lib/rubocop/cop/lint/raise_exception.rb +30 -11
  231. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  232. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
  233. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  234. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
  235. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  236. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -25
  237. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -12
  238. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  239. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +267 -0
  240. data/lib/rubocop/cop/lint/redundant_with_index.rb +5 -3
  241. data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -0
  242. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  243. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  244. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  245. data/lib/rubocop/cop/lint/require_range_parentheses.rb +3 -2
  246. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  247. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  248. data/lib/rubocop/cop/lint/rescue_type.rb +2 -2
  249. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  250. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +28 -4
  251. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +9 -5
  252. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  253. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  254. data/lib/rubocop/cop/lint/self_assignment.rb +63 -6
  255. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  256. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  257. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  258. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -1
  259. data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
  260. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  261. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  262. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  263. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +122 -0
  264. data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
  265. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  266. data/lib/rubocop/cop/lint/to_enum_arguments.rb +73 -5
  267. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  268. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  269. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  270. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
  271. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  272. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
  273. data/lib/rubocop/cop/lint/unreachable_code.rb +16 -9
  274. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  275. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  276. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  277. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  278. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  279. data/lib/rubocop/cop/lint/useless_access_modifier.rb +31 -6
  280. data/lib/rubocop/cop/lint/useless_assignment.rb +63 -27
  281. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +107 -0
  282. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
  283. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  284. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
  285. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  286. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -3
  287. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +13 -7
  288. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
  289. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  290. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +201 -0
  291. data/lib/rubocop/cop/lint/void.rb +68 -22
  292. data/lib/rubocop/cop/lint.rb +179 -0
  293. data/lib/rubocop/cop/message_annotator.rb +7 -3
  294. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  295. data/lib/rubocop/cop/metrics/block_length.rb +2 -1
  296. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  297. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  298. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  299. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  300. data/lib/rubocop/cop/metrics/method_length.rb +3 -2
  301. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  302. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  303. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  304. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  305. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  306. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  307. data/lib/rubocop/cop/metrics.rb +31 -0
  308. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  309. data/lib/rubocop/cop/migration.rb +13 -0
  310. data/lib/rubocop/cop/mixin/alignment.rb +7 -3
  311. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  312. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
  313. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  314. data/lib/rubocop/cop/mixin/check_line_breakable.rb +44 -23
  315. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +10 -8
  316. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  317. data/lib/rubocop/cop/mixin/comments_help.rb +2 -3
  318. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  319. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  320. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  321. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +13 -2
  322. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  323. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
  324. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  325. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  326. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
  327. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  328. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  329. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +59 -17
  330. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +52 -25
  331. data/lib/rubocop/cop/mixin/hash_subset.rb +28 -6
  332. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  333. data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
  334. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  335. data/lib/rubocop/cop/mixin/line_length_help.rb +52 -11
  336. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  337. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  338. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  339. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  340. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
  341. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +2 -2
  342. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  343. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  344. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
  345. data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
  346. data/lib/rubocop/cop/mixin/range_help.rb +16 -5
  347. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
  348. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  349. data/lib/rubocop/cop/mixin/statement_modifier.rb +66 -10
  350. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  351. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  352. data/lib/rubocop/cop/mixin/trailing_comma.rb +23 -6
  353. data/lib/rubocop/cop/mixin.rb +93 -0
  354. data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
  355. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  356. data/lib/rubocop/cop/naming/block_forwarding.rb +7 -4
  357. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  358. data/lib/rubocop/cop/naming/file_name.rb +6 -5
  359. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  360. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  361. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  362. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +13 -6
  363. data/lib/rubocop/cop/naming/method_name.rb +190 -15
  364. data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
  365. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +65 -8
  366. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -6
  367. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  368. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  369. data/lib/rubocop/cop/naming.rb +31 -0
  370. data/lib/rubocop/cop/offense.rb +108 -9
  371. data/lib/rubocop/cop/registry.rb +234 -65
  372. data/lib/rubocop/cop/security/eval.rb +17 -3
  373. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  374. data/lib/rubocop/cop/security/json_load.rb +45 -11
  375. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  376. data/lib/rubocop/cop/security/open.rb +1 -0
  377. data/lib/rubocop/cop/security.rb +19 -0
  378. data/lib/rubocop/cop/severity.rb +12 -0
  379. data/lib/rubocop/cop/style/access_modifier_declarations.rb +54 -13
  380. data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
  381. data/lib/rubocop/cop/style/alias.rb +33 -8
  382. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  383. data/lib/rubocop/cop/style/and_or.rb +6 -1
  384. data/lib/rubocop/cop/style/arguments_forwarding.rb +52 -37
  385. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  386. data/lib/rubocop/cop/style/array_intersect.rb +136 -38
  387. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
  388. data/lib/rubocop/cop/style/array_join.rb +4 -2
  389. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  390. data/lib/rubocop/cop/style/attr.rb +8 -6
  391. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  392. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  393. data/lib/rubocop/cop/style/bitwise_predicate.rb +13 -5
  394. data/lib/rubocop/cop/style/block_delimiters.rb +71 -40
  395. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  396. data/lib/rubocop/cop/style/case_like_if.rb +12 -11
  397. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  398. data/lib/rubocop/cop/style/class_and_module_children.rb +179 -27
  399. data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
  400. data/lib/rubocop/cop/style/class_methods_definitions.rb +19 -5
  401. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  402. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  403. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  404. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  405. data/lib/rubocop/cop/style/combinable_loops.rb +88 -9
  406. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  407. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  408. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  409. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  410. data/lib/rubocop/cop/style/concat_array_literals.rb +53 -9
  411. data/lib/rubocop/cop/style/conditional_assignment.rb +58 -24
  412. data/lib/rubocop/cop/style/constant_visibility.rb +23 -12
  413. data/lib/rubocop/cop/style/copyright.rb +27 -12
  414. data/lib/rubocop/cop/style/data_inheritance.rb +25 -0
  415. data/lib/rubocop/cop/style/date_time.rb +4 -4
  416. data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
  417. data/lib/rubocop/cop/style/dig_chain.rb +6 -1
  418. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  419. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  420. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
  421. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  422. data/lib/rubocop/cop/style/documentation.rb +53 -6
  423. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  424. data/lib/rubocop/cop/style/double_negation.rb +14 -3
  425. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  426. data/lib/rubocop/cop/style/each_with_object.rb +4 -3
  427. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  428. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  429. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  430. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  431. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  432. data/lib/rubocop/cop/style/empty_literal.rb +12 -3
  433. data/lib/rubocop/cop/style/empty_method.rb +15 -9
  434. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -0
  435. data/lib/rubocop/cop/style/encoding.rb +7 -1
  436. data/lib/rubocop/cop/style/end_block.rb +3 -1
  437. data/lib/rubocop/cop/style/endless_method.rb +252 -19
  438. data/lib/rubocop/cop/style/env_home.rb +4 -0
  439. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  440. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  441. data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
  442. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  443. data/lib/rubocop/cop/style/explicit_block_argument.rb +62 -9
  444. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  445. data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
  446. data/lib/rubocop/cop/style/file_null.rb +6 -4
  447. data/lib/rubocop/cop/style/file_open.rb +84 -0
  448. data/lib/rubocop/cop/style/file_write.rb +21 -16
  449. data/lib/rubocop/cop/style/float_division.rb +43 -15
  450. data/lib/rubocop/cop/style/for.rb +48 -1
  451. data/lib/rubocop/cop/style/format_string.rb +44 -9
  452. data/lib/rubocop/cop/style/format_string_token.rb +86 -16
  453. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +5 -3
  454. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  455. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  456. data/lib/rubocop/cop/style/guard_clause.rb +41 -24
  457. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  458. data/lib/rubocop/cop/style/hash_conversion.rb +52 -16
  459. data/lib/rubocop/cop/style/hash_each_methods.rb +4 -4
  460. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  461. data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
  462. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  463. data/lib/rubocop/cop/style/hash_syntax.rb +23 -6
  464. data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
  465. data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
  466. data/lib/rubocop/cop/style/identical_conditional_branches.rb +39 -11
  467. data/lib/rubocop/cop/style/if_inside_else.rb +46 -21
  468. data/lib/rubocop/cop/style/if_unless_modifier.rb +90 -66
  469. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +19 -19
  470. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
  471. data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
  472. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  473. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  474. data/lib/rubocop/cop/style/inverse_methods.rb +34 -8
  475. data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
  476. data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
  477. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  478. data/lib/rubocop/cop/style/it_block_parameter.rb +150 -0
  479. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  480. data/lib/rubocop/cop/style/keyword_parameters_order.rb +23 -11
  481. data/lib/rubocop/cop/style/lambda.rb +30 -1
  482. data/lib/rubocop/cop/style/lambda_call.rb +31 -10
  483. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  484. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  485. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  486. data/lib/rubocop/cop/style/map_into_array.rb +6 -4
  487. data/lib/rubocop/cop/style/map_join.rb +123 -0
  488. data/lib/rubocop/cop/style/map_to_hash.rb +13 -5
  489. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  490. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +75 -24
  491. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  492. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +58 -6
  493. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
  494. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  495. data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
  496. data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
  497. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  498. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  499. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  500. data/lib/rubocop/cop/style/module_function.rb +4 -2
  501. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  502. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  503. data/lib/rubocop/cop/style/multiline_if_modifier.rb +47 -5
  504. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  505. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  506. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  507. data/lib/rubocop/cop/style/multiline_method_signature.rb +15 -22
  508. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  509. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  510. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  511. data/lib/rubocop/cop/style/mutable_constant.rb +139 -13
  512. data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
  513. data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
  514. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  515. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  516. data/lib/rubocop/cop/style/next.rb +68 -10
  517. data/lib/rubocop/cop/style/nil_comparison.rb +53 -13
  518. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  519. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  520. data/lib/rubocop/cop/style/not.rb +12 -3
  521. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  522. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  523. data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
  524. data/lib/rubocop/cop/style/object_then.rb +1 -0
  525. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  526. data/lib/rubocop/cop/style/one_line_conditional.rb +35 -15
  527. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  528. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  529. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  530. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  531. data/lib/rubocop/cop/style/parallel_assignment.rb +58 -27
  532. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  533. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  534. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
  535. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  536. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  537. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  538. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  539. data/lib/rubocop/cop/style/proc.rb +4 -2
  540. data/lib/rubocop/cop/style/raise_args.rb +9 -9
  541. data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
  542. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  543. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  544. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  545. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  546. data/lib/rubocop/cop/style/redundant_begin.rb +58 -6
  547. data/lib/rubocop/cop/style/redundant_condition.rb +93 -18
  548. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  549. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
  550. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
  551. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  552. data/lib/rubocop/cop/style/redundant_exception.rb +22 -4
  553. data/lib/rubocop/cop/style/redundant_fetch_block.rb +11 -11
  554. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  555. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  556. data/lib/rubocop/cop/style/redundant_format.rb +319 -0
  557. data/lib/rubocop/cop/style/redundant_freeze.rb +12 -3
  558. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  559. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  560. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  561. data/lib/rubocop/cop/style/redundant_line_continuation.rb +83 -119
  562. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  563. data/lib/rubocop/cop/style/redundant_parentheses.rb +176 -83
  564. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  565. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +15 -0
  566. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  567. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
  568. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +16 -0
  569. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  570. data/lib/rubocop/cop/style/redundant_self.rb +20 -7
  571. data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -3
  572. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  573. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  574. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  575. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  576. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  577. data/lib/rubocop/cop/style/regexp_literal.rb +107 -29
  578. data/lib/rubocop/cop/style/require_order.rb +9 -0
  579. data/lib/rubocop/cop/style/rescue_modifier.rb +10 -12
  580. data/lib/rubocop/cop/style/return_nil.rb +19 -4
  581. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  582. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  583. data/lib/rubocop/cop/style/safe_navigation.rb +76 -20
  584. data/lib/rubocop/cop/style/sample.rb +19 -13
  585. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  586. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  587. data/lib/rubocop/cop/style/select_by_regexp.rb +54 -22
  588. data/lib/rubocop/cop/style/self_assignment.rb +13 -16
  589. data/lib/rubocop/cop/style/semicolon.rb +56 -14
  590. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  591. data/lib/rubocop/cop/style/single_line_do_end_block.rb +22 -8
  592. data/lib/rubocop/cop/style/single_line_methods.rb +28 -11
  593. data/lib/rubocop/cop/style/sole_nested_conditional.rb +96 -104
  594. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  595. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +32 -6
  596. data/lib/rubocop/cop/style/static_class.rb +21 -0
  597. data/lib/rubocop/cop/style/string_concatenation.rb +38 -16
  598. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  599. data/lib/rubocop/cop/style/struct_inheritance.rb +38 -2
  600. data/lib/rubocop/cop/style/super_arguments.rb +7 -6
  601. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  602. data/lib/rubocop/cop/style/symbol_proc.rb +34 -14
  603. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  604. data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
  605. data/lib/rubocop/cop/style/time_now.rb +41 -0
  606. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
  607. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  608. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  609. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
  610. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  611. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  612. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
  613. data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
  614. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  615. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  616. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  617. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -1
  618. data/lib/rubocop/cop/style/word_array.rb +1 -0
  619. data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
  620. data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
  621. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  622. data/lib/rubocop/cop/style.rb +311 -0
  623. data/lib/rubocop/cop/team.rb +172 -49
  624. data/lib/rubocop/cop/util.rb +7 -10
  625. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  626. data/lib/rubocop/cop/variable_force/assignment.rb +8 -4
  627. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  628. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  629. data/lib/rubocop/cop/variable_force/variable.rb +42 -11
  630. data/lib/rubocop/cop/variable_force.rb +26 -9
  631. data/lib/rubocop/cops_documentation_generator.rb +49 -15
  632. data/lib/rubocop/directive_comment.rb +147 -5
  633. data/lib/rubocop/ext/regexp_node.rb +0 -1
  634. data/lib/rubocop/feature_loader.rb +0 -6
  635. data/lib/rubocop/file_patterns.rb +9 -1
  636. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  637. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  638. data/lib/rubocop/formatter/disabled_config_formatter.rb +57 -14
  639. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  640. data/lib/rubocop/formatter/formatter_set.rb +7 -2
  641. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  642. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  643. data/lib/rubocop/formatter/html_formatter.rb +3 -5
  644. data/lib/rubocop/formatter/json_formatter.rb +82 -7
  645. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  646. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  647. data/lib/rubocop/formatter/offense_count_formatter.rb +5 -4
  648. data/lib/rubocop/formatter/pacman_formatter.rb +5 -2
  649. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  650. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  651. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  652. data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
  653. data/lib/rubocop/formatter.rb +23 -21
  654. data/lib/rubocop/lockfile.rb +18 -0
  655. data/lib/rubocop/lsp/diagnostic.rb +22 -41
  656. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  657. data/lib/rubocop/lsp/routes.rb +136 -33
  658. data/lib/rubocop/lsp/runtime.rb +66 -15
  659. data/lib/rubocop/lsp/server.rb +4 -2
  660. data/lib/rubocop/lsp/stdin_runner.rb +38 -19
  661. data/lib/rubocop/lsp.rb +5 -2
  662. data/lib/rubocop/magic_comment.rb +55 -0
  663. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  664. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  665. data/lib/rubocop/mcp/scope.rb +65 -0
  666. data/lib/rubocop/mcp/server.rb +307 -0
  667. data/lib/rubocop/mcp/source_files.rb +35 -0
  668. data/lib/rubocop/offense_limit.rb +30 -0
  669. data/lib/rubocop/options.rb +166 -23
  670. data/lib/rubocop/path_util.rb +20 -5
  671. data/lib/rubocop/pending_cops_reporter.rb +51 -0
  672. data/lib/rubocop/plugin/configuration_integrator.rb +153 -0
  673. data/lib/rubocop/plugin/load_error.rb +26 -0
  674. data/lib/rubocop/plugin/loader.rb +100 -0
  675. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  676. data/lib/rubocop/plugin.rb +46 -0
  677. data/lib/rubocop/project_index_loader.rb +82 -0
  678. data/lib/rubocop/rake_task.rb +6 -4
  679. data/lib/rubocop/remote_config.rb +18 -13
  680. data/lib/rubocop/result_cache.rb +110 -65
  681. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  682. data/lib/rubocop/rspec/expect_offense.rb +11 -7
  683. data/lib/rubocop/rspec/shared_contexts.rb +85 -3
  684. data/lib/rubocop/rspec/support.rb +4 -0
  685. data/lib/rubocop/runner.rb +368 -106
  686. data/lib/rubocop/server/cache.rb +67 -48
  687. data/lib/rubocop/server/cli.rb +2 -4
  688. data/lib/rubocop/server/client_command/base.rb +10 -0
  689. data/lib/rubocop/server/client_command/exec.rb +2 -1
  690. data/lib/rubocop/server/client_command/start.rb +11 -1
  691. data/lib/rubocop/server/core.rb +8 -0
  692. data/lib/rubocop/server.rb +14 -0
  693. data/lib/rubocop/target_finder.rb +25 -11
  694. data/lib/rubocop/target_ruby.rb +31 -14
  695. data/lib/rubocop/todo_audit.rb +111 -0
  696. data/lib/rubocop/unified_diff.rb +257 -0
  697. data/lib/rubocop/util.rb +69 -0
  698. data/lib/rubocop/version.rb +48 -10
  699. data/lib/rubocop.rb +35 -682
  700. data/lib/ruby_lsp/rubocop/addon.rb +28 -17
  701. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  702. metadata +129 -21
  703. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
  704. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  705. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for directive scopes that can be expressed with the tighter
7
+ # next-statement forms: a `disable`/`enable` pair, an
8
+ # `enable`/`disable` pair, or a `push`/`pop` with signed arguments
9
+ # wrapping exactly one statement. A statement-scoped directive cannot
10
+ # drift as the surrounding code changes and needs no closing boundary.
11
+ #
12
+ # @safety
13
+ # The autocorrection is unsafe because the suppression scope shrinks
14
+ # from the whole region to the statement: offenses of the suppressed
15
+ # cops located on the directive lines themselves resurface.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # # rubocop:disable Metrics/AbcSize
20
+ # def foo
21
+ # end
22
+ # # rubocop:enable Metrics/AbcSize
23
+ #
24
+ # # good
25
+ # # rubocop:disable-next Metrics/AbcSize
26
+ # def foo
27
+ # end
28
+ #
29
+ # # bad
30
+ # # rubocop:push -Metrics/AbcSize
31
+ # def foo
32
+ # end
33
+ # # rubocop:pop
34
+ #
35
+ # # good
36
+ # # rubocop:disable-next Metrics/AbcSize
37
+ # def foo
38
+ # end
39
+ #
40
+ # # bad
41
+ # # rubocop:disable Metrics/AbcSize
42
+ # # rubocop:push +Metrics/AbcSize
43
+ # def foo
44
+ # end
45
+ # # rubocop:pop
46
+ # # rubocop:enable Metrics/AbcSize
47
+ #
48
+ # # good
49
+ # # rubocop:disable Metrics/AbcSize
50
+ # # rubocop:enable-next Metrics/AbcSize
51
+ # def foo
52
+ # end
53
+ # # rubocop:enable Metrics/AbcSize
54
+ #
55
+ # # good - the region spans more than one statement
56
+ # # rubocop:disable Metrics/AbcSize
57
+ # def foo
58
+ # end
59
+ #
60
+ # def bar
61
+ # end
62
+ # # rubocop:enable Metrics/AbcSize
63
+ #
64
+ class DirectiveScope < Base
65
+ include RangeHelp
66
+ extend AutoCorrector
67
+
68
+ MSG_PAIR = 'Use `%<mode>s-next` instead of a `%<mode>s`/`enable` pair ' \
69
+ 'around a single statement.'
70
+ MSG_ENABLE_PAIR = 'Use `enable-next` instead of an `enable`/`disable` pair ' \
71
+ 'around a single statement.'
72
+ MSG_PUSH_POP = 'Use `%<replacement>s` instead of `push`/`pop` around a single statement.'
73
+
74
+ def on_new_investigation
75
+ processed_source.comments.each do |comment|
76
+ directive = DirectiveComment.new(comment)
77
+ next unless comment_config.comment_only_line?(directive.line_number)
78
+
79
+ if plain_disable?(directive)
80
+ check_pair(directive)
81
+ elsif signed_push?(directive)
82
+ check_push_pop(directive)
83
+ elsif plain_enable?(directive)
84
+ check_enable_pair(directive)
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def comment_config
92
+ processed_source.comment_config
93
+ end
94
+
95
+ def plain_disable?(directive)
96
+ directive.disabled? && !directive.disable_next?
97
+ end
98
+
99
+ def plain_enable?(directive)
100
+ directive.enabled? && !directive.enable_next? && !directive.all_cops?
101
+ end
102
+
103
+ def signed_push?(directive)
104
+ directive.push? && !directive.signed_args.empty?
105
+ end
106
+
107
+ def check_pair(directive)
108
+ enable = single_statement_closing_directive(directive)
109
+ return unless enable&.enabled?
110
+ return unless enable.raw_cop_names.sort == directive.raw_cop_names.sort
111
+
112
+ message = format(MSG_PAIR, mode: directive.mode)
113
+ add_offense(directive.comment, message: message) do |corrector|
114
+ convert_pair(corrector, directive, enable)
115
+ end
116
+ end
117
+
118
+ def convert_pair(corrector, directive, enable)
119
+ replacement = directive.comment.text.sub(/\b#{directive.mode}\b/,
120
+ "#{directive.mode}-next")
121
+ corrector.replace(directive.comment, replacement)
122
+ remove_line(corrector, enable.comment)
123
+ end
124
+
125
+ def check_push_pop(directive)
126
+ pop_line = balancing_pop_line(directive)
127
+ return unless pop_line && comment_config.comment_only_line?(pop_line)
128
+ return unless wraps_single_statement?(directive, pop_line)
129
+
130
+ pop_comment = processed_source.comment_at_line(pop_line)
131
+ replacement = push_replacement(directive)
132
+ message = format(MSG_PUSH_POP, replacement: replacement_mode(directive))
133
+ add_offense(directive.comment, message: message) do |corrector|
134
+ corrector.replace(directive.comment, replacement)
135
+ remove_line(corrector, pop_comment)
136
+ end
137
+ end
138
+
139
+ # The line of the `pop` balancing this `push`, taking nesting into
140
+ # account, or `nil` when the push is never popped.
141
+ def balancing_pop_line(push_directive)
142
+ depth = 0
143
+ each_directive_after(push_directive) do |directive|
144
+ if directive.push?
145
+ depth += 1
146
+ elsif directive.pop?
147
+ return directive.line_number if depth.zero?
148
+
149
+ depth -= 1
150
+ end
151
+ end
152
+ nil
153
+ end
154
+
155
+ def each_directive_after(reference)
156
+ processed_source.comments.each do |comment|
157
+ directive = DirectiveComment.new(comment)
158
+ next unless directive.cop_names || directive.push? || directive.pop?
159
+
160
+ yield directive if directive.line_number > reference.line_number
161
+ end
162
+ end
163
+
164
+ def replacement_mode(directive)
165
+ ops = directive.signed_args.keys.sort
166
+ if ops == ['-']
167
+ 'disable-next'
168
+ elsif ops == ['+']
169
+ 'enable-next'
170
+ else
171
+ 'next'
172
+ end
173
+ end
174
+
175
+ def push_replacement(directive)
176
+ text = case replacement_mode(directive)
177
+ when 'disable-next'
178
+ "# rubocop:disable-next #{directive.signed_args['-'].join(', ')}"
179
+ when 'enable-next'
180
+ "# rubocop:enable-next #{directive.signed_args['+'].join(', ')}"
181
+ else
182
+ "# rubocop:next #{directive.cops}"
183
+ end
184
+ reason = directive.reason
185
+ reason ? "#{text} -- #{reason}" : text
186
+ end
187
+
188
+ # An `enable`/`disable` pair around one statement inside a disabled
189
+ # region re-enables the cops for just that statement - `enable-next`
190
+ # says the same without the closing boundary. The pair only counts
191
+ # when the `enable` really closed open disables (otherwise the
192
+ # trailing `disable` opens a new region and the conversion would
193
+ # change what is covered).
194
+ def check_enable_pair(directive)
195
+ closing = enable_pair_closing(directive)
196
+ return unless closing
197
+
198
+ add_offense(directive.comment, message: MSG_ENABLE_PAIR) do |corrector|
199
+ corrector.replace(directive.comment,
200
+ directive.comment.text.sub(/\benable\b/, 'enable-next'))
201
+ remove_line(corrector, closing.comment)
202
+ end
203
+ end
204
+
205
+ def enable_pair_closing(directive)
206
+ scope = comment_config.statement_scope_after(directive.line_number)
207
+ return nil unless scope && scope.begin == directive.line_number + 1
208
+
209
+ closing = re_disable_below(directive, scope.end + 1)
210
+ closing if closing && closed_open_disables?(directive, closing)
211
+ end
212
+
213
+ def re_disable_below(directive, line)
214
+ return nil unless comment_config.comment_only_line?(line)
215
+
216
+ comment = processed_source.comment_at_line(line)
217
+ return nil unless comment
218
+
219
+ closing = DirectiveComment.new(comment)
220
+ return nil unless closing.disabled? && !closing.disable_next?
221
+ return nil unless closing.raw_cop_names.sort == directive.raw_cop_names.sort
222
+
223
+ closing
224
+ end
225
+
226
+ # Every cop of the pair must have a range the `enable` closed and a
227
+ # range the trailing `disable` reopened - otherwise the `enable` was
228
+ # not inside a disabled region and the conversion would change what
229
+ # is covered.
230
+ def closed_open_disables?(directive, closing)
231
+ directive.cop_names.all? do |cop|
232
+ ranges = comment_config.cop_disabled_line_ranges[qualified_name(cop)]
233
+ ranges && closed_at?(ranges, directive.line_number) && reopened_by?(ranges, closing)
234
+ end
235
+ end
236
+
237
+ def closed_at?(ranges, line)
238
+ ranges.any? { |range| range.end == line }
239
+ end
240
+
241
+ def reopened_by?(ranges, closing)
242
+ ranges.any? do |range|
243
+ range.respond_to?(:directive) && range.directive.comment.equal?(closing.comment)
244
+ end
245
+ end
246
+
247
+ def qualified_name(cop_name)
248
+ Registry.qualified_cop_name(cop_name.strip, processed_source.file_path,
249
+ correct_namespace: false)
250
+ end
251
+
252
+ # The directive closing this one's scope, when that scope wraps
253
+ # exactly one statement - `nil` otherwise.
254
+ def single_statement_closing_directive(directive)
255
+ closing_line = single_closing_line(directive)
256
+ return nil unless closing_line
257
+
258
+ closing_comment = processed_source.comment_at_line(closing_line)
259
+ return nil unless closing_comment
260
+ return nil unless wraps_single_statement?(directive, closing_line)
261
+
262
+ DirectiveComment.new(closing_comment)
263
+ end
264
+
265
+ # The single line on which every disabled range opened by this
266
+ # directive ends, or `nil` when the ranges disagree or never close.
267
+ # For a `disable` that is the `enable` line; for a `push` it is the
268
+ # line before the `pop`.
269
+ def single_closing_line(directive)
270
+ ranges = ranges_opened_by(directive)
271
+ return nil if ranges.empty?
272
+
273
+ ends = ranges.map(&:end).uniq
274
+ return nil unless ends.size == 1 && ends.first.to_f.finite?
275
+
276
+ ends.first
277
+ end
278
+
279
+ def ranges_opened_by(directive)
280
+ comment_config.cop_disabled_line_ranges.each_value.flat_map do |ranges|
281
+ ranges.select do |range|
282
+ range.respond_to?(:directive) && range.directive.comment.equal?(directive.comment)
283
+ end
284
+ end
285
+ end
286
+
287
+ # The region wraps a single statement only when the directive sits
288
+ # immediately above it and the closing directive immediately below -
289
+ # any other line inside the region (a comment, a blank line) may
290
+ # carry offenses of the suppressed cops that the tighter scope
291
+ # would no longer cover.
292
+ def wraps_single_statement?(directive, closing_line)
293
+ scope = comment_config.statement_scope_after(directive.line_number)
294
+
295
+ !scope.nil? && scope.begin == directive.line_number + 1 && scope.end + 1 == closing_line
296
+ end
297
+
298
+ def remove_line(corrector, comment)
299
+ corrector.remove(range_by_whole_lines(comment.source_range, include_final_newline: true))
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
@@ -1,17 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Lint/RedundantCopDisableDirective
3
+ # rubocop:disable Lint/RedundantCopDisableDirective -- the examples below read as real directives
4
4
 
5
5
  module RuboCop
6
6
  module Cop
7
7
  module Style
8
8
  # Detects comments to enable/disable RuboCop.
9
- # This is useful if want to make sure that every RuboCop error gets fixed
9
+ # This is useful if you want to make sure that every RuboCop error gets fixed
10
10
  # and not quickly disabled with a comment.
11
11
  #
12
12
  # Specific cops can be allowed with the `AllowedCops` configuration. Note that
13
13
  # if this configuration is set, `rubocop:disable all` is still disallowed.
14
14
  #
15
+ # `AllowedCops` and `DisallowedCops` accept cop names and department names
16
+ # alike. Listing a cop does not cover its whole department: a directive
17
+ # disabling `Metrics` is broader than one disabling `Metrics/AbcSize`.
18
+ #
19
+ # Alternatively, specific cops can be disallowed with the `DisallowedCops`
20
+ # configuration. When `DisallowedCops` is set, only directives for the listed
21
+ # cops (and `all`) will be flagged. This is useful when you want
22
+ # to protect a small set of critical cops from being disabled rather than
23
+ # allowlisting all other cops. `AllowedCops` and `DisallowedCops` should not
24
+ # both be set at the same time; if `DisallowedCops` is set, it takes precedence.
25
+ #
26
+ # `AllowedDirectives` names directive forms - `disable`, `todo`,
27
+ # `disable-next`, `todo-next`, `push`, `next` - and exempts them from the
28
+ # cop entirely. `rubocop:todo` is the usual candidate, since
29
+ # `--disable-uncorrectable` generates those and they record debt rather
30
+ # than a decision someone should be asked to justify.
31
+ #
32
+ # With `AllowWithReason` set to `true`, a disable directive carrying
33
+ # a `--` trailing justification comment is allowed, so a team can require
34
+ # every disable to be documented instead of banning them outright. Enable
35
+ # directives are not checked in this mode, since they end a suppression
36
+ # rather than start one. Offenses in this mode are not autocorrected,
37
+ # since only a human can supply the missing justification.
38
+ #
39
+ # This cop cannot be disabled via directive comments when it is explicitly
40
+ # enabled with `Enabled: true`. This prevents users from bypassing the cop
41
+ # with `# rubocop:disable Style/DisableCopsWithinSourceCodeDirective`.
42
+ #
15
43
  # @example
16
44
  # # bad
17
45
  # # rubocop:disable Metrics/AbcSize
@@ -30,57 +58,193 @@ module RuboCop
30
58
  # end
31
59
  # # rubocop:enable Metrics/AbcSize
32
60
  #
61
+ # @example DisallowedCops: [Lint/Void]
62
+ # # bad
63
+ # # rubocop:disable Lint/Void
64
+ # foo
65
+ # # rubocop:enable Lint/Void
66
+ #
67
+ # # good
68
+ # # rubocop:disable Metrics/AbcSize
69
+ # foo
70
+ # # rubocop:enable Metrics/AbcSize
71
+ #
72
+ # @example AllowedDirectives: [todo]
73
+ # # good - the cop does not look at `todo` directives at all
74
+ # x = 0 # rubocop:todo Layout/SpaceAroundOperators
75
+ #
76
+ # # bad
77
+ # x = 0 # rubocop:disable Layout/SpaceAroundOperators
78
+ #
79
+ # @example AllowedCops: [Metrics]
80
+ # # good - every cop the directive disables is in an exempt department
81
+ # # rubocop:disable Metrics/AbcSize
82
+ # def foo
83
+ # end
84
+ # # rubocop:enable Metrics/AbcSize
85
+ #
86
+ # @example AllowWithReason: true
87
+ # # bad
88
+ # x = 0 # rubocop:disable Layout/SpaceAroundOperators
89
+ #
90
+ # # good
91
+ # x = 0 # rubocop:disable Layout/SpaceAroundOperators -- would misalign the table
92
+ #
33
93
  class DisableCopsWithinSourceCodeDirective < Base
34
94
  extend AutoCorrector
35
95
 
36
96
  # rubocop:enable Lint/RedundantCopDisableDirective
37
97
  MSG = 'RuboCop disable/enable directives are not permitted.'
38
98
  MSG_FOR_COPS = 'RuboCop disable/enable directives for %<cops>s are not permitted.'
99
+ MSG_MISSING_REASON = 'RuboCop disable directives without a `--` justification ' \
100
+ 'comment are not permitted.'
39
101
 
40
102
  def on_new_investigation
103
+ @matching_pops = nil
104
+
41
105
  processed_source.comments.each do |comment|
42
- directive_cops = directive_cops(comment)
43
- disallowed_cops = directive_cops - allowed_cops
106
+ directive = DirectiveComment.new(comment)
107
+ next if ignored?(directive)
108
+
109
+ directive_cops = directive_cops(directive)
110
+ disallowed_cops = compute_disallowed_cops(directive_cops)
44
111
 
45
112
  next unless disallowed_cops.any?
46
113
 
47
- register_offense(comment, directive_cops, disallowed_cops)
114
+ register_offense(directive, directive_cops, disallowed_cops)
48
115
  end
49
116
  end
50
117
 
51
118
  private
52
119
 
53
- def register_offense(comment, directive_cops, disallowed_cops)
54
- message = if any_cops_allowed?
55
- format(MSG_FOR_COPS, cops: "`#{disallowed_cops.join('`, `')}`")
56
- else
57
- MSG
58
- end
120
+ def compute_disallowed_cops(directive_cops)
121
+ if disallowed_cops_config.any?
122
+ if directive_cops.include?('all')
123
+ directive_cops
124
+ else
125
+ directive_cops.uniq.select { |cop| listed?(disallowed_cops_config, cop) }
126
+ end
127
+ else
128
+ directive_cops.reject { |cop| cop != 'all' && listed?(allowed_cops, cop) }
129
+ end
130
+ end
59
131
 
60
- add_offense(comment, message: message) do |corrector|
61
- replacement = ''
132
+ def register_offense(directive, directive_cops, disallowed_cops)
133
+ comment = directive.comment
62
134
 
63
- if directive_cops.length != disallowed_cops.length
64
- replacement = comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
65
- .sub(/,\s*$/, '')
135
+ add_offense(comment, message: offense_message(disallowed_cops)) do |corrector|
136
+ # The remedy in `AllowWithReason` mode is to write the missing `--` justification,
137
+ # which cannot be autocorrected. Removing the directive would also unsuppress
138
+ # the disabled cops and let their autocorrections rewrite the annotated code.
139
+ next if allow_with_reason?
140
+
141
+ if directive_cops.length == disallowed_cops.length
142
+ remove_directive(corrector, directive)
143
+ elsif signed_args?(directive)
144
+ remove_signed_args(corrector, directive, disallowed_cops)
145
+ else
146
+ remove_cops(corrector, comment, disallowed_cops)
66
147
  end
148
+ end
149
+ end
67
150
 
68
- corrector.replace(comment, replacement)
151
+ # A `push` without its `pop` leaves an orphan `pop` behind, so the pair goes together.
152
+ def remove_directive(corrector, directive)
153
+ corrector.replace(directive.comment, '')
154
+ return unless directive.push? && (pop = matching_pop(directive.comment))
155
+
156
+ corrector.replace(pop, '')
157
+ end
158
+
159
+ def matching_pop(push_comment)
160
+ @matching_pops ||= pair_pushes_with_pops
161
+ @matching_pops[push_comment]
162
+ end
163
+
164
+ def pair_pushes_with_pops
165
+ pushes = []
166
+ processed_source.comments.each_with_object({}) do |comment, pairs|
167
+ directive = DirectiveComment.new(comment)
168
+ if directive.push?
169
+ pushes.push(comment)
170
+ elsif directive.pop? && (push = pushes.pop)
171
+ pairs[push] = comment
172
+ end
69
173
  end
70
174
  end
71
175
 
72
- def directive_cops(comment)
73
- match_captures = DirectiveComment.new(comment).match_captures
176
+ def remove_signed_args(corrector, directive, disallowed_cops)
177
+ range = directive.range
178
+ names = Regexp.union(disallowed_cops)
179
+ corrector.replace(range, range.source.gsub(/\s+[+-]#{names}(?!\S)/, ''))
180
+ end
181
+
182
+ def remove_cops(corrector, comment, disallowed_cops)
183
+ corrector.replace(comment, comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
184
+ .sub(/,\s*$/, ''))
185
+ end
186
+
187
+ def offense_message(disallowed_cops)
188
+ if allow_with_reason?
189
+ MSG_MISSING_REASON
190
+ elsif any_cops_allowed? || disallowed_cops_config.any?
191
+ format(MSG_FOR_COPS, cops: "`#{disallowed_cops.join('`, `')}`")
192
+ else
193
+ MSG
194
+ end
195
+ end
196
+
197
+ def directive_cops(directive)
198
+ return directive.signed_args.values.flatten if signed_args?(directive)
199
+
200
+ match_captures = directive.match_captures
74
201
  match_captures && match_captures[1] ? match_captures[1].split(',').map(&:strip) : []
75
202
  end
76
203
 
204
+ def signed_args?(directive)
205
+ directive.push? || directive.next?
206
+ end
207
+
208
+ def ignored?(directive)
209
+ return true if exempt_mode?(directive)
210
+
211
+ allow_with_reason? && (directive.reason || directive.enabled?)
212
+ end
213
+
214
+ def exempt_mode?(directive)
215
+ allowed_directives.include?(directive.mode)
216
+ end
217
+
218
+ def allowed_directives
219
+ @allowed_directives ||= Array(cop_config['AllowedDirectives'])
220
+ end
221
+
222
+ def allow_with_reason?
223
+ # TODO: The obsolete `AllowTrailingComment` is honored for backward compatibility
224
+ # and will be removed in RuboCop 2.0.
225
+ allow_trailing_comment = cop_config['AllowTrailingComment'] # rubocop:disable InternalAffairs/UndefinedConfig -- obsolete key, gone from default.yml on purpose
226
+ return allow_trailing_comment unless allow_trailing_comment.nil?
227
+
228
+ cop_config['AllowWithReason']
229
+ end
230
+
77
231
  def allowed_cops
78
- Array(cop_config['AllowedCops'])
232
+ @allowed_cops ||= Array(cop_config['AllowedCops']).to_set
233
+ end
234
+
235
+ # A name matches either outright or through its department, so
236
+ # `Metrics` covers `Metrics/AbcSize` but not the other way round.
237
+ def listed?(names, cop)
238
+ names.include?(cop) || names.include?(cop.split('/').first)
79
239
  end
80
240
 
81
241
  def any_cops_allowed?
82
242
  allowed_cops.any?
83
243
  end
244
+
245
+ def disallowed_cops_config
246
+ @disallowed_cops_config ||= Array(cop_config['DisallowedCops']).to_set
247
+ end
84
248
  end
85
249
  end
86
250
  end
@@ -161,7 +161,12 @@ module RuboCop
161
161
  source = source.gsub(COMMENT_REGEXP, '')
162
162
  return if source.blank?
163
163
 
164
- /\s*#{Regexp.escape(source.strip)}/
164
+ # Treat `\#` (an escaped interpolation marker in the heredoc) as matching
165
+ # either `\#` or `#` in the comment, since the comment may show either
166
+ # the literal source form or the runtime appearance.
167
+ segments = source.strip.split('\\#', -1).map { |segment| Regexp.escape(segment) }
168
+
169
+ /\s*#{segments.join('\\\\?#')}/
165
170
  end
166
171
  end
167
172
  end
@@ -13,6 +13,11 @@ module RuboCop
13
13
  # a `#:nodoc:` comment next to it. Likewise, `#:nodoc: all` does the
14
14
  # same for all its children.
15
15
  #
16
+ # When `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is
17
+ # installed, a reopened class or module is not reported when any of its
18
+ # other definition sites (in the same or another file) carries a
19
+ # documentation comment.
20
+ #
16
21
  # @example
17
22
  # # bad
18
23
  # class Person
@@ -62,19 +67,24 @@ module RuboCop
62
67
  #
63
68
  # @example AllowedConstants: ['ClassMethods']
64
69
  #
65
- # # good
66
- # module A
67
- # module ClassMethods
68
- # # ...
69
- # end
70
- # end
70
+ # # good
71
+ # module A
72
+ # module ClassMethods
73
+ # # ...
74
+ # end
75
+ # end
71
76
  #
72
77
  class Documentation < Base
73
78
  include DocumentationComment
79
+ include ProjectIndexHelp
74
80
  include RangeHelp
75
81
 
76
82
  MSG = 'Missing top-level documentation comment for `%<type>s %<identifier>s`.'
77
83
 
84
+ # Comments that configure tooling rather than document the code.
85
+ DIRECTIVE_COMMENT_REGEXP = /\A\#\s*(rubocop:|frozen_string_literal:|encoding:|
86
+ shareable_constant_value:|typed:|-\*-)/x.freeze
87
+
78
88
  # @!method constant_definition?(node)
79
89
  def_node_matcher :constant_definition?, '{class module casgn}'
80
90
 
@@ -109,12 +119,49 @@ module RuboCop
109
119
  return if constant_allowed?(node)
110
120
  return if nodoc_self_or_outer_module?(node)
111
121
  return if include_statement_only?(body)
122
+ return if documented_elsewhere?(node)
123
+
124
+ add_documentation_offense(node)
125
+ end
112
126
 
127
+ def add_documentation_offense(node)
113
128
  range = range_between(node.source_range.begin_pos, node.loc.name.end_pos)
114
129
  message = format(MSG, type: node.type, identifier: identifier(node))
115
130
  add_offense(range, message: message)
116
131
  end
117
132
 
133
+ # A reopened class or module is typically documented at a single
134
+ # definition site. When `AllCops/UseProjectIndex` is enabled, the
135
+ # documentation requirement is satisfied by a comment on any other
136
+ # definition of the same class or module.
137
+ def documented_elsewhere?(node)
138
+ return false unless project_index
139
+
140
+ declaration = resolve_constant_in_index(node.identifier)
141
+ return false unless declaration.is_a?(Rubydex::Namespace)
142
+
143
+ declaration.definitions.any? do |definition|
144
+ other_definition?(definition, node) && documenting_comments?(definition)
145
+ end
146
+ rescue StandardError
147
+ false
148
+ end
149
+
150
+ def other_definition?(definition, node)
151
+ location = definition.location
152
+ return false unless location.uri.start_with?(FILE_URI_PREFIX)
153
+
154
+ !same_file?(location.to_file_path, processed_source.file_path) ||
155
+ location.to_display.start_line != node.first_line
156
+ end
157
+
158
+ def documenting_comments?(definition)
159
+ definition.comments.to_a.any? do |comment|
160
+ text = comment.string.strip
161
+ !text.empty? && !DIRECTIVE_COMMENT_REGEXP.match?(text)
162
+ end
163
+ end
164
+
118
165
  def nodoc_self_or_outer_module?(node)
119
166
  nodoc_comment?(node) ||
120
167
  (compact_namespace?(node) && nodoc_comment?(outer_module(node).first))