rubocop 1.72.1 → 1.81.7

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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -18
  3. data/config/default.yml +240 -65
  4. data/config/internal_affairs.yml +20 -0
  5. data/config/obsoletion.yml +8 -3
  6. data/exe/rubocop +1 -8
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  8. data/lib/rubocop/cli.rb +19 -4
  9. data/lib/rubocop/config.rb +35 -6
  10. data/lib/rubocop/config_loader.rb +8 -40
  11. data/lib/rubocop/config_loader_resolver.rb +9 -7
  12. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  13. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  14. data/lib/rubocop/config_obsoletion.rb +46 -2
  15. data/lib/rubocop/config_store.rb +5 -0
  16. data/lib/rubocop/config_validator.rb +7 -6
  17. data/lib/rubocop/cop/autocorrect_logic.rb +22 -14
  18. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  19. data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
  20. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  21. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  22. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  23. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
  24. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  25. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  26. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  28. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  29. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  30. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  31. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  32. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
  33. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  34. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  35. data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  37. data/lib/rubocop/cop/layout/class_structure.rb +36 -1
  38. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  39. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  40. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  41. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  43. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +32 -14
  44. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  45. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  46. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  47. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  48. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  49. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  50. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -7
  51. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  52. data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
  53. data/lib/rubocop/cop/layout/line_length.rb +43 -10
  54. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  55. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  56. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  57. data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
  58. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +11 -5
  59. data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
  60. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  61. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  62. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  63. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -38
  64. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +12 -3
  65. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  66. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  67. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  68. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  69. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  70. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  71. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
  72. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  73. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
  74. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  75. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  76. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  77. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -23
  78. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  79. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  80. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  81. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  82. data/lib/rubocop/cop/lint/float_comparison.rb +32 -10
  83. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  84. data/lib/rubocop/cop/lint/literal_as_condition.rb +124 -10
  85. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  86. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  87. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  88. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  89. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  90. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  91. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  92. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  93. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  94. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  95. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +43 -13
  96. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  97. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  98. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  99. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  100. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  101. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  102. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  103. data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
  104. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  105. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -1
  106. data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
  107. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  108. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  109. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  110. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  111. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
  112. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  113. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  114. data/lib/rubocop/cop/lint/useless_access_modifier.rb +30 -4
  115. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
  116. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +9 -12
  117. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  118. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  119. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  120. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  121. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  122. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  123. data/lib/rubocop/cop/lint/void.rb +16 -2
  124. data/lib/rubocop/cop/message_annotator.rb +7 -3
  125. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  126. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  127. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  128. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  129. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  130. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  131. data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -3
  132. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  133. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  134. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  135. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  136. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  137. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  138. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  139. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  140. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  141. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  142. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  143. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
  144. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
  145. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  146. data/lib/rubocop/cop/mixin/range_help.rb +12 -0
  147. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  148. data/lib/rubocop/cop/mixin/trailing_comma.rb +18 -2
  149. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  150. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  151. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  152. data/lib/rubocop/cop/naming/method_name.rb +187 -15
  153. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  154. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  155. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  156. data/lib/rubocop/cop/registry.rb +9 -6
  157. data/lib/rubocop/cop/security/eval.rb +2 -1
  158. data/lib/rubocop/cop/security/json_load.rb +33 -11
  159. data/lib/rubocop/cop/security/open.rb +1 -0
  160. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
  161. data/lib/rubocop/cop/style/accessor_grouping.rb +32 -6
  162. data/lib/rubocop/cop/style/arguments_forwarding.rb +21 -24
  163. data/lib/rubocop/cop/style/array_intersect.rb +113 -38
  164. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  165. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  166. data/lib/rubocop/cop/style/block_delimiters.rb +3 -2
  167. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  168. data/lib/rubocop/cop/style/class_and_module_children.rb +48 -10
  169. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  170. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  171. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  172. data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
  173. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  174. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  175. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  176. data/lib/rubocop/cop/style/conditional_assignment.rb +26 -8
  177. data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
  178. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  179. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  180. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  181. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  182. data/lib/rubocop/cop/style/empty_literal.rb +4 -0
  183. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  184. data/lib/rubocop/cop/style/endless_method.rb +176 -18
  185. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  186. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  187. data/lib/rubocop/cop/style/explicit_block_argument.rb +3 -3
  188. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  189. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  190. data/lib/rubocop/cop/style/float_division.rb +15 -1
  191. data/lib/rubocop/cop/style/for.rb +1 -0
  192. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  193. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  194. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  195. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  196. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  197. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
  198. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  199. data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
  200. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  201. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  202. data/lib/rubocop/cop/style/identical_conditional_branches.rb +3 -3
  203. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  204. data/lib/rubocop/cop/style/if_unless_modifier.rb +35 -8
  205. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  206. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  207. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  208. data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
  209. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  210. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  211. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  212. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  213. data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
  214. data/lib/rubocop/cop/style/lambda.rb +1 -0
  215. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  216. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  217. data/lib/rubocop/cop/style/map_into_array.rb +4 -1
  218. data/lib/rubocop/cop/style/map_to_hash.rb +12 -3
  219. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  220. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +9 -8
  221. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
  222. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  223. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  224. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  225. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  226. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  227. data/lib/rubocop/cop/style/next.rb +44 -0
  228. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  229. data/lib/rubocop/cop/style/object_then.rb +1 -0
  230. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  231. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  232. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  233. data/lib/rubocop/cop/style/proc.rb +1 -0
  234. data/lib/rubocop/cop/style/raise_args.rb +8 -8
  235. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  236. data/lib/rubocop/cop/style/redundant_begin.rb +35 -0
  237. data/lib/rubocop/cop/style/redundant_condition.rb +57 -0
  238. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
  239. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  240. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  241. data/lib/rubocop/cop/style/redundant_format.rb +79 -18
  242. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  243. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  244. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -4
  245. data/lib/rubocop/cop/style/redundant_parentheses.rb +73 -18
  246. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  247. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  248. data/lib/rubocop/cop/style/redundant_self.rb +9 -5
  249. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  250. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  251. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  252. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  253. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  254. data/lib/rubocop/cop/style/safe_navigation.rb +61 -14
  255. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  256. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  257. data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
  258. data/lib/rubocop/cop/style/single_line_methods.rb +10 -7
  259. data/lib/rubocop/cop/style/sole_nested_conditional.rb +75 -101
  260. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  261. data/lib/rubocop/cop/style/string_concatenation.rb +18 -15
  262. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  263. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  264. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  265. data/lib/rubocop/cop/style/symbol_proc.rb +3 -1
  266. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
  267. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  268. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  269. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  270. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  271. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  272. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  273. data/lib/rubocop/cop/team.rb +1 -1
  274. data/lib/rubocop/cop/util.rb +1 -1
  275. data/lib/rubocop/cop/utils/format_string.rb +15 -2
  276. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  277. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  278. data/lib/rubocop/cop/variable_force/variable.rb +3 -8
  279. data/lib/rubocop/cop/variable_force.rb +26 -9
  280. data/lib/rubocop/cops_documentation_generator.rb +23 -7
  281. data/lib/rubocop/directive_comment.rb +1 -1
  282. data/lib/rubocop/ext/regexp_node.rb +0 -1
  283. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
  284. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  285. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  286. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  287. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  288. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  289. data/lib/rubocop/lsp/diagnostic.rb +25 -24
  290. data/lib/rubocop/lsp/routes.rb +65 -9
  291. data/lib/rubocop/lsp/runtime.rb +5 -5
  292. data/lib/rubocop/lsp/server.rb +2 -2
  293. data/lib/rubocop/lsp/stdin_runner.rb +3 -17
  294. data/lib/rubocop/magic_comment.rb +8 -0
  295. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  296. data/lib/rubocop/plugin/configuration_integrator.rb +2 -0
  297. data/lib/rubocop/plugin/load_error.rb +1 -1
  298. data/lib/rubocop/plugin.rb +9 -2
  299. data/lib/rubocop/result_cache.rb +14 -12
  300. data/lib/rubocop/rspec/cop_helper.rb +6 -1
  301. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  302. data/lib/rubocop/rspec/shared_contexts.rb +34 -0
  303. data/lib/rubocop/rspec/support.rb +3 -0
  304. data/lib/rubocop/runner.rb +10 -4
  305. data/lib/rubocop/server/cache.rb +17 -12
  306. data/lib/rubocop/server/client_command/base.rb +10 -0
  307. data/lib/rubocop/server/client_command/exec.rb +2 -1
  308. data/lib/rubocop/server/client_command/start.rb +11 -1
  309. data/lib/rubocop/target_finder.rb +13 -9
  310. data/lib/rubocop/target_ruby.rb +11 -2
  311. data/lib/rubocop/version.rb +14 -7
  312. data/lib/rubocop.rb +17 -2
  313. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  314. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +57 -5
  315. metadata +24 -8
  316. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Check for redundant line continuation.
6
+ # Checks for redundant line continuation.
7
7
  #
8
8
  # This cop marks a line continuation as redundant if removing the backslash
9
9
  # does not result in a syntax error.
@@ -181,9 +181,7 @@ module RuboCop
181
181
  ARGUMENT_TYPES.include?(next_token.type)
182
182
  end
183
183
 
184
- # rubocop:disable Metrics/AbcSize
185
184
  def argument_newline?(node)
186
- node = node.to_a.last if node.assignment?
187
185
  return false if node.parenthesized_call?
188
186
 
189
187
  node = node.children.first if node.root? && node.begin_type?
@@ -196,7 +194,6 @@ module RuboCop
196
194
  node.loc.selector.line != node.first_argument.loc.line
197
195
  end
198
196
  end
199
- # rubocop:enable Metrics/AbcSize
200
197
 
201
198
  def find_node_for_line(last_line)
202
199
  processed_source.ast.each_node do |node|
@@ -13,21 +13,17 @@ module RuboCop
13
13
  # # good
14
14
  # x if y.z.nil?
15
15
  #
16
- # rubocop:disable Metrics/ClassLength
17
- class RedundantParentheses < Base
16
+ class RedundantParentheses < Base # rubocop:disable Metrics/ClassLength
18
17
  include Parentheses
19
18
  extend AutoCorrector
20
19
 
21
- ALLOWED_NODE_TYPES = %i[and or send splat kwsplat].freeze
20
+ ALLOWED_NODE_TYPES = %i[or send splat kwsplat].freeze
22
21
 
23
22
  # @!method square_brackets?(node)
24
23
  def_node_matcher :square_brackets?, <<~PATTERN
25
24
  (send `{(send _recv _msg) str array hash const #variable?} :[] ...)
26
25
  PATTERN
27
26
 
28
- # @!method method_node_and_args(node)
29
- def_node_matcher :method_node_and_args, '$(call _recv _msg $...)'
30
-
31
27
  # @!method rescue?(node)
32
28
  def_node_matcher :rescue?, '{^resbody ^^resbody}'
33
29
 
@@ -50,6 +46,7 @@ module RuboCop
50
46
  empty_parentheses?(node) ||
51
47
  first_arg_begins_with_hash_literal?(node) ||
52
48
  rescue?(node) ||
49
+ in_pattern_matching_in_method_argument?(node) ||
53
50
  allowed_pin_operator?(node) ||
54
51
  allowed_expression?(node)
55
52
  end
@@ -79,7 +76,7 @@ module RuboCop
79
76
  ancestor = node.ancestors.first
80
77
  return false unless ancestor
81
78
 
82
- !ancestor.type?(:begin, :def, :any_block)
79
+ !ancestor.type?(:begin, :any_def, :any_block)
83
80
  end
84
81
 
85
82
  def allowed_ternary?(node)
@@ -99,7 +96,7 @@ module RuboCop
99
96
  return false unless node.type?(:send, :super, :yield)
100
97
 
101
98
  node.arguments.one? && !node.parenthesized? &&
102
- !node.arithmetic_operation? && node.first_argument.begin_type?
99
+ !node.operator_method? && node.first_argument.begin_type?
103
100
  end
104
101
 
105
102
  def multiline_control_flow_statements?(node)
@@ -123,6 +120,13 @@ module RuboCop
123
120
  hash_literal && first_argument?(node) && !parentheses?(hash_literal) && !parenthesized
124
121
  end
125
122
 
123
+ def in_pattern_matching_in_method_argument?(begin_node)
124
+ return false unless begin_node.parent&.call_type?
125
+ return false unless (node = begin_node.children.first)
126
+
127
+ target_ruby_version <= 2.7 ? node.match_pattern_type? : node.match_pattern_p_type?
128
+ end
129
+
126
130
  def method_chain_begins_with_hash_literal(node)
127
131
  return if node.nil?
128
132
  return node if node.hash_type?
@@ -135,12 +139,14 @@ module RuboCop
135
139
  node = begin_node.children.first
136
140
 
137
141
  if (message = find_offense_message(begin_node, node))
138
- begin_node = begin_node.parent if node.range_type?
142
+ if node.range_type? && !argument_of_parenthesized_method_call?(begin_node, node)
143
+ begin_node = begin_node.parent
144
+ end
139
145
 
140
146
  return offense(begin_node, message)
141
147
  end
142
148
 
143
- check_send(begin_node, node) if node.call_type?
149
+ check_send(begin_node, node) if call_node?(node)
144
150
  end
145
151
 
146
152
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
@@ -155,7 +161,12 @@ module RuboCop
155
161
  if node.lambda_or_proc? && (node.braces? || node.send_node.lambda_literal?)
156
162
  return 'an expression'
157
163
  end
164
+ if disallowed_one_line_pattern_matching?(begin_node, node)
165
+ return 'a one-line pattern matching'
166
+ end
158
167
  return 'an interpolated expression' if interpolation?(begin_node)
168
+ return 'a method argument' if argument_of_parenthesized_method_call?(begin_node, node)
169
+ return 'a one-line rescue' if oneline_rescue_parentheses_required?(begin_node, node)
159
170
 
160
171
  return if begin_node.chained?
161
172
 
@@ -163,6 +174,7 @@ module RuboCop
163
174
  return if node.semantic_operator? && begin_node.parent
164
175
  return if node.multiline? && allow_in_multiline_conditions?
165
176
  return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
177
+ return if !node.and_type? && begin_node.parent&.and_type?
166
178
  return if begin_node.parent&.if_type? && begin_node.parent.ternary?
167
179
 
168
180
  'a logical expression'
@@ -177,14 +189,44 @@ module RuboCop
177
189
  # @!method interpolation?(node)
178
190
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
179
191
 
192
+ def argument_of_parenthesized_method_call?(begin_node, node)
193
+ if node.basic_conditional? || node.rescue_type? || method_call_parentheses_required?(node)
194
+ return false
195
+ end
196
+ return false unless (parent = begin_node.parent)
197
+
198
+ parent.call_type? && parent.parenthesized? && parent.receiver != begin_node
199
+ end
200
+
201
+ def oneline_rescue_parentheses_required?(begin_node, node)
202
+ return false unless node.rescue_type?
203
+ return false unless (parent = begin_node.parent)
204
+ return false if parent.if_type? && parent.ternary?
205
+ return false if parent.conditional? && parent.condition == begin_node
206
+
207
+ !parent.type?(:call, :array, :pair)
208
+ end
209
+
210
+ def method_call_parentheses_required?(node)
211
+ return false unless node.call_type?
212
+
213
+ (node.receiver.nil? || node.loc.dot) && node.arguments.any?
214
+ end
215
+
180
216
  def allow_in_multiline_conditions?
181
217
  !!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
182
218
  end
183
219
 
220
+ def call_node?(node)
221
+ node.call_type? || (node.any_block_type? && node.braces? && !node.lambda_or_proc?)
222
+ end
223
+
184
224
  def check_send(begin_node, node)
225
+ node = node.send_node if node.any_block_type?
226
+
185
227
  return check_unary(begin_node, node) if node.unary_operation?
186
228
 
187
- return unless method_call_with_redundant_parentheses?(node)
229
+ return unless method_call_with_redundant_parentheses?(begin_node, node)
188
230
  return if call_chain_starts_with_int?(begin_node, node) ||
189
231
  do_end_block_in_method_chain?(begin_node, node)
190
232
 
@@ -195,8 +237,7 @@ module RuboCop
195
237
  return if begin_node.chained?
196
238
 
197
239
  node = node.children.first while suspect_unary?(node)
198
-
199
- return if node.send_type? && !method_call_with_redundant_parentheses?(node)
240
+ return unless method_call_with_redundant_parentheses?(begin_node, node)
200
241
 
201
242
  offense(begin_node, 'a unary operation')
202
243
  end
@@ -225,6 +266,15 @@ module RuboCop
225
266
  end
226
267
  end
227
268
 
269
+ def disallowed_one_line_pattern_matching?(begin_node, node)
270
+ if (parent = begin_node.parent)
271
+ return false if parent.any_def_type? && parent.endless?
272
+ return false if parent.assignment?
273
+ end
274
+
275
+ node.any_match_pattern_type? && node.each_ancestor.none?(&:operator_keyword?)
276
+ end
277
+
228
278
  def raised_to_power_negative_numeric?(begin_node, node)
229
279
  return false unless node.numeric_type?
230
280
 
@@ -249,13 +299,19 @@ module RuboCop
249
299
  end
250
300
  end
251
301
 
252
- def method_call_with_redundant_parentheses?(node)
253
- return false unless node.call_type?
302
+ def method_call_with_redundant_parentheses?(begin_node, node)
303
+ return false unless node.type?(:call, :super, :yield, :defined?)
254
304
  return false if node.prefix_not?
305
+ return true if singular_parenthesized_parent?(begin_node)
306
+
307
+ node.arguments.empty? || parentheses?(node) || square_brackets?(node)
308
+ end
255
309
 
256
- send_node, args = method_node_and_args(node)
310
+ def singular_parenthesized_parent?(begin_node)
311
+ return true unless begin_node.parent
312
+ return false if begin_node.parent.type?(:splat, :kwsplat)
257
313
 
258
- args.empty? || parentheses?(send_node) || square_brackets?(send_node)
314
+ parentheses?(begin_node) && begin_node.parent.children.one?
259
315
  end
260
316
 
261
317
  def only_begin_arg?(args)
@@ -299,7 +355,6 @@ module RuboCop
299
355
  block.keywords? && begin_node.each_ancestor(:call).any?
300
356
  end
301
357
  end
302
- # rubocop:enable Metrics/ClassLength
303
358
  end
304
359
  end
305
360
  end
@@ -66,6 +66,7 @@ module RuboCop
66
66
  DETERMINISTIC_REGEX.match?(regexp_node.source)
67
67
  end
68
68
 
69
+ # rubocop:disable Metrics/MethodLength
69
70
  def preferred_argument(regexp_node)
70
71
  new_argument = replacement(regexp_node)
71
72
 
@@ -73,6 +74,8 @@ module RuboCop
73
74
  new_argument.gsub!("'", "\\\\'")
74
75
  new_argument.gsub!('\"', '"')
75
76
  quote = "'"
77
+ elsif new_argument.include?("\\'")
78
+ quote = "'"
76
79
  elsif new_argument.include?('\'')
77
80
  new_argument.gsub!("'", "\\\\'")
78
81
  quote = "'"
@@ -84,6 +87,7 @@ module RuboCop
84
87
 
85
88
  "#{quote}#{new_argument}#{quote}"
86
89
  end
90
+ # rubocop:enable Metrics/MethodLength
87
91
 
88
92
  def replacement(regexp_node)
89
93
  regexp_content = regexp_node.content
@@ -41,6 +41,7 @@ module RuboCop
41
41
  ALLOWED_ALWAYS_ESCAPES = " \n[]^\\#".chars.freeze
42
42
  ALLOWED_WITHIN_CHAR_CLASS_METACHAR_ESCAPES = '-'.chars.freeze
43
43
  ALLOWED_OUTSIDE_CHAR_CLASS_METACHAR_ESCAPES = '.*+?{}()|$'.chars.freeze
44
+ INTERPOLATION_SIGILS = %w[@ $].freeze
44
45
 
45
46
  def on_regexp(node)
46
47
  each_escape(node) do |char, index, within_character_class|
@@ -64,6 +65,7 @@ module RuboCop
64
65
  # different versions of Ruby so that e.g. /\i/ != /i/
65
66
  return true if /[[:alnum:]]/.match?(char)
66
67
  return true if ALLOWED_ALWAYS_ESCAPES.include?(char) || delimiter?(node, char)
68
+ return true if requires_escape_to_avoid_interpolation?(node.source[index], char)
67
69
 
68
70
  if within_character_class
69
71
  ALLOWED_WITHIN_CHAR_CLASS_METACHAR_ESCAPES.include?(char) &&
@@ -95,6 +97,12 @@ module RuboCop
95
97
  delimiters.include?(char)
96
98
  end
97
99
 
100
+ def requires_escape_to_avoid_interpolation?(char_before_escape, escaped_char)
101
+ # Preserve escapes after '#' that would otherwise trigger interpolation:
102
+ # '#@ivar', '#@@cvar', and '#$gvar'.
103
+ char_before_escape == '#' && INTERPOLATION_SIGILS.include?(escaped_char)
104
+ end
105
+
98
106
  def each_escape(node)
99
107
  node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
100
108
  yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
@@ -67,6 +67,9 @@ module RuboCop
67
67
 
68
68
  def on_or_asgn(node)
69
69
  allow_self(node.lhs)
70
+
71
+ lhs_name = node.lhs.lvasgn_type? ? node.lhs.name : node.lhs
72
+ add_lhs_to_local_variables_scopes(node.rhs, lhs_name)
70
73
  end
71
74
  alias on_and_asgn on_or_asgn
72
75
 
@@ -118,15 +121,16 @@ module RuboCop
118
121
  end
119
122
 
120
123
  alias on_numblock on_block
124
+ alias on_itblock on_block
121
125
 
122
126
  def on_if(node)
123
127
  # Allow conditional nodes to use `self` in the condition if that variable
124
128
  # name is used in an `lvasgn` or `masgn` within the `if`.
125
- node.child_nodes.each do |child_node|
126
- if child_node.lvasgn_type?
127
- add_lhs_to_local_variables_scopes(node.condition, child_node.lhs)
128
- elsif child_node.masgn_type?
129
- add_masgn_lhs_variables(node.condition, child_node.lhs)
129
+ node.each_descendant(:lvasgn, :masgn) do |descendant_node|
130
+ if descendant_node.lvasgn_type?
131
+ add_lhs_to_local_variables_scopes(node.condition, descendant_node.lhs)
132
+ else
133
+ add_masgn_lhs_variables(node.condition, descendant_node.lhs)
130
134
  end
131
135
  end
132
136
  end
@@ -58,7 +58,7 @@ module RuboCop
58
58
  # rubocop:disable Metrics/AbcSize
59
59
  def on_lvasgn(node)
60
60
  return unless (rhs = node.rhs)
61
- return unless rhs.call_type? && method_returning_self?(rhs.method_name)
61
+ return unless rhs.type?(:any_block, :call) && method_returning_self?(rhs.method_name)
62
62
  return unless (receiver = rhs.receiver)
63
63
 
64
64
  receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
@@ -21,6 +21,7 @@ module RuboCop
21
21
 
22
22
  MSG_BLOCK = 'Use `sort` instead of `sort_by { |%<var>s| %<var>s }`.'
23
23
  MSG_NUMBLOCK = 'Use `sort` instead of `sort_by { _1 }`.'
24
+ MSG_ITBLOCK = 'Use `sort` instead of `sort_by { it }`.'
24
25
 
25
26
  def on_block(node)
26
27
  redundant_sort_by_block(node) do |send, var_name|
@@ -36,7 +37,17 @@ module RuboCop
36
37
  redundant_sort_by_numblock(node) do |send|
37
38
  range = sort_by_range(send, node)
38
39
 
39
- add_offense(range, message: format(MSG_NUMBLOCK)) do |corrector|
40
+ add_offense(range, message: MSG_NUMBLOCK) do |corrector|
41
+ corrector.replace(range, 'sort')
42
+ end
43
+ end
44
+ end
45
+
46
+ def on_itblock(node)
47
+ redundant_sort_by_itblock(node) do |send|
48
+ range = sort_by_range(send, node)
49
+
50
+ add_offense(range, message: MSG_ITBLOCK) do |corrector|
40
51
  corrector.replace(range, 'sort')
41
52
  end
42
53
  end
@@ -54,6 +65,11 @@ module RuboCop
54
65
  (numblock $(call _ :sort_by) 1 (lvar :_1))
55
66
  PATTERN
56
67
 
68
+ # @!method redundant_sort_by_itblock(node)
69
+ def_node_matcher :redundant_sort_by_itblock, <<~PATTERN
70
+ (itblock $(call _ :sort_by) _ (lvar :it))
71
+ PATTERN
72
+
57
73
  def sort_by_range(send, node)
58
74
  range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
59
75
  end
@@ -155,7 +155,7 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def preferred_delimiters
158
- config.for_cop('Style/PercentLiteralDelimiters') ['PreferredDelimiters']['%r'].chars
158
+ config.for_cop('Style/PercentLiteralDelimiters')['PreferredDelimiters']['%r'].chars
159
159
  end
160
160
 
161
161
  def allowed_omit_parentheses_with_percent_r_literal?(node)
@@ -67,11 +67,13 @@ module RuboCop
67
67
  node.parent && parentheses?(node.parent)
68
68
  end
69
69
 
70
+ # rubocop:disable Metrics/AbcSize
70
71
  def correct_rescue_block(corrector, node, parenthesized)
71
72
  operation = node.body
72
73
 
73
74
  node_indentation, node_offset = indentation_and_offset(node, parenthesized)
74
75
 
76
+ corrector.wrap(operation, '[', ']') if operation.array_type? && !operation.bracketed?
75
77
  corrector.remove(range_between(operation.source_range.end_pos, node.source_range.end_pos))
76
78
  corrector.insert_before(operation, "begin\n#{node_indentation}")
77
79
  corrector.insert_after(heredoc_end(operation) || operation, <<~RESCUE_CLAUSE.chop)
@@ -81,6 +83,7 @@ module RuboCop
81
83
  #{node_offset}end
82
84
  RESCUE_CLAUSE
83
85
  end
86
+ # rubocop:enable Metrics/AbcSize
84
87
 
85
88
  def indentation_and_offset(node, parenthesized)
86
89
  node_indentation = indentation(node)
@@ -47,7 +47,7 @@ module RuboCop
47
47
 
48
48
  def on_return(node)
49
49
  # Check Lint/NonLocalExitFromIterator first before this cop
50
- node.each_ancestor(:block, :def, :defs) do |n|
50
+ node.each_ancestor(:block, :any_def) do |n|
51
51
  break if scoped_node?(n)
52
52
 
53
53
  send_node, args_node, _body_node = *n
@@ -83,7 +83,7 @@ module RuboCop
83
83
  end
84
84
 
85
85
  def scoped_node?(node)
86
- node.type?(:def, :defs) || node.lambda?
86
+ node.any_def_type? || node.lambda?
87
87
  end
88
88
 
89
89
  # @!method chained_send?(node)
@@ -86,6 +86,10 @@ module RuboCop
86
86
  # foo.baz = bar if foo
87
87
  # foo.baz + bar if foo
88
88
  # foo.bar > 2 if foo
89
+ #
90
+ # foo ? foo[index] : nil # Ignored `foo&.[](index)` due to unclear readability benefit.
91
+ # foo ? foo[idx] = v : nil # Ignored `foo&.[]=(idx, v)` due to unclear readability benefit.
92
+ # foo ? foo * 42 : nil # Ignored `foo&.*(42)` due to unclear readability benefit.
89
93
  class SafeNavigation < Base # rubocop:disable Metrics/ClassLength
90
94
  include NilMethods
91
95
  include RangeHelp
@@ -138,6 +142,7 @@ module RuboCop
138
142
  # @!method strip_begin(node)
139
143
  def_node_matcher :strip_begin, '{ (begin $!begin) $!(begin) }'
140
144
 
145
+ # rubocop:disable Metrics/AbcSize
141
146
  def on_if(node)
142
147
  return if allowed_if_condition?(node)
143
148
 
@@ -146,13 +151,16 @@ module RuboCop
146
151
 
147
152
  body = extract_if_body(node)
148
153
  method_call = receiver.parent
154
+ return if dotless_operator_call?(method_call) || method_call.double_colon?
149
155
 
150
156
  removal_ranges = [begin_range(node, body), end_range(node, body)]
151
157
 
152
158
  report_offense(node, method_chain, method_call, *removal_ranges) do |corrector|
159
+ corrector.replace(receiver, checked_variable.source) if checked_variable.csend_type?
153
160
  corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
154
161
  end
155
162
  end
163
+ # rubocop:enable Metrics/AbcSize
156
164
 
157
165
  def on_and(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
158
166
  collect_and_clauses(node).each do |(lhs, lhs_operator_range), (rhs, _rhs_operator_range)|
@@ -174,12 +182,19 @@ module RuboCop
174
182
  range_with_surrounding_space(range: lhs.source_range, side: :right),
175
183
  range_with_surrounding_space(range: lhs_operator_range, side: :right),
176
184
  offense_range: range_between(lhs.source_range.begin_pos, rhs.source_range.end_pos)
177
- )
185
+ ) do |corrector|
186
+ corrector.replace(rhs_receiver, lhs_receiver.source)
187
+ end
188
+ ignore_node(node)
178
189
  end
179
190
  end
180
191
 
192
+ private
193
+
181
194
  def report_offense(node, rhs, rhs_receiver, *removal_ranges, offense_range: node)
182
195
  add_offense(offense_range) do |corrector|
196
+ next if ignored_node?(node)
197
+
183
198
  # If the RHS is an `or` we cannot safely autocorrect because in order to remove
184
199
  # the non-nil check we need to add safe-navs to all clauses where the receiver is used
185
200
  next if and_with_rhs_or?(node)
@@ -193,8 +208,6 @@ module RuboCop
193
208
  end
194
209
  end
195
210
 
196
- private
197
-
198
211
  def find_method_chain(node)
199
212
  return node unless node&.parent&.call_type?
200
213
 
@@ -227,10 +240,10 @@ module RuboCop
227
240
  end
228
241
 
229
242
  def offending_node?(node, lhs_receiver, rhs, rhs_receiver) # rubocop:disable Metrics/CyclomaticComplexity
230
- return false if lhs_receiver != rhs_receiver || rhs_receiver.nil?
243
+ return false if !matching_nodes?(lhs_receiver, rhs_receiver) || rhs_receiver.nil?
231
244
  return false if use_var_only_in_unless_modifier?(node, lhs_receiver)
232
245
  return false if chain_length(rhs, rhs_receiver) > max_chain_length
233
- return false if unsafe_method_used?(rhs, rhs_receiver.parent)
246
+ return false if unsafe_method_used?(node, rhs, rhs_receiver.parent)
234
247
  return false if rhs.send_type? && rhs.method?(:empty?)
235
248
 
236
249
  true
@@ -248,6 +261,20 @@ module RuboCop
248
261
  end
249
262
  end
250
263
 
264
+ def dotless_operator_call?(method_call)
265
+ return true if dotless_operator_method?(method_call)
266
+
267
+ method_call = method_call.parent while method_call.parent.send_type?
268
+
269
+ dotless_operator_method?(method_call)
270
+ end
271
+
272
+ def dotless_operator_method?(method_call)
273
+ return false if method_call.loc.dot
274
+
275
+ method_call.method?(:[]) || method_call.method?(:[]=) || method_call.operator_method?
276
+ end
277
+
251
278
  def handle_comments(corrector, node, method_call)
252
279
  comments = comments(node)
253
280
  return if comments.empty?
@@ -306,11 +333,29 @@ module RuboCop
306
333
 
307
334
  receiver = method_chain.receiver
308
335
 
309
- return receiver if receiver == checked_variable
336
+ return receiver if matching_nodes?(receiver, checked_variable)
310
337
 
311
338
  find_matching_receiver_invocation(receiver, checked_variable)
312
339
  end
313
340
 
341
+ def matching_nodes?(left, right)
342
+ left == right || matching_call_nodes?(left, right)
343
+ end
344
+
345
+ def matching_call_nodes?(left, right)
346
+ return false unless left && right.respond_to?(:call_type?)
347
+ return false unless left.call_type? && right.call_type?
348
+
349
+ # Compare receiver and method name, but ignore the difference between
350
+ # safe navigation method call (`&.`) and dot method call (`.`).
351
+ left_receiver, left_method, *left_args = left.children
352
+ right_receiver, right_method, *right_args = right.children
353
+
354
+ left_method == right_method &&
355
+ matching_nodes?(left_receiver, right_receiver) &&
356
+ left_args == right_args
357
+ end
358
+
314
359
  def chain_length(method_chain, method)
315
360
  method.each_ancestor(:call).inject(0) do |total, ancestor|
316
361
  break total + 1 if ancestor == method_chain
@@ -319,21 +364,24 @@ module RuboCop
319
364
  end
320
365
  end
321
366
 
322
- def unsafe_method_used?(method_chain, method)
323
- return true if unsafe_method?(method)
367
+ def unsafe_method_used?(node, method_chain, method)
368
+ return true if unsafe_method?(node, method)
324
369
 
325
370
  method.each_ancestor(:send).any? do |ancestor|
326
371
  break true unless config.cop_enabled?('Lint/SafeNavigationChain')
327
372
 
328
- break true if unsafe_method?(ancestor)
373
+ break true if unsafe_method?(node, ancestor)
329
374
  break true if nil_methods.include?(ancestor.method_name)
330
375
  break false if ancestor == method_chain
331
376
  end
332
377
  end
333
378
 
334
- def unsafe_method?(send_node)
335
- negated?(send_node) ||
336
- send_node.assignment? ||
379
+ def unsafe_method?(node, send_node)
380
+ return true if negated?(send_node)
381
+
382
+ return false if node.respond_to?(:ternary?) && node.ternary?
383
+
384
+ send_node.assignment? ||
337
385
  (!send_node.dot? && !send_node.safe_navigation?)
338
386
  end
339
387
 
@@ -362,8 +410,7 @@ module RuboCop
362
410
  method_chain)
363
411
  start_method.each_ancestor do |ancestor|
364
412
  break unless %i[send block].include?(ancestor.type)
365
- next unless ancestor.send_type?
366
- next if ancestor.safe_navigation?
413
+ next if !ancestor.send_type? || ancestor.operator_method?
367
414
 
368
415
  corrector.insert_before(ancestor.loc.dot, '&')
369
416
 
@@ -59,6 +59,7 @@ module RuboCop
59
59
  {
60
60
  (block call (args (arg $_)) ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
61
61
  (numblock call $1 ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
62
+ (itblock call $_ ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
62
63
  }
63
64
  PATTERN
64
65
 
@@ -137,6 +138,7 @@ module RuboCop
137
138
  return unless (block_arg_name, regexp_method_send_node = regexp_match?(block_node))
138
139
 
139
140
  block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
141
+
140
142
  return unless calls_lvar?(regexp_method_send_node, block_arg_name)
141
143
 
142
144
  regexp_method_send_node
@@ -150,7 +152,8 @@ module RuboCop
150
152
  return node.child_nodes.first if node.match_with_lvasgn_type?
151
153
 
152
154
  if node.receiver.lvar_type? &&
153
- (block.numblock_type? || node.receiver.source == block.first_argument.source)
155
+ (block.type?(:numblock, :itblock) ||
156
+ node.receiver.source == block.first_argument.source)
154
157
  node.first_argument
155
158
  elsif node.first_argument.lvar_type?
156
159
  node.receiver