rubocop 1.66.0 → 1.72.1

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 (434) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +160 -14
  5. data/config/internal_affairs.yml +11 -0
  6. data/lib/rubocop/cached_data.rb +12 -4
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
  8. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  9. data/lib/rubocop/cli/command/lsp.rb +2 -2
  10. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  11. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  12. data/lib/rubocop/cli/command/version.rb +2 -2
  13. data/lib/rubocop/comment_config.rb +6 -10
  14. data/lib/rubocop/config.rb +21 -20
  15. data/lib/rubocop/config_loader.rb +62 -16
  16. data/lib/rubocop/config_loader_resolver.rb +36 -11
  17. data/lib/rubocop/config_validator.rb +25 -18
  18. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  19. data/lib/rubocop/cop/base.rb +13 -3
  20. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  21. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  22. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  23. data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
  24. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  25. data/lib/rubocop/cop/cop.rb +8 -0
  26. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  28. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  30. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  31. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  32. data/lib/rubocop/cop/generator.rb +6 -0
  33. data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
  34. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  35. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  36. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  37. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  38. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  39. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  40. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  41. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  42. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  43. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  44. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  45. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  46. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  47. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  48. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  49. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  50. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +11 -2
  51. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  52. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  53. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  54. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
  55. data/lib/rubocop/cop/internal_affairs.rb +6 -0
  56. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +6 -2
  57. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  58. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  59. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  60. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  61. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  62. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  63. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  64. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  65. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -3
  66. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  67. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +3 -3
  68. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  69. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  70. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  71. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  72. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  73. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  74. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  75. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  76. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  77. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  78. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  79. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  80. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  81. data/lib/rubocop/cop/layout/indentation_width.rb +11 -12
  82. data/lib/rubocop/cop/layout/leading_comment_space.rb +71 -1
  83. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  84. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  85. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  86. data/lib/rubocop/cop/layout/line_length.rb +119 -4
  87. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  88. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  89. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  90. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  91. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  92. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  93. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  94. data/lib/rubocop/cop/layout/redundant_line_break.rb +10 -41
  95. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -3
  96. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  97. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  98. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  99. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  100. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  101. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  102. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  103. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -20
  104. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  105. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  106. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  107. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  108. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
  109. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  110. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  111. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  112. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  113. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  114. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  115. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  116. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  117. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  118. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  119. data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
  120. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  121. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  122. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  123. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  124. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
  125. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  126. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  127. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  128. data/lib/rubocop/cop/lint/duplicate_set_element.rb +87 -0
  129. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  130. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  131. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  132. data/lib/rubocop/cop/lint/ensure_return.rb +1 -4
  133. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  134. data/lib/rubocop/cop/lint/float_comparison.rb +20 -9
  135. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  136. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  137. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  138. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +11 -5
  139. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  140. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +8 -14
  141. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -0
  142. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  143. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +49 -8
  144. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  145. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -6
  146. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  147. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  148. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  149. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  150. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  151. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  152. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  153. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  154. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  155. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  156. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  157. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  158. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +6 -11
  159. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  160. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  161. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +13 -8
  162. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  163. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  164. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +231 -0
  165. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  166. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  167. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  168. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  169. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  170. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +109 -41
  171. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  172. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  173. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  174. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  175. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  176. data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -2
  177. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  178. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  179. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  180. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  181. data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
  182. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  183. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  184. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  185. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  186. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  187. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +74 -0
  188. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  189. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  190. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  191. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  192. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  193. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  194. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  195. data/lib/rubocop/cop/lint/void.rb +8 -11
  196. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  197. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  198. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  199. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  200. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  201. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  202. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  203. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  204. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
  205. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  206. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  207. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  208. data/lib/rubocop/cop/mixin/check_line_breakable.rb +20 -10
  209. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  210. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  211. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  212. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  213. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -2
  214. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  215. data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
  216. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  217. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  218. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  219. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  220. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  221. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  222. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  223. data/lib/rubocop/cop/mixin/range_help.rb +3 -4
  224. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  225. data/lib/rubocop/cop/mixin/statement_modifier.rb +11 -5
  226. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  227. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  228. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  229. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  230. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  231. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  232. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  233. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  234. data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
  235. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  236. data/lib/rubocop/cop/naming/predicate_name.rb +45 -1
  237. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  238. data/lib/rubocop/cop/naming/variable_name.rb +3 -4
  239. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  240. data/lib/rubocop/cop/offense.rb +4 -5
  241. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  242. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  243. data/lib/rubocop/cop/style/access_modifier_declarations.rb +96 -28
  244. data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
  245. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  246. data/lib/rubocop/cop/style/and_or.rb +1 -1
  247. data/lib/rubocop/cop/style/arguments_forwarding.rb +78 -22
  248. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  249. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  250. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  251. data/lib/rubocop/cop/style/block_delimiters.rb +49 -19
  252. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  253. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  254. data/lib/rubocop/cop/style/collection_compact.rb +10 -10
  255. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  256. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  257. data/lib/rubocop/cop/style/combinable_loops.rb +9 -2
  258. data/lib/rubocop/cop/style/commented_keyword.rb +17 -1
  259. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  260. data/lib/rubocop/cop/style/conditional_assignment.rb +26 -26
  261. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  262. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  263. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  264. data/lib/rubocop/cop/style/documentation.rb +1 -1
  265. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  266. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  267. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  268. data/lib/rubocop/cop/style/empty_else.rb +5 -2
  269. data/lib/rubocop/cop/style/empty_literal.rb +2 -2
  270. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  271. data/lib/rubocop/cop/style/endless_method.rb +1 -14
  272. data/lib/rubocop/cop/style/eval_with_location.rb +2 -2
  273. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  274. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  275. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  276. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  277. data/lib/rubocop/cop/style/file_null.rb +89 -0
  278. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  279. data/lib/rubocop/cop/style/float_division.rb +8 -4
  280. data/lib/rubocop/cop/style/for.rb +0 -1
  281. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  282. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  283. data/lib/rubocop/cop/style/guard_clause.rb +16 -3
  284. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  285. data/lib/rubocop/cop/style/hash_each_methods.rb +9 -6
  286. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  287. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  288. data/lib/rubocop/cop/style/hash_syntax.rb +8 -5
  289. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  290. data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
  291. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  292. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -3
  293. data/lib/rubocop/cop/style/if_with_semicolon.rb +28 -6
  294. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  295. data/lib/rubocop/cop/style/inverse_methods.rb +6 -7
  296. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  297. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  298. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  299. data/lib/rubocop/cop/style/lambda.rb +1 -1
  300. data/lib/rubocop/cop/style/lambda_call.rb +3 -2
  301. data/lib/rubocop/cop/style/magic_comment_format.rb +3 -8
  302. data/lib/rubocop/cop/style/map_into_array.rb +61 -12
  303. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  304. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  305. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +32 -20
  306. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  307. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  308. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  309. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  310. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  311. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  312. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  313. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  314. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  315. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  316. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  317. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  318. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  319. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  320. data/lib/rubocop/cop/style/not.rb +1 -1
  321. data/lib/rubocop/cop/style/object_then.rb +14 -15
  322. data/lib/rubocop/cop/style/one_line_conditional.rb +29 -4
  323. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  324. data/lib/rubocop/cop/style/operator_method_call.rb +25 -7
  325. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  326. data/lib/rubocop/cop/style/parallel_assignment.rb +9 -18
  327. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  328. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  329. data/lib/rubocop/cop/style/proc.rb +1 -2
  330. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  331. data/lib/rubocop/cop/style/raise_args.rb +7 -5
  332. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  333. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  334. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  335. data/lib/rubocop/cop/style/redundant_begin.rb +5 -1
  336. data/lib/rubocop/cop/style/redundant_condition.rb +39 -24
  337. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  338. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  339. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  340. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  341. data/lib/rubocop/cop/style/redundant_format.rb +222 -0
  342. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  343. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  344. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +1 -1
  345. data/lib/rubocop/cop/style/redundant_line_continuation.rb +56 -17
  346. data/lib/rubocop/cop/style/redundant_parentheses.rb +38 -24
  347. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  348. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  349. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  350. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  351. data/lib/rubocop/cop/style/redundant_self.rb +8 -15
  352. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  353. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  354. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  355. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  356. data/lib/rubocop/cop/style/require_order.rb +1 -1
  357. data/lib/rubocop/cop/style/rescue_modifier.rb +15 -4
  358. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  359. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
  360. data/lib/rubocop/cop/style/safe_navigation.rb +105 -51
  361. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  362. data/lib/rubocop/cop/style/select_by_regexp.rb +10 -7
  363. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  364. data/lib/rubocop/cop/style/semicolon.rb +2 -2
  365. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  366. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  367. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  368. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  369. data/lib/rubocop/cop/style/single_line_do_end_block.rb +12 -3
  370. data/lib/rubocop/cop/style/single_line_methods.rb +3 -4
  371. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  372. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -5
  373. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  374. data/lib/rubocop/cop/style/string_concatenation.rb +14 -13
  375. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  376. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  377. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  378. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  379. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  380. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  381. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  382. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  383. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  384. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  385. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  386. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  387. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  388. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  389. data/lib/rubocop/cop/team.rb +8 -1
  390. data/lib/rubocop/cop/util.rb +12 -5
  391. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  392. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  393. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  394. data/lib/rubocop/cop/variable_force/variable.rb +18 -2
  395. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  396. data/lib/rubocop/cop/variable_force.rb +4 -10
  397. data/lib/rubocop/cops_documentation_generator.rb +100 -51
  398. data/lib/rubocop/directive_comment.rb +44 -10
  399. data/lib/rubocop/file_finder.rb +9 -4
  400. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  401. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  402. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  403. data/lib/rubocop/lsp/logger.rb +2 -2
  404. data/lib/rubocop/lsp/routes.rb +7 -23
  405. data/lib/rubocop/lsp/runtime.rb +18 -48
  406. data/lib/rubocop/lsp/server.rb +0 -3
  407. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  408. data/lib/rubocop/magic_comment.rb +3 -3
  409. data/lib/rubocop/options.rb +28 -12
  410. data/lib/rubocop/path_util.rb +15 -8
  411. data/lib/rubocop/plugin/configuration_integrator.rb +141 -0
  412. data/lib/rubocop/plugin/load_error.rb +26 -0
  413. data/lib/rubocop/plugin/loader.rb +100 -0
  414. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  415. data/lib/rubocop/plugin.rb +39 -0
  416. data/lib/rubocop/rake_task.rb +4 -1
  417. data/lib/rubocop/result_cache.rb +13 -13
  418. data/lib/rubocop/rspec/cop_helper.rb +7 -0
  419. data/lib/rubocop/rspec/expect_offense.rb +7 -2
  420. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  421. data/lib/rubocop/rspec/support.rb +1 -2
  422. data/lib/rubocop/runner.rb +22 -12
  423. data/lib/rubocop/server/cache.rb +39 -1
  424. data/lib/rubocop/server/cli.rb +2 -2
  425. data/lib/rubocop/server/core.rb +1 -0
  426. data/lib/rubocop/target_finder.rb +1 -0
  427. data/lib/rubocop/target_ruby.rb +28 -13
  428. data/lib/rubocop/version.rb +42 -6
  429. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  430. data/lib/rubocop.rb +29 -0
  431. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  432. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
  433. metadata +75 -19
  434. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,141 @@
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
+ ConfigLoader.merge_with_default(plugin_config, plugin_config_path)
61
+ end
62
+ end
63
+ end
64
+
65
+ def merge_plugin_config_into_all_cops!(rubocop_config, plugin_config)
66
+ rubocop_config['AllCops'].merge!(plugin_config['AllCops'])
67
+ end
68
+
69
+ def merge_plugin_config_into_default_config!(default_config, plugin_config)
70
+ plugin_config.each do |key, value|
71
+ default_config[key] = if default_config[key].is_a?(Hash)
72
+ resolver.merge(default_config[key], value)
73
+ else
74
+ value
75
+ end
76
+ end
77
+ end
78
+
79
+ def fake_out_rubocop_default_configuration(default_config)
80
+ orig_default_config = ConfigLoader.instance_variable_get(:@default_configuration)
81
+
82
+ result = yield default_config
83
+
84
+ ConfigLoader.instance_variable_set(:@default_configuration, orig_default_config)
85
+
86
+ result
87
+ end
88
+
89
+ # rubocop:disable Metrics/AbcSize
90
+ def load_plugin_rubocop_config(plugin, runner_context)
91
+ rules = plugin.rules(runner_context)
92
+
93
+ case rules.type
94
+ when :path
95
+ [ConfigLoader.load_file(rules.value, check: false), rules.value]
96
+ when :object
97
+ path = plugin.method(:rules).source_location[0]
98
+ [Config.create(rules.value, path, check: true), path]
99
+ when :error
100
+ plugin_name = plugin.about&.name || plugin.inspect
101
+ error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
102
+
103
+ raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
104
+ end
105
+ end
106
+ # rubocop:enable Metrics/AbcSize
107
+
108
+ # This is how we ensure "first-in wins": plugins can override AllCops settings that are
109
+ # set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
110
+ # have exclusive first-in-wins rights to that setting.
111
+ #
112
+ # The one exception to this are array fields, because we don't want to
113
+ # overwrite the AllCops defaults but rather munge the arrays (`existing |
114
+ # new`) to allow plugins to add to the array, for example Include and
115
+ # Exclude paths and patterns.
116
+ def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
117
+ return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash)
118
+
119
+ combined_all_cops = existing_all_cops.dup
120
+ combined_configured_keys = already_configured_keys.dup
121
+
122
+ new_all_cops.each do |key, value|
123
+ if combined_all_cops[key].is_a?(Array) && value.is_a?(Array)
124
+ combined_all_cops[key] |= value
125
+ combined_configured_keys |= [key]
126
+ elsif !combined_configured_keys.include?(key)
127
+ combined_all_cops[key] = value
128
+ combined_configured_keys << key
129
+ end
130
+ end
131
+
132
+ [combined_all_cops, combined_configured_keys]
133
+ end
134
+
135
+ def resolver
136
+ @resolver ||= ConfigLoaderResolver.new
137
+ end
138
+ end
139
+ end
140
+ end
141
+ 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,39 @@
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
+ return false unless (gem = Gem.loaded_specs[feature_name])
26
+
27
+ !!gem.metadata['default_lint_roller_plugin']
28
+ end
29
+
30
+ def integrate_plugins(rubocop_config, plugins)
31
+ plugins = Plugin::Loader.load(plugins)
32
+
33
+ ConfigurationIntegrator.integrate_plugins_into_rubocop_config(rubocop_config, plugins)
34
+
35
+ plugins
36
+ end
37
+ end
38
+ end
39
+ 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))
@@ -13,6 +13,13 @@ module CopHelper
13
13
  let(:parser_engine) { ENV.fetch('PARSER_ENGINE', :parser_whitequark).to_sym }
