rubocop 1.67.0 → 1.73.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 (412) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +168 -19
  5. data/config/internal_affairs.yml +16 -0
  6. data/lib/rubocop/cached_data.rb +12 -4
  7. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  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/command/version.rb +2 -2
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +17 -4
  13. data/lib/rubocop/config_loader.rb +48 -8
  14. data/lib/rubocop/config_loader_resolver.rb +35 -10
  15. data/lib/rubocop/config_validator.rb +19 -9
  16. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  17. data/lib/rubocop/cop/base.rb +7 -1
  18. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  19. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  20. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  21. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  22. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  23. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  24. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  25. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  27. data/lib/rubocop/cop/generator.rb +6 -0
  28. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  29. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
  30. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  31. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  32. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  33. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  35. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  36. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  37. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  38. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  39. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  40. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  41. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  42. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  43. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  45. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  46. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  47. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  48. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  49. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  50. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  51. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  52. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  53. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  54. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  55. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  56. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  57. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  58. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  59. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +29 -4
  60. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  61. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  62. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  63. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  64. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  65. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  66. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  67. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  68. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  69. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  70. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  71. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  72. data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
  73. data/lib/rubocop/cop/layout/leading_comment_space.rb +44 -1
  74. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  75. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  76. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  77. data/lib/rubocop/cop/layout/line_length.rb +119 -4
  78. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  79. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  80. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  81. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  82. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  83. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  84. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  85. data/lib/rubocop/cop/layout/redundant_line_break.rb +10 -41
  86. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -3
  87. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  88. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  89. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  90. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  91. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  92. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  93. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  94. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -20
  95. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  96. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  97. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  98. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  99. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
  100. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  101. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  102. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  103. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  104. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  105. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  106. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  107. data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
  108. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  109. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  110. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  111. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  112. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
  113. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  114. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  115. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  116. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  117. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  118. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  119. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  120. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  121. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  122. data/lib/rubocop/cop/lint/float_comparison.rb +20 -14
  123. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  124. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  125. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  126. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  127. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  128. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  129. data/lib/rubocop/cop/lint/literal_as_condition.rb +105 -7
  130. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  131. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  132. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  133. data/lib/rubocop/cop/lint/mixed_case_range.rb +4 -7
  134. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  135. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  136. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  137. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  138. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  139. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  140. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  141. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  142. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  143. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  144. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  145. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  146. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  147. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  148. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  149. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  150. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
  151. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  152. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  153. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
  154. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  155. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  156. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  157. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  158. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  159. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  160. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  161. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  162. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  163. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  164. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  165. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  166. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  167. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  168. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  169. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  170. data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
  171. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  172. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  173. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  174. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  175. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
  176. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  177. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  178. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  179. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  180. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  181. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  182. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  183. data/lib/rubocop/cop/lint/void.rb +14 -11
  184. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  185. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  186. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  187. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  188. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  189. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  190. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  191. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  192. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
  193. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  194. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  195. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  196. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  197. data/lib/rubocop/cop/mixin/check_line_breakable.rb +20 -10
  198. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  199. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  200. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  201. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  202. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -2
  203. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  204. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  205. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  206. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  207. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  208. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  209. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  210. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  211. data/lib/rubocop/cop/mixin/range_help.rb +3 -4
  212. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  213. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  214. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  215. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  216. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  217. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  218. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  219. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  220. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  221. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  222. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  223. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  224. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  225. data/lib/rubocop/cop/naming/variable_name.rb +63 -6
  226. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  227. data/lib/rubocop/cop/offense.rb +2 -3
  228. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  229. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  230. data/lib/rubocop/cop/style/access_modifier_declarations.rb +86 -28
  231. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  232. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  233. data/lib/rubocop/cop/style/and_or.rb +1 -1
  234. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  235. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  236. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  237. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  238. data/lib/rubocop/cop/style/block_delimiters.rb +41 -24
  239. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  240. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  241. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  242. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  243. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  244. data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
  245. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  246. data/lib/rubocop/cop/style/conditional_assignment.rb +25 -25
  247. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  248. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  249. data/lib/rubocop/cop/style/documentation.rb +1 -1
  250. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  251. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  252. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  253. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  254. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  255. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  256. data/lib/rubocop/cop/style/endless_method.rb +150 -18
  257. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  258. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  259. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  260. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  261. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  262. data/lib/rubocop/cop/style/file_null.rb +89 -0
  263. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  264. data/lib/rubocop/cop/style/float_division.rb +8 -4
  265. data/lib/rubocop/cop/style/for.rb +0 -1
  266. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  267. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  268. data/lib/rubocop/cop/style/guard_clause.rb +15 -2
  269. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  270. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  271. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  272. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  273. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  274. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  275. data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
  276. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  277. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -3
  278. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -9
  279. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  280. data/lib/rubocop/cop/style/inverse_methods.rb +6 -7
  281. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  282. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  283. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  284. data/lib/rubocop/cop/style/lambda_call.rb +3 -2
  285. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  286. data/lib/rubocop/cop/style/map_into_array.rb +7 -2
  287. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  288. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  289. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -13
  290. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  291. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  292. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  293. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  294. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  295. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  296. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  297. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  298. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  299. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  300. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  301. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  302. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  303. data/lib/rubocop/cop/style/not.rb +1 -1
  304. data/lib/rubocop/cop/style/object_then.rb +14 -15
  305. data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
  306. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  307. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  308. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  309. data/lib/rubocop/cop/style/parallel_assignment.rb +9 -18
  310. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  311. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  312. data/lib/rubocop/cop/style/proc.rb +1 -2
  313. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  314. data/lib/rubocop/cop/style/raise_args.rb +7 -5
  315. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  316. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  317. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  318. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  319. data/lib/rubocop/cop/style/redundant_condition.rb +72 -23
  320. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  321. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  322. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  323. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  324. data/lib/rubocop/cop/style/redundant_format.rb +250 -0
  325. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  326. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  327. data/lib/rubocop/cop/style/redundant_line_continuation.rb +54 -15
  328. data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -24
  329. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  330. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  331. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  332. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  333. data/lib/rubocop/cop/style/redundant_self.rb +8 -15
  334. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  335. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  336. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  337. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  338. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
  339. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  340. data/lib/rubocop/cop/style/safe_navigation.rb +14 -2
  341. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  342. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  343. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  344. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  345. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  346. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  347. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  348. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  349. data/lib/rubocop/cop/style/single_line_do_end_block.rb +12 -3
  350. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  351. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  352. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -5
  353. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  354. data/lib/rubocop/cop/style/string_concatenation.rb +15 -14
  355. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  356. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  357. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  358. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  359. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  360. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  361. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  362. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  363. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  364. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  365. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  366. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  367. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  368. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  369. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  370. data/lib/rubocop/cop/util.rb +12 -5
  371. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  372. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  373. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  374. data/lib/rubocop/cop/variable_force/variable.rb +18 -2
  375. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  376. data/lib/rubocop/cop/variable_force.rb +4 -10
  377. data/lib/rubocop/cops_documentation_generator.rb +44 -23
  378. data/lib/rubocop/directive_comment.rb +44 -10
  379. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  380. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  381. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  382. data/lib/rubocop/lsp/logger.rb +2 -2
  383. data/lib/rubocop/lsp/routes.rb +7 -23
  384. data/lib/rubocop/lsp/runtime.rb +17 -49
  385. data/lib/rubocop/lsp/server.rb +0 -2
  386. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  387. data/lib/rubocop/magic_comment.rb +3 -3
  388. data/lib/rubocop/options.rb +28 -12
  389. data/lib/rubocop/path_util.rb +15 -8
  390. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  391. data/lib/rubocop/plugin/load_error.rb +26 -0
  392. data/lib/rubocop/plugin/loader.rb +100 -0
  393. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  394. data/lib/rubocop/plugin.rb +46 -0
  395. data/lib/rubocop/rake_task.rb +4 -1
  396. data/lib/rubocop/result_cache.rb +13 -13
  397. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  398. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  399. data/lib/rubocop/rspec/shared_contexts.rb +19 -1
  400. data/lib/rubocop/rspec/support.rb +2 -2
  401. data/lib/rubocop/runner.rb +21 -14
  402. data/lib/rubocop/server/cache.rb +35 -2
  403. data/lib/rubocop/server/cli.rb +2 -2
  404. data/lib/rubocop/target_finder.rb +1 -0
  405. data/lib/rubocop/target_ruby.rb +16 -1
  406. data/lib/rubocop/version.rb +41 -7
  407. data/lib/rubocop.rb +27 -1
  408. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  409. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
  410. metadata +73 -20
  411. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  412. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/standardrb/standard.
