rubocop 1.69.2 → 1.75.2

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 (360) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +154 -23
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +3 -1
  7. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  8. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  9. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  10. data/lib/rubocop/cli.rb +1 -1
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +52 -10
  13. data/lib/rubocop/config_loader.rb +52 -9
  14. data/lib/rubocop/config_loader_resolver.rb +36 -10
  15. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  16. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  17. data/lib/rubocop/config_obsoletion.rb +46 -2
  18. data/lib/rubocop/config_validator.rb +20 -9
  19. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  20. data/lib/rubocop/cop/base.rb +6 -0
  21. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  24. data/lib/rubocop/cop/internal_affairs/example_description.rb +7 -3
  25. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  26. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  27. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  28. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  30. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  31. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +230 -0
  32. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  33. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  34. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  35. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  36. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  37. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  38. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  40. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  41. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  42. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  43. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  44. data/lib/rubocop/cop/layout/block_alignment.rb +3 -1
  45. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  46. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  47. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  48. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  49. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  50. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  51. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  52. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  53. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +28 -1
  54. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  55. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  56. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  57. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  58. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  59. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  60. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  61. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  62. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  63. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  64. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  65. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  66. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  67. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  68. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  69. data/lib/rubocop/cop/layout/line_length.rb +9 -4
  70. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  71. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  72. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  73. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  74. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  75. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  76. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -11
  77. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -5
  78. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  79. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  80. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  81. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  82. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  83. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  84. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  85. data/lib/rubocop/cop/layout/space_around_operators.rb +7 -4
  86. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  87. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  88. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  89. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  90. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  91. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  92. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  93. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  94. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  95. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  96. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  97. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  98. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  99. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  100. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  101. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
  102. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  103. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  104. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  105. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  106. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  107. data/lib/rubocop/cop/lint/float_comparison.rb +6 -8
  108. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  109. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  110. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  111. data/lib/rubocop/cop/lint/literal_as_condition.rb +103 -9
  112. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  113. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  114. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -3
  115. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  116. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  117. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  118. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  119. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  120. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  121. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  122. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  123. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  124. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  125. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  126. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  127. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  128. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  129. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  130. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  131. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  132. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  133. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  134. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  135. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  136. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  137. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  138. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  139. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  140. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  141. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  142. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  143. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  144. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  145. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -1
  146. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  147. data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
  148. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  149. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  150. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  151. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  152. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  153. data/lib/rubocop/cop/lint/void.rb +12 -9
  154. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  155. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  156. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  157. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  158. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  159. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  160. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  161. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  162. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  163. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  164. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  165. data/lib/rubocop/cop/mixin/check_line_breakable.rb +13 -13
  166. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  167. data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
  168. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  169. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  170. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  171. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  172. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  173. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
  174. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  175. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  176. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  177. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  178. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  179. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  180. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  181. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  182. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  183. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  184. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  185. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  186. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  187. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  188. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  189. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  190. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  191. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  192. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  193. data/lib/rubocop/cop/registry.rb +9 -6
  194. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  195. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  196. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  197. data/lib/rubocop/cop/style/and_or.rb +1 -1
  198. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  199. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  200. data/lib/rubocop/cop/style/array_intersect.rb +39 -28
  201. data/lib/rubocop/cop/style/block_delimiters.rb +9 -21
  202. data/lib/rubocop/cop/style/class_and_module_children.rb +35 -10
  203. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  204. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  205. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  206. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  207. data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
  208. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  209. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  210. data/lib/rubocop/cop/style/conditional_assignment.rb +9 -4
  211. data/lib/rubocop/cop/style/documentation.rb +1 -1
  212. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  213. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  214. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  215. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  216. data/lib/rubocop/cop/style/empty_literal.rb +5 -1
  217. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  218. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  219. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  220. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  221. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  222. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  223. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  224. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  225. data/lib/rubocop/cop/style/float_division.rb +8 -4
  226. data/lib/rubocop/cop/style/for.rb +1 -0
  227. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  228. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  229. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  230. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  231. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  232. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  233. data/lib/rubocop/cop/style/hash_fetch_chain.rb +105 -0
  234. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  235. data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
  236. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  237. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  238. data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
  239. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  240. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  241. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  242. data/lib/rubocop/cop/style/inverse_methods.rb +15 -11
  243. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  244. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  245. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  246. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  247. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  248. data/lib/rubocop/cop/style/lambda.rb +1 -0
  249. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  250. data/lib/rubocop/cop/style/map_into_array.rb +2 -1
  251. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  252. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  253. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -16
  254. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  255. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  256. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  257. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  258. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  259. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  260. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  261. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  262. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  263. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  264. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  265. data/lib/rubocop/cop/style/next.rb +44 -0
  266. data/lib/rubocop/cop/style/object_then.rb +14 -15
  267. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  268. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  269. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  270. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  271. data/lib/rubocop/cop/style/proc.rb +2 -2
  272. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  273. data/lib/rubocop/cop/style/raise_args.rb +14 -12
  274. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  275. data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
  276. data/lib/rubocop/cop/style/redundant_condition.rb +59 -2
  277. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  278. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  279. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  280. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  281. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  282. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  283. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  284. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  285. data/lib/rubocop/cop/style/redundant_parentheses.rb +30 -15
  286. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  287. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  288. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  289. data/lib/rubocop/cop/style/redundant_self.rb +1 -0
  290. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  291. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  292. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  293. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  294. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  295. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  296. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  297. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  298. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  299. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  300. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  301. data/lib/rubocop/cop/style/single_line_do_end_block.rb +4 -3
  302. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  303. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  304. data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
  305. data/lib/rubocop/cop/style/string_concatenation.rb +2 -2
  306. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  307. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  308. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  309. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  310. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  311. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  312. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  313. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  314. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  315. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  316. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  317. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  318. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  319. data/lib/rubocop/cop/util.rb +12 -5
  320. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  321. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  322. data/lib/rubocop/cop/variable_force/variable.rb +10 -3
  323. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  324. data/lib/rubocop/cop/variable_force.rb +1 -1
  325. data/lib/rubocop/cops_documentation_generator.rb +25 -14
  326. data/lib/rubocop/directive_comment.rb +45 -11
  327. data/lib/rubocop/ext/regexp_node.rb +0 -1
  328. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  329. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  330. data/lib/rubocop/lsp/logger.rb +2 -2
  331. data/lib/rubocop/lsp/routes.rb +7 -23
  332. data/lib/rubocop/lsp/runtime.rb +18 -50
  333. data/lib/rubocop/lsp/server.rb +0 -2
  334. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  335. data/lib/rubocop/magic_comment.rb +8 -0
  336. data/lib/rubocop/options.rb +28 -12
  337. data/lib/rubocop/path_util.rb +15 -8
  338. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  339. data/lib/rubocop/plugin/load_error.rb +26 -0
  340. data/lib/rubocop/plugin/loader.rb +100 -0
  341. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  342. data/lib/rubocop/plugin.rb +46 -0
  343. data/lib/rubocop/rake_task.rb +4 -1
  344. data/lib/rubocop/result_cache.rb +13 -13
  345. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  346. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  347. data/lib/rubocop/rspec/shared_contexts.rb +39 -1
  348. data/lib/rubocop/rspec/support.rb +4 -2
  349. data/lib/rubocop/runner.rb +10 -7
  350. data/lib/rubocop/server/cache.rb +47 -11
  351. data/lib/rubocop/server/cli.rb +2 -2
  352. data/lib/rubocop/target_finder.rb +2 -1
  353. data/lib/rubocop/target_ruby.rb +16 -1
  354. data/lib/rubocop/version.rb +30 -8
  355. data/lib/rubocop.rb +16 -1
  356. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  357. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  358. metadata +59 -16
  359. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  360. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'plugin/configuration_integrator'