14
14
  let(:rails_version) { false }
15
15
 
16
+ before(:all) do
17
+ plugins = Gem.loaded_specs.filter_map do |feature_name, feature_specification|
18
+ feature_name if feature_specification.metadata['default_lint_roller_plugin']
19
+ end
20
+ RuboCop::Plugin.integrate_plugins(RuboCop::Config.new, plugins)
21
+ end
22
+
16
23
  def inspect_source(source, file = nil)
17
24
  RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
18
25
  RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
@@ -169,6 +169,7 @@ module RuboCop
169
169
  raise 'Expected correction but no corrections were made' if new_source == source
170
170
 
171
171
  expect(new_source).to eq(correction)
172
+ expect(@processed_source).to be_valid_syntax, 'Expected correction to be valid syntax'
172
173
  end
173
174
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
174
175
 
@@ -189,7 +190,10 @@ module RuboCop
189
190
  def expect_no_offenses(source, file = nil)
190
191
  offenses = inspect_source(source, file)
191
192
 
192
- 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, [])
193
197
  actual_annotations = expected_annotations.with_offense_annotations(offenses)
194
198
  expect(actual_annotations.to_s).to eq(source)
195
199
  end
@@ -220,7 +224,8 @@ module RuboCop
220
224
 
221
225
  # Parsed representation of code annotated with the `^^^ Message` style
222
226
  class AnnotatedSource
223
- ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
227
+ # Ignore escaped carets, don't treat as annotations
228
+ ANNOTATION_PATTERN = /\A\s*((?<!\\)\^+|\^{}) ?/.freeze
224
229
  ABBREV = "[...]\n"
225
230
 
226
231
  # @param annotated_source [String] string passed to the matchers
@@ -98,6 +98,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
98
98
 
99
99
  let(:cop_options) { {} }
100
100
 
101
+ let(:gem_versions) { {} }
102
+
101
103
  ### Utilities
102
104
 
103
105
  def source_range(range, buffer: source_buffer)
@@ -138,7 +140,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
138
140
 
139
141
  allow(config).to receive(:gem_versions_in_target).and_return(
140
142
  {
141
- 'railties' => rails_version_in_gemfile
143
+ 'railties' => rails_version_in_gemfile,
144
+ **gem_versions.transform_values { |value| Gem::Version.new(value) }
142
145
  }
143
146
  )
144
147
 
@@ -4,13 +4,12 @@
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
@@ -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
 
@@ -139,7 +135,7 @@ module RuboCop
139
135
  offenses = process_file(file)
140
136
  yield file
141
137
 
142
- if offenses.any? { |o| considered_failure?(o) }
138
+ if offenses.any? { |o| considered_failure?(o) && offense_displayed?(o) }
143
139
  break false if @options[:fail_fast]
144
140
 
145
141
  next false
@@ -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
@@ -362,6 +361,13 @@ module RuboCop
362
361
  self.class.ruby_extractors.find do |ruby_extractor|
363
362
  result = ruby_extractor.call(processed_source)
364
363
  break result if result
364
+ rescue StandardError
365
+ location = if ruby_extractor.is_a?(Proc)
366
+ ruby_extractor.source_location
367
+ else
368
+ ruby_extractor.method(:call).source_location
369
+ end
370
+ raise Error, "Ruby extractor #{location[0]} failed to process #{processed_source.path}."
365
371
  end
366
372
  end
367
373
 
@@ -433,18 +439,22 @@ module RuboCop
433
439
  !offense.corrected? && offense.severity >= minimum_severity_to_fail
434
440
  end
435
441
 
436
- def offenses_to_report(offenses)
442
+ def offense_displayed?(offense)
437
443
  if @options[:display_only_fail_level_offenses]
438
- offenses.select { |o| considered_failure?(o) }
444
+ considered_failure?(offense)
439
445
  elsif @options[:display_only_safe_correctable]
440
- offenses.select { |o| supports_safe_autocorrect?(o) }
446
+ supports_safe_autocorrect?(offense)
441
447
  elsif @options[:display_only_correctable]
442
- offenses.select(&:correctable?)
448
+ offense.correctable?
443
449
  else
444
- offenses
450
+ true
445
451
  end
446
452
  end
447
453
 
454
+ def offenses_to_report(offenses)
455
+ offenses.select { |o| offense_displayed?(o) }
456
+ end
457
+
448
458
  def supports_safe_autocorrect?(offense)
449
459
  cop_class = Cop::Registry.global.find_by_cop_name(offense.cop_name)
450
460
  default_cfg = default_config(offense.cop_name)
@@ -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.
@@ -43,13 +45,20 @@ module RuboCop
43
45
  @project_dir_cache_key ||= project_dir[1..].tr('/', '+')
44
46
  end
45
47
 
48
+ # rubocop:disable Metrics/AbcSize
46
49
  def restart_key
47
50
  lockfile_path = LOCKFILE_NAMES.map do |lockfile_name|
48
51
  Pathname(project_dir).join(lockfile_name)
49
52
  end.find(&:exist?)
53
+ version_data = lockfile_path&.read || RuboCop::Version::STRING
54
+ config_data = Pathname(ConfigFinder.find_config_path(Dir.pwd)).read
55
+ yaml = YAML.safe_load(config_data, permitted_classes: [Regexp, Symbol], aliases: true)
56
+ inherit_from_data = inherit_from_data(yaml)
57
+ require_data = require_data(yaml)
50
58
 
51
- Digest::SHA1.hexdigest(lockfile_path&.read || RuboCop::Version::STRING)
59
+ Digest::SHA1.hexdigest(version_data + config_data + inherit_from_data + require_data)
52
60
  end
61
+ # rubocop:enable Metrics/AbcSize
53
62
 
54
63
  def dir
55
64
  Pathname.new(File.join(cache_path, project_dir_cache_key)).tap do |d|
@@ -159,6 +168,35 @@ module RuboCop
159
168
  def write_version_file(version)
160
169
  version_path.write(version)
161
170
  end
171
+
172
+ def inherit_from_data(yaml)
173
+ return '' unless (inherit_from_paths = yaml['inherit_from'])
174
+
175
+ Array(inherit_from_paths).map do |path|
176
+ next if PathUtil.remote_file?(path)
177
+
178
+ path = Pathname(path)
179
+
180
+ path.exist? ? path.read : ''
181
+ end.join
182
+ end
183
+
184
+ def require_data(yaml)
185
+ return '' unless (require_paths = yaml['require'])
186
+
187
+ Array(require_paths).map do |path|
188
+ # NOTE: This targets only relative or absolute path specifications.
189
+ # For example, specifications like `require: rubocop-performance`,
190
+ # which can be loaded from `$LOAD_PATH`, are ignored.
191
+ next unless path.start_with?('.', '/')
192
+
193
+ # NOTE: `.so` files are not typically specified, so only `.rb` files are targeted.
194
+ path = "#{path}.rb" unless path.end_with?('.rb')
195
+ path = Pathname(path)
196
+
197
+ path.exist? ? path.read : ''
198
+ end.join
199
+ end
162
200
  end
163
201
  end
164
202
  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') }