5
+ #
6
+ # Copyright (c) 2023 Test Double, Inc.
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Lsp
14
+ # Originally lifted from:
15
+ # https://github.com/Shopify/ruby-lsp/blob/8d4c17efce4e8ecc8e7c557ab2981db6b22c0b6d/lib/ruby_lsp/requests/support/rubocop_runner.rb#L20
16
+ # @api private
17
+ class StdinRunner < RuboCop::Runner
18
+ class ConfigurationError < StandardError; end
19
+
20
+ attr_reader :offenses, :config_for_working_directory
21
+
22
+ DEFAULT_RUBOCOP_OPTIONS = {
23
+ stderr: true,
24
+ force_exclusion: true,
25
+ formatters: ['RuboCop::Formatter::BaseFormatter'],
26
+ raise_cop_error: true,
27
+ todo_file: nil,
28
+ todo_ignore_files: []
29
+ }.freeze
30
+
31
+ def initialize(config_store)
32
+ @options = {}
33
+
34
+ @offenses = []
35
+ @warnings = []
36
+ @errors = []
37
+
38
+ @config_for_working_directory = config_store.for_pwd
39
+
40
+ super(@options, config_store)
41
+ end
42
+
43
+ # rubocop:disable Metrics/MethodLength
44
+ def run(path, contents, options)
45
+ @options = options.merge(DEFAULT_RUBOCOP_OPTIONS)
46
+ @options[:stdin] = contents
47
+
48
+ @offenses = []
49
+ @warnings = []
50
+ @errors = []
51
+
52
+ super([path])
53
+
54
+ raise Interrupt if aborting?
55
+ rescue RuboCop::Runner::InfiniteCorrectionLoop => e
56
+ if defined?(::RubyLsp::Requests::Formatting::Error)
57
+ raise ::RubyLsp::Requests::Formatting::Error, e.message
58
+ end
59
+
60
+ raise e
61
+ rescue RuboCop::ValidationError => e
62
+ raise ConfigurationError, e.message
63
+ rescue StandardError => e
64
+ if defined?(::RubyLsp::Requests::Formatting::Error)
65
+ raise ::RubyLsp::Requests::Support::InternalRuboCopError, e
66
+ end
67
+
68
+ raise e
69
+ end
70
+ # rubocop:enable Metrics/MethodLength
71
+
72
+ def formatted_source
73
+ @options[:stdin]
74
+ end
75
+
76
+ private
77
+
78
+ def file_finished(_file, offenses)
79
+ @offenses = offenses
80
+ end
81
+ end
82
+ end
83
+ end
@@ -80,13 +80,13 @@ module RuboCop
80
80
 
81
81
  # Expose the `frozen_string_literal` value coerced to a boolean if possible.
82
82
  #
83
- # @return [Boolean] if value is `true` or `false`
83
+ # @return [Boolean] if value is `true` or `false` in any case
84
84
  # @return [nil] if frozen_string_literal comment isn't found
85
85
  # @return [String] if comment is found but isn't true or false
86
86
  def frozen_string_literal
87
87
  return unless (setting = extract_frozen_string_literal)
88
88
 
89
- case setting
89
+ case setting.downcase
90
90
  when 'true' then true
91
91
  when 'false' then false
92
92
  else
@@ -283,7 +283,7 @@ module RuboCop
283
283
  # is the only text in the comment.
284
284
  #
285
285
  # Case-insensitive and dashes/underscores are acceptable.
286
- # @see https://github.com/ruby/ruby/blob/78b95b4/parse.y#L7134-L7138
286
+ # @see https://github.com/ruby/ruby/blob/78b95b49f8/parse.y#L7134-L7138
287
287
  def extract_frozen_string_literal
288
288
  extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io)
289
289
  end
@@ -243,6 +243,7 @@ module RuboCop
243
243
  option(opts, '--init')
244
244
  option(opts, '-c', '--config FILE')
245
245
  option(opts, '-d', '--debug')
246
+ option(opts, '--plugin FILE') { |f| plugin_feature(f) }
246
247
  option(opts, '-r', '--require FILE') { |f| require_feature(f) }
247
248
  option(opts, '--[no-]color')
248
249
  option(opts, '-v', '--version')
@@ -299,11 +300,25 @@ module RuboCop
299
300
  long_opt[2..].sub('[no-]', '').sub(/ .*/, '').tr('-', '_').gsub(/[\[\]]/, '').to_sym
300
301
  end
301
302
 
302
- def require_feature(file)
303
- # If any features were added on the CLI from `--require`,
303
+ def plugin_feature(file)
304
+ # If any features were added on the CLI from `--plugin`,
304
305
  # add them to the config.
305
- ConfigLoader.add_loaded_features(file)
306
- require file
306
+ ConfigLoaderResolver.new.resolve_plugins(Config.new, file)
307
+ end
308
+
309
+ def require_feature(file)
310
+ if Plugin.plugin_capable?(file)
311
+ # NOTE: Compatibility for before plugins style.
312
+ warn Rainbow(<<~MESSAGE).yellow
313
+ #{file} gem supports plugin, use `--plugin` instead of `--require`.
314
+ MESSAGE
315
+ plugin_feature(file)
316
+ else
317
+ # If any features were added on the CLI from `--require`,
318
+ # add them to the config.
319
+ require file
320
+ ConfigLoader.add_loaded_features(file)
321
+ end
307
322
  end
308
323
  end
309
324
 
@@ -397,7 +412,7 @@ module RuboCop
397
412
  return if @options[:format] == 'junit'
398
413
 
399
414
  raise OptionArgumentError,
400
- format('--display-only-failed can only be used together with --format junit.')
415
+ '--display-only-failed can only be used together with --format junit.'
401
416
  end
402
417
 
403
418
  def validate_display_only_correctable_and_autocorrect
@@ -415,14 +430,13 @@ module RuboCop
415
430
  !@options.key?(:display_only_safe_correctable)
416
431
 
417
432
  raise OptionArgumentError,
418
- format('--display-only-failed cannot be used together with other display options.')
433
+ '--display-only-failed cannot be used together with other display options.'
419
434
  end
420
435
 
421
436
  def validate_lsp_and_editor_mode
422
437
  return if !@options.key?(:lsp) || !@options.key?(:editor_mode)
423
438
 
424
- raise OptionArgumentError,
425
- format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
439
+ raise OptionArgumentError, 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
426
440
  end
427
441
 
428
442
  def validate_autocorrect
@@ -436,7 +450,7 @@ module RuboCop
436
450
  return unless @options.key?(:disable_uncorrectable)
437
451
 
438
452
  raise OptionArgumentError,
439
- format('--disable-uncorrectable can only be used together with --autocorrect.')
453
+ '--disable-uncorrectable can only be used together with --autocorrect.'
440
454
  end
441
455
 
442
456
  def disable_parallel_when_invalid_option_combo
@@ -504,6 +518,7 @@ module RuboCop
504
518
  only_guide_cops: ['Run only cops for rules that link to a',
505
519
  'style guide.'],
506
520
  except: 'Exclude the given cop(s).',
521
+ plugin: 'Load a RuboCop plugin.',
507
522
  require: 'Require Ruby file.',
508
523
  config: 'Specify configuration file.',
509
524
  auto_gen_config: ['Generate a configuration file acting as a',
@@ -542,8 +557,8 @@ module RuboCop
542
557
  only_recognized_file_types: ['Inspect files given on the command line only if',
543
558
  'they are listed in `AllCops/Include` parameters',
544
559
  'of user configuration or default configuration.'],
545
- ignore_disable_comments: ['Run cops even when they are disabled locally',
546
- 'by a `rubocop:disable` directive.'],
560
+ ignore_disable_comments: ['Report offenses even if they have been manually disabled',
561
+ 'with a `rubocop:disable` or `rubocop:todo` directive.'],
547
562
  ignore_parent_exclusion: ['Prevent from inheriting `AllCops/Exclude` from',
548
563
  'parent folders.'],
549
564
  ignore_unrecognized_cops: ['Ignore unrecognized cops or departments in the config.'],
@@ -579,7 +594,8 @@ module RuboCop
579
594
  'when combined with --display-only-correctable.'],
580
595
  show_cops: ['Shows the given cops, or all cops by',
581
596
  'default, and their configurations for the',
582
- 'current directory.'],
597
+ 'current directory.',
598
+ 'You can use `*` as a wildcard.'],
583
599
  show_docs_url: ['Display url to documentation for the given',
584
600
  'cops, or base url by default.'],
585
601
  fail_fast: ['Inspect files in order of modification',
@@ -28,20 +28,27 @@ module RuboCop
28
28
  end
29
29
  end
30
30
 
31
+ def remote_file?(uri)
32
+ uri.start_with?('http://', 'https://')
33
+ end
34
+
31
35
  SMART_PATH_CACHE = {} # rubocop:disable Style/MutableConstant
32
36
  private_constant :SMART_PATH_CACHE
33
37
 
34
38
  def smart_path(path)
35
- SMART_PATH_CACHE[path] ||= begin
36
- # Ideally, we calculate this relative to the project root.
37
- base_dir = Dir.pwd
38
-
39
- if path.start_with? base_dir
40
- relative_path(path, base_dir)
39
+ SMART_PATH_CACHE[path] ||=
40
+ if path.is_a?(RemoteConfig)
41
+ path.uri.to_s
41
42
  else
42
- path
43
+ # Ideally, we calculate this relative to the project root.
44
+ base_dir = Dir.pwd
45
+
46
+ if path.start_with? base_dir
47
+ relative_path(path, base_dir)
48
+ else
49
+ path
50
+ end
43
51
  end
44
- end
45
52
  end
46
53
 
47
54
  # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lint_roller/context'
4
+ require_relative 'not_supported_error'
5
+
6
+ module RuboCop
7
+ module Plugin
8
+ # A class for integrating plugin configurations into RuboCop.
9
+ # Handles configuration merging, validation, and compatibility for plugins.
10
+ # @api private
11
+ class ConfigurationIntegrator
12
+ class << self
13
+ def integrate_plugins_into_rubocop_config(rubocop_config, plugins)
14
+ default_config = ConfigLoader.default_configuration
15
+ runner_context = create_context(rubocop_config)
16
+
17
+ validate_plugins!(plugins, runner_context)
18
+
19
+ plugin_config = combine_rubocop_configs(default_config, runner_context, plugins).to_h
20
+
21
+ merge_plugin_config_into_all_cops!(default_config, plugin_config)
22
+ merge_plugin_config_into_default_config!(default_config, plugin_config)
23
+ end
24
+
25
+ private
26
+
27
+ def create_context(rubocop_config)
28
+ LintRoller::Context.new(
29
+ runner: :rubocop,
30
+ runner_version: Version.version,
31
+ engine: :rubocop,
32
+ engine_version: Version.version,
33
+ target_ruby_version: rubocop_config.target_ruby_version
34
+ )
35
+ end
36
+
37
+ def validate_plugins!(plugins, runner_context)
38
+ unsupported_plugins = plugins.reject { |plugin| plugin.supported?(runner_context) }
39
+ return if unsupported_plugins.none?
40
+
41
+ raise Plugin::NotSupportedError, unsupported_plugins
42
+ end
43
+
44
+ def combine_rubocop_configs(default_config, runner_context, plugins)
45
+ fake_out_rubocop_default_configuration(default_config) do |fake_config|
46
+ all_cop_keys_configured_by_plugins = []
47
+
48
+ plugins.reduce(fake_config) do |combined_config, plugin|
49
+ RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, combined_config)
50
+
51
+ print 'Plugin ' if ConfigLoader.debug
52
+
53
+ plugin_config, plugin_config_path = load_plugin_rubocop_config(plugin, runner_context)
54
+
55
+ plugin_config['AllCops'], all_cop_keys_configured_by_plugins = merge_all_cop_settings(
56
+ combined_config['AllCops'], plugin_config['AllCops'],
57
+ all_cop_keys_configured_by_plugins
58
+ )
59
+
60
+ plugin_config.make_excludes_absolute
61
+
62
+ ConfigLoader.merge_with_default(plugin_config, plugin_config_path)
63
+ end
64
+ end
65
+ end
66
+
67
+ def merge_plugin_config_into_all_cops!(rubocop_config, plugin_config)
68
+ rubocop_config['AllCops'].merge!(plugin_config['AllCops'])
69
+ end
70
+
71
+ def merge_plugin_config_into_default_config!(default_config, plugin_config)
72
+ plugin_config.each do |key, value|
73
+ default_config[key] = if default_config[key].is_a?(Hash)
74
+ resolver.merge(default_config[key], value)
75
+ else
76
+ value
77
+ end
78
+ end
79
+ end
80
+
81
+ def fake_out_rubocop_default_configuration(default_config)
82
+ orig_default_config = ConfigLoader.instance_variable_get(:@default_configuration)
83
+
84
+ result = yield default_config
85
+
86
+ ConfigLoader.instance_variable_set(:@default_configuration, orig_default_config)
87
+
88
+ result
89
+ end
90
+
91
+ # rubocop:disable Metrics/AbcSize
92
+ def load_plugin_rubocop_config(plugin, runner_context)
93
+ rules = plugin.rules(runner_context)
94
+
95
+ case rules.type
96
+ when :path
97
+ [ConfigLoader.load_file(rules.value, check: false), rules.value]
98
+ when :object
99
+ path = plugin.method(:rules).source_location[0]
100
+ [Config.create(rules.value, path, check: true), path]
101
+ when :error
102
+ plugin_name = plugin.about&.name || plugin.inspect
103
+ error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
104
+
105
+ raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
106
+ end
107
+ end
108
+ # rubocop:enable Metrics/AbcSize
109
+
110
+ # This is how we ensure "first-in wins": plugins can override AllCops settings that are
111
+ # set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
112
+ # have exclusive first-in-wins rights to that setting.
113
+ #
114
+ # The one exception to this are array fields, because we don't want to
115
+ # overwrite the AllCops defaults but rather munge the arrays (`existing |
116
+ # new`) to allow plugins to add to the array, for example Include and
117
+ # Exclude paths and patterns.
118
+ def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
119
+ return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash)
120
+
121
+ combined_all_cops = existing_all_cops.dup
122
+ combined_configured_keys = already_configured_keys.dup
123
+
124
+ new_all_cops.each do |key, value|
125
+ if combined_all_cops[key].is_a?(Array) && value.is_a?(Array)
126
+ combined_all_cops[key] |= value
127
+ combined_configured_keys |= [key]
128
+ elsif !combined_configured_keys.include?(key)
129
+ combined_all_cops[key] = value
130
+ combined_configured_keys << key
131
+ end
132
+ end
133
+
134
+ [combined_all_cops, combined_configured_keys]
135
+ end
136
+
137
+ def resolver
138
+ @resolver ||= ConfigLoaderResolver.new
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Plugin
5
+ # An exception raised when a plugin fails to load.
6
+ # @api private
7
+ class LoadError < Error
8
+ def initialize(plugin_name)
9
+ super
10
+
11
+ @plugin_name = plugin_name
12
+ end
13
+
14
+ def message
15
+ <<~MESSAGE
16
+ Failed to load plugin `#{@plugin_name}` because the corresponding plugin class could not be determined for instantiation.
17
+ Try upgrading it first (e.g., `bundle update #{@plugin_name}`).
18
+ If `#{@plugin_name}` is not yet a plugin, use `require: #{@plugin_name}` instead of `plugins: #{@plugin_name}` in your configuration.
19
+
20
+ For further assistance, check with the developer regarding the following points:
21
+ https://docs.rubocop.org/rubocop/plugin_migration_guide.html
22
+ MESSAGE
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../feature_loader'
4
+ require_relative 'load_error'
5
+
6
+ module RuboCop
7
+ module Plugin
8
+ # A class for loading and resolving plugins.
9
+ # @api private
10
+ class Loader
11
+ # rubocop:disable Layout/LineLength
12
+ DEFAULT_PLUGIN_CONFIG = {
13
+ 'enabled' => true,
14
+ 'require_path' => nil, # If not set, will be set to the plugin name
15
+ 'plugin_class_name' => nil # If not set, looks for gemspec `spec.metadata["default_lint_roller_plugin"]`
16
+ }.freeze
17
+
18
+ # rubocop:enable Layout/LineLength
19
+ class << self
20
+ def load(plugins)
21
+ normalized_plugin_configs = normalize(plugins)
22
+ normalized_plugin_configs.filter_map do |plugin_name, plugin_config|
23
+ next unless plugin_config['enabled']
24
+
25
+ plugin_class = constantize_plugin_from(plugin_name, plugin_config)
26
+
27
+ plugin_class.new(plugin_config)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # rubocop:disable Metrics/MethodLength
34
+ def normalize(plugin_configs)
35
+ plugin_configs.to_h do |plugin_config|
36
+ if plugin_config == Plugin::OBSOLETE_INTERNAL_AFFAIRS_PLUGIN_NAME
37
+ warn Rainbow(<<~MESSAGE).yellow
38
+ Specify `rubocop-internal_affairs` instead of `rubocop/cop/internal_affairs` in your configuration.
39
+ MESSAGE
40
+ plugin_config = Plugin::INTERNAL_AFFAIRS_PLUGIN_NAME
41
+ end
42
+
43
+ if plugin_config.is_a?(Hash)
44
+ plugin_name = plugin_config.keys.first
45
+
46
+ [
47
+ plugin_name, DEFAULT_PLUGIN_CONFIG.merge(
48
+ { 'require_path' => plugin_name }, plugin_config.values.first
49
+ )
50
+ ]
51
+ # NOTE: Compatibility is maintained when `require: rubocop/cop/internal_affairs` remains
52
+ # specified in `.rubocop.yml`.
53
+ elsif (builtin_plugin_config = Plugin::BUILTIN_INTERNAL_PLUGINS[plugin_config])
54
+ [plugin_config, builtin_plugin_config]
55
+ else
56
+ [plugin_config, DEFAULT_PLUGIN_CONFIG.merge('require_path' => plugin_config)]
57
+ end
58
+ end
59
+ end
60
+
61
+ def constantize_plugin_from(plugin_name, plugin_config)
62
+ if plugin_name.is_a?(String) || plugin_name.is_a?(Symbol)
63
+ constantize(plugin_name, plugin_config)
64
+ else
65
+ plugin_name
66
+ end
67
+ end
68
+
69
+ # rubocop:enable Metrics/MethodLength
70
+ def constantize(plugin_name, plugin_config)
71
+ require_plugin(plugin_config['require_path'])
72
+
73
+ if (constant_name = plugin_config['plugin_class_name'])
74
+ begin
75
+ Kernel.const_get(constant_name)
76
+ rescue StandardError
77
+ raise <<~MESSAGE
78
+ Failed while configuring plugin `#{plugin_name}': no constant with name `#{constant_name}' was found.
79
+ MESSAGE
80
+ end
81
+ else
82
+ constantize_plugin_from_gemspec_metadata(plugin_name)
83
+ end
84
+ end
85
+
86
+ def require_plugin(require_path)
87
+ FeatureLoader.load(config_directory_path: Dir.pwd, feature: require_path)
88
+ end
89
+
90
+ def constantize_plugin_from_gemspec_metadata(plugin_name)
91
+ plugin_class_name = Gem.loaded_specs[plugin_name].metadata['default_lint_roller_plugin']
92
+
93
+ Kernel.const_get(plugin_class_name)
94
+ rescue LoadError, StandardError
95
+ raise Plugin::LoadError, plugin_name
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Plugin
5
+ # An exception raised when a plugin is not supported by the RuboCop engine.
6
+ # @api private
7
+ class NotSupportedError < Error
8
+ def initialize(unsupported_plugins)
9
+ super
10
+
11
+ @unsupported_plugins = unsupported_plugins
12
+ end
13
+
14
+ def message
15
+ if @unsupported_plugins.one?
16
+ about = @unsupported_plugins.first.about
17
+
18
+ "#{about.name} #{about.version} is not a plugin supported by RuboCop engine."
19
+ else
20
+ unsupported_plugin_names = @unsupported_plugins.map do |plugin|
21
+ "#{plugin.about.name} #{plugin.about.version}"
22
+ end.join(', ')
23
+
24
+ "#{unsupported_plugin_names} are not plugins supported by RuboCop engine."
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -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))