rubocop 1.90.0 → 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +241 -11
  4. data/config/obsoletion.yml +9 -0
  5. data/lib/rubocop/cached_data.rb +47 -7
  6. data/lib/rubocop/changed_files.rb +134 -0
  7. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  8. data/lib/rubocop/cli/command/execute_runner.rb +23 -3
  9. data/lib/rubocop/cli/command/explain.rb +34 -0
  10. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  11. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  12. data/lib/rubocop/cli.rb +11 -4
  13. data/lib/rubocop/comment_config/directive_range.rb +3 -1
  14. data/lib/rubocop/comment_config/disable_next.rb +49 -3
  15. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  16. data/lib/rubocop/comment_config.rb +32 -53
  17. data/lib/rubocop/config.rb +10 -0
  18. data/lib/rubocop/config_loader.rb +18 -7
  19. data/lib/rubocop/config_loader_resolver.rb +79 -12
  20. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  21. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  22. data/lib/rubocop/config_obsoletion.rb +1 -1
  23. data/lib/rubocop/config_validator.rb +29 -3
  24. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  25. data/lib/rubocop/cop/badge.rb +1 -1
  26. data/lib/rubocop/cop/base.rb +57 -24
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  28. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  29. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  30. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  32. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
  33. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
  35. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  36. data/lib/rubocop/cop/correctors.rb +2 -2
  37. data/lib/rubocop/cop/documentation.rb +1 -1
  38. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  39. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  40. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  41. data/lib/rubocop/cop/generator.rb +1 -1
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  43. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  44. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  45. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  46. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
  48. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  49. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  50. data/lib/rubocop/cop/layout/class_structure.rb +9 -1
  51. data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
  52. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  53. data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
  54. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
  55. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  56. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  57. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  58. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
  59. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  60. data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
  61. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
  62. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  63. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
  64. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
  65. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  66. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  67. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  68. data/lib/rubocop/cop/layout/hash_alignment.rb +15 -10
  69. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
  70. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  71. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  72. data/lib/rubocop/cop/layout/indentation_width.rb +4 -4
  73. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  74. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  75. data/lib/rubocop/cop/layout/line_length.rb +71 -19
  76. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  77. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  78. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
  79. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  80. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
  81. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  82. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  83. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
  84. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  85. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  86. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  87. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  88. data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
  89. data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
  90. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  91. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
  92. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  93. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  94. data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
  95. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
  96. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
  97. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  98. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  99. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  100. data/lib/rubocop/cop/lint/literal_as_condition.rb +23 -2
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  102. data/lib/rubocop/cop/lint/loop.rb +24 -2
  103. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  104. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -4
  105. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  107. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  108. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
  109. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +42 -17
  110. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  111. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  112. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  113. data/lib/rubocop/cop/lint/void.rb +8 -1
  114. data/lib/rubocop/cop/lint.rb +1 -0
  115. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  116. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  117. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  118. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  119. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  120. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  121. data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
  122. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
  123. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  124. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  125. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
  126. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  127. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -2
  128. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +31 -3
  129. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  130. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  131. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  132. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  133. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  134. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  135. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +29 -3
  136. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  137. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  138. data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
  139. data/lib/rubocop/cop/mixin.rb +4 -2
  140. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  141. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  142. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  143. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  144. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  145. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  146. data/lib/rubocop/cop/offense.rb +59 -3
  147. data/lib/rubocop/cop/registry.rb +10 -2
  148. data/lib/rubocop/cop/security/json_load.rb +16 -4
  149. data/lib/rubocop/cop/severity.rb +12 -0
  150. data/lib/rubocop/cop/style/access_modifier_declarations.rb +10 -2
  151. data/lib/rubocop/cop/style/alias.rb +18 -5
  152. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  153. data/lib/rubocop/cop/style/and_or.rb +4 -0
  154. data/lib/rubocop/cop/style/arguments_forwarding.rb +6 -3
  155. data/lib/rubocop/cop/style/attr.rb +3 -4
  156. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  157. data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
  158. data/lib/rubocop/cop/style/case_like_if.rb +9 -6
  159. data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
  160. data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
  161. data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
  162. data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
  163. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  164. data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
  165. data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
  166. data/lib/rubocop/cop/style/directive_scope.rb +154 -21
  167. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +118 -18
  168. data/lib/rubocop/cop/style/documentation_method.rb +1 -9
  169. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  170. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  171. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  172. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  173. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  174. data/lib/rubocop/cop/style/empty_method.rb +15 -3
  175. data/lib/rubocop/cop/style/endless_method.rb +91 -11
  176. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  177. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  178. data/lib/rubocop/cop/style/file_null.rb +2 -2
  179. data/lib/rubocop/cop/style/float_division.rb +28 -14
  180. data/lib/rubocop/cop/style/for.rb +44 -1
  181. data/lib/rubocop/cop/style/format_string.rb +28 -6
  182. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  183. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  184. data/lib/rubocop/cop/style/guard_clause.rb +13 -1
  185. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  186. data/lib/rubocop/cop/style/hash_lookup_method.rb +35 -9
  187. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  188. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  189. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  190. data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
  191. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  192. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  193. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  194. data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
  195. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  196. data/lib/rubocop/cop/style/lambda.rb +18 -0
  197. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  198. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  199. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  200. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
  201. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
  202. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  203. data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
  204. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  205. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  206. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  207. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  208. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  209. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  210. data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
  211. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  212. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  213. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  214. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  215. data/lib/rubocop/cop/style/next.rb +24 -10
  216. data/lib/rubocop/cop/style/nil_comparison.rb +48 -8
  217. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  218. data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
  219. data/lib/rubocop/cop/style/not.rb +10 -3
  220. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  221. data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
  222. data/lib/rubocop/cop/style/one_line_conditional.rb +14 -3
  223. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  224. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  225. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  226. data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
  227. data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
  228. data/lib/rubocop/cop/style/redundant_condition.rb +34 -17
  229. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -1
  230. data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
  231. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
  232. data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
  233. data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -2
  234. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  235. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  236. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +25 -5
  237. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  238. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  239. data/lib/rubocop/cop/style/require_order.rb +9 -0
  240. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
  241. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  242. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  243. data/lib/rubocop/cop/style/sample.rb +9 -8
  244. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  245. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  246. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  247. data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
  248. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  249. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  250. data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
  251. data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
  252. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  253. data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
  254. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  255. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  256. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  257. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  258. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  259. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  260. data/lib/rubocop/cop/style.rb +0 -1
  261. data/lib/rubocop/cop/team.rb +10 -5
  262. data/lib/rubocop/cop/util.rb +1 -1
  263. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  264. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  265. data/lib/rubocop/cops_documentation_generator.rb +23 -2
  266. data/lib/rubocop/directive_comment.rb +37 -8
  267. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  268. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
  269. data/lib/rubocop/formatter/formatter_set.rb +6 -1
  270. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  271. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  272. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  273. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  274. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  275. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  276. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  277. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  278. data/lib/rubocop/formatter.rb +1 -0
  279. data/lib/rubocop/lsp/runtime.rb +47 -11
  280. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  281. data/lib/rubocop/lsp.rb +5 -2
  282. data/lib/rubocop/magic_comment.rb +27 -0
  283. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  284. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  285. data/lib/rubocop/mcp/scope.rb +65 -0
  286. data/lib/rubocop/mcp/server.rb +184 -76
  287. data/lib/rubocop/mcp/source_files.rb +35 -0
  288. data/lib/rubocop/offense_limit.rb +30 -0
  289. data/lib/rubocop/options.rb +97 -4
  290. data/lib/rubocop/path_util.rb +1 -1
  291. data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
  292. data/lib/rubocop/plugin/loader.rb +1 -1
  293. data/lib/rubocop/rake_task.rb +1 -1
  294. data/lib/rubocop/remote_config.rb +8 -5
  295. data/lib/rubocop/result_cache.rb +36 -18
  296. data/lib/rubocop/runner.rb +160 -49
  297. data/lib/rubocop/server/cache.rb +2 -2
  298. data/lib/rubocop/unified_diff.rb +257 -0
  299. data/lib/rubocop/util.rb +69 -0
  300. data/lib/rubocop/version.rb +1 -1
  301. data/lib/rubocop.rb +9 -1
  302. metadata +21 -6
  303. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -6,6 +6,7 @@ module RuboCop
6
6
  class CommentConfig
7
7
  extend SimpleForwardable
8
8
  include DisableNext
9
+ include PushPop
9
10
 
10
11
  CONFIG_DISABLED_LINE_RANGE_MIN = -Float::INFINITY
11
12
 
@@ -75,20 +76,19 @@ module RuboCop
75
76
  non_comment_token_line_numbers.none?(line_number)
76
77
  end
77
78
 
78
- # The names of the cops that are opted in by an `enable` comment directive,
79
- # used to mobilize cops disabled in the config on demand.
79
+ # The names of the cops that are opted in by an `enable` comment directive
80
+ # or a `+` argument of a `push`/`next` directive, used to mobilize cops
81
+ # disabled in the config on demand. Departments are expanded for the
82
+ # opt-in forms only: a plain `enable` naming a department usually just
83
+ # closes a `disable` of it, and expanding it would switch on every
84
+ # config-disabled cop of the department for the rest of the file.
80
85
  #
81
86
  # @api private
82
87
  # @return [Set<String>]
83
88
  def opt_in_cops
84
89
  @opt_in_cops ||= begin
85
90
  cops = Set.new
86
- each_directive do |directive|
87
- next unless directive.enabled?
88
- next if directive.all_cops?
89
-
90
- cops.merge(directive.raw_cop_names)
91
- end
91
+ each_directive { |directive| cops.merge(opted_in_by(directive)) }
92
92
  cops
93
93
  end
94
94
  end
@@ -98,9 +98,7 @@ module RuboCop
98
98
  def extra_enabled_comments_with_names(extras:, names:)
99
99
  each_directive do |directive|
100
100
  next unless comment_only_line?(directive.line_number)
101
- # Push/pop and next-statement directives close themselves, so they
102
- # play no part in the disable/enable pairing.
103
- next if directive.push? || directive.pop? || directive.disable_next?
101
+ next if self_closing_directive?(directive)
104
102
 
105
103
  if directive.enabled_all?
106
104
  handle_enable_all(directive, names, extras)
@@ -112,6 +110,18 @@ module RuboCop
112
110
  extras
113
111
  end
114
112
 
113
+ def opted_in_by(directive)
114
+ if directive.push? || directive.next?
115
+ directive.signed_args.fetch('+', []).flat_map { |name| expand_cop_name(name) }
116
+ elsif !directive.enabled? || directive.all_cops?
117
+ []
118
+ elsif directive.enable_next?
119
+ directive.cop_names
120
+ else
121
+ directive.raw_cop_names
122
+ end
123
+ end
124
+
115
125
  # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
116
126
  def analyze
117
127
  return {} if @no_directives
@@ -128,6 +138,10 @@ module RuboCop
128
138
  pop_state(analyses, directive.line_number) if @stack.any?
129
139
  elsif directive.disable_next?
130
140
  apply_disable_next(analyses, directive)
141
+ elsif directive.next?
142
+ apply_next_directive(analyses, resolve_push_cops(directive), directive)
143
+ elsif directive.enable_next?
144
+ apply_enable_next(analyses, directive)
131
145
  else
132
146
  directive.cop_names.each do |cop_name|
133
147
  cop_name = qualified_cop_name(cop_name)
@@ -144,48 +158,6 @@ module RuboCop
144
158
  end
145
159
  end
146
160
 
147
- def resolve_push_cops(directive)
148
- directive.push_args.transform_values do |names|
149
- names.flat_map { |name| expand_cop_name(name) }
150
- end
151
- end
152
-
153
- def expand_cop_name(name)
154
- registry = Cop::Registry.global
155
- cops = registry.department?(name) ? registry.names_for_department(name) : [name]
156
- cops.map { |c| qualified_cop_name(c) }
157
- end
158
-
159
- def apply_push(analyses, resolved_cops, directive)
160
- resolved_cops.each do |op, cops|
161
- cops.each { |cop| apply_cop_op(analyses, op, cop, directive) }
162
- end
163
- end
164
-
165
- def apply_cop_op(analyses, operation, cop, directive)
166
- analysis = analyses[cop]
167
- line = directive.line_number
168
- if operation == '-' && !analysis.start_line_number
169
- analyses[cop] = CopAnalysis.new(analysis.line_ranges, line, directive)
170
- elsif operation == '+' && analysis.start_line_number
171
- analyses[cop] = CopAnalysis.new(analysis.close(line), nil)
172
- end
173
- end
174
-
175
- def pop_state(analyses, line)
176
- restore_point = @stack.pop
177
- (restore_point.keys | analyses.keys).each do |cop|
178
- analyses[cop] = popped_analysis(analyses[cop], restore_point[cop], line)
179
- end
180
- end
181
-
182
- def popped_analysis(current, restored, line)
183
- ranges = current.close(line - 1)
184
- return CopAnalysis.new(ranges, nil) unless restored&.start_line_number
185
-
186
- CopAnalysis.new(ranges, line, restored.start_directive)
187
- end
188
-
189
161
  def inject_disabled_cops_directives(analyses)
190
162
  registry.disabled_names(config).each do |cop_name|
191
163
  analyses[cop_name] = analyze_cop(
@@ -236,6 +208,13 @@ module RuboCop
236
208
  end
237
209
  end
238
210
 
211
+ # Push/pop and next-statement directives close themselves, so they
212
+ # play no part in the disable/enable pairing.
213
+ def self_closing_directive?(directive)
214
+ directive.push? || directive.pop? || directive.disable_next? ||
215
+ directive.next? || directive.enable_next?
216
+ end
217
+
239
218
  def qualified_cop_name(cop_name)
240
219
  # A directive naming a cop under the wrong department is not honored -
241
220
  # the mistake is surfaced by `Lint/RedundantCopDisableDirective` (with a
@@ -226,6 +226,16 @@ module RuboCop
226
226
  end
227
227
  end
228
228
 
229
+ # Whether preview behavior is on, for cops that gate an unstable change
230
+ # behind it and for cops that are themselves `Enabled: preview`.
231
+ # `--preview` / `--no-preview` win over `AllCops: Preview`.
232
+ def preview?(options = {})
233
+ preview = options[:preview]
234
+ return preview unless preview.nil?
235
+
236
+ for_all_cops['Preview'] == true
237
+ end
238
+
229
239
  def active_support_extensions_enabled?
230
240
  for_all_cops['ActiveSupportExtensionsEnabled']
231
241
  end
@@ -24,7 +24,8 @@ module RuboCop
24
24
  include FileFinder
25
25
 
26
26
  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
27
- :enabled_by_default, :disabled_by_default, :ignore_unrecognized_cops
27
+ :enabled_by_default, :disabled_by_default, :ignore_unrecognized_cops,
28
+ :preview
28
29
  attr_writer :default_configuration, :cache_root
29
30
  attr_reader :loaded_plugins, :loaded_features
30
31
 
@@ -41,6 +42,7 @@ module RuboCop
41
42
  @loaded_features = Set.new
42
43
  @disable_pending_cops = nil
43
44
  @enable_pending_cops = nil
45
+ @preview = nil
44
46
  @enabled_by_default = nil
45
47
  @disabled_by_default = nil
46
48
  @ignore_parent_exclusion = nil
@@ -171,7 +173,8 @@ module RuboCop
171
173
  hash = ConfigLoader.load_yaml_configuration(path)
172
174
  config = Config.new(hash, path).tap(&:make_excludes_absolute)
173
175
 
174
- @default_configuration = ConfigLoader.merge_with_default(config, path)
176
+ @default_configuration =
177
+ ConfigLoader.merge_with_default(config, path, resolve_preview: false)
175
178
  end
176
179
 
177
180
  # Returns the path RuboCop inferred as the root of the project. No file
@@ -187,20 +190,28 @@ module RuboCop
187
190
  end
188
191
 
189
192
  # Merges the given configuration with the default one.
190
- def merge_with_default(config, config_file, unset_nil: true)
191
- resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
193
+ def merge_with_default(config, config_file, unset_nil: true, resolve_preview: true)
194
+ resolver.merge_with_default(
195
+ config, config_file, unset_nil: unset_nil, resolve_preview: resolve_preview
196
+ )
192
197
  end
193
198
 
194
199
  # Applies CLI overrides for `AllCops/EnabledByDefault` and
195
200
  # `AllCops/DisabledByDefault` to the given configuration. Used when the
196
201
  # configuration would otherwise be returned without going through
197
202
  # `merge_with_default` (e.g. there is no user-supplied `.rubocop.yml`).
203
+ # Used when there is no configuration file, so the defaults are the whole
204
+ # configuration and still need the same treatment `merge_with_default`
205
+ # would have given them.
198
206
  def apply_default_overrides(config)
199
- return config if @enabled_by_default.nil? && @disabled_by_default.nil?
207
+ hash = resolver.apply_preview_defaults(config, preview == true)
200
208
 
201
- hash = config.transform_values do |params|
202
- params.is_a?(Hash) ? params.merge('Enabled' => !@disabled_by_default) : params
209
+ unless @enabled_by_default.nil? && @disabled_by_default.nil?
210
+ hash = hash.transform_values do |params|
211
+ params.is_a?(Hash) ? params.merge('Enabled' => !@disabled_by_default) : params
212
+ end
203
213
  end
214
+
204
215
  Config.new(hash, config.loaded_path)
205
216
  end
206
217
 
@@ -37,8 +37,9 @@ module RuboCop
37
37
 
38
38
  def resolve_inheritance(path, hash, file, debug) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
39
39
  inherited_files = Array(hash['inherit_from'])
40
- base_configs(path, inherited_files, file)
41
- .each_with_index.reverse_each do |base_config, index|
40
+ base_configs = base_configs(path, inherited_files, file)
41
+ preview = inherited_preview?(hash, base_configs)
42
+ base_configs.each_with_index.reverse_each do |base_config, index|
42
43
  override_department_setting_for_cops(base_config, hash)
43
44
  override_enabled_for_disabled_departments(base_config, hash)
44
45
 
@@ -50,7 +51,7 @@ module RuboCop
50
51
  v = merge(v, hash[k],
51
52
  cop_name: k, file: file, debug: debug,
52
53
  inherited_file: inherited_files[index],
53
- inherit_mode: determine_inherit_mode(hash, k))
54
+ inherit_mode: determine_inherit_mode(hash, k, preview))
54
55
  end
55
56
  hash[k] = v
56
57
  fix_include_paths(base_config.loaded_path, hash, path, k, v) if only_base_has_include
@@ -94,20 +95,28 @@ module RuboCop
94
95
  # only cops explicitly disabled in user configuration are disabled.
95
96
  # When the `--disable-all-cops` or `--enable-all-cops` CLI option is given,
96
97
  # it takes precedence over the configuration values.
97
- def merge_with_default(config, config_file, unset_nil:)
98
- default_configuration = ConfigLoader.default_configuration
98
+ #
99
+ # With `resolve_preview: false` the `Preview` sections of the default
100
+ # configuration are left in place and preview is treated as off. That is
101
+ # what extending the default configuration itself needs: preview gets
102
+ # applied later, when a project configuration is resolved against it.
103
+ def merge_with_default(config, config_file, unset_nil:, resolve_preview: true)
104
+ base_defaults, preview = defaults_with_preview(config, resolve_preview)
105
+ default_configuration = base_defaults
99
106
  disabled_by_default, enabled_by_default = resolve_default_overrides(config)
100
107
 
101
108
  if disabled_by_default || enabled_by_default
102
- default_configuration = transform(default_configuration) do |params|
109
+ default_configuration = transform(base_defaults) do |params|
103
110
  params.merge('Enabled' => !disabled_by_default)
104
111
  end
105
112
  end
106
113
 
107
- config = handle_disabled_by_default(config, default_configuration) if disabled_by_default
114
+ if disabled_by_default
115
+ config = handle_disabled_by_default(config, default_configuration, base_defaults)
116
+ end
108
117
  override_enabled_for_disabled_departments(default_configuration, config)
109
118
 
110
- opts = { inherit_mode: config['inherit_mode'] || {}, unset_nil: unset_nil }
119
+ opts = { inherit_mode: inherit_mode_for_default(config, preview), unset_nil: unset_nil }
111
120
  Config.new(merge(default_configuration, config, **opts), config_file)
112
121
  end
113
122
 
@@ -166,8 +175,55 @@ module RuboCop
166
175
  end
167
176
  end
168
177
 
178
+ # A cop's entry in the default configuration may carry a `Preview` section
179
+ # with the defaults it is expected to adopt in the next major release. Under
180
+ # `Preview` those replace the current defaults. The section is dropped either
181
+ # way, so the resolved configuration only ever shows what is in effect.
182
+ def apply_preview_defaults(default_configuration, preview)
183
+ transform(default_configuration) do |params|
184
+ next params unless params['Preview'].is_a?(Hash)
185
+
186
+ params = params.dup
187
+ preview_params = params.delete('Preview')
188
+ preview ? params.merge(preview_params) : params
189
+ end
190
+ end
191
+
169
192
  private
170
193
 
194
+ def defaults_with_preview(config, resolve_preview)
195
+ defaults = ConfigLoader.default_configuration
196
+ return [defaults, false] unless resolve_preview
197
+
198
+ preview = preview?(config)
199
+ [apply_preview_defaults(defaults, preview), preview]
200
+ end
201
+
202
+ def inherit_mode_for_default(config, preview)
203
+ with_preview_exclude_merge(config['inherit_mode'] || {}, preview)
204
+ end
205
+
206
+ # Under `Preview`, `Exclude` is merged rather than replaced, so that excluding
207
+ # one directory does not silently drop the excludes it would have inherited -
208
+ # from the default configuration or from a file named in `inherit_from`. An
209
+ # explicit `inherit_mode` still wins, in either direction.
210
+ def with_preview_exclude_merge(mode, preview)
211
+ return mode unless preview
212
+ return mode if Array(mode['override']).include?('Exclude')
213
+ return mode if Array(mode['merge']).include?('Exclude')
214
+
215
+ mode.merge('merge' => Array(mode['merge']) + ['Exclude'])
216
+ end
217
+
218
+ # `config` has already been through `handle_disabled_by_default` by this
219
+ # point, which returns a plain hash, so read `AllCops` directly rather than
220
+ # going through `Config#for_all_cops`.
221
+ def preview?(config)
222
+ return ConfigLoader.preview unless ConfigLoader.preview.nil?
223
+
224
+ (config['AllCops'] || {})['Preview'] == true
225
+ end
226
+
171
227
  def resolve_default_overrides(config)
172
228
  if ConfigLoader.disabled_by_default || ConfigLoader.enabled_by_default
173
229
  [ConfigLoader.disabled_by_default, ConfigLoader.enabled_by_default]
@@ -207,10 +263,21 @@ module RuboCop
207
263
  "the same parameter in #{opts[:inherited_file]}"
208
264
  end
209
265
 
210
- def determine_inherit_mode(hash, key)
266
+ # The `AllCops: Preview` in effect once inheritance is resolved: the file
267
+ # itself wins, then the files it inherits from, last one first. It has to be
268
+ # known before merging, since the keys are merged in whatever order they
269
+ # appear and `AllCops` may well come after the cops whose `Exclude` it affects.
270
+ def inherited_preview?(hash, base_configs)
271
+ all_cops = [hash, *base_configs.reverse].map { |config| config['AllCops'] }.find do |params|
272
+ params.is_a?(Hash) && params.key?('Preview')
273
+ end
274
+ preview?('AllCops' => all_cops)
275
+ end
276
+
277
+ def determine_inherit_mode(hash, key, preview)
211
278
  cop_cfg = hash[key]
212
279
  local_inherit = cop_cfg['inherit_mode'] if cop_cfg.is_a?(Hash)
213
- local_inherit || hash['inherit_mode'] || {}
280
+ with_preview_exclude_merge(local_inherit || hash['inherit_mode'] || {}, preview)
214
281
  end
215
282
 
216
283
  def should_union?(derived_hash, base_hash, root_mode, key)
@@ -276,7 +343,7 @@ module RuboCop
276
343
  file.is_a?(RemoteConfig)
277
344
  end
278
345
 
279
- def handle_disabled_by_default(config, new_default_configuration)
346
+ def handle_disabled_by_default(config, new_default_configuration, base_defaults)
280
347
  department_config = config.to_hash.reject { |cop| cop.include?('/') }
281
348
  department_config.each do |dept, dept_params|
282
349
  next unless dept_params['Enabled']
@@ -285,7 +352,7 @@ module RuboCop
285
352
  next unless cop.start_with?("#{dept}/")
286
353
 
287
354
  # Retain original default configuration for cops in the department.
288
- params['Enabled'] = ConfigLoader.default_configuration[cop]['Enabled']
355
+ params['Enabled'] = base_defaults[cop]['Enabled']
289
356
  end
290
357
  end
291
358
 
@@ -20,7 +20,8 @@ module RuboCop
20
20
  rule_message + "\n(obsolete configuration found in #{smart_loaded_path}, please update it)"
21
21
  end
22
22
 
23
- # Cop rules currently can only be failures, not warnings
23
+ # Failure by default; rules that accept `severity: warning` say so
24
+ # themselves.
24
25
  def warning?
25
26
  false
26
27
  end
@@ -20,15 +20,23 @@ module RuboCop
20
20
 
21
21
  if reason
22
22
  "#{base} since #{reason.chomp}."
23
- elsif alternatives
23
+ elsif alternatives.any?
24
24
  "#{base}. Please use #{to_sentence(alternatives, connector: 'and/or')} instead."
25
25
  else
26
26
  "#{base}."
27
27
  end
28
28
  end
29
29
 
30
+ def warning?
31
+ severity == 'warning'
32
+ end
33
+
30
34
  private
31
35
 
36
+ def severity
37
+ metadata['severity']
38
+ end
39
+
32
40
  def reason
33
41
  metadata['reason']
34
42
  end
@@ -15,7 +15,7 @@ module RuboCop
15
15
  'changed_parameters' => ChangedParameter,
16
16
  'changed_enforced_styles' => ChangedEnforcedStyles
17
17
  }.freeze
18
- LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant
18
+ LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant -- a cache, written to at runtime
19
19
  private_constant :LOAD_RULES_CACHE
20
20
 
21
21
  attr_reader :rules, :warnings
@@ -11,7 +11,7 @@ module RuboCop
11
11
  COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
12
12
  Enabled Reference References Safe SafeAutoCorrect].freeze
13
13
  # @api private
14
- INTERNAL_PARAMS = %w[Description StyleGuide
14
+ INTERNAL_PARAMS = %w[Description StyleGuide Preview
15
15
  VersionAdded VersionChanged VersionRemoved
16
16
  Reference References Safe SafeAutoCorrect].freeze
17
17
  # @api private
@@ -21,7 +21,7 @@ module RuboCop
21
21
 
22
22
  # @api private
23
23
  CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect References].to_set.freeze
24
- CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
24
+ CONFIG_CHECK_DEPARTMENTS = %w[pending preview override_department].freeze
25
25
  CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
26
26
  private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
27
27
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
 
49
49
  check_obsoletions
50
50
  alert_about_unrecognized_cops(invalid_cop_names)
51
- validate_new_cops_parameter
51
+ validate_all_cops_parameters
52
52
  validate_parameter_names(valid_cop_names)
53
53
  validate_enforced_styles(valid_cop_names)
54
54
  validate_syntax_cop
@@ -170,6 +170,32 @@ module RuboCop
170
170
  validate_department_new_cops_parameters
171
171
  end
172
172
 
173
+ def validate_all_cops_parameters
174
+ validate_new_cops_parameter
175
+ validate_fail_level_parameter
176
+ validate_preview_parameter
177
+ end
178
+
179
+ def validate_fail_level_parameter
180
+ fail_level = @config.for_all_cops['FailLevel']
181
+ return if fail_level.nil? || Cop::Severity::NAMES.include?(fail_level.to_sym)
182
+
183
+ message = "invalid #{fail_level} for `FailLevel` found in #{smart_loaded_path}\n" \
184
+ "Valid choices are: #{Cop::Severity::NAMES.join(', ')}"
185
+
186
+ raise ValidationError, message
187
+ end
188
+
189
+ def validate_preview_parameter
190
+ preview = @config.for_all_cops['Preview']
191
+ return if [nil, true, false].include?(preview)
192
+
193
+ message = "invalid #{preview} for `Preview` found in #{smart_loaded_path}\n" \
194
+ 'Valid choices are: true, false'
195
+
196
+ raise ValidationError, message
197
+ end
198
+
173
199
  def validate_all_cops_new_cops_parameter
174
200
  new_cop_parameter = @config.for_all_cops['NewCops']
175
201
  return if new_cop_parameter.nil? || NEW_COPS_VALUES.include?(new_cop_parameter)
@@ -40,12 +40,9 @@ module RuboCop
40
40
  # allow turning off autocorrect on a cop by cop basis
41
41
  return true unless cop_config
42
42
 
43
- # `false` is the same as `disabled` for backward compatibility.
44
- return false if ['disabled', false].include?(cop_config['AutoCorrect'])
43
+ return false if disabled_autocorrect?
45
44
 
46
- # When LSP is enabled or the `--editor-mode` option is on, it is considered as editing
47
- # source code, and autocorrection with `AutoCorrect: contextual` will not be performed.
48
- return false if contextual_autocorrect? && LSP.enabled?
45
+ return false if contextual_autocorrect_held_back?
49
46
 
50
47
  # :safe_autocorrect is a derived option based on several command-line
51
48
  # arguments - see RuboCop::Options#add_autocorrection_options
@@ -56,6 +53,14 @@ module RuboCop
56
53
 
57
54
  private
58
55
 
56
+ # When LSP is enabled or the `--editor-mode` option is on, it is considered as editing
57
+ # source code, and autocorrection with `AutoCorrect: contextual` will not be performed.
58
+ # The `editing` option says the same without the rest of LSP mode, which
59
+ # is about showing offenses in an editor.
60
+ def contextual_autocorrect_held_back?
61
+ contextual_autocorrect? && (LSP.enabled? || @options.fetch(:editing, false))
62
+ end
63
+
59
64
  def disable_offense(offense_range)
60
65
  unbreakable_range = multiline_ranges(offense_range)&.find do |range|
61
66
  offense_range.overlaps?(range) &&
@@ -45,7 +45,7 @@ module RuboCop
45
45
 
46
46
  def hash
47
47
  # Do hashing manually to reduce Array allocations.
48
- department.hash ^ cop_name.hash # rubocop:disable Security/CompoundHash
48
+ department.hash ^ cop_name.hash # rubocop:disable Security/CompoundHash -- hashing manually avoids the Array allocation
49
49
  end
50
50
 
51
51
  def match?(other)
@@ -49,7 +49,12 @@ module RuboCop
49
49
  InvestigationReport = Struct.new(:cop, :processed_source, :offenses, :corrector)
50
50
 
51
51
  # List of methods names to restrict calls for `on_send` / `on_csend`
52
- RESTRICT_ON_SEND = Set[].freeze # rubocop:disable InternalAffairs/UselessRestrictOnSend
52
+ RESTRICT_ON_SEND = Set[].freeze # rubocop:disable InternalAffairs/UselessRestrictOnSend -- the base class default, which cops override
53
+
54
+ # Departments whose cops report above `convention` unless a cop says
55
+ # otherwise. The exceptions live in `config/default.yml` as an explicit
56
+ # `Severity`, such as the lint-like cops in `Bundler` and `Gemspec`.
57
+ DEPARTMENT_SEVERITIES = { Lint: :warning, Security: :warning, Metrics: :refactor }.freeze
53
58
 
54
59
  # List of cops that should not try to autocorrect at the same
55
60
  # time as this cop
@@ -211,14 +216,8 @@ module RuboCop
211
216
  message = find_message(range_to_pass, message)
212
217
 
213
218
  status, corrector = enabled_lines?(range) ? correct(range, &block) : :disabled
214
- justification = suppression_reason(range) if status == :disabled
215
-
216
- # Since this range may be generated from Ruby code embedded in some
217
- # template file, we convert it to location info in the original file.
218
- range = range_for_original(range)
219
219
 
220
- current_offenses << Offense.new(severity, range, message, name, status, corrector,
221
- justification: justification)
220
+ current_offenses << new_offense(range, severity, message, status, corrector)
222
221
  end
223
222
 
224
223
  # This method should be overridden when a cop's behavior depends
@@ -266,10 +265,21 @@ module RuboCop
266
265
  @config.target_ruby_version
267
266
  end
268
267
 
269
- # Returns a gems locked versions (i.e. from Gemfile.lock or gems.locked)
270
- # @returns [Gem::Version | nil] The locked gem version, or nil if the gem is not present.
268
+ # Returns the version of a gem in the target, by default its locked version
269
+ # (i.e. from Gemfile.lock or gems.locked).
270
+ #
271
+ # The requirements declared with `requires_gem` are checked against the version
272
+ # this method returns, so an extension that lets users state the version of its
273
+ # gem in `AllCops` (e.g. `TargetFrameworkVersion`) can override it for that gem,
274
+ # returning a `Gem::Version`, and fall back to `super` for any other gem.
275
+ #
276
+ # @param [String] gem_name
277
+ # @return [Gem::Version, nil] The gem version, or nil if the gem is not present.
278
+ #
279
+ # @api public
271
280
  def target_gem_version(gem_name)
272
- @config.gem_versions_in_target && @config.gem_versions_in_target[gem_name]
281
+ gem_versions = @config.gem_versions_in_target
282
+ gem_versions && gem_versions[gem_name]
273
283
  end
274
284
 
275
285
  def parser_engine
@@ -288,6 +298,13 @@ module RuboCop
288
298
  @config.string_literals_frozen_by_default?
289
299
  end
290
300
 
301
+ # Whether the user opted in to unstable behavior, with `--preview` or
302
+ # `AllCops: Preview`. Cops branch on this to ship a change that is not
303
+ # ready to be the default yet.
304
+ def preview?
305
+ @config.preview?(@options)
306
+ end
307
+
291
308
  def relevant_file?(file)
292
309
  return false unless target_satisfies_all_gem_version_requirements?
293
310
  return true unless @config.clusivity_config_for_badge?(self.class.badge)
@@ -326,7 +343,7 @@ module RuboCop
326
343
 
327
344
  ### Reserved for Commissioner
328
345
 
329
- # rubocop:disable Layout/ClassStructure
346
+ # rubocop:disable Layout/ClassStructure -- grouped under the Commissioner heading above
330
347
  # @api private
331
348
  def callbacks_needed
332
349
  self.class.callbacks_needed
@@ -370,6 +387,12 @@ module RuboCop
370
387
  cop_config.fetch('AutoCorrect', 'always') == 'contextual'
371
388
  end
372
389
 
390
+ # @api private
391
+ def disabled_autocorrect?
392
+ # `false` is the same as `'disabled'` for backward compatibility.
393
+ ['disabled', false].include?(cop_config['AutoCorrect'])
394
+ end
395
+
373
396
  def inspect # :nodoc:
374
397
  "#<#{self.class.name}:#{object_id} @config=#{@config} @options=#{@options}>"
375
398
  end
@@ -382,6 +405,22 @@ module RuboCop
382
405
  @restrict_on_send ||= self::RESTRICT_ON_SEND.to_a.freeze
383
406
  end
384
407
 
408
+ # @return [Offense]
409
+ def new_offense(range, severity, message, status, corrector)
410
+ justification = suppression_reason(range) if status == :disabled
411
+
412
+ # Since this range may be generated from Ruby code embedded in some
413
+ # template file, we convert it to location info in the original file.
414
+ # A cop configured with `AutoCorrect: false` reports no edits, since
415
+ # nothing that honors the configuration applies them. The corrector
416
+ # stays, so an editor can still offer it as a quick fix to choose.
417
+ corrections = [] if corrector && disabled_autocorrect?
418
+
419
+ Offense.new(severity, range_for_original(range), message, name, status, corrector,
420
+ justification: justification, correction_safe: safe_autocorrect?,
421
+ corrections: corrections)
422
+ end
423
+
385
424
  ### Reserved for Cop::Cop
386
425
 
387
426
  def callback_argument(range)
@@ -453,7 +492,8 @@ module RuboCop
453
492
  # The unsafe correction will not run, so the offense is
454
493
  # uncorrectable for this run and gets a todo comment.
455
494
  attempt_correction(range, nil)
456
- elsif corrector && (always_autocorrect? || (contextual_autocorrect? && !LSP.enabled?))
495
+ elsif corrector && (always_autocorrect? ||
496
+ (contextual_autocorrect? && !contextual_autocorrect_held_back?))
457
497
  :uncorrected
458
498
  else
459
499
  :unsupported
@@ -561,7 +601,7 @@ module RuboCop
561
601
  end
562
602
 
563
603
  def default_severity
564
- self.class.lint? ? :warning : :convention
604
+ DEPARTMENT_SEVERITIES.fetch(self.class.department, :convention)
565
605
  end
566
606
 
567
607
  def custom_severity
@@ -589,17 +629,10 @@ module RuboCop
589
629
  end
590
630
 
591
631
  def target_satisfies_all_gem_version_requirements?
592
- gem_requirements = self.class.gem_requirements
593
- return true if gem_requirements.empty?
594
-
595
- gem_requirements.all? do |gem_name, version_req|
596
- all_gem_versions_in_target = @config.gem_versions_in_target
597
- next false unless all_gem_versions_in_target
598
-
599
- gem_version_in_target = all_gem_versions_in_target[gem_name]
600
- next false unless gem_version_in_target
632
+ self.class.gem_requirements.all? do |gem_name, version_requirement|
633
+ gem_version = target_gem_version(gem_name)
601
634
 
602
- version_req.satisfied_by?(gem_version_in_target)
635
+ gem_version && version_requirement.satisfied_by?(gem_version)
603
636
  end
604
637
  end
605
638
  end
@@ -81,7 +81,6 @@ module RuboCop
81
81
  # gem 'bar', '< 2.1'
82
82
  #
83
83
  class GemComment < Base
84
- include DefNode
85
84
  include GemDeclaration
86
85
 
87
86
  MSG = 'Missing gem description comment.'