rubocop 1.69.2 → 1.75.4

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 (372) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +183 -41
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +3 -1
  7. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  8. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  9. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  10. data/lib/rubocop/cli.rb +1 -1
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +52 -10
  13. data/lib/rubocop/config_loader.rb +52 -9
  14. data/lib/rubocop/config_loader_resolver.rb +36 -10
  15. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  16. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  17. data/lib/rubocop/config_obsoletion.rb +46 -2
  18. data/lib/rubocop/config_validator.rb +25 -14
  19. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  20. data/lib/rubocop/cop/base.rb +6 -0
  21. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  24. data/lib/rubocop/cop/internal_affairs/example_description.rb +8 -4
  25. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  26. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  27. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  28. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  30. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  31. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +230 -0
  32. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  33. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  34. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  35. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  36. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  37. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  38. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  40. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  41. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  42. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  43. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  44. data/lib/rubocop/cop/layout/block_alignment.rb +3 -1
  45. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  46. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  47. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  48. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  49. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  50. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  51. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  52. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  53. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +28 -1
  54. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  55. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  56. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  57. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  58. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  59. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  60. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  61. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  62. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  63. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  64. data/lib/rubocop/cop/layout/hash_alignment.rb +7 -5
  65. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  66. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  67. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  68. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  69. data/lib/rubocop/cop/layout/line_length.rb +9 -4
  70. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  71. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  72. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  73. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  74. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  75. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  76. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
  77. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -11
  78. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -5
  79. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  80. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  81. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  82. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  83. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  84. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  85. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  86. data/lib/rubocop/cop/layout/space_around_operators.rb +7 -4
  87. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  88. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  89. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  90. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  91. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  92. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  93. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  94. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  95. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  96. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  97. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
  98. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  99. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  100. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  101. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  102. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  103. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  104. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
  105. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  106. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  107. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  108. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  109. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  110. data/lib/rubocop/cop/lint/float_comparison.rb +6 -8
  111. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  112. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  113. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  114. data/lib/rubocop/cop/lint/literal_as_condition.rb +117 -9
  115. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  116. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  117. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  118. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -3
  119. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  120. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  121. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  122. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  123. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  124. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  125. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  126. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  127. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  128. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  129. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  130. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  131. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  132. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  133. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  134. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  135. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  136. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  137. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  138. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  139. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  140. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  141. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  142. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  143. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  144. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  145. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  146. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  147. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  148. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  149. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -1
  150. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  151. data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
  152. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  153. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  154. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  155. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  156. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  157. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  158. data/lib/rubocop/cop/lint/void.rb +12 -9
  159. data/lib/rubocop/cop/message_annotator.rb +7 -3
  160. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  161. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  162. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  163. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  164. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  165. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  166. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  167. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  168. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  169. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  170. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  171. data/lib/rubocop/cop/mixin/check_line_breakable.rb +13 -13
  172. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  173. data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
  174. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  175. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  176. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  177. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  178. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  179. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
  180. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  181. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  182. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  183. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  184. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
  185. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  186. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  187. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  188. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  189. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  190. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  191. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  192. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  193. data/lib/rubocop/cop/mixin/trailing_comma.rb +16 -4
  194. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  195. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  196. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  197. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  198. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  199. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  200. data/lib/rubocop/cop/registry.rb +9 -6
  201. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  202. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  203. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  204. data/lib/rubocop/cop/style/and_or.rb +1 -1
  205. data/lib/rubocop/cop/style/arguments_forwarding.rb +44 -28
  206. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  207. data/lib/rubocop/cop/style/array_intersect.rb +39 -28
  208. data/lib/rubocop/cop/style/block_delimiters.rb +9 -21
  209. data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
  210. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  211. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  212. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  213. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  214. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  215. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  216. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  217. data/lib/rubocop/cop/style/conditional_assignment.rb +20 -6
  218. data/lib/rubocop/cop/style/documentation.rb +1 -1
  219. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  220. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  221. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  222. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  223. data/lib/rubocop/cop/style/empty_literal.rb +5 -1
  224. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  225. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  226. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  227. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  228. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  229. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  230. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  231. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  232. data/lib/rubocop/cop/style/float_division.rb +8 -4
  233. data/lib/rubocop/cop/style/for.rb +1 -0
  234. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  235. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  236. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  237. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  238. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  239. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  240. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  241. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  242. data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
  243. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  244. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  245. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  246. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  247. data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
  248. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -2
  249. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  250. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  251. data/lib/rubocop/cop/style/inverse_methods.rb +15 -11
  252. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  253. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  254. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  255. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  256. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  257. data/lib/rubocop/cop/style/lambda.rb +1 -0
  258. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  259. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  260. data/lib/rubocop/cop/style/map_into_array.rb +5 -2
  261. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  262. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  263. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -16
  264. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  265. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  266. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  267. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  268. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  269. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  270. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  271. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  272. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  273. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  274. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  275. data/lib/rubocop/cop/style/next.rb +44 -0
  276. data/lib/rubocop/cop/style/object_then.rb +14 -15
  277. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  278. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  279. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  280. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  281. data/lib/rubocop/cop/style/proc.rb +2 -2
  282. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  283. data/lib/rubocop/cop/style/raise_args.rb +14 -12
  284. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  285. data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
  286. data/lib/rubocop/cop/style/redundant_condition.rb +59 -2
  287. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  288. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  289. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  290. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  291. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  292. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  293. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  294. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -16
  295. data/lib/rubocop/cop/style/redundant_parentheses.rb +48 -16
  296. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  297. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  298. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  299. data/lib/rubocop/cop/style/redundant_self.rb +1 -0
  300. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  301. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  302. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  303. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  304. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  305. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  306. data/lib/rubocop/cop/style/safe_navigation.rb +20 -5
  307. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  308. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  309. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  310. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  311. data/lib/rubocop/cop/style/single_line_do_end_block.rb +4 -3
  312. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  313. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  314. data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
  315. data/lib/rubocop/cop/style/string_concatenation.rb +2 -2
  316. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  317. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  318. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  319. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  320. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  321. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  322. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +11 -2
  323. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  324. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  325. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  326. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  327. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  328. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  329. data/lib/rubocop/cop/util.rb +12 -5
  330. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  331. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  332. data/lib/rubocop/cop/variable_force/variable.rb +10 -3
  333. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  334. data/lib/rubocop/cop/variable_force.rb +1 -1
  335. data/lib/rubocop/cops_documentation_generator.rb +31 -16
  336. data/lib/rubocop/directive_comment.rb +45 -11
  337. data/lib/rubocop/ext/regexp_node.rb +0 -1
  338. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  339. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  340. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  341. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  342. data/lib/rubocop/lsp/logger.rb +2 -2
  343. data/lib/rubocop/lsp/routes.rb +7 -23
  344. data/lib/rubocop/lsp/runtime.rb +18 -50
  345. data/lib/rubocop/lsp/server.rb +0 -2
  346. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  347. data/lib/rubocop/magic_comment.rb +8 -0
  348. data/lib/rubocop/options.rb +28 -12
  349. data/lib/rubocop/path_util.rb +15 -8
  350. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  351. data/lib/rubocop/plugin/load_error.rb +26 -0
  352. data/lib/rubocop/plugin/loader.rb +100 -0
  353. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  354. data/lib/rubocop/plugin.rb +46 -0
  355. data/lib/rubocop/rake_task.rb +4 -1
  356. data/lib/rubocop/result_cache.rb +13 -13
  357. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  358. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  359. data/lib/rubocop/rspec/shared_contexts.rb +38 -1
  360. data/lib/rubocop/rspec/support.rb +4 -2
  361. data/lib/rubocop/runner.rb +10 -7
  362. data/lib/rubocop/server/cache.rb +47 -11
  363. data/lib/rubocop/server/cli.rb +2 -2
  364. data/lib/rubocop/target_finder.rb +7 -2
  365. data/lib/rubocop/target_ruby.rb +16 -1
  366. data/lib/rubocop/version.rb +30 -8
  367. data/lib/rubocop.rb +16 -1
  368. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  369. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  370. metadata +59 -16
  371. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  372. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -3,15 +3,18 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for `raise` or `fail` statements which are
7
- # raising `Exception` class.
6
+ # Checks for `raise` or `fail` statements which raise `Exception` or
7
+ # `Exception.new`. Use `StandardError` or a specific exception class instead.
8
8
  #
9
- # You can specify a module name that will be an implicit namespace
10
- # using `AllowedImplicitNamespaces` option. The cop cause a false positive
11
- # for namespaced `Exception` when a namespace is omitted. This option can
12
- # prevent the false positive by specifying a namespace to be omitted for
13
- # `Exception`. Alternatively, make `Exception` a fully qualified class
14
- # name with an explicit namespace.
9
+ # If you have defined your own namespaced `Exception` class, it is possible
10
+ # to configure the cop to allow it by setting `AllowedImplicitNamespaces` to
11
+ # an array with the names of the namespaces to allow. By default, this is set to
12
+ # `['Gem']`, which allows `Gem::Exception` to be raised without an explicit namespace.
13
+ # If not allowed, a false positive may be registered if `raise Exception` is called
14
+ # within the namespace.
15
+ #
16
+ # Alternatively, use a fully qualified name with `raise`/`fail`
17
+ # (eg. `raise Namespace::Exception`).
15
18
  #
16
19
  # @safety
17
20
  # This cop is unsafe because it will change the exception class being
@@ -20,15 +23,31 @@ module RuboCop
20
23
  # @example
21
24
  # # bad
22
25
  # raise Exception, 'Error message here'
26
+ # raise Exception.new('Error message here')
23
27
  #
24
28
  # # good
25
29
  # raise StandardError, 'Error message here'
30
+ # raise MyError.new, 'Error message here'
31
+ #
32
+ # @example AllowedImplicitNamespaces: ['Gem'] (default)
33
+ # # bad - `Foo` is not an allowed implicit namespace
34
+ # module Foo
35
+ # def self.foo
36
+ # raise Exception # This is qualified to `Foo::Exception`.
37
+ # end
38
+ # end
26
39
  #
27
- # @example AllowedImplicitNamespaces: ['Gem']
28
40
  # # good
29
41
  # module Gem
30
42
  # def self.foo
31
- # raise Exception # This exception means `Gem::Exception`.
43
+ # raise Exception # This is qualified to `Gem::Exception`.
44
+ # end
45
+ # end
46
+ #
47
+ # # good
48
+ # module Foo
49
+ # def self.foo
50
+ # raise Foo::Exception
32
51
  # end
33
52
  # end
34
53
  class RaiseException < Base
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for redundant quantifiers inside Regexp literals.
6
+ # Checks for redundant quantifiers inside `Regexp` literals.
7
7
  #
8
8
  # It is always allowed when interpolation is used in a regexp literal,
9
9
  # because it's unknown what kind of string will be expanded as a result:
@@ -17,17 +17,12 @@ module RuboCop
17
17
  # * 2.0+ ... `enumerator`
18
18
  # * 2.1+ ... `thread`
19
19
  # * 2.2+ ... Add `rational` and `complex` above
20
- # * 2.5+ ... Add `pp` above
21
20
  # * 2.7+ ... Add `ruby2_keywords` above
22
21
  # * 3.1+ ... Add `fiber` above
23
22
  # * 3.2+ ... `set`
24
23
  #
25
24
  # This cop target those features.
26
25
  #
27
- # @safety
28
- # This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
29
- # `NameError` can be encountered when another file uses `PP.pp`.
30
- #
31
26
  # @example
32
27
  # # bad
33
28
  # require 'unloaded_feature'
@@ -42,10 +37,6 @@ module RuboCop
42
37
  MSG = 'Remove unnecessary `require` statement.'
43
38
  RESTRICT_ON_SEND = %i[require].freeze
44
39
  RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
45
- PRETTY_PRINT_METHODS = %i[
46
- pretty_inspect pretty_print pretty_print_cycle
47
- pretty_print_inspect pretty_print_instance_variables
48
- ].freeze
49
40
 
50
41
  # @!method redundant_require_statement?(node)
51
42
  def_node_matcher :redundant_require_statement?, <<~PATTERN
@@ -53,11 +44,6 @@ module RuboCop
53
44
  (str #redundant_feature?))
54
45
  PATTERN
55
46
 
56
- # @!method pp_const?(node)
57
- def_node_matcher :pp_const?, <<~PATTERN
58
- (const {nil? cbase} :PP)
59
- PATTERN
60
-
61
47
  def on_send(node)
62
48
  return unless redundant_require_statement?(node)
63
49
 
@@ -81,18 +67,11 @@ module RuboCop
81
67
  feature_name == 'enumerator' ||
82
68
  (target_ruby_version >= 2.1 && feature_name == 'thread') ||
83
69
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
84
- (target_ruby_version >= 2.5 && feature_name == 'pp' && !need_to_require_pp?) ||
85
70
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
86
71
  (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
87
72
  (target_ruby_version >= 3.2 && feature_name == 'set')
88
73
  end
89
74
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
90
-
91
- def need_to_require_pp?
92
- processed_source.ast.each_descendant(:send).any? do |node|
93
- pp_const?(node.receiver) || PRETTY_PRINT_METHODS.include?(node.method_name)
94
- end
95
- end
96
75
  end
97
76
  end
98
77
  end
@@ -29,7 +29,7 @@ module RuboCop
29
29
  RESTRICT_ON_SEND = %i[print puts warn].freeze
30
30
 
31
31
  # @!method to_s_without_args?(node)
32
- def_node_matcher :to_s_without_args?, '(send _ :to_s)'
32
+ def_node_matcher :to_s_without_args?, '(call _ :to_s)'
33
33
 
34
34
  def on_interpolation(begin_node)
35
35
  final_node = begin_node.children.last
@@ -42,7 +42,7 @@ module RuboCop
42
42
  def on_send(node)
43
43
  return if node.receiver
44
44
 
45
- node.each_child_node(:send) do |child|
45
+ node.each_child_node(:call) do |child|
46
46
  next if !child.method?(:to_s) || child.arguments.any?
47
47
 
48
48
  register_offense(child, "`#{node.method_name}`")
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_d`, `to_r`, `to_c`,
7
+ # `to_a`, `to_h`, and `to_set`.
8
+ #
9
+ # When one of these methods is called on an object of the same type, that object
10
+ # is returned, making the call unnecessary. The cop detects conversion methods called
11
+ # on object literals, class constructors, class `[]` methods, and the `Kernel` methods
12
+ # `String()`, `Integer()`, `Float()`, BigDecimal(), `Rational()`, `Complex()`, and `Array()`.
13
+ #
14
+ # Specifically, these cases are detected for each conversion method:
15
+ #
16
+ # * `to_s` when called on a string literal, interpolated string, heredoc,
17
+ # or with `String.new` or `String()`.
18
+ # * `to_sym` when called on a symbol literal or interpolated symbol.
19
+ # * `to_i` when called on an integer literal or with `Integer()`.
20
+ # * `to_f` when called on a float literal of with `Float()`.
21
+ # * `to_r` when called on a rational literal or with `Rational()`.
22
+ # * `to_c` when called on a complex literal of with `Complex()`.
23
+ # * `to_a` when called on an array literal, or with `Array.new`, `Array()` or `Array[]`.
24
+ # * `to_h` when called on a hash literal, or with `Hash.new`, `Hash()` or `Hash[]`.
25
+ # * `to_set` when called on `Set.new` or `Set[]`.
26
+ #
27
+ # In all cases, chaining one same `to_*` conversion methods listed above is redundant.
28
+ #
29
+ # The cop can also register an offense for chaining conversion methods on methods that are
30
+ # expected to return a specific type regardless of receiver (eg. `foo.inspect.to_s` and
31
+ # `foo.to_json.to_s`).
32
+ #
33
+ # @example
34
+ # # bad
35
+ # "text".to_s
36
+ # :sym.to_sym
37
+ # 42.to_i
38
+ # 8.5.to_f
39
+ # 12r.to_r
40
+ # 1i.to_c
41
+ # [].to_a
42
+ # {}.to_h
43
+ # Set.new.to_set
44
+ #
45
+ # # good
46
+ # "text"
47
+ # :sym
48
+ # 42
49
+ # 8.5
50
+ # 12r
51
+ # 1i
52
+ # []
53
+ # {}
54
+ # Set.new
55
+ #
56
+ # # bad
57
+ # Integer(var).to_i
58
+ #
59
+ # # good
60
+ # Integer(var)
61
+ #
62
+ # # good - chaining to a type constructor with exceptions suppressed
63
+ # # in this case, `Integer()` could return `nil`
64
+ # Integer(var, exception: false).to_i
65
+ #
66
+ # # bad - chaining the same conversion
67
+ # foo.to_s.to_s
68
+ #
69
+ # # good
70
+ # foo.to_s
71
+ #
72
+ # # bad - chaining a conversion to a method that is expected to return the same type
73
+ # foo.inspect.to_s
74
+ # foo.to_json.to_s
75
+ #
76
+ # # good
77
+ # foo.inspect
78
+ # foo.to_json
79
+ #
80
+ class RedundantTypeConversion < Base
81
+ extend AutoCorrector
82
+
83
+ MSG = 'Redundant `%<method>s` detected.'
84
+
85
+ # Maps conversion methods to the node types for the literals of that type
86
+ LITERAL_NODE_TYPES = {
87
+ to_s: %i[str dstr],
88
+ to_sym: %i[sym dsym],
89
+ to_i: %i[int],
90
+ to_f: %i[float],
91
+ to_r: %i[rational],
92
+ to_c: %i[complex],
93
+ to_a: %i[array],
94
+ to_h: %i[hash],
95
+ to_set: [] # sets don't have a literal or node type
96
+ }.freeze
97
+
98
+ # Maps each conversion method to the pattern matcher for that type's constructors
99
+ # Not every type has a constructor, for instance Symbol.
100
+ CONSTRUCTOR_MAPPING = {
101
+ to_s: 'string_constructor?',
102
+ to_i: 'integer_constructor?',
103
+ to_f: 'float_constructor?',
104
+ to_d: 'bigdecimal_constructor?',
105
+ to_r: 'rational_constructor?',
106
+ to_c: 'complex_constructor?',
107
+ to_a: 'array_constructor?',
108
+ to_h: 'hash_constructor?',
109
+ to_set: 'set_constructor?'
110
+ }.freeze
111
+
112
+ # Methods that already are expected to return a given type, which makes a further
113
+ # conversion redundant.
114
+ TYPED_METHODS = { to_s: %i[inspect to_json] }.freeze
115
+
116
+ CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
117
+ RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
118
+
119
+ private_constant :LITERAL_NODE_TYPES, :CONSTRUCTOR_MAPPING
120
+
121
+ # @!method type_constructor?(node, type_symbol)
122
+ def_node_matcher :type_constructor?, <<~PATTERN
123
+ (send {nil? (const {cbase nil?} :Kernel)} %1 ...)
124
+ PATTERN
125
+
126
+ # @!method string_constructor?(node)
127
+ def_node_matcher :string_constructor?, <<~PATTERN
128
+ {
129
+ (send (const {cbase nil?} :String) :new ...)
130
+ #type_constructor?(:String)
131
+ }
132
+ PATTERN
133
+
134
+ # @!method integer_constructor?(node)
135
+ def_node_matcher :integer_constructor?, <<~PATTERN
136
+ #type_constructor?(:Integer)
137
+ PATTERN
138
+
139
+ # @!method float_constructor?(node)
140
+ def_node_matcher :float_constructor?, <<~PATTERN
141
+ #type_constructor?(:Float)
142
+ PATTERN
143
+
144
+ # @!method bigdecimal_constructor?(node)
145
+ def_node_matcher :bigdecimal_constructor?, <<~PATTERN
146
+ #type_constructor?(:BigDecimal)
147
+ PATTERN
148
+
149
+ # @!method rational_constructor?(node)
150
+ def_node_matcher :rational_constructor?, <<~PATTERN
151
+ #type_constructor?(:Rational)
152
+ PATTERN
153
+
154
+ # @!method complex_constructor?(node)
155
+ def_node_matcher :complex_constructor?, <<~PATTERN
156
+ #type_constructor?(:Complex)
157
+ PATTERN
158
+
159
+ # @!method array_constructor?(node)
160
+ def_node_matcher :array_constructor?, <<~PATTERN
161
+ {
162
+ (send (const {cbase nil?} :Array) {:new :[]} ...)
163
+ #type_constructor?(:Array)
164
+ }
165
+ PATTERN
166
+
167
+ # @!method hash_constructor?(node)
168
+ def_node_matcher :hash_constructor?, <<~PATTERN
169
+ {
170
+ (block (send (const {cbase nil?} :Hash) :new) ...)
171
+ (send (const {cbase nil?} :Hash) {:new :[]} ...)
172
+ (send {nil? (const {cbase nil?} :Kernel)} :Hash ...)
173
+ }
174
+ PATTERN
175
+
176
+ # @!method set_constructor?(node)
177
+ def_node_matcher :set_constructor?, <<~PATTERN
178
+ {
179
+ (send (const {cbase nil?} :Set) {:new :[]} ...)
180
+ }
181
+ PATTERN
182
+
183
+ # @!method exception_false_keyword_argument?(node)
184
+ def_node_matcher :exception_false_keyword_argument?, <<~PATTERN
185
+ (hash (pair (sym :exception) false))
186
+ PATTERN
187
+
188
+ # rubocop:disable Metrics/AbcSize
189
+ def on_send(node)
190
+ return if hash_or_set_with_block?(node)
191
+
192
+ receiver = find_receiver(node)
193
+ return unless literal_receiver?(node, receiver) ||
194
+ constructor?(node, receiver) ||
195
+ chained_conversion?(node, receiver) ||
196
+ chained_to_typed_method?(node, receiver)
197
+
198
+ message = format(MSG, method: node.method_name)
199
+
200
+ add_offense(node.loc.selector, message: message) do |corrector|
201
+ corrector.remove(node.loc.dot.join(node.loc.selector))
202
+ end
203
+ end
204
+ # rubocop:enable Metrics/AbcSize
205
+ alias on_csend on_send
206
+
207
+ private
208
+
209
+ def hash_or_set_with_block?(node)
210
+ return false if !node.method?(:to_h) && !node.method?(:to_set)
211
+
212
+ node.parent&.any_block_type? || node.last_argument&.block_pass_type?
213
+ end
214
+
215
+ def find_receiver(node)
216
+ receiver = node.receiver
217
+ return unless receiver
218
+
219
+ while receiver.begin_type?
220
+ break unless receiver.children.one?
221
+
222
+ receiver = receiver.children.first
223
+ end
224
+
225
+ receiver
226
+ end
227
+
228
+ def literal_receiver?(node, receiver)
229
+ return false unless receiver
230
+
231
+ receiver.type?(*LITERAL_NODE_TYPES[node.method_name])
232
+ end
233
+
234
+ def constructor?(node, receiver)
235
+ matcher = CONSTRUCTOR_MAPPING[node.method_name]
236
+ return false unless matcher
237
+
238
+ public_send(matcher, receiver) && !constructor_suppresses_exceptions?(receiver)
239
+ end
240
+
241
+ def constructor_suppresses_exceptions?(receiver)
242
+ # If the constructor suppresses exceptions with `exception: false`, it is possible
243
+ # it could return `nil`, and therefore a chained conversion is not redundant.
244
+ receiver.arguments.any? { |arg| exception_false_keyword_argument?(arg) }
245
+ end
246
+
247
+ def chained_conversion?(node, receiver)
248
+ return false unless receiver&.call_type?
249
+
250
+ receiver.method?(node.method_name)
251
+ end
252
+
253
+ def chained_to_typed_method?(node, receiver)
254
+ return false unless receiver&.call_type?
255
+
256
+ TYPED_METHODS.fetch(node.method_name, []).include?(receiver.method_name)
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -53,6 +53,7 @@ module RuboCop
53
53
  # rubocop:enable Metrics/AbcSize
54
54
 
55
55
  alias on_numblock on_block
56
+ alias on_itblock on_block
56
57
 
57
58
  private
58
59
 
@@ -64,6 +65,8 @@ module RuboCop
64
65
  (args (arg _)) ...)
65
66
  (numblock
66
67
  $(call _ {:each_with_index :with_index} ...) 1 ...)
68
+ (itblock
69
+ $(call _ {:each_with_index :with_index} ...) _ ...)
67
70
  }
68
71
  PATTERN
69
72
 
@@ -49,6 +49,7 @@ module RuboCop
49
49
  end
50
50
 
51
51
  alias on_numblock on_block
52
+ alias on_itblock on_block
52
53
 
53
54
  private
54
55
 
@@ -59,6 +60,8 @@ module RuboCop
59
60
  $(call _ {:each_with_object :with_object} _) (args (arg _)) ...)
60
61
  (numblock
61
62
  $(call _ {:each_with_object :with_object} _) 1 ...)
63
+ (itblock
64
+ $(call _ {:each_with_object :with_object} _) _ ...)
62
65
  }
63
66
  PATTERN
64
67
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for `rescue` blocks targeting the Exception class.
6
+ # Checks for `rescue` blocks targeting the `Exception` class.
7
7
  #
8
8
  # @example
9
9
  #
@@ -32,25 +32,23 @@ module RuboCop
32
32
  class ReturnInVoidContext < Base
33
33
  MSG = 'Do not return a value in `%<method>s`.'
34
34
 
35
+ # Returning out of these methods only exits the block itself.
36
+ SCOPE_CHANGING_METHODS = %i[lambda define_method define_singleton_method].freeze
37
+
35
38
  def on_return(return_node)
36
39
  return unless return_node.descendants.any?
37
40
 
38
- context_node = non_void_context(return_node)
39
-
40
- return unless context_node&.def_type?
41
- return unless context_node&.void_context?
41
+ def_node = return_node.each_ancestor(:any_def).first
42
+ return unless def_node&.void_context?
43
+ return if return_node.each_ancestor(:any_block).any? do |block_node|
44
+ SCOPE_CHANGING_METHODS.include?(block_node.method_name)
45
+ end
42
46
 
43
47
  add_offense(
44
48
  return_node.loc.keyword,
45
- message: format(message, method: context_node.method_name)
49
+ message: format(message, method: def_node.method_name)
46
50
  )
47
51
  end
48
-
49
- private
50
-
51
- def non_void_context(return_node)
52
- return_node.each_ancestor(:block, :def, :defs).first
53
- end
54
52
  end
55
53
  end
56
54
  end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def_node_matcher :bad_method?, <<~PATTERN
34
34
  {
35
35
  (send $(csend ...) $_ ...)
36
- (send $({block numblock} (csend ...) ...) $_ ...)
36
+ (send $(any_block (csend ...) ...) $_ ...)
37
37
  }
38
38
  PATTERN
39
39
 
@@ -97,12 +97,19 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def require_parentheses?(send_node)
100
+ return true if operator_inside_hash?(send_node)
100
101
  return false unless send_node.comparison_method?
101
102
  return false unless (node = send_node.parent)
102
103
 
103
104
  (node.respond_to?(:logical_operator?) && node.logical_operator?) ||
104
105
  (node.respond_to?(:comparison_method?) && node.comparison_method?)
105
106
  end
107
+
108
+ def operator_inside_hash?(send_node)
109
+ # If an operator call (without a dot) is inside a hash, it needs
110
+ # to be parenthesized when converted to safe navigation.
111
+ send_node.parent&.pair_type? && !send_node.loc.dot
112
+ end
106
113
  end
107
114
  end
108
115
  end
@@ -56,19 +56,26 @@ module RuboCop
56
56
 
57
57
  outer_local_variable = variable_table.find_variable(variable.name)
58
58
  return unless outer_local_variable
59
+ return if variable_used_in_declaration_of_outer?(variable, outer_local_variable)
59
60
  return if same_conditions_node_different_branch?(variable, outer_local_variable)
60
61
 
61
62
  message = format(MSG, variable: variable.name)
62
63
  add_offense(variable.declaration_node, message: message)
63
64
  end
64
65
 
66
+ private
67
+
68
+ def variable_used_in_declaration_of_outer?(variable, outer_local_variable)
69
+ variable.scope.node.each_ancestor.any?(outer_local_variable.declaration_node)
70
+ end
71
+
65
72
  def same_conditions_node_different_branch?(variable, outer_local_variable)
66
73
  variable_node = variable_node(variable)
67
74
  return false unless node_or_its_ascendant_conditional?(variable_node)
68
75
 
69
76
  outer_local_variable_node =
70
77
  find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
71
- return true unless outer_local_variable_node
78
+ return false unless outer_local_variable_node
72
79
  return false unless outer_local_variable_node.conditional?
73
80
  return true if variable_node == outer_local_variable_node
74
81
 
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for `Hash` creation with a mutable default value.
7
+ # Creating a `Hash` in such a way will share the default value
8
+ # across all keys, causing unexpected behavior when modifying it.
9
+ #
10
+ # For example, when the `Hash` was created with an `Array` as the argument,
11
+ # calling `hash[:foo] << 'bar'` will also change the value of all
12
+ # other keys that have not been explicitly assigned to.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # Hash.new([])
17
+ # Hash.new({})
18
+ # Hash.new(Array.new)
19
+ # Hash.new(Hash.new)
20
+ #
21
+ # # okay -- In rare cases that intentionally have this behavior,
22
+ # # without disabling the cop, you can set the default explicitly.
23
+ # h = Hash.new
24
+ # h.default = []
25
+ # h[:a] << 1
26
+ # h[:b] << 2
27
+ # h # => {:a => [1, 2], :b => [1, 2]}
28
+ #
29
+ # # okay -- beware this will discard mutations and only remember assignments
30
+ # Hash.new { Array.new }
31
+ # Hash.new { Hash.new }
32
+ # Hash.new { {} }
33
+ # Hash.new { [] }
34
+ #
35
+ # # good - frozen solution will raise an error when mutation attempted
36
+ # Hash.new([].freeze)
37
+ # Hash.new({}.freeze)
38
+ #
39
+ # # good - using a proc will create a new object for each key
40
+ # h = Hash.new
41
+ # h.default_proc = ->(h, k) { [] }
42
+ # h.default_proc = ->(h, k) { {} }
43
+ #
44
+ # # good - using a block will create a new object for each key
45
+ # Hash.new { |h, k| h[k] = [] }
46
+ # Hash.new { |h, k| h[k] = {} }
47
+ class SharedMutableDefault < Base
48
+ MSG = 'Do not create a Hash with a mutable default value ' \
49
+ 'as the default value can accidentally be changed.'
50
+ RESTRICT_ON_SEND = %i[new].freeze
51
+
52
+ # @!method hash_initialized_with_mutable_shared_object?(node)
53
+ def_node_matcher :hash_initialized_with_mutable_shared_object?, <<~PATTERN
54
+ {
55
+ (send (const {nil? cbase} :Hash) :new [
56
+ {array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
57
+ !#capacity_keyword_argument?
58
+ ])
59
+ (send (const {nil? cbase} :Hash) :new hash #capacity_keyword_argument?)
60
+ }
61
+ PATTERN
62
+
63
+ # @!method capacity_keyword_argument?(node)
64
+ def_node_matcher :capacity_keyword_argument?, <<~PATTERN
65
+ (hash (pair (sym :capacity) _))
66
+ PATTERN
67
+
68
+ def on_send(node)
69
+ return unless hash_initialized_with_mutable_shared_object?(node)
70
+
71
+ add_offense(node)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -116,7 +116,7 @@ module RuboCop
116
116
  private
117
117
 
118
118
  def comment_between_rescue_and_end?(node)
119
- ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
119
+ ancestor = node.each_ancestor(:kwbegin, :any_def, :any_block).first
120
120
  return false unless ancestor
121
121
 
122
122
  end_line = ancestor.loc.end&.line || ancestor.loc.last_line