4
+ require_relative 'plugin/loader'
5
+
6
+ module RuboCop
7
+ # Provides a plugin for RuboCop extensions that conform to lint_roller.
8
+ # https://github.com/standardrb/lint_roller
9
+ # @api private
10
+ module Plugin
11
+ BUILTIN_INTERNAL_PLUGINS = {
12
+ 'rubocop-internal_affairs' => {
13
+ 'enabled' => true,
14
+ 'require_path' => 'rubocop/cop/internal_affairs/plugin',
15
+ 'plugin_class_name' => 'RuboCop::InternalAffairs::Plugin'
16
+ }
17
+ }.freeze
18
+ INTERNAL_AFFAIRS_PLUGIN_NAME = Plugin::BUILTIN_INTERNAL_PLUGINS.keys.first
19
+ OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME = 'rubocop/cop/internal_affairs'
20
+
21
+ class << self
22
+ def plugin_capable?(feature_name)
23
+ return true if BUILTIN_INTERNAL_PLUGINS.key?(feature_name)
24
+ return true if feature_name == OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME
25
+
26
+ begin
27
+ # When not using Bundler. Makes the spec available but does not require it.
28
+ gem feature_name
29
+ rescue Gem::LoadError
30
+ # The user requested a gem that they do not have installed
31
+ end
32
+ return false unless (spec = Gem.loaded_specs[feature_name])
33
+
34
+ !!spec.metadata['default_lint_roller_plugin']
35
+ end
36
+
37
+ def integrate_plugins(rubocop_config, plugins)
38
+ plugins = Plugin::Loader.load(plugins)
39
+
40
+ ConfigurationIntegrator.integrate_plugins_into_rubocop_config(rubocop_config, plugins)
41
+
42
+ plugins
43
+ end
44
+ end
45
+ end
46
+ end
@@ -12,7 +12,8 @@ module RuboCop
12
12
  # Use global Rake namespace here to avoid namespace issues with custom
13
13
  # rubocop-rake tasks
14
14
  class RakeTask < ::Rake::TaskLib
15
- attr_accessor :name, :verbose, :fail_on_error, :patterns, :formatters, :requires, :options
15
+ attr_accessor :name, :verbose, :fail_on_error, :patterns, :formatters, :plugins, :requires,
16
+ :options
16
17
 
17
18
  def initialize(name = :rubocop, *args, &task_block)
18
19
  super()
@@ -54,6 +55,7 @@ module RuboCop
54
55
 
55
56
  def full_options
56
57
  formatters.map { |f| ['--format', f] }.flatten
58
+ .concat(plugins.map { |plugin| ['--plugin', plugin] }.flatten)
57
59
  .concat(requires.map { |r| ['--require', r] }.flatten)
58
60
  .concat(options.flatten)
59
61
  .concat(patterns)
@@ -64,6 +66,7 @@ module RuboCop
64
66
  @verbose = true
65
67
  @fail_on_error = true
66
68
  @patterns = []
69
+ @plugins = []
67
70
  @requires = []
68
71
  @options = []
69
72
  @formatters = []
@@ -25,16 +25,16 @@ module RuboCop
25
25
  # cleaning should be done relatively seldom, since there is a slight risk
26
26
  # that some other RuboCop process was just about to read the file, when
27
27
  # there's parallel execution and the cache is shared.
28
- def self.cleanup(config_store, verbose, cache_root = nil)
28
+ def self.cleanup(config_store, verbose, cache_root_override = nil)
29
29
  return if inhibit_cleanup # OPTIMIZE: For faster testing
30
30
 
31
- cache_root ||= cache_root(config_store)
32
- return unless File.exist?(cache_root)
31
+ rubocop_cache_dir = cache_root(config_store, cache_root_override)
32
+ return unless File.exist?(rubocop_cache_dir)
33
33
 
34
- files, dirs = Find.find(cache_root).partition { |path| File.file?(path) }
34
+ files, dirs = Find.find(rubocop_cache_dir).partition { |path| File.file?(path) }
35
35
  return unless requires_file_removal?(files.length, config_store)
36
36
 
37
- remove_oldest_files(files, dirs, cache_root, verbose)
37
+ remove_oldest_files(files, dirs, rubocop_cache_dir, verbose)
38
38
  end
39
39
 
40
40
  class << self
@@ -49,11 +49,11 @@ module RuboCop
49
49
  file_count > 1 && file_count > config_store.for_pwd.for_all_cops['MaxFilesInCache']
50
50
  end
51
51
 
52
- def remove_oldest_files(files, dirs, cache_root, verbose)
52
+ def remove_oldest_files(files, dirs, rubocop_cache_dir, verbose)
53
53
  # Add 1 to half the number of files, so that we remove the file if
54
54
  # there's only 1 left.
55
55
  remove_count = (files.length / 2) + 1
56
- puts "Removing the #{remove_count} oldest files from #{cache_root}" if verbose
56
+ puts "Removing the #{remove_count} oldest files from #{rubocop_cache_dir}" if verbose
57
57
  sorted = files.sort_by { |path| File.mtime(path) }
58
58
  remove_files(sorted, dirs, remove_count)
59
59
  rescue Errno::ENOENT
@@ -72,9 +72,9 @@ module RuboCop
72
72
  end
73
73
  end
74
74
 
75
- def self.cache_root(config_store)
75
+ def self.cache_root(config_store, cache_root_override = nil)
76
76
  CacheConfig.root_dir do
77
- config_store.for_pwd.for_all_cops['CacheRootDirectory']
77
+ cache_root_override || config_store.for_pwd.for_all_cops['CacheRootDirectory']
78
78
  end
79
79
  end
80
80
 
@@ -84,12 +84,12 @@ module RuboCop
84
84
 
85
85
  attr_reader :path
86
86
 
87
- def initialize(file, team, options, config_store, cache_root = nil)
88
- cache_root ||= File.join(options[:cache_root], 'rubocop_cache') if options[:cache_root]
89
- cache_root ||= ResultCache.cache_root(config_store)
87
+ def initialize(file, team, options, config_store, cache_root_override = nil)
88
+ cache_root_override ||= options[:cache_root] if options[:cache_root]
89
+ rubocop_cache_dir = ResultCache.cache_root(config_store, cache_root_override)
90
90
  @allow_symlinks_in_cache_location =
91
91
  ResultCache.allow_symlinks_in_cache_location?(config_store)
92
- @path = File.join(cache_root,
92
+ @path = File.join(rubocop_cache_dir,
93
93
  rubocop_checksum,
94
94
  context_checksum(team, options),
95
95
  file_checksum(file, config_store))
@@ -10,9 +10,21 @@ module CopHelper
10
10
  # The minimum version Prism can parse is 3.3.
11
11
  ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : RuboCop::TargetRuby::DEFAULT_VERSION
12
12
  end
13
- let(:parser_engine) { ENV.fetch('PARSER_ENGINE', :parser_whitequark).to_sym }
13
+ let(:parser_engine) do
14
+ # The maximum version Parser can parse is 3.4.
15
+ ruby_version >= 3.5 ? :parser_prism : ENV.fetch('PARSER_ENGINE', :parser_whitequark).to_sym
16
+ end
14
17
  let(:rails_version) { false }
15
18
 
19
+ before(:all) do
20
+ next if ENV['RUBOCOP_CORE_DEVELOPMENT']
21
+
22
+ plugins = Gem.loaded_specs.filter_map do |feature_name, feature_specification|
23
+ feature_name if feature_specification.metadata['default_lint_roller_plugin']
24
+ end
25
+ RuboCop::Plugin.integrate_plugins(RuboCop::Config.new, plugins)
26
+ end
27
+
16
28
  def inspect_source(source, file = nil)
17
29
  RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
18
30
  RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
@@ -190,7 +190,10 @@ module RuboCop
190
190
  def expect_no_offenses(source, file = nil)
191
191
  offenses = inspect_source(source, file)
192
192
 
193
- expected_annotations = AnnotatedSource.parse(source)
193
+ # Since source given `expect_no_offenses` does not have annotations, we do not need to parse
194
+ # for them, and can just build an `AnnotatedSource` object from the source lines.
195
+ # This also prevents treating source lines that begin with a caret as an annotation.
196
+ expected_annotations = AnnotatedSource.new(source.each_line.to_a, [])
194
197
  actual_annotations = expected_annotations.with_offense_annotations(offenses)
195
198
  expect(actual_annotations.to_s).to eq(source)
196
199
  end
@@ -221,7 +224,8 @@ module RuboCop
221
224
 
222
225
  # Parsed representation of code annotated with the `^^^ Message` style
223
226
  class AnnotatedSource
224
- ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
227
+ # Ignore escaped carets, don't treat as annotations
228
+ ANNOTATION_PATTERN = /\A\s*((?<!\\)\^+|\^{}) ?/.freeze
225
229
  ABBREV = "[...]\n"
226
230
 
227
231
  # @param annotated_source [String] string passed to the matchers
@@ -80,6 +80,21 @@ RSpec.shared_context 'maintain registry' do
80
80
  end
81
81
  end
82
82
 
83
+ RSpec.shared_context 'maintain default configuration' do
84
+ around(:each) do |example|
85
+ # Make a copy of the current configuration that will not change when source hash changes
86
+ default_configuration = RuboCop::ConfigLoader.default_configuration
87
+ config = RuboCop::Config.create(
88
+ default_configuration.to_h.clone,
89
+ default_configuration.loaded_path
90
+ )
91
+
92
+ example.run
93
+
94
+ RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, config)
95
+ end
96
+ end
97
+
83
98
  # This context assumes nothing and defines `cop`, among others.
84
99
  RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
85
100
  ### Meant to be overridden at will
@@ -98,6 +113,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
98
113
 
99
114
  let(:cop_options) { {} }
100
115
 
116
+ let(:gem_versions) { {} }
117
+
101
118
  ### Utilities
102
119
 
103
120
  def source_range(range, buffer: source_buffer)
@@ -138,7 +155,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
138
155
 
139
156
  allow(config).to receive(:gem_versions_in_target).and_return(
140
157
  {
141
- 'railties' => rails_version_in_gemfile
158
+ 'railties' => rails_version_in_gemfile,
159
+ **gem_versions.transform_values { |value| Gem::Version.new(value) }
142
160
  }
143
161
  )
144
162
 
@@ -160,6 +178,21 @@ RSpec.shared_context 'mock console output' do
160
178
  end
161
179
  end
162
180
 
181
+ RSpec.shared_context 'mock obsoletion' do
182
+ include_context 'mock console output'
183
+
184
+ let(:obsoletion_configuration_path) { 'obsoletions.yml' }
185
+
186
+ before do
187
+ RuboCop::ConfigObsoletion.reset!
188
+ allow(RuboCop::ConfigObsoletion).to receive(:files).and_return([obsoletion_configuration_path])
189
+ end
190
+
191
+ after do
192
+ RuboCop::ConfigObsoletion.reset!
193
+ end
194
+ end
195
+
163
196
  RSpec.shared_context 'lsp' do
164
197
  before do
165
198
  RuboCop::LSP.enable
@@ -232,3 +265,8 @@ end
232
265
  RSpec.shared_context 'ruby 3.4' do
233
266
  let(:ruby_version) { 3.4 }
234
267
  end
268
+
269
+ RSpec.shared_context 'ruby 3.5' do
270
+ # Parser supports parsing Ruby <= 3.4.
271
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.5 : 3.4 }
272
+ end
@@ -4,18 +4,19 @@
4
4
 
5
5
  require_relative 'cop_helper'
6
6
  require_relative 'expect_offense'
7
- require_relative 'host_environment_simulation_helper'
8
7
  require_relative 'parallel_formatter'
9
8
  require_relative 'shared_contexts'
10
9
 
11
10
  RSpec.configure do |config|
12
11
  config.include CopHelper
13
- config.include HostEnvironmentSimulatorHelper
12
+ config.include RuboCop::RSpec::ExpectOffense
14
13
  config.include_context 'config', :config
15
14
  config.include_context 'isolated environment', :isolated_environment
16
15
  config.include_context 'isolated bundler', :isolated_bundler
17
16
  config.include_context 'lsp', :lsp
18
17
  config.include_context 'maintain registry', :restore_registry
18
+ config.include_context 'maintain default configuration', :restore_configuration
19
+ config.include_context 'mock obsoletion', :mock_obsoletion
19
20
  config.include_context 'ruby 2.0', :ruby20
20
21
  config.include_context 'ruby 2.1', :ruby21
21
22
  config.include_context 'ruby 2.2', :ruby22
@@ -29,4 +30,5 @@ RSpec.configure do |config|
29
30
  config.include_context 'ruby 3.2', :ruby32
30
31
  config.include_context 'ruby 3.3', :ruby33
31
32
  config.include_context 'ruby 3.4', :ruby34
33
+ config.include_context 'ruby 3.5', :ruby35
32
34
  end
@@ -20,11 +20,7 @@ module RuboCop
20
20
  message = 'Infinite loop detected'
21
21
  message += " in #{path}" if path
22
22
  message += " and caused by #{root_cause}" if root_cause
23
- message += "\n"
24
- hint = 'Hint: Please update to the latest RuboCop version if not already in use, ' \
25
- "and report a bug if the issue still occurs on this version.\n" \
26
- 'Please check the latest version at https://rubygems.org/gems/rubocop.'
27
- super(Rainbow(message).red + Rainbow(hint).yellow)
23
+ super(message)
28
24
  end
29
25
  end
30
26
 
@@ -157,8 +153,11 @@ module RuboCop
157
153
  file_started(file)
158
154
  offenses = file_offenses(file)
159
155
  rescue InfiniteCorrectionLoop => e
156
+ raise e if @options[:raise_cop_error]
157
+
158
+ errors << e
159
+ warn Rainbow(e.message).red
160
160
  offenses = e.offenses.compact.sort.freeze
161
- raise
162
161
  ensure
163
162
  file_finished(file, offenses || [])
164
163
  end
@@ -490,7 +489,11 @@ module RuboCop
490
489
 
491
490
  processed_source = if @options[:stdin]
492
491
  ProcessedSource.new(
493
- @options[:stdin], ruby_version, file, parser_engine: parser_engine
492
+ @options[:stdin],
493
+ ruby_version,
494
+ file,
495
+ parser_engine: parser_engine,
496
+ prism_result: @prism_result
494
497
  )
495
498
  else
496
499
  begin
@@ -2,8 +2,10 @@
2
2
 
3
3
  require 'digest'
4
4
  require 'pathname'
5
+ require 'yaml'
5
6
  require_relative '../cache_config'
6
7
  require_relative '../config_finder'
8
+ require_relative '../path_util'
7
9
 
8
10
  #
9
11
  # This code is based on https://github.com/fohte/rubocop-daemon.
@@ -50,9 +52,12 @@ module RuboCop
50
52
  end.find(&:exist?)
51
53
  version_data = lockfile_path&.read || RuboCop::Version::STRING
52
54
  config_data = Pathname(ConfigFinder.find_config_path(Dir.pwd)).read
53
- todo_data = (rubocop_todo = Pathname('.rubocop_todo.yml')).exist? ? rubocop_todo.read : ''
55
+ yaml = load_erb_templated_yaml(config_data)
54
56
 
55
- Digest::SHA1.hexdigest(version_data + config_data + todo_data)
57
+ inherit_from_data = inherit_from_data(yaml)
58
+ require_data = require_data(yaml)
59
+
60
+ Digest::SHA1.hexdigest(version_data + config_data + inherit_from_data + require_data)
56
61
  end
57
62
  # rubocop:enable Metrics/AbcSize
58
63
 
@@ -72,7 +77,6 @@ module RuboCop
72
77
  File.expand_path(File.join(cache_root_dir, 'server'))
73
78
  end
74
79
 
75
- # rubocop:disable Metrics/MethodLength
76
80
  def cache_root_dir_from_config
77
81
  CacheConfig.root_dir do
78
82
  # `RuboCop::ConfigStore` has heavy dependencies, this is a lightweight implementation
@@ -83,13 +87,7 @@ module RuboCop
83
87
  # Returns early if `CacheRootDirectory` is not used before requiring `erb` or `yaml`.
84
88
  next unless file_contents.include?('CacheRootDirectory')
85
89
 
86
- require 'erb'
87
- yaml_code = ERB.new(file_contents).result
88
-
89
- require 'yaml'
90
- config_yaml = YAML.safe_load(
91
- yaml_code, permitted_classes: [Regexp, Symbol], aliases: true
92
- )
90
+ config_yaml = load_erb_templated_yaml(file_contents)
93
91
 
94
92
  # For compatibility with Ruby 3.0 or lower.
95
93
  if Gem::Version.new(Psych::VERSION) < Gem::Version.new('4.0.0')
@@ -99,7 +97,6 @@ module RuboCop
99
97
  config_yaml&.dig('AllCops', 'CacheRootDirectory')
100
98
  end
101
99
  end
102
- # rubocop:enable Metrics/MethodLength
103
100
 
104
101
  def port_path
105
102
  dir.join('port')
@@ -164,6 +161,45 @@ module RuboCop
164
161
  def write_version_file(version)
165
162
  version_path.write(version)
166
163
  end
164
+
165
+ def inherit_from_data(yaml)
166
+ return '' unless (inherit_from_paths = yaml['inherit_from'])
167
+
168
+ Array(inherit_from_paths).map do |path|
169
+ next if PathUtil.remote_file?(path)
170
+
171
+ path = Pathname(path)
172
+
173
+ path.exist? ? path.read : ''
174
+ end.join
175
+ end
176
+
177
+ def require_data(yaml)
178
+ return '' unless (require_paths = yaml['require'])
179
+
180
+ Array(require_paths).map do |path|
181
+ # NOTE: This targets only relative or absolute path specifications.
182
+ # For example, specifications like `require: rubocop-performance`,
183
+ # which can be loaded from `$LOAD_PATH`, are ignored.
184
+ next unless path.start_with?('.', '/')
185
+
186
+ # NOTE: `.so` files are not typically specified, so only `.rb` files are targeted.
187
+ path = "#{path}.rb" unless path.end_with?('.rb')
188
+ path = Pathname(path)
189
+
190
+ path.exist? ? path.read : ''
191
+ end.join
192
+ end
193
+
194
+ private
195
+
196
+ def load_erb_templated_yaml(content)
197
+ require 'erb'
198
+ yaml_code = ERB.new(content).result
199
+
200
+ require 'yaml'
201
+ YAML.safe_load(yaml_code, permitted_classes: [Regexp, Symbol], aliases: true)
202
+ end
167
203
  end
168
204
  end
169
205
  end
@@ -86,7 +86,7 @@ module RuboCop
86
86
  end
87
87
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
88
88
 
89
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength:
89
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
90
90
  def run_command(server_command, detach:)
91
91
  case server_command
92
92
  when '--server'
@@ -107,7 +107,7 @@ module RuboCop
107
107
  Server::ClientCommand::Status.new.run
108
108
  end
109
109
  end
110
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength:
110
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
111
111
 
112
112
  def fetch_cache_root_path_from(arguments)
113
113
  cache_root = arguments.detect { |argument| argument.start_with?('--cache-root') }
@@ -127,6 +127,7 @@ module RuboCop
127
127
  if mode == :only_recognized_file_types || force_exclusion?
128
128
  files.select! { |file| included_file?(file) }
129
129
  end
130
+ files.reject! { |file| FileTest.directory?(file) }
130
131
 
131
132
  force_exclusion? ? without_excluded(files) : files
132
133
  end
@@ -174,7 +175,7 @@ module RuboCop
174
175
  end
175
176
 
176
177
  def ruby_executable?(file)
177
- return false unless File.extname(file).empty? && File.exist?(file)
178
+ return false if !File.extname(file).empty? || !File.exist?(file) || File.empty?(file)
178
179
 
179
180
  first_line = File.open(file, &:readline)
180
181
  /#!.*(#{ruby_interpreters(file).join('|')})/.match?(first_line)
@@ -4,7 +4,7 @@ module RuboCop
4
4
  # The kind of Ruby that code inspected by RuboCop is written in.
5
5
  # @api private
6
6
  class TargetRuby
7
- KNOWN_RUBIES = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4].freeze
7
+ KNOWN_RUBIES = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5].freeze
8
8
  DEFAULT_VERSION = 2.7
9
9
 
10
10
  OBSOLETE_RUBIES = {
@@ -34,6 +34,20 @@ module RuboCop
34
34
  end
35
35
  end
36
36
 
37
+ # The target ruby version may be configured by setting the
38
+ # `RUBOCOP_TARGET_RUBY_VERSION` environment variable.
39
+ class RuboCopEnvVar < Source
40
+ def name
41
+ '`RUBOCOP_TARGET_RUBY_VERSION` environment variable'
42
+ end
43
+
44
+ private
45
+
46
+ def find_version
47
+ ENV.fetch('RUBOCOP_TARGET_RUBY_VERSION', nil)&.to_f
48
+ end
49
+ end
50
+
37
51
  # The target ruby version may be configured in RuboCop's config.
38
52
  # @api private
39
53
  class RuboCopConfig < Source
@@ -246,6 +260,7 @@ module RuboCop
246
260
  end
247
261
 
248
262
  SOURCES = [
263
+ RuboCopEnvVar,
249
264
  RuboCopConfig,
250
265
  GemspecFile,
251
266
  RubyVersionFile,
@@ -3,13 +3,15 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.69.2'
6
+ STRING = '1.75.2'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
10
10
  'analyzing as Ruby %<target_ruby_version>s, ' \
11
11
  'running on %<ruby_engine>s %<ruby_version>s)%<server_mode>s [%<ruby_platform>s]'
12
12
 
13
+ MINIMUM_PARSABLE_PRISM_VERSION = 3.3
14
+
13
15
  CANONICAL_FEATURE_NAMES = {
14
16
  'Rspec' => 'RSpec', 'Graphql' => 'GraphQL', 'Md' => 'Markdown', 'Factory_bot' => 'FactoryBot',
15
17
  'Thread_safety' => 'ThreadSafety', 'Rspec_rails' => 'RSpecRails'
@@ -20,11 +22,14 @@ module RuboCop
20
22
 
21
23
  # NOTE: Marked as private but used by gems like standard.
22
24
  # @api private
25
+ # rubocop:disable Metrics/MethodLength
23
26
  def self.version(debug: false, env: nil)
24
27
  if debug
25
- verbose_version = format(MSG, version: STRING, parser_version: parser_version,
28
+ target_ruby_version = target_ruby_version(env)
29
+ verbose_version = format(MSG, version: STRING,
30
+ parser_version: parser_version(target_ruby_version),
26
31
  rubocop_ast_version: RuboCop::AST::Version::STRING,
27
- target_ruby_version: target_ruby_version(env),
32
+ target_ruby_version: target_ruby_version,
28
33
  ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
29
34
  server_mode: server_mode,
30
35
  ruby_platform: RUBY_PLATFORM)
@@ -41,6 +46,7 @@ module RuboCop
41
46
  STRING
42
47
  end
43
48
  end
49
+ # rubocop:enable Metrics/MethodLength
44
50
 
45
51
  # @api private
46
52
  def self.verbose(env: nil)
@@ -48,24 +54,37 @@ module RuboCop
48
54
  end
49
55
 
50
56
  # @api private
51
- def self.parser_version
57
+ def self.parser_version(target_ruby_version)
52
58
  config_path = ConfigFinder.find_config_path(Dir.pwd)
53
59
  yaml = Util.silence_warnings do
54
60
  ConfigLoader.load_yaml_configuration(config_path)
55
61
  end
62
+ parser_engine = yaml.dig('AllCops', 'ParserEngine')
63
+ parser_engine_text = ", #{parser_engine}" if parser_engine
56
64
 
57
- if yaml.dig('AllCops', 'ParserEngine') == 'parser_prism'
58
- require 'prism'
59
- "Prism #{Prism::VERSION}"
65
+ if target_ruby_version >= MINIMUM_PARSABLE_PRISM_VERSION
66
+ "Parser #{Parser::VERSION}, Prism #{Prism::VERSION}#{parser_engine_text}"
60
67
  else
61
68
  "Parser #{Parser::VERSION}"
62
69
  end
63
70
  end
64
71
 
65
72
  # @api private
73
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
66
74
  def self.extension_versions(env)
75
+ plugins = config_for_pwd(env).loaded_plugins
76
+ plugin_versions = plugins.filter_map do |plugin|
77
+ next if Plugin::BUILTIN_INTERNAL_PLUGINS.key?(plugin.about.name)
78
+ next unless (plugin_name = plugin.about.name)
79
+
80
+ " - #{plugin_name} #{plugin.about.version}"
81
+ end
82
+
83
+ # TODO: It needs to be maintained for a while to ensure compatibility with extensions that
84
+ # don't support plugins. It should be removed in future once the old style becomes obsolete.
67
85
  features = config_for_pwd(env).loaded_features.sort
68
- features.filter_map do |loaded_feature|
86
+ features -= plugins.map { |plugin| plugin.about.name }
87
+ feature_versions = features.filter_map do |loaded_feature|
69
88
  next unless (match = loaded_feature.match(/rubocop-(?<feature>.*)/))
70
89
 
71
90
  # Get the expected name of the folder containing the extension code.
@@ -84,7 +103,10 @@ module RuboCop
84
103
 
85
104
  " - #{loaded_feature} #{feature_version}"
86
105
  end
106
+
107
+ plugin_versions + feature_versions
87
108
  end
109
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
88
110
 
89
111
  # @api private
90
112
  def self.target_ruby_version(env)