rubocop 1.69.2 → 1.74.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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +122 -17
  5. data/config/internal_affairs.yml +20 -0
  6. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  7. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  8. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  9. data/lib/rubocop/comment_config.rb +2 -2
  10. data/lib/rubocop/config.rb +17 -4
  11. data/lib/rubocop/config_loader.rb +48 -9
  12. data/lib/rubocop/config_loader_resolver.rb +36 -10
  13. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  14. data/lib/rubocop/config_obsoletion.rb +1 -1
  15. data/lib/rubocop/config_validator.rb +19 -9
  16. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  17. data/lib/rubocop/cop/base.rb +6 -0
  18. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  19. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  21. data/lib/rubocop/cop/internal_affairs/example_description.rb +7 -3
  22. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  23. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  24. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  25. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  26. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  27. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  28. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  29. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  30. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  31. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  32. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  33. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  34. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  35. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  36. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  37. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  38. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  39. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  40. data/lib/rubocop/cop/layout/block_alignment.rb +3 -1
  41. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  42. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  43. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  44. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  45. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  46. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  47. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +27 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  49. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  50. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  51. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  52. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  53. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  54. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  55. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  59. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  60. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  61. data/lib/rubocop/cop/layout/line_length.rb +4 -3
  62. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  63. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  64. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  65. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  66. data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -6
  67. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  68. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  69. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  70. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  71. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  72. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  73. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  74. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  75. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  76. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  77. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  78. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  79. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  80. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  81. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  82. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  83. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  84. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  85. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  86. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  87. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  88. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  89. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  90. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  91. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  92. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  93. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  94. data/lib/rubocop/cop/lint/float_comparison.rb +6 -8
  95. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  96. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  97. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  98. data/lib/rubocop/cop/lint/literal_as_condition.rb +103 -9
  99. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  100. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  101. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -3
  102. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  103. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -4
  104. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  105. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  106. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  107. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  108. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  109. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  110. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  111. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  112. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  113. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +258 -0
  114. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  115. data/lib/rubocop/cop/lint/return_in_void_context.rb +4 -11
  116. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  117. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  118. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  119. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  120. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  121. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  122. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  123. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  124. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  125. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  126. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  127. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  128. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  129. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  130. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  131. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  132. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  133. data/lib/rubocop/cop/lint/void.rb +11 -9
  134. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  135. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  136. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  137. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  138. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  139. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  140. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  141. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  142. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  143. data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -11
  144. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
  145. data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
  146. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  147. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  148. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  149. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  150. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  151. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  152. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  153. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  154. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  155. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  156. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  157. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  158. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  159. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  160. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  161. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  162. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  163. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  164. data/lib/rubocop/cop/naming/variable_name.rb +64 -6
  165. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  166. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  167. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  168. data/lib/rubocop/cop/style/and_or.rb +1 -1
  169. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  170. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  171. data/lib/rubocop/cop/style/block_delimiters.rb +7 -20
  172. data/lib/rubocop/cop/style/class_and_module_children.rb +35 -10
  173. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  174. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  175. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  176. data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
  177. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  178. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  179. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  180. data/lib/rubocop/cop/style/documentation.rb +1 -1
  181. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  182. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  183. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  184. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  185. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  186. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  187. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  188. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  189. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  190. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  191. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  192. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  193. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  194. data/lib/rubocop/cop/style/float_division.rb +8 -4
  195. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  196. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  197. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  198. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  199. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  200. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  201. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  202. data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
  203. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  204. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  205. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  206. data/lib/rubocop/cop/style/inverse_methods.rb +14 -11
  207. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  208. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  209. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  210. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  211. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  212. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  213. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +22 -15
  214. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  215. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  216. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  217. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  218. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  219. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -2
  220. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  221. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  222. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  223. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  224. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  225. data/lib/rubocop/cop/style/object_then.rb +13 -15
  226. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  227. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  228. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  229. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  230. data/lib/rubocop/cop/style/proc.rb +1 -2
  231. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  232. data/lib/rubocop/cop/style/raise_args.rb +6 -4
  233. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  234. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  235. data/lib/rubocop/cop/style/redundant_condition.rb +47 -2
  236. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  237. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  238. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  239. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  240. data/lib/rubocop/cop/style/redundant_format.rb +250 -0
  241. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  242. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  243. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  244. data/lib/rubocop/cop/style/redundant_parentheses.rb +28 -14
  245. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  246. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  247. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  248. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  249. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  250. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  251. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  252. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  253. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  254. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  255. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  256. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  257. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  258. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  259. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  260. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -8
  261. data/lib/rubocop/cop/style/string_concatenation.rb +2 -2
  262. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  263. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  264. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  265. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  266. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  267. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  268. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  269. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  270. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  271. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  272. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  273. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  274. data/lib/rubocop/cop/util.rb +12 -5
  275. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  276. data/lib/rubocop/cop/variable_force/variable.rb +14 -2
  277. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  278. data/lib/rubocop/cops_documentation_generator.rb +25 -14
  279. data/lib/rubocop/directive_comment.rb +45 -11
  280. data/lib/rubocop/ext/regexp_node.rb +0 -1
  281. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  282. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  283. data/lib/rubocop/lsp/logger.rb +2 -2
  284. data/lib/rubocop/lsp/routes.rb +7 -23
  285. data/lib/rubocop/lsp/runtime.rb +17 -49
  286. data/lib/rubocop/lsp/server.rb +0 -2
  287. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  288. data/lib/rubocop/options.rb +28 -12
  289. data/lib/rubocop/path_util.rb +15 -8
  290. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  291. data/lib/rubocop/plugin/load_error.rb +26 -0
  292. data/lib/rubocop/plugin/loader.rb +100 -0
  293. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  294. data/lib/rubocop/plugin.rb +46 -0
  295. data/lib/rubocop/rake_task.rb +4 -1
  296. data/lib/rubocop/result_cache.rb +13 -13
  297. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  298. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  299. data/lib/rubocop/rspec/shared_contexts.rb +19 -1
  300. data/lib/rubocop/rspec/support.rb +2 -2
  301. data/lib/rubocop/runner.rb +5 -6
  302. data/lib/rubocop/server/cache.rb +35 -2
  303. data/lib/rubocop/server/cli.rb +2 -2
  304. data/lib/rubocop/target_finder.rb +1 -0
  305. data/lib/rubocop/target_ruby.rb +15 -0
  306. data/lib/rubocop/version.rb +17 -2
  307. data/lib/rubocop.rb +12 -1
  308. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  309. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
  310. metadata +55 -16
  311. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  312. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for constant reassignments.
7
+ #
8
+ # Emulates Ruby's runtime warning "already initialized constant X"
9
+ # when a constant is reassigned in the same file and namespace using the
10
+ # `NAME = value` syntax.
11
+ #
12
+ # The cop cannot catch all offenses, like, for example, when a constant
13
+ # is reassigned in another file, or when using metaprogramming (`Module#const_set`).
14
+ #
15
+ # The cop only takes into account constants assigned in a "simple" way: directly
16
+ # inside class/module definition, or within another constant. Other type of assignments
17
+ # (e.g., inside a conditional) are disregarded.
18
+ #
19
+ # The cop also tracks constant removal using `Module#remove_const` with symbol
20
+ # or string argument.
21
+ #
22
+ # @example
23
+ # # bad
24
+ # X = :foo
25
+ # X = :bar
26
+ #
27
+ # # bad
28
+ # class A
29
+ # X = :foo
30
+ # X = :bar
31
+ # end
32
+ #
33
+ # # bad
34
+ # module A
35
+ # X = :foo
36
+ # X = :bar
37
+ # end
38
+ #
39
+ # # good - keep only one assignment
40
+ # X = :bar
41
+ #
42
+ # class A
43
+ # X = :bar
44
+ # end
45
+ #
46
+ # module A
47
+ # X = :bar
48
+ # end
49
+ #
50
+ # # good - use OR assignment
51
+ # X = :foo
52
+ # X ||= :bar
53
+ #
54
+ # # good - use conditional assignment
55
+ # X = :foo
56
+ # X = :bar unless defined?(X)
57
+ #
58
+ # # good - remove the assigned constant first
59
+ # class A
60
+ # X = :foo
61
+ # remove_const :X
62
+ # X = :bar
63
+ # end
64
+ #
65
+ class ConstantReassignment < Base
66
+ MSG = 'Constant `%<constant>s` is already assigned in this namespace.'
67
+
68
+ RESTRICT_ON_SEND = %i[remove_const].freeze
69
+
70
+ # @!method remove_constant(node)
71
+ def_node_matcher :remove_constant, <<~PATTERN
72
+ (send _ :remove_const
73
+ ({sym str} $_))
74
+ PATTERN
75
+
76
+ def on_casgn(node)
77
+ return unless fixed_constant_path?(node)
78
+ return unless simple_assignment?(node)
79
+ return if constant_names.add?(fully_qualified_constant_name(node))
80
+
81
+ add_offense(node, message: format(MSG, constant: node.name))
82
+ end
83
+
84
+ def on_send(node)
85
+ constant = remove_constant(node)
86
+
87
+ return unless constant
88
+
89
+ namespaces = ancestor_namespaces(node)
90
+
91
+ return if namespaces.none?
92
+
93
+ constant_names.delete(fully_qualified_name_for(namespaces, constant))
94
+ end
95
+
96
+ private
97
+
98
+ def fixed_constant_path?(node)
99
+ node.each_path.all? { |path| path.type?(:cbase, :const, :self) }
100
+ end
101
+
102
+ def simple_assignment?(node)
103
+ node.ancestors.all? do |ancestor|
104
+ return true if ancestor.type?(:module, :class)
105
+
106
+ ancestor.begin_type? || ancestor.literal? || ancestor.casgn_type? ||
107
+ freeze_method?(ancestor)
108
+ end
109
+ end
110
+
111
+ def freeze_method?(node)
112
+ node.send_type? && node.method?(:freeze)
113
+ end
114
+
115
+ def fully_qualified_constant_name(node)
116
+ if node.absolute?
117
+ namespace = node.namespace.const_type? ? node.namespace.source : nil
118
+
119
+ "#{namespace}::#{node.name}"
120
+ else
121
+ constant_namespaces = ancestor_namespaces(node) + constant_namespaces(node)
122
+
123
+ fully_qualified_name_for(constant_namespaces, node.name)
124
+ end
125
+ end
126
+
127
+ def fully_qualified_name_for(namespaces, constant)
128
+ ['', *namespaces, constant].join('::')
129
+ end
130
+
131
+ def constant_namespaces(node)
132
+ node.each_path.select(&:const_type?).map(&:short_name)
133
+ end
134
+
135
+ def ancestor_namespaces(node)
136
+ node
137
+ .each_ancestor(:class, :module)
138
+ .map { |ancestor| ancestor.identifier.short_name }
139
+ .reverse
140
+ end
141
+
142
+ def constant_names
143
+ @constant_names ||= Set.new
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Lint/RedundantCopDisableDirective
4
+ # rubocop:disable Style/DoubleCopDisableDirective
5
+ module RuboCop
6
+ module Cop
7
+ module Lint
8
+ # Checks that `# rubocop:enable ...` and `# rubocop:disable ...` statements
9
+ # are strictly formatted.
10
+ #
11
+ # A comment can be added to the directive by prefixing it with `--`.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # # rubocop:disable Layout/LineLength Style/Encoding
16
+ # # ^ missing comma
17
+ #
18
+ # # bad
19
+ # # rubocop:disable
20
+ #
21
+ # # bad
22
+ # # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
23
+ #
24
+ # # bad
25
+ # # rubocop:wrongmode Layout/LineLength
26
+ #
27
+ # # good
28
+ # # rubocop:disable Layout/LineLength
29
+ #
30
+ # # good
31
+ # # rubocop:disable Layout/LineLength, Style/Encoding
32
+ #
33
+ # # good
34
+ # # rubocop:disable all
35
+ #
36
+ # # good
37
+ # # rubocop:disable Layout/LineLength -- This is a good comment.
38
+ #
39
+ class CopDirectiveSyntax < Base
40
+ COMMON_MSG = 'Malformed directive comment detected.'
41
+
42
+ MISSING_MODE_NAME_MSG = 'The mode name is missing.'
43
+ INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, or `todo`.'
44
+ MISSING_COP_NAME_MSG = 'The cop name is missing.'
45
+ MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
46
+ 'Comment in the directive must start with `--`.'
47
+
48
+ def on_new_investigation
49
+ processed_source.comments.each do |comment|
50
+ directive_comment = DirectiveComment.new(comment)
51
+ next unless directive_comment.start_with_marker?
52
+ next unless directive_comment.malformed?
53
+
54
+ message = offense_message(directive_comment)
55
+ add_offense(comment, message: message)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # rubocop:disable Metrics/MethodLength
62
+ def offense_message(directive_comment)
63
+ comment = directive_comment.comment
64
+ after_marker = comment.text.sub(DirectiveComment::DIRECTIVE_MARKER_REGEXP, '')
65
+ mode = after_marker.split(' ', 2).first
66
+ additional_msg = if mode.nil?
67
+ MISSING_MODE_NAME_MSG
68
+ elsif !DirectiveComment::AVAILABLE_MODES.include?(mode)
69
+ INVALID_MODE_NAME_MSG
70
+ elsif directive_comment.missing_cop_name?
71
+ MISSING_COP_NAME_MSG
72
+ else
73
+ MALFORMED_COP_NAMES_MSG
74
+ end
75
+
76
+ "#{COMMON_MSG} #{additional_msg}"
77
+ end
78
+ # rubocop:enable Metrics/MethodLength
79
+ end
80
+ end
81
+ end
82
+ end
83
+ # rubocop:enable Lint/RedundantCopDisableDirective
84
+ # rubocop:enable Style/DoubleCopDisableDirective
@@ -116,7 +116,7 @@ module RuboCop
116
116
 
117
117
  def assumed_usage_context?(node)
118
118
  # Basically, debugger methods are not used as a method argument without arguments.
119
- return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
119
+ return false unless node.arguments.empty? && node.each_ancestor(:call).any?
120
120
  return true if assumed_argument?(node)
121
121
 
122
122
  node.each_ancestor.none? do |ancestor|
@@ -106,7 +106,7 @@ module RuboCop
106
106
  private
107
107
 
108
108
  def pattern_identity(pattern)
109
- pattern_source = if pattern.hash_pattern_type? || pattern.match_alt_type?
109
+ pattern_source = if pattern.type?(:hash_pattern, :match_alt)
110
110
  pattern.children.map(&:source).sort.to_s
111
111
  else
112
112
  pattern.source
@@ -54,14 +54,12 @@ module RuboCop
54
54
  # if a method definition is inside an if, it is very likely
55
55
  # that a different definition is used depending on platform, etc.
56
56
  return if node.each_ancestor.any?(&:if_type?)
57
- return if possible_dsl?(node)
58
57
 
59
58
  found_instance_method(node, node.method_name)
60
59
  end
61
60
 
62
61
  def on_defs(node)
63
62
  return if node.each_ancestor.any?(&:if_type?)
64
- return if possible_dsl?(node)
65
63
 
66
64
  if node.receiver.const_type?
67
65
  _, const_name = *node.receiver
@@ -79,7 +77,6 @@ module RuboCop
79
77
  def on_alias(node)
80
78
  return unless (name = method_alias?(node))
81
79
  return if node.ancestors.any?(&:if_type?)
82
- return if possible_dsl?(node)
83
80
 
84
81
  found_instance_method(node, name)
85
82
  end
@@ -94,7 +91,6 @@ module RuboCop
94
91
  def on_send(node)
95
92
  if (name = alias_method?(node))
96
93
  return if node.ancestors.any?(&:if_type?)
97
- return if possible_dsl?(node)
98
94
 
99
95
  found_instance_method(node, name)
100
96
  elsif (attr = node.attribute_accessor?)
@@ -237,16 +233,6 @@ module RuboCop
237
233
  end
238
234
  end
239
235
 
240
- def possible_dsl?(node)
241
- # DSL methods may evaluate a block in the context of a newly created
242
- # class or module
243
- # Assume that if a method definition is inside any block call which
244
- # we can't identify, it could be a DSL
245
- node.each_ancestor(:block).any? do |ancestor|
246
- !ancestor.method?(:class_eval) && !ancestor.class_constructor?
247
- end
248
- end
249
-
250
236
  def source_location(node)
251
237
  range = node.source_range
252
238
  path = smart_path(range.source_buffer.name)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate elements in Regexp character classes.
6
+ # Checks for duplicate elements in `Regexp` character classes.
7
7
  #
8
8
  # @example
9
9
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate literal, constant, or variable elements in Set.
6
+ # Checks for duplicate literal, constant, or variable elements in `Set` and `SortedSet`.
7
7
  #
8
8
  # @example
9
9
  #
@@ -25,17 +25,28 @@ module RuboCop
25
25
  # # good
26
26
  # [:foo, :bar].to_set
27
27
  #
28
+ # # bad
29
+ # SortedSet[:foo, :bar, :foo]
30
+ #
31
+ # # good
32
+ # SortedSet[:foo, :bar]
33
+ #
34
+ # # bad
35
+ # SortedSet.new([:foo, :bar, :foo])
36
+ #
37
+ # # good
38
+ # SortedSet.new([:foo, :bar])
28
39
  class DuplicateSetElement < Base
29
40
  extend AutoCorrector
30
41
 
31
- MSG = 'Remove the duplicate element in Set.'
42
+ MSG = 'Remove the duplicate element in %<class_name>s.'
32
43
  RESTRICT_ON_SEND = %i[\[\] new to_set].freeze
33
44
 
34
45
  # @!method set_init_elements(node)
35
46
  def_node_matcher :set_init_elements, <<~PATTERN
36
47
  {
37
- (send (const {nil? cbase} :Set) :[] $...)
38
- (send (const {nil? cbase} :Set) :new (array $...))
48
+ (send (const {nil? cbase} {:Set :SortedSet}) :[] $...)
49
+ (send (const {nil? cbase} {:Set :SortedSet}) :new (array $...))
39
50
  (call (array $...) :to_set)
40
51
  }
41
52
  PATTERN
@@ -51,7 +62,7 @@ module RuboCop
51
62
  next if !set_element.literal? && !set_element.const_type? && !set_element.variable?
52
63
 
53
64
  if seen_elements.include?(set_element)
54
- register_offense(set_element, set_elements[index - 1])
65
+ register_offense(set_element, set_elements[index - 1], node)
55
66
  else
56
67
  seen_elements << set_element
57
68
  end
@@ -61,8 +72,10 @@ module RuboCop
61
72
 
62
73
  private
63
74
 
64
- def register_offense(current_element, prev_element)
65
- add_offense(current_element) do |corrector|
75
+ def register_offense(current_element, prev_element, node)
76
+ class_name = node.receiver.const_type? ? node.receiver.const_name : 'Set'
77
+
78
+ add_offense(current_element, message: format(MSG, class_name: class_name)) do |corrector|
66
79
  range = prev_element.source_range.end.join(current_element.source_range.end)
67
80
 
68
81
  corrector.remove(range)
@@ -7,11 +7,6 @@ module RuboCop
7
7
  #
8
8
  # NOTE: empty `else` branches are handled by `Style/EmptyElse`.
9
9
  #
10
- # @safety
11
- # Autocorrection for this cop is not safe. The conditions for empty branches that
12
- # the autocorrection removes may have side effects, or the logic in subsequent
13
- # branches may change due to the removal of a previous condition.
14
- #
15
10
  # @example
16
11
  # # bad
17
12
  # if condition
@@ -41,6 +36,13 @@ module RuboCop
41
36
  # if condition
42
37
  # do_something
43
38
  # elsif other_condition
39
+ # nil
40
+ # end
41
+ #
42
+ # # good
43
+ # if condition
44
+ # do_something
45
+ # elsif other_condition
44
46
  # do_something_else
45
47
  # end
46
48
  #
@@ -63,11 +65,9 @@ module RuboCop
63
65
  class EmptyConditionalBody < Base
64
66
  extend AutoCorrector
65
67
  include CommentsHelp
66
- include RangeHelp
67
68
 
68
69
  MSG = 'Avoid `%<keyword>s` branches without a body.'
69
70
 
70
- # rubocop:disable Metrics/AbcSize
71
71
  def on_if(node)
72
72
  return if node.body || same_line?(node.loc.begin, node.loc.end)
73
73
  return if cop_config['AllowComments'] && contains_comments?(node)
@@ -75,12 +75,11 @@ module RuboCop
75
75
  range = offense_range(node)
76
76
 
77
77
  add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
78
- next if node.parent&.call_type?
78
+ next unless can_simplify_conditional?(node)
79
79
 
80
- autocorrect(corrector, node)
80
+ flip_orphaned_else(corrector, node)
81
81
  end
82
82
  end
83
- # rubocop:enable Metrics/AbcSize
84
83
 
85
84
  private
86
85
 
@@ -92,53 +91,23 @@ module RuboCop
92
91
  end
93
92
  end
94
93
 
95
- def autocorrect(corrector, node)
96
- remove_comments(corrector, node)
97
- remove_empty_branch(corrector, node)
98
- correct_other_branches(corrector, node)
99
- end
100
-
101
- def remove_comments(corrector, node)
102
- comments_in_range(node).each do |comment|
103
- range = range_by_whole_lines(comment.source_range, include_final_newline: true)
104
- corrector.remove(range)
105
- end
94
+ def can_simplify_conditional?(node)
95
+ node.else_branch && node.loc.else.source == 'else'
106
96
  end
107
97
 
108
- # rubocop:disable Metrics/AbcSize
109
98
  def remove_empty_branch(corrector, node)
110
99
  range = if empty_if_branch?(node) && else_branch?(node)
111
100
  branch_range(node)
112
- elsif same_line?(node, else_kw_loc = node.loc.else)
113
- node.source_range.begin.join(else_kw_loc.begin)
114
- elsif node.parent&.loc.respond_to?(:end) &&
115
- same_line?(node, end_loc = node.parent.loc.end)
116
- node.source_range.begin.join(end_loc.begin)
117
101
  else
118
102
  deletion_range(branch_range(node))
119
103
  end
120
104
 
121
105
  corrector.remove(range)
122
106
  end
123
- # rubocop:enable Metrics/AbcSize
124
-
125
- def correct_other_branches(corrector, node)
126
- return unless require_other_branches_correction?(node)
127
-
128
- if node.else_branch&.if_type? && !node.else_branch.modifier_form?
129
- # Replace an orphaned `elsif` with `if`
130
- corrector.replace(node.else_branch.loc.keyword, 'if')
131
- else
132
- # Flip orphaned `else`
133
- corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
134
- end
135
- end
136
-
137
- def require_other_branches_correction?(node)
138
- return false unless node.if_type? && node.else?
139
- return false if !empty_if_branch?(node) && node.elsif?
140
107
 
141
- !empty_elsif_branch?(node)
108
+ def flip_orphaned_else(corrector, node)
109
+ corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
110
+ remove_empty_branch(corrector, node)
142
111
  end
143
112
 
144
113
  def empty_if_branch?(node)
@@ -149,36 +118,17 @@ module RuboCop
149
118
  if_branch.if_type? && !if_branch.body
150
119
  end
151
120
 
152
- def empty_elsif_branch?(node)
153
- return false unless (else_branch = node.else_branch)
154
-
155
- else_branch.if_type? && !else_branch.body
156
- end
157
-
158
121
  def else_branch?(node)
159
122
  node.else_branch && !node.else_branch.if_type?
160
123
  end
161
124
 
162
- # rubocop:disable Metrics/AbcSize
163
125
  def branch_range(node)
164
126
  if empty_if_branch?(node) && else_branch?(node)
165
127
  node.source_range.with(end_pos: node.loc.else.begin_pos)
166
128
  elsif node.loc.else
167
129
  node.source_range.with(end_pos: node.condition.source_range.end_pos)
168
- elsif all_branches_body_missing?(node)
169
- if_node = node.ancestors.detect(&:if?)
170
- node.source_range.join(if_node.loc.end.end)
171
- else
172
- node.source_range
173
130
  end
174
131
  end
175
- # rubocop:enable Metrics/AbcSize
176
-
177
- def all_branches_body_missing?(node)
178
- return false unless node.parent&.if_type?
179
-
180
- node.parent.branches.compact.empty?
181
- end
182
132
 
183
133
  def deletion_range(range)
184
134
  # Collect a range between the start of the `if` node and the next relevant node,
@@ -14,8 +14,6 @@ module RuboCop
14
14
  # bar
15
15
  # end
16
16
  #
17
- # @example
18
- #
19
17
  # # good
20
18
  #
21
19
  # foo = (some_expression)
@@ -156,12 +156,6 @@ module RuboCop
156
156
 
157
157
  overridden_kwargs
158
158
  end
159
-
160
- def arguments_range(node)
161
- arguments = node.arguments
162
-
163
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
164
- end
165
159
  end
166
160
  end
167
161
  end
@@ -36,7 +36,8 @@ module RuboCop
36
36
  # # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
37
37
  #
38
38
  class FloatComparison < Base
39
- MSG = 'Avoid (in)equality comparisons of floats as they are unreliable.'
39
+ MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
40
+ MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
40
41
 
41
42
  EQUALITY_METHODS = %i[== != eql? equal?].freeze
42
43
  FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
@@ -52,8 +53,10 @@ module RuboCop
52
53
 
53
54
  return if literal_safe?(lhs) || literal_safe?(rhs)
54
55
 
55
- add_offense(node) if float?(lhs) || float?(rhs)
56
+ message = node.method?(:!=) ? MSG_INEQUALITY : MSG_EQUALITY
57
+ add_offense(node, message: message) if float?(lhs) || float?(rhs)
56
58
  end
59
+ alias on_csend on_send
57
60
 
58
61
  private
59
62
 
@@ -78,21 +81,16 @@ module RuboCop
78
81
  (node.numeric_type? && node.value.zero?) || node.nil_type?
79
82
  end
80
83
 
81
- # rubocop:disable Metrics/PerceivedComplexity
82
84
  def check_send(node)
83
85
  if node.arithmetic_operation?
84
86
  float?(node.receiver) || float?(node.first_argument)
85
87
  elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
86
88
  true
87
89
  elsif node.receiver&.float_type?
88
- if FLOAT_INSTANCE_METHODS.include?(node.method_name)
89
- true
90
- else
90
+ FLOAT_INSTANCE_METHODS.include?(node.method_name) ||
91
91
  check_numeric_returning_method(node)
92
- end
93
92
  end
94
93
  end
95
- # rubocop:enable Metrics/PerceivedComplexity
96
94
 
97
95
  def check_numeric_returning_method(node)
98
96
  return false unless node.receiver
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Identifies Float literals which are, like, really really really
6
+ # Identifies `Float` literals which are, like, really really really
7
7
  # really really really really really big. Too big. No-one needs Floats
8
8
  # that big. If you need a float that big, something is wrong with you.
9
9
  #
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # expected fields for format/sprintf/#% and what is actually
8
8
  # passed as arguments.
9
9
  #
10
- # In addition it checks whether different formats are used in the same
10
+ # In addition, it checks whether different formats are used in the same
11
11
  # format string. Do not mix numbered, unnumbered, and named formats in
12
12
  # the same format string.
13
13
  #
@@ -73,7 +73,7 @@ module RuboCop
73
73
 
74
74
  first_arg = node.first_argument
75
75
  return false if num_of_expected_fields.zero? &&
76
- (first_arg.dstr_type? || first_arg.array_type?)
76
+ first_arg.type?(:dstr, :array)
77
77
 
78
78
  matched_arguments_count?(num_of_expected_fields, num_of_format_args)
79
79
  end
@@ -82,7 +82,7 @@ module RuboCop
82
82
  end
83
83
 
84
84
  def string_literal?(node)
85
- node.str_type? || node.dstr_type?
85
+ node.type?(:str, :dstr)
86
86
  end
87
87
 
88
88
  def string_literals?(node1, node2)