rubocop 1.67.0 → 1.81.6

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 (526) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +384 -72
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +8 -3
  7. data/exe/rubocop +1 -8
  8. data/lib/rubocop/cached_data.rb +12 -4
  9. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  10. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  11. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  12. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  13. data/lib/rubocop/cli/command/version.rb +2 -2
  14. data/lib/rubocop/cli.rb +19 -4
  15. data/lib/rubocop/comment_config.rb +2 -2
  16. data/lib/rubocop/config.rb +52 -10
  17. data/lib/rubocop/config_loader.rb +56 -48
  18. data/lib/rubocop/config_loader_resolver.rb +36 -10
  19. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  20. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  21. data/lib/rubocop/config_obsoletion.rb +46 -2
  22. data/lib/rubocop/config_store.rb +5 -0
  23. data/lib/rubocop/config_validator.rb +25 -14
  24. data/lib/rubocop/cop/autocorrect_logic.rb +53 -28
  25. data/lib/rubocop/cop/base.rb +7 -1
  26. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  28. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  29. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  30. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -16
  32. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +8 -3
  33. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  34. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  35. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  36. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  37. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
  38. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  40. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  41. data/lib/rubocop/cop/generator.rb +6 -0
  42. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  43. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  44. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  45. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  46. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  47. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  48. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  49. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  50. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  51. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +233 -0
  52. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  53. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  54. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  55. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  56. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  57. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  58. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  59. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  60. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  61. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  62. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  63. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  64. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  65. data/lib/rubocop/cop/internal_affairs.rb +7 -16
  66. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  67. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  68. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  69. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  70. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  71. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  72. data/lib/rubocop/cop/layout/class_structure.rb +45 -10
  73. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  74. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  75. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  76. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  77. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -3
  78. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +34 -20
  79. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  80. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +37 -7
  81. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  82. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  83. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  84. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  85. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  86. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  87. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  88. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  89. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -9
  90. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  91. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  92. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  93. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  94. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -11
  95. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  96. data/lib/rubocop/cop/layout/indentation_width.rb +8 -7
  97. data/lib/rubocop/cop/layout/leading_comment_space.rb +57 -2
  98. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  99. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  100. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  101. data/lib/rubocop/cop/layout/line_length.rb +158 -10
  102. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  103. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  104. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  105. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  106. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  107. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  108. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  109. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +11 -8
  110. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  111. data/lib/rubocop/cop/layout/redundant_line_break.rb +19 -46
  112. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +14 -7
  113. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  114. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  115. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  116. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  117. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  118. data/lib/rubocop/cop/layout/space_around_keyword.rb +8 -2
  119. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  120. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -21
  121. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  122. data/lib/rubocop/cop/layout/space_before_brackets.rb +7 -40
  123. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  124. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  125. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +18 -3
  126. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +5 -0
  127. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +7 -0
  128. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  129. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -4
  130. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  131. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  132. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +118 -0
  133. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  134. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  135. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  136. data/lib/rubocop/cop/lint/circular_argument_reference.rb +4 -1
  137. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  138. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  139. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  140. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +90 -0
  141. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  142. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  143. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +7 -3
  144. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  145. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  146. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -23
  147. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +6 -43
  148. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  149. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  150. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  151. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  152. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  153. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  154. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  155. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  156. data/lib/rubocop/cop/lint/float_comparison.rb +51 -18
  157. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  158. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  159. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  160. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  161. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  162. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  163. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  164. data/lib/rubocop/cop/lint/literal_as_condition.rb +125 -10
  165. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  166. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  167. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
  168. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  169. data/lib/rubocop/cop/lint/mixed_case_range.rb +5 -8
  170. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  171. data/lib/rubocop/cop/lint/nested_method_definition.rb +10 -6
  172. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  173. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  174. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  175. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  176. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  177. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  178. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  179. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +94 -0
  180. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -3
  181. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  182. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  183. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  184. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  185. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +2 -2
  186. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  187. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +113 -9
  188. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  189. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  190. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  191. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  192. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  193. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  194. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  195. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  196. data/lib/rubocop/cop/lint/rescue_exception.rb +2 -5
  197. data/lib/rubocop/cop/lint/rescue_type.rb +4 -8
  198. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  199. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  200. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  201. data/lib/rubocop/cop/lint/self_assignment.rb +39 -15
  202. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  203. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  204. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -1
  205. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  206. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  207. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  208. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  209. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  210. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  211. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  212. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  213. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  214. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  215. data/lib/rubocop/cop/lint/unreachable_code.rb +52 -2
  216. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  217. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  218. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  219. data/lib/rubocop/cop/lint/useless_access_modifier.rb +34 -8
  220. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -1
  221. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  222. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  223. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  224. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  225. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  226. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +3 -1
  227. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  228. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -2
  229. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -5
  230. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  231. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  232. data/lib/rubocop/cop/lint/void.rb +23 -12
  233. data/lib/rubocop/cop/message_annotator.rb +7 -3
  234. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  235. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  236. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  237. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  238. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  239. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  240. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  241. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  242. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  243. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  244. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -4
  245. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  246. data/lib/rubocop/cop/mixin/alignment.rb +3 -3
  247. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  248. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  249. data/lib/rubocop/cop/mixin/check_line_breakable.rb +22 -12
  250. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  251. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  252. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  253. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  254. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  255. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  256. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  257. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  258. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  259. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -3
  260. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  261. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  262. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  263. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  264. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  265. data/lib/rubocop/cop/mixin/line_length_help.rb +27 -10
  266. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  267. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -9
  268. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  269. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  270. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  271. data/lib/rubocop/cop/mixin/range_help.rb +15 -4
  272. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  273. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  274. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  275. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  276. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  277. data/lib/rubocop/cop/mixin/trailing_comma.rb +21 -5
  278. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  279. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  280. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  281. data/lib/rubocop/cop/naming/file_name.rb +2 -4
  282. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -13
  283. data/lib/rubocop/cop/naming/method_name.rb +185 -15
  284. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  285. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +48 -4
  286. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  287. data/lib/rubocop/cop/naming/variable_name.rb +50 -6
  288. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  289. data/lib/rubocop/cop/offense.rb +2 -3
  290. data/lib/rubocop/cop/registry.rb +9 -6
  291. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  292. data/lib/rubocop/cop/security/eval.rb +2 -1
  293. data/lib/rubocop/cop/security/json_load.rb +33 -11
  294. data/lib/rubocop/cop/security/open.rb +1 -0
  295. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  296. data/lib/rubocop/cop/style/access_modifier_declarations.rb +114 -34
  297. data/lib/rubocop/cop/style/accessor_grouping.rb +32 -6
  298. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  299. data/lib/rubocop/cop/style/and_or.rb +1 -1
  300. data/lib/rubocop/cop/style/arguments_forwarding.rb +57 -44
  301. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  302. data/lib/rubocop/cop/style/array_intersect.rb +115 -39
  303. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  304. data/lib/rubocop/cop/style/bitwise_predicate.rb +107 -0
  305. data/lib/rubocop/cop/style/block_delimiters.rb +44 -26
  306. data/lib/rubocop/cop/style/case_like_if.rb +9 -12
  307. data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
  308. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  309. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  310. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  311. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  312. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  313. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  314. data/lib/rubocop/cop/style/commented_keyword.rb +20 -3
  315. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  316. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  317. data/lib/rubocop/cop/style/conditional_assignment.rb +49 -31
  318. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  319. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  320. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  321. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  322. data/lib/rubocop/cop/style/documentation.rb +1 -1
  323. data/lib/rubocop/cop/style/double_negation.rb +5 -5
  324. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  325. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  326. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  327. data/lib/rubocop/cop/style/empty_literal.rb +5 -1
  328. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  329. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  330. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  331. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  332. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  333. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  334. data/lib/rubocop/cop/style/explicit_block_argument.rb +17 -4
  335. data/lib/rubocop/cop/style/exponential_notation.rb +6 -5
  336. data/lib/rubocop/cop/style/fetch_env_var.rb +34 -7
  337. data/lib/rubocop/cop/style/file_null.rb +89 -0
  338. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  339. data/lib/rubocop/cop/style/float_division.rb +8 -4
  340. data/lib/rubocop/cop/style/for.rb +1 -1
  341. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  342. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  343. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  344. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  345. data/lib/rubocop/cop/style/guard_clause.rb +17 -3
  346. data/lib/rubocop/cop/style/hash_conversion.rb +16 -9
  347. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  348. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  349. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  350. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  351. data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
  352. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  353. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  354. data/lib/rubocop/cop/style/identical_conditional_branches.rb +25 -6
  355. data/lib/rubocop/cop/style/if_inside_else.rb +10 -14
  356. data/lib/rubocop/cop/style/if_unless_modifier.rb +36 -9
  357. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  358. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -4
  359. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -9
  360. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  361. data/lib/rubocop/cop/style/inverse_methods.rb +16 -13
  362. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  363. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  364. data/lib/rubocop/cop/style/it_assignment.rb +93 -0
  365. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  366. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  367. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  368. data/lib/rubocop/cop/style/lambda.rb +1 -0
  369. data/lib/rubocop/cop/style/lambda_call.rb +10 -4
  370. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  371. data/lib/rubocop/cop/style/map_into_array.rb +11 -3
  372. data/lib/rubocop/cop/style/map_to_hash.rb +13 -4
  373. data/lib/rubocop/cop/style/map_to_set.rb +4 -5
  374. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +28 -20
  375. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +18 -0
  376. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  377. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  378. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  379. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  380. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  381. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  382. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  383. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  384. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  385. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  386. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  387. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  388. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  389. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  390. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  391. data/lib/rubocop/cop/style/next.rb +44 -0
  392. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  393. data/lib/rubocop/cop/style/not.rb +1 -1
  394. data/lib/rubocop/cop/style/object_then.rb +15 -15
  395. data/lib/rubocop/cop/style/one_line_conditional.rb +42 -13
  396. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  397. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  398. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  399. data/lib/rubocop/cop/style/parallel_assignment.rb +41 -38
  400. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  401. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  402. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  403. data/lib/rubocop/cop/style/proc.rb +2 -2
  404. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  405. data/lib/rubocop/cop/style/raise_args.rb +15 -13
  406. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  407. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  408. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  409. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  410. data/lib/rubocop/cop/style/redundant_begin.rb +36 -1
  411. data/lib/rubocop/cop/style/redundant_condition.rb +95 -23
  412. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  413. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  414. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  415. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  416. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  417. data/lib/rubocop/cop/style/redundant_format.rb +283 -0
  418. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  419. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  420. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  421. data/lib/rubocop/cop/style/redundant_line_continuation.rb +55 -19
  422. data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -36
  423. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -0
  424. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  425. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -1
  426. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  427. data/lib/rubocop/cop/style/redundant_self.rb +15 -18
  428. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  429. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  430. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  431. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  432. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  433. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  434. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
  435. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  436. data/lib/rubocop/cop/style/safe_navigation.rb +75 -16
  437. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  438. data/lib/rubocop/cop/style/select_by_regexp.rb +5 -2
  439. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  440. data/lib/rubocop/cop/style/semicolon.rb +21 -6
  441. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  442. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  443. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  444. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  445. data/lib/rubocop/cop/style/single_line_do_end_block.rb +15 -4
  446. data/lib/rubocop/cop/style/single_line_methods.rb +13 -11
  447. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  448. data/lib/rubocop/cop/style/sole_nested_conditional.rb +68 -102
  449. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  450. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  451. data/lib/rubocop/cop/style/string_concatenation.rb +21 -17
  452. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  453. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  454. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  455. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  456. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  457. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  458. data/lib/rubocop/cop/style/symbol_proc.rb +3 -1
  459. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  460. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  461. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +56 -2
  462. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  463. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  464. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  465. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  466. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  467. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  468. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  469. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  470. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  471. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  472. data/lib/rubocop/cop/team.rb +1 -1
  473. data/lib/rubocop/cop/util.rb +12 -5
  474. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  475. data/lib/rubocop/cop/variable_force/assignment.rb +24 -5
  476. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  477. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  478. data/lib/rubocop/cop/variable_force/variable.rb +14 -3
  479. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  480. data/lib/rubocop/cop/variable_force.rb +30 -19
  481. data/lib/rubocop/cops_documentation_generator.rb +54 -28
  482. data/lib/rubocop/directive_comment.rb +45 -11
  483. data/lib/rubocop/ext/regexp_node.rb +0 -1
  484. data/lib/rubocop/formatter/disabled_config_formatter.rb +20 -6
  485. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  486. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  487. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  488. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  489. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  490. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  491. data/lib/rubocop/lsp/diagnostic.rb +190 -0
  492. data/lib/rubocop/lsp/logger.rb +2 -2
  493. data/lib/rubocop/lsp/routes.rb +66 -26
  494. data/lib/rubocop/lsp/runtime.rb +18 -50
  495. data/lib/rubocop/lsp/server.rb +2 -4
  496. data/lib/rubocop/lsp/stdin_runner.rb +69 -0
  497. data/lib/rubocop/magic_comment.rb +11 -3
  498. data/lib/rubocop/options.rb +28 -12
  499. data/lib/rubocop/path_util.rb +15 -8
  500. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  501. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  502. data/lib/rubocop/plugin/load_error.rb +26 -0
  503. data/lib/rubocop/plugin/loader.rb +100 -0
  504. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  505. data/lib/rubocop/plugin.rb +46 -0
  506. data/lib/rubocop/rake_task.rb +4 -1
  507. data/lib/rubocop/result_cache.rb +27 -25
  508. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  509. data/lib/rubocop/rspec/expect_offense.rb +15 -5
  510. data/lib/rubocop/rspec/shared_contexts.rb +38 -1
  511. data/lib/rubocop/rspec/support.rb +4 -2
  512. data/lib/rubocop/runner.rb +31 -18
  513. data/lib/rubocop/server/cache.rb +51 -13
  514. data/lib/rubocop/server/cli.rb +2 -2
  515. data/lib/rubocop/server/client_command/base.rb +10 -0
  516. data/lib/rubocop/server/client_command/exec.rb +2 -1
  517. data/lib/rubocop/server/client_command/start.rb +11 -1
  518. data/lib/rubocop/target_finder.rb +14 -9
  519. data/lib/rubocop/target_ruby.rb +27 -3
  520. data/lib/rubocop/version.rb +53 -12
  521. data/lib/rubocop.rb +44 -2
  522. data/lib/ruby_lsp/rubocop/addon.rb +90 -0
  523. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  524. metadata +91 -21
  525. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  526. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for redundant safe navigation calls.
7
7
  # Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
8
8
  # and an offense is not detected when the receiver is a constant. The detection also applies
9
- # to literal receivers, except for `nil`.
9
+ # to `self`, and to literal receivers, except for `nil`.
10
10
  #
11
11
  # For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
12
12
  # and `equal?` methods are checked by default.
@@ -20,6 +20,15 @@ module RuboCop
20
20
  # In the example below, the safe navigation operator (`&.`) is unnecessary
21
21
  # because `NilClass` has methods like `respond_to?` and `is_a?`.
22
22
  #
23
+ # The `InferNonNilReceiver` option specifies whether to look into previous code
24
+ # paths to infer if the receiver can't be nil. This check is unsafe because the receiver
25
+ # can be redefined between the safe navigation call and previous regular method call.
26
+ # It does the inference only in the current scope, e.g. within the same method definition etc.
27
+ #
28
+ # The `AdditionalNilMethods` option specifies additional custom methods which are
29
+ # defined on `NilClass`. When `InferNonNilReceiver` is set, they are used to determine
30
+ # whether the receiver can be nil.
31
+ #
23
32
  # @safety
24
33
  # This cop is unsafe, because autocorrection can change the return type of
25
34
  # the expression. An offending expression that previously could return `nil`
@@ -29,6 +38,23 @@ module RuboCop
29
38
  # # bad
30
39
  # CamelCaseConst&.do_something
31
40
  #
41
+ # # good
42
+ # CamelCaseConst.do_something
43
+ #
44
+ # # bad
45
+ # foo.to_s&.strip
46
+ # foo.to_i&.zero?
47
+ # foo.to_f&.zero?
48
+ # foo.to_a&.size
49
+ # foo.to_h&.size
50
+ #
51
+ # # good
52
+ # foo.to_s.strip
53
+ # foo.to_i.zero?
54
+ # foo.to_f.zero?
55
+ # foo.to_a.size
56
+ # foo.to_h.size
57
+ #
32
58
  # # bad
33
59
  # do_something if attrs&.respond_to?(:[])
34
60
  #
@@ -41,9 +67,6 @@ module RuboCop
41
67
  # end
42
68
  #
43
69
  # # good
44
- # CamelCaseConst.do_something
45
- #
46
- # # good
47
70
  # while node.is_a?(BeginNode)
48
71
  # node = node.parent
49
72
  # end
@@ -67,6 +90,12 @@ module RuboCop
67
90
  # foo.to_f
68
91
  # foo.to_s
69
92
  #
93
+ # # bad
94
+ # self&.foo
95
+ #
96
+ # # good
97
+ # self.foo
98
+ #
70
99
  # @example AllowedMethods: [nil_safe_method]
71
100
  # # bad
72
101
  # do_something if attrs&.nil_safe_method(:[])
@@ -75,17 +104,59 @@ module RuboCop
75
104
  # do_something if attrs.nil_safe_method(:[])
76
105
  # do_something if attrs&.not_nil_safe_method(:[])
77
106
  #
107
+ # @example InferNonNilReceiver: false (default)
108
+ # # good
109
+ # foo.bar
110
+ # foo&.baz
111
+ #
112
+ # @example InferNonNilReceiver: true
113
+ # # bad
114
+ # foo.bar
115
+ # foo&.baz # would raise on previous line if `foo` is nil
116
+ #
117
+ # # good
118
+ # foo.bar
119
+ # foo.baz
120
+ #
121
+ # # bad
122
+ # if foo.condition?
123
+ # foo&.bar
124
+ # end
125
+ #
126
+ # # good
127
+ # if foo.condition?
128
+ # foo.bar
129
+ # end
130
+ #
131
+ # # good (different scopes)
132
+ # def method1
133
+ # foo.bar
134
+ # end
135
+ #
136
+ # def method2
137
+ # foo&.bar
138
+ # end
139
+ #
140
+ # @example AdditionalNilMethods: [present?]
141
+ # # good
142
+ # foo.present?
143
+ # foo&.bar
144
+ #
78
145
  class RedundantSafeNavigation < Base
79
146
  include AllowedMethods
80
147
  extend AutoCorrector
81
148
 
82
149
  MSG = 'Redundant safe navigation detected, use `.` instead.'
83
150
  MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
151
+ MSG_NON_NIL = 'Redundant safe navigation on non-nil receiver (detected by analyzing ' \
152
+ 'previous code/method invocations).'
84
153
 
85
154
  NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
86
155
 
87
156
  SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
88
157
 
158
+ GUARANTEED_INSTANCE_METHODS = %i[to_s to_i to_f to_a to_h].freeze
159
+
89
160
  # @!method respond_to_nil_specific_method?(node)
90
161
  def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
91
162
  (csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
@@ -105,15 +176,27 @@ module RuboCop
105
176
 
106
177
  # rubocop:disable Metrics/AbcSize
107
178
  def on_csend(node)
179
+ range = node.loc.dot
180
+
181
+ if infer_non_nil_receiver?
182
+ checker = Lint::Utils::NilReceiverChecker.new(node.receiver, additional_nil_methods)
183
+
184
+ if checker.cant_be_nil?
185
+ add_offense(range, message: MSG_NON_NIL) { |corrector| corrector.replace(range, '.') }
186
+ return
187
+ end
188
+ end
189
+
108
190
  unless assume_receiver_instance_exists?(node.receiver)
109
- return unless check?(node) && allowed_method?(node.method_name)
191
+ return if !guaranteed_instance?(node.receiver) && !check?(node)
110
192
  return if respond_to_nil_specific_method?(node)
111
193
  end
112
194
 
113
- range = node.loc.dot
114
195
  add_offense(range) { |corrector| corrector.replace(range, '.') }
115
196
  end
197
+ # rubocop:enable Metrics/AbcSize
116
198
 
199
+ # rubocop:disable Metrics/AbcSize
117
200
  def on_or(node)
118
201
  conversion_with_default?(node) do |send_node|
119
202
  range = send_node.loc.dot.begin.join(node.source_range.end)
@@ -133,22 +216,43 @@ module RuboCop
133
216
  def assume_receiver_instance_exists?(receiver)
134
217
  return true if receiver.const_type? && !receiver.short_name.match?(SNAKE_CASE)
135
218
 
136
- receiver.literal? && !receiver.nil_type?
219
+ receiver.self_type? || (receiver.literal? && !receiver.nil_type?)
220
+ end
221
+
222
+ def guaranteed_instance?(node)
223
+ receiver = if node.any_block_type?
224
+ node.send_node
225
+ else
226
+ node
227
+ end
228
+ return false unless receiver.send_type?
229
+
230
+ GUARANTEED_INSTANCE_METHODS.include?(receiver.method_name)
137
231
  end
138
232
 
139
233
  def check?(node)
234
+ return false unless allowed_method?(node.method_name)
235
+
140
236
  parent = node.parent
141
237
  return false unless parent
142
238
 
143
239
  condition?(parent, node) ||
144
- parent.and_type? ||
145
- parent.or_type? ||
240
+ parent.operator_keyword? ||
146
241
  (parent.send_type? && parent.negation_method?)
147
242
  end
148
243
 
149
244
  def condition?(parent, node)
150
245
  (parent.conditional? || parent.post_condition_loop?) && parent.condition == node
151
246
  end
247
+
248
+ def infer_non_nil_receiver?
249
+ cop_config['InferNonNilReceiver']
250
+ end
251
+
252
+ def additional_nil_methods
253
+ @additional_nil_methods ||=
254
+ Array(cop_config.fetch('AdditionalNilMethods', []).map(&:to_sym))
255
+ end
152
256
  end
153
257
  end
154
258
  end
@@ -135,10 +135,10 @@ module RuboCop
135
135
  grandparent.array_type? && grandparent.children.size > 1
136
136
  end
137
137
 
138
+ # rubocop:disable Metrics/AbcSize
138
139
  def replacement_range_and_content(node)
139
- variable, = *node
140
- loc = node.loc
141
- expression = loc.expression
140
+ variable = node.children.first
141
+ expression = node.source_range
142
142
 
143
143
  if array_new?(variable)
144
144
  expression = node.parent.source_range if node.parent.array_type?
@@ -148,16 +148,17 @@ module RuboCop
148
148
  elsif redundant_brackets?(node)
149
149
  [expression, remove_brackets(variable)]
150
150
  else
151
- [loc.operator, '']
151
+ [node.loc.operator, '']
152
152
  end
153
153
  end
154
+ # rubocop:enable Metrics/AbcSize
154
155
 
155
156
  def array_splat?(node)
156
157
  node.children.first.array_type?
157
158
  end
158
159
 
159
160
  def method_argument?(node)
160
- node.parent.send_type?
161
+ node.parent.call_type?
161
162
  end
162
163
 
163
164
  def part_of_an_array?(node)
@@ -171,7 +172,7 @@ module RuboCop
171
172
  parent = node.parent
172
173
  grandparent = node.parent.parent
173
174
 
174
- parent.when_type? || parent.send_type? || part_of_an_array?(node) ||
175
+ parent.when_type? || method_argument?(node) || part_of_an_array?(node) ||
175
176
  grandparent&.resbody_type?
176
177
  end
177
178
 
@@ -196,7 +197,7 @@ module RuboCop
196
197
  def use_percent_literal_array_argument?(node)
197
198
  argument = node.children.first
198
199
 
199
- node.parent.send_type? &&
200
+ method_argument?(node) &&
200
201
  (argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
201
202
  end
202
203
 
@@ -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, Metrics/CyclomaticComplexity
189
+ def on_send(node)
190
+ return if node.arguments.any? || 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.end || node.loc.selector))
202
+ end
203
+ end
204
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
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
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks if `include` or `prepend` is called in `refine` block.
7
7
  # These methods are deprecated and should be replaced with `Refinement#import_methods`.
8
8
  #
9
- # It emulates deprecation warnings in Ruby 3.1.
9
+ # It emulates deprecation warnings in Ruby 3.1. Functionality has been removed in Ruby 3.2.
10
10
  #
11
11
  # @safety
12
12
  # This cop's autocorrection is unsafe because `include M` will affect the included class
@@ -17,7 +17,6 @@ module RuboCop
17
17
  # do_something
18
18
  # end
19
19
  class RegexpAsCondition < Base
20
- include IgnoredNode
21
20
  extend AutoCorrector
22
21
 
23
22
  MSG = 'Do not use regexp literal as a condition. ' \
@@ -43,7 +43,7 @@ module RuboCop
43
43
  def on_irange(node)
44
44
  return if node.parent&.begin_type?
45
45
  return unless node.begin && node.end
46
- return if same_line?(node.begin, node.end)
46
+ return if same_line?(node.loc.operator, node.end)
47
47
 
48
48
  message = format(MSG, range: "#{node.begin.source}#{node.loc.operator.source}")
49
49
 
@@ -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
  #
@@ -24,10 +24,7 @@ module RuboCop
24
24
  MSG = 'Avoid rescuing the `Exception` class. Perhaps you meant to rescue `StandardError`?'
25
25
 
26
26
  def on_resbody(node)
27
- return unless node.children.first
28
-
29
- rescue_args = node.children.first.children
30
- return unless rescue_args.any? { |a| targets_exception?(a) }
27
+ return unless node.exceptions.any? { |exception| targets_exception?(exception) }
31
28
 
32
29
  add_offense(node)
33
30
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Check for arguments to `rescue` that will result in a `TypeError`
6
+ # Checks for arguments to `rescue` that will result in a `TypeError`
7
7
  # if an exception is raised.
8
8
  #
9
9
  # @example
@@ -42,15 +42,11 @@ module RuboCop
42
42
  INVALID_TYPES = %i[array dstr float hash nil int str sym].freeze
43
43
 
44
44
  def on_resbody(node)
45
- rescued, _, _body = *node
46
- return if rescued.nil?
47
-
48
- exceptions = *rescued
49
- invalid_exceptions = invalid_exceptions(exceptions)
45
+ invalid_exceptions = invalid_exceptions(node.exceptions)
50
46
  return if invalid_exceptions.empty?
51
47
 
52
48
  add_offense(
53
- node.loc.keyword.join(rescued.source_range),
49
+ node.loc.keyword.join(node.children.first.source_range),
54
50
  message: format(MSG, invalid_exceptions: invalid_exceptions.map(&:source).join(', '))
55
51
  ) do |corrector|
56
52
  autocorrect(corrector, node)
@@ -58,7 +54,7 @@ module RuboCop
58
54
  end
59
55
 
60
56
  def autocorrect(corrector, node)
61
- rescued, _, _body = *node
57
+ rescued = node.children.first
62
58
  range = node.loc.keyword.end.join(rescued.source_range.end)
63
59
 
64
60
  corrector.replace(range, correction(*rescued))
@@ -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