rubocop 1.80.2 → 1.86.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +170 -19
  5. data/config/obsoletion.yml +9 -0
  6. data/lib/rubocop/cache_config.rb +29 -0
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +3 -3
  8. data/lib/rubocop/cli/command/lsp.rb +1 -1
  9. data/lib/rubocop/cli/command/mcp.rb +19 -0
  10. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  11. data/lib/rubocop/cli/command/show_docs_url.rb +1 -1
  12. data/lib/rubocop/cli.rb +28 -6
  13. data/lib/rubocop/comment_config.rb +62 -17
  14. data/lib/rubocop/config.rb +14 -10
  15. data/lib/rubocop/config_finder.rb +1 -1
  16. data/lib/rubocop/config_loader.rb +20 -21
  17. data/lib/rubocop/config_loader_resolver.rb +9 -7
  18. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  19. data/lib/rubocop/config_store.rb +6 -1
  20. data/lib/rubocop/config_validator.rb +1 -1
  21. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  22. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  24. data/lib/rubocop/cop/correctors/alignment_corrector.rb +22 -6
  25. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  27. data/lib/rubocop/cop/documentation.rb +2 -3
  28. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  29. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  31. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  32. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  33. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
  35. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  37. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  39. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  40. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  41. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  43. data/lib/rubocop/cop/layout/class_structure.rb +13 -6
  44. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  45. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +12 -2
  46. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
  47. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  50. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  51. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  52. data/lib/rubocop/cop/layout/end_alignment.rb +8 -1
  53. data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
  54. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  55. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  56. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  59. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  60. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  61. data/lib/rubocop/cop/layout/indentation_width.rb +111 -7
  62. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  63. data/lib/rubocop/cop/layout/line_length.rb +26 -9
  64. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  65. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  66. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  67. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  68. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +204 -39
  69. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -4
  70. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  71. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  72. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  73. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  74. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  75. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  76. data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
  77. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  78. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  79. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  80. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  81. data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
  82. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  83. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  84. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  85. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  86. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  87. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  88. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
  89. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  90. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  91. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  92. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  93. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  94. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  95. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  96. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  97. data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
  98. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  99. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +16 -6
  100. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  101. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  102. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
  103. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  104. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  105. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
  106. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  107. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
  108. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
  109. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  110. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  111. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  112. data/lib/rubocop/cop/lint/self_assignment.rb +10 -2
  113. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  114. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  115. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  116. data/lib/rubocop/cop/lint/to_json.rb +12 -16
  117. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  118. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  119. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  120. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  121. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  122. data/lib/rubocop/cop/lint/useless_assignment.rb +45 -17
  123. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  124. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  125. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  126. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +24 -9
  127. data/lib/rubocop/cop/lint/void.rb +39 -12
  128. data/lib/rubocop/cop/message_annotator.rb +1 -1
  129. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  130. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  131. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  132. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  133. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
  134. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  135. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
  136. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  137. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  138. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  139. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  140. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  141. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  142. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  143. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  144. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  145. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  146. data/lib/rubocop/cop/naming/method_name.rb +4 -2
  147. data/lib/rubocop/cop/naming/predicate_method.rb +27 -4
  148. data/lib/rubocop/cop/naming/predicate_prefix.rb +11 -11
  149. data/lib/rubocop/cop/offense.rb +9 -1
  150. data/lib/rubocop/cop/registry.rb +20 -13
  151. data/lib/rubocop/cop/security/eval.rb +15 -2
  152. data/lib/rubocop/cop/security/json_load.rb +33 -11
  153. data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
  154. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  155. data/lib/rubocop/cop/style/alias.rb +4 -1
  156. data/lib/rubocop/cop/style/and_or.rb +1 -0
  157. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  158. data/lib/rubocop/cop/style/array_intersect.rb +2 -2
  159. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  160. data/lib/rubocop/cop/style/array_join.rb +4 -2
  161. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  162. data/lib/rubocop/cop/style/attr.rb +5 -2
  163. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  164. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  165. data/lib/rubocop/cop/style/block_delimiters.rb +27 -34
  166. data/lib/rubocop/cop/style/case_equality.rb +15 -13
  167. data/lib/rubocop/cop/style/class_and_module_children.rb +11 -2
  168. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  169. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  170. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  171. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -18
  172. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  173. data/lib/rubocop/cop/style/copyright.rb +1 -1
  174. data/lib/rubocop/cop/style/documentation.rb +6 -6
  175. data/lib/rubocop/cop/style/documentation_method.rb +8 -8
  176. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  177. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  178. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  179. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  180. data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
  181. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  182. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  183. data/lib/rubocop/cop/style/encoding.rb +7 -1
  184. data/lib/rubocop/cop/style/end_block.rb +3 -1
  185. data/lib/rubocop/cop/style/endless_method.rb +23 -5
  186. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  187. data/lib/rubocop/cop/style/file_open.rb +84 -0
  188. data/lib/rubocop/cop/style/float_division.rb +15 -1
  189. data/lib/rubocop/cop/style/for.rb +3 -0
  190. data/lib/rubocop/cop/style/format_string_token.rb +49 -5
  191. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  192. data/lib/rubocop/cop/style/guard_clause.rb +27 -22
  193. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  194. data/lib/rubocop/cop/style/hash_lookup_method.rb +101 -0
  195. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  196. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  197. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  198. data/lib/rubocop/cop/style/if_inside_else.rb +1 -5
  199. data/lib/rubocop/cop/style/if_unless_modifier.rb +57 -17
  200. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
  201. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  202. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  203. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  204. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  205. data/lib/rubocop/cop/style/lambda_call.rb +8 -8
  206. data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
  207. data/lib/rubocop/cop/style/map_join.rb +123 -0
  208. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  209. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  210. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
  211. data/lib/rubocop/cop/style/module_member_existence_check.rb +107 -0
  212. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
  213. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  214. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  215. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  216. data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
  217. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  218. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  219. data/lib/rubocop/cop/style/not.rb +2 -0
  220. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  221. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  222. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
  223. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  224. data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
  225. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  226. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  227. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  228. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  229. data/lib/rubocop/cop/style/proc.rb +3 -2
  230. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  231. data/lib/rubocop/cop/style/reduce_to_hash.rb +184 -0
  232. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  233. data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
  234. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  235. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  236. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  237. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  238. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  239. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  240. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  241. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  242. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  243. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -22
  244. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  245. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  246. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  247. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  248. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  249. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  250. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  251. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  252. data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
  253. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  254. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  255. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  256. data/lib/rubocop/cop/style/semicolon.rb +25 -7
  257. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  258. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  259. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  260. data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
  261. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  262. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  263. data/lib/rubocop/cop/style/symbol_proc.rb +4 -3
  264. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  265. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  266. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  267. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  268. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  269. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  270. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  271. data/lib/rubocop/cop/team.rb +4 -4
  272. data/lib/rubocop/cop/util.rb +2 -3
  273. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  274. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  275. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  276. data/lib/rubocop/directive_comment.rb +48 -4
  277. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  278. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
  279. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  280. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  281. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  282. data/lib/rubocop/formatter/tap_formatter.rb +5 -2
  283. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  284. data/lib/rubocop/formatter.rb +22 -21
  285. data/lib/rubocop/lsp/diagnostic.rb +18 -33
  286. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  287. data/lib/rubocop/lsp/routes.rb +12 -5
  288. data/lib/rubocop/lsp/runtime.rb +13 -3
  289. data/lib/rubocop/lsp/stdin_runner.rb +8 -17
  290. data/lib/rubocop/magic_comment.rb +20 -0
  291. data/lib/rubocop/mcp/server.rb +200 -0
  292. data/lib/rubocop/options.rb +10 -1
  293. data/lib/rubocop/path_util.rb +14 -2
  294. data/lib/rubocop/plugin/loader.rb +1 -1
  295. data/lib/rubocop/rake_task.rb +1 -1
  296. data/lib/rubocop/remote_config.rb +10 -8
  297. data/lib/rubocop/result_cache.rb +60 -37
  298. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  299. data/lib/rubocop/rspec/shared_contexts.rb +18 -5
  300. data/lib/rubocop/rspec/support.rb +2 -1
  301. data/lib/rubocop/runner.rb +12 -3
  302. data/lib/rubocop/server/cache.rb +6 -29
  303. data/lib/rubocop/server/core.rb +2 -0
  304. data/lib/rubocop/target_finder.rb +1 -1
  305. data/lib/rubocop/target_ruby.rb +31 -14
  306. data/lib/rubocop/version.rb +2 -2
  307. data/lib/rubocop.rb +20 -0
  308. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  309. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  310. metadata +33 -9
@@ -6,8 +6,11 @@ module RuboCop
6
6
  # Checks for constant reassignments.
7
7
  #
8
8
  # Emulates Ruby's runtime warning "already initialized constant X"
9
- # when a constant is reassigned in the same file and namespace using the
10
- # `NAME = value` syntax.
9
+ # when a constant is reassigned in the same file and namespace.
10
+ #
11
+ # The cop tracks constants defined via `NAME = value` syntax as well as
12
+ # class/module keyword definitions. It detects reassignment when a constant
13
+ # is first defined one way and then redefined using the `NAME = value` syntax.
11
14
  #
12
15
  # The cop cannot catch all offenses, like, for example, when a constant
13
16
  # is reassigned in another file, or when using metaprogramming (`Module#const_set`).
@@ -36,6 +39,14 @@ module RuboCop
36
39
  # X = :bar
37
40
  # end
38
41
  #
42
+ # # bad
43
+ # class FooError < StandardError; end
44
+ # FooError = Class.new(RuntimeError)
45
+ #
46
+ # # bad
47
+ # module M; end
48
+ # M = 1
49
+ #
39
50
  # # good - keep only one assignment
40
51
  # X = :bar
41
52
  #
@@ -69,16 +80,30 @@ module RuboCop
69
80
 
70
81
  # @!method remove_constant(node)
71
82
  def_node_matcher :remove_constant, <<~PATTERN
72
- (send _ :remove_const
83
+ (send {nil? self} :remove_const
73
84
  ({sym str} $_))
74
85
  PATTERN
75
86
 
87
+ def on_class(node)
88
+ return unless unconditional_definition?(node)
89
+
90
+ constant_definitions[definition_name(node)] ||= :class
91
+ end
92
+
93
+ def on_module(node)
94
+ return unless unconditional_definition?(node)
95
+
96
+ constant_definitions[definition_name(node)] ||= :module
97
+ end
98
+
76
99
  def on_casgn(node)
77
100
  return unless fixed_constant_path?(node)
78
101
  return unless simple_assignment?(node)
79
- return if constant_names.add?(fully_qualified_constant_name(node))
80
102
 
81
- add_offense(node, message: format(MSG, constant: node.name))
103
+ name = fully_qualified_constant_name(node)
104
+ return constant_definitions[name] = :casgn unless constant_definitions.key?(name)
105
+
106
+ add_offense(node, message: format(MSG, constant: constant_display_name(node)))
82
107
  end
83
108
 
84
109
  def on_send(node)
@@ -90,7 +115,7 @@ module RuboCop
90
115
 
91
116
  return if namespaces.none?
92
117
 
93
- constant_names.delete(fully_qualified_name_for(namespaces, constant))
118
+ constant_definitions.delete(fully_qualified_name_for(namespaces, constant))
94
119
  end
95
120
 
96
121
  private
@@ -104,7 +129,7 @@ module RuboCop
104
129
  return true if ancestor.type?(:module, :class)
105
130
 
106
131
  ancestor.begin_type? || ancestor.literal? || ancestor.casgn_type? ||
107
- freeze_method?(ancestor)
132
+ ancestor.type?(:masgn, :mlhs) || freeze_method?(ancestor)
108
133
  end
109
134
  end
110
135
 
@@ -128,6 +153,10 @@ module RuboCop
128
153
  ['', *namespaces, constant].join('::')
129
154
  end
130
155
 
156
+ def constant_display_name(node)
157
+ [*constant_namespaces(node), node.name].join('::')
158
+ end
159
+
131
160
  def constant_namespaces(node)
132
161
  node.each_path.select(&:const_type?).map(&:short_name)
133
162
  end
@@ -139,8 +168,29 @@ module RuboCop
139
168
  .reverse
140
169
  end
141
170
 
142
- def constant_names
143
- @constant_names ||= Set.new
171
+ def unconditional_definition?(node)
172
+ node.each_ancestor.all? do |ancestor|
173
+ ancestor.type?(:begin, :module, :class)
174
+ end
175
+ end
176
+
177
+ def definition_name(node)
178
+ identifier = node.identifier
179
+
180
+ if identifier.namespace&.cbase_type?
181
+ fully_qualified_name_for([], identifier.short_name)
182
+ else
183
+ namespaces = ancestor_namespaces(node) + identifier_namespaces(identifier)
184
+ fully_qualified_name_for(namespaces, identifier.short_name)
185
+ end
186
+ end
187
+
188
+ def identifier_namespaces(identifier)
189
+ identifier.each_path.select(&:const_type?).map(&:short_name)
190
+ end
191
+
192
+ def constant_definitions
193
+ @constant_definitions ||= {}
144
194
  end
145
195
  end
146
196
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Check that certain constants are fully qualified.
6
+ # Checks that certain constants are fully qualified.
7
7
  #
8
8
  # This is not enabled by default because it would mark a lot of offenses
9
9
  # unnecessarily.
@@ -13,34 +13,40 @@ module RuboCop
13
13
  # @example
14
14
  # # bad
15
15
  # # rubocop:disable Layout/LineLength Style/Encoding
16
- # # ^ missing comma
16
+ #
17
+ # # good
18
+ # # rubocop:disable Layout/LineLength, Style/Encoding
17
19
  #
18
20
  # # bad
19
21
  # # rubocop:disable
20
22
  #
23
+ # # good
24
+ # # rubocop:disable all
25
+ #
21
26
  # # bad
22
27
  # # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
23
28
  #
29
+ # # good
30
+ # # rubocop:disable Layout/LineLength
31
+ # # rubocop:disable Style/Encoding
32
+ #
24
33
  # # bad
25
34
  # # rubocop:wrongmode Layout/LineLength
26
35
  #
27
36
  # # good
28
37
  # # rubocop:disable Layout/LineLength
29
38
  #
30
- # # good
31
- # # rubocop:disable Layout/LineLength, Style/Encoding
32
- #
33
- # # good
34
- # # rubocop:disable all
39
+ # # bad
40
+ # # rubocop:disable Layout/LineLength comment
35
41
  #
36
42
  # # good
37
- # # rubocop:disable Layout/LineLength -- This is a good comment.
43
+ # # rubocop:disable Layout/LineLength -- comment
38
44
  #
39
45
  class CopDirectiveSyntax < Base
40
46
  COMMON_MSG = 'Malformed directive comment detected.'
41
47
 
42
48
  MISSING_MODE_NAME_MSG = 'The mode name is missing.'
43
- INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, or `todo`.'
49
+ INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `todo`, `push`, or `pop`.' # rubocop:disable Layout/LineLength
44
50
  MISSING_COP_NAME_MSG = 'The cop name is missing.'
45
51
  MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
46
52
  'Comment in the directive must start with `--`.'
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks unexpected overrides of the `Data` built-in methods
7
+ # via `Data.define`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Bad = Data.define(:members, :clone, :to_s)
12
+ # b = Bad.new(members: [], clone: true, to_s: 'bad')
13
+ # b.members #=> [] (overriding `Data#members`)
14
+ # b.clone #=> true (overriding `Object#clone`)
15
+ # b.to_s #=> "bad" (overriding `Data#to_s`)
16
+ #
17
+ # # good
18
+ # Good = Data.define(:id, :name)
19
+ # g = Good.new(id: 1, name: "foo")
20
+ # g.members #=> [:id, :name]
21
+ # g.clone #=> #<data Good id=1, name="foo">
22
+ #
23
+ class DataDefineOverride < Base
24
+ MSG = '`%<member_name>s` member overrides `Data#%<method_name>s` and it may be unexpected.'
25
+ RESTRICT_ON_SEND = %i[define].freeze
26
+
27
+ # This is based on `Data.define.instance_methods.sort` in Ruby 4.0.0.
28
+ DATA_METHOD_NAMES = %i[
29
+ ! != !~ <=> == === __id__ __send__ class clone deconstruct deconstruct_keys
30
+ define_singleton_method display dup enum_for eql? equal? extend freeze frozen? hash
31
+ inspect instance_eval instance_exec instance_of? instance_variable_defined?
32
+ instance_variable_get instance_variable_set instance_variables is_a? itself kind_of?
33
+ members method methods nil? object_id private_methods protected_methods
34
+ public_method public_methods public_send remove_instance_variable respond_to? send
35
+ singleton_class singleton_method singleton_methods tap then to_enum to_h to_s with
36
+ yield_self
37
+ ].freeze
38
+ MEMBER_NAME_TYPES = %i[sym str].freeze
39
+
40
+ # @!method data_define(node)
41
+ def_node_matcher :data_define, <<~PATTERN
42
+ (send
43
+ (const {nil? cbase} :Data) :define ...)
44
+ PATTERN
45
+
46
+ def on_send(node)
47
+ return unless data_define(node)
48
+
49
+ node.arguments.each do |arg|
50
+ next unless MEMBER_NAME_TYPES.include?(arg.type)
51
+
52
+ member_name = arg.value
53
+
54
+ next unless DATA_METHOD_NAMES.include?(member_name.to_sym)
55
+
56
+ message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
57
+ add_offense(arg, message: message)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -102,8 +102,6 @@ module RuboCop
102
102
  end
103
103
 
104
104
  def debugger_method?(send_node)
105
- return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
106
-
107
105
  debugger_methods.include?(chained_method_name(send_node))
108
106
  end
109
107
 
@@ -118,8 +118,11 @@ module RuboCop
118
118
 
119
119
  def replacement_args(node)
120
120
  algorithm_constant, = algorithm_const(node)
121
- algorithm_name = algorithm_name(algorithm_constant)
121
+ if algorithm_constant.source == 'OpenSSL::Cipher::Cipher'
122
+ return node.first_argument.source
123
+ end
122
124
 
125
+ algorithm_name = algorithm_name(algorithm_constant)
123
126
  if openssl_class(algorithm_constant) == 'OpenSSL::Cipher'
124
127
  build_cipher_arguments(node, algorithm_name, node.arguments.empty?)
125
128
  else
@@ -25,17 +25,17 @@ module RuboCop
25
25
  #
26
26
  # # bad - repeated alternate patterns with the same conditions don't depend on the order
27
27
  # case x
28
- # in foo | bar
28
+ # in 0 | 1
29
29
  # first_method
30
- # in bar | foo
30
+ # in 1 | 0
31
31
  # second_method
32
32
  # end
33
33
  #
34
34
  # # good
35
35
  # case x
36
- # in foo | bar
36
+ # in 0 | 1
37
37
  # first_method
38
- # in bar | baz
38
+ # in 2 | 3
39
39
  # second_method
40
40
  # end
41
41
  #
@@ -56,6 +56,27 @@ module RuboCop
56
56
  # 1
57
57
  # end
58
58
  #
59
+ # # bad
60
+ # class MyClass
61
+ # extend Forwardable
62
+ #
63
+ # # or with: `def_instance_delegator`, `def_delegators`, `def_instance_delegators`
64
+ # def_delegator :delegation_target, :delegated_method_name
65
+ #
66
+ # def delegated_method_name
67
+ # end
68
+ # end
69
+ #
70
+ # # good
71
+ # class MyClass
72
+ # extend Forwardable
73
+ #
74
+ # def_delegator :delegation_target, :delegated_method_name
75
+ #
76
+ # def non_duplicated_delegated_method_name
77
+ # end
78
+ # end
79
+ #
59
80
  # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
60
81
  #
61
82
  # # good
@@ -97,10 +118,11 @@ module RuboCop
97
118
  # delegate :foo, to: :bar
98
119
  # end
99
120
  #
100
- class DuplicateMethods < Base
121
+ class DuplicateMethods < Base # rubocop:disable Metrics/ClassLength
101
122
  MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
102
123
  RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
103
- delegate].freeze
124
+ delegate def_delegator def_instance_delegator def_delegators
125
+ def_instance_delegators].freeze
104
126
 
105
127
  def initialize(config = nil, options = nil)
106
128
  super
@@ -154,23 +176,56 @@ module RuboCop
154
176
  )
155
177
  PATTERN
156
178
 
179
+ # @!method delegator?(node)
180
+ def_node_matcher :delegator?, <<~PATTERN
181
+ (send nil? {:def_delegator :def_instance_delegator}
182
+ {
183
+ {sym str} ({sym str} $_) |
184
+ {sym str} {sym str} ({sym str} $_)
185
+ }
186
+ )
187
+ PATTERN
188
+
189
+ # @!method delegators?(node)
190
+ def_node_matcher :delegators?, <<~PATTERN
191
+ (send nil? {:def_delegators :def_instance_delegators}
192
+ {sym str}
193
+ ({sym str} $_)+
194
+ )
195
+ PATTERN
196
+
157
197
  # @!method sym_name(node)
158
198
  def_node_matcher :sym_name, '(sym $_name)'
159
199
 
160
- def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
200
+ # @!method class_or_module_new_block?(node)
201
+ def_node_matcher :class_or_module_new_block?, <<~PATTERN
202
+ (block
203
+ (send (const _ {:Class :Module}) :new ...)
204
+ ...)
205
+ PATTERN
206
+
207
+ def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
161
208
  name, original_name = alias_method?(node)
162
209
 
163
210
  if name && original_name
164
211
  return if name == original_name
165
- return if node.ancestors.any?(&:if_type?)
212
+ return if inside_condition?(node)
166
213
 
167
214
  found_instance_method(node, name)
168
215
  elsif (attr = node.attribute_accessor?)
169
216
  on_attr(node, *attr)
170
217
  elsif active_support_extensions_enabled? && (names = delegate_method?(node))
171
- return if node.ancestors.any?(&:if_type?)
218
+ return if inside_condition?(node)
172
219
 
173
220
  on_delegate(node, names)
221
+ elsif (name = delegator?(node))
222
+ return if inside_condition?(node)
223
+
224
+ found_instance_method(node, name)
225
+ elsif (names = delegators?(node))
226
+ return if inside_condition?(node)
227
+
228
+ names.each { |name| found_instance_method(node, name) }
174
229
  end
175
230
  end
176
231
 
@@ -185,9 +240,16 @@ module RuboCop
185
240
 
186
241
  def check_self_receiver(node, name)
187
242
  enclosing = node.parent_module_name
188
- return unless enclosing
243
+ if enclosing
244
+ found_method(node, "#{enclosing}.#{name}")
245
+ elsif (anon_block = anonymous_class_block(node))
246
+ scope = qualified_name(anon_block.parent_module_name, nil, 'Object')
247
+ found_method(node, "#{scope}.#{name}", scope_id: anon_block_scope_id(anon_block))
248
+ end
249
+ end
189
250
 
190
- found_method(node, "#{enclosing}.#{name}")
251
+ def inside_condition?(node)
252
+ node.ancestors.any?(&:if_type?)
191
253
  end
192
254
 
193
255
  def message_for_dup(node, method_name, key)
@@ -222,16 +284,50 @@ module RuboCop
222
284
  end
223
285
 
224
286
  def found_instance_method(node, name)
225
- return found_sclass_method(node, name) unless (scope = node.parent_module_name)
287
+ if (scope = node.parent_module_name)
288
+ found_method(node, "#{humanize_scope(scope)}#{name}")
289
+ elsif (anon_block = anonymous_class_block(node))
290
+ base = qualified_name(anon_block.parent_module_name, nil, 'Object')
291
+ scope = node.each_ancestor(:sclass).any? ? "#<Class:#{base}>" : base
292
+ found_method(
293
+ node, "#{humanize_scope(scope)}#{name}", scope_id: anon_block_scope_id(anon_block)
294
+ )
295
+ else
296
+ found_sclass_method(node, name)
297
+ end
298
+ end
226
299
 
227
- # Humanize the scope
300
+ def humanize_scope(scope)
228
301
  scope = scope.sub(
229
302
  /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
230
303
  '\k<name>.'
231
304
  )
232
- scope << '#' unless scope.end_with?('.')
305
+ scope.end_with?('.') ? scope : "#{scope}#"
306
+ end
307
+
308
+ def anonymous_class_block(node)
309
+ first_block = node.each_ancestor(:block).first
310
+ return unless class_or_module_new_block?(first_block)
311
+ return if first_block.parent&.type?(:lvasgn)
312
+ return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? }
313
+
314
+ first_block
315
+ end
316
+
317
+ def anon_block_scope_id(anon_block)
318
+ parent = anon_block.parent
319
+ return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def)
320
+
321
+ if (receiver = named_receiver(parent))
322
+ "#{receiver.source}.#{parent.method_name}"
323
+ elsif !parent.begin_type? || parent.parent&.any_block_type?
324
+ source_location(anon_block)
325
+ end
326
+ end
233
327
 
234
- found_method(node, "#{scope}#{name}")
328
+ def named_receiver(node)
329
+ receiver = node.receiver
330
+ receiver unless class_or_module_new_block?(receiver)
235
331
  end
236
332
 
237
333
  def found_sclass_method(node, name)
@@ -244,8 +340,10 @@ module RuboCop
244
340
  found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
245
341
  end
246
342
 
247
- def found_method(node, method_name)
343
+ # rubocop:disable Metrics/AbcSize
344
+ def found_method(node, method_name, scope_id: nil)
248
345
  key = method_key(node, method_name)
346
+ key = "#{key}@#{scope_id}" if scope_id
249
347
  scope = node.each_ancestor(:rescue, :ensure).first&.type
250
348
 
251
349
  if @definitions.key?(key)
@@ -262,6 +360,7 @@ module RuboCop
262
360
  @definitions[key] = node
263
361
  end
264
362
  end
363
+ # rubocop:enable Metrics/AbcSize
265
364
 
266
365
  def method_key(node, method_name)
267
366
  if (ancestor_def = node.each_ancestor(:any_def).first)
@@ -38,6 +38,24 @@ module RuboCop
38
38
  # elsif do_this
39
39
  # do_that
40
40
  # end
41
+ #
42
+ # # bad
43
+ #
44
+ # # For single-line conditionals using `then` the layout is disallowed
45
+ # # when the `else` body is multiline because it is treated as a lint offense.
46
+ # if something then on_the_same_line_as_then
47
+ # else first_line
48
+ # second_line
49
+ # end
50
+ #
51
+ # # good
52
+ #
53
+ # # For single-line conditional using `then` the layout is allowed
54
+ # # when `else` body is a single-line because it is treated as intentional.
55
+ #
56
+ # if something then on_the_same_line_as_then
57
+ # else single_line
58
+ # end
41
59
  class ElseLayout < Base
42
60
  include Alignment
43
61
  include RangeHelp
@@ -47,6 +65,7 @@ module RuboCop
47
65
 
48
66
  def on_if(node)
49
67
  return if node.ternary?
68
+ return if node.then? && !node.else_branch&.begin_type?
50
69
 
51
70
  # If the if is on a single line, it'll be handled by `Style/OneLineConditional`
52
71
  return if node.single_line?
@@ -63,7 +63,7 @@ module RuboCop
63
63
  class EmptyBlock < Base
64
64
  MSG = 'Empty block detected.'
65
65
 
66
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
66
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
67
67
  return if node.body
68
68
  return if allow_empty_lambdas? && node.lambda_or_proc?
69
69
  return if cop_config['AllowComments'] && allow_comment?(node)
@@ -70,7 +70,7 @@ module RuboCop
70
70
 
71
71
  def on_if(node)
72
72
  return if node.body || same_line?(node.loc.begin, node.loc.end)
73
- return if cop_config['AllowComments'] && contains_comments?(node)
73
+ return if allow_comments?(node)
74
74
 
75
75
  range = offense_range(node)
76
76
 
@@ -83,6 +83,11 @@ module RuboCop
83
83
 
84
84
  private
85
85
 
86
+ def allow_comments?(node)
87
+ cop_config['AllowComments'] && contains_comments?(node) &&
88
+ !comments_contain_disables?(node, name)
89
+ end
90
+
86
91
  def offense_range(node)
87
92
  if node.loc.else
88
93
  node.source_range.begin.join(node.loc.else.begin)
@@ -53,11 +53,18 @@ module RuboCop
53
53
  def on_case_match(node)
54
54
  node.in_pattern_branches.each do |branch|
55
55
  next if branch.body
56
- next if cop_config['AllowComments'] && contains_comments?(branch)
56
+ next if allow_comments?(branch)
57
57
 
58
58
  add_offense(branch)
59
59
  end
60
60
  end
61
+
62
+ private
63
+
64
+ def allow_comments?(node)
65
+ cop_config['AllowComments'] && contains_comments?(node) &&
66
+ !comments_contain_disables?(node, name)
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -19,12 +19,23 @@ module RuboCop
19
19
  MSG = 'Empty interpolation detected.'
20
20
 
21
21
  def on_interpolation(begin_node)
22
+ return if in_percent_literal_array?(begin_node)
23
+
22
24
  node_children = begin_node.children.dup
23
25
  node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
24
26
  return unless node_children.empty?
25
27
 
26
28
  add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
27
29
  end
30
+
31
+ private
32
+
33
+ def in_percent_literal_array?(begin_node)
34
+ array_node = begin_node.each_ancestor(:array).first
35
+ return false unless array_node
36
+
37
+ array_node.percent_literal?
38
+ end
28
39
  end
29
40
  end
30
41
  end
@@ -50,11 +50,18 @@ module RuboCop
50
50
  def on_case(node)
51
51
  node.when_branches.each do |when_node|
52
52
  next if when_node.body
53
- next if cop_config['AllowComments'] && contains_comments?(when_node)
53
+ next if allow_comments?(when_node)
54
54
 
55
55
  add_offense(when_node)
56
56
  end
57
57
  end
58
+
59
+ private
60
+
61
+ def allow_comments?(node)
62
+ cop_config['AllowComments'] && contains_comments?(node) &&
63
+ !comments_contain_disables?(node, name)
64
+ end
58
65
  end
59
66
  end
60
67
  end
@@ -77,7 +77,7 @@ module RuboCop
77
77
 
78
78
  def on_case(node)
79
79
  node.when_branches.each do |when_branch|
80
- when_branch.each_condition do |condition|
80
+ when_branch.conditions.each do |condition|
81
81
  next if !float?(condition) || literal_safe?(condition)
82
82
 
83
83
  add_offense(condition, message: MSG_CASE)
@@ -54,9 +54,14 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def valid_syntax?(node)
57
- double_quoted_string = node.source.gsub(/\A'|'\z/, '"')
57
+ double_quoted_string = if node.source.include?('"')
58
+ node.source.sub(/\A'/, '%{').sub(/'\z/, '}')
59
+ else
60
+ node.source.gsub(/\A'|'\z/, '"')
61
+ end
58
62
 
59
- parse(double_quoted_string).valid_syntax?
63
+ processed_source = parse(double_quoted_string)
64
+ processed_source.valid_syntax? && processed_source.ast.dstr_type?
60
65
  end
61
66
  end
62
67
  end
@@ -157,7 +157,7 @@ module RuboCop
157
157
 
158
158
  check_case(case_match_node)
159
159
  else
160
- case_match_node.each_in_pattern do |in_pattern_node|
160
+ case_match_node.in_pattern_branches.each do |in_pattern_node|
161
161
  next unless in_pattern_node.condition.literal?
162
162
 
163
163
  add_offense(in_pattern_node)
@@ -269,7 +269,11 @@ module RuboCop
269
269
  end
270
270
 
271
271
  add_offense(cond) do |corrector|
272
+ next if part_of_ignored_node?(node)
273
+
272
274
  corrector.replace(node, new_node)
275
+
276
+ ignore_node(node)
273
277
  end
274
278
  end
275
279
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -66,7 +66,7 @@ module RuboCop
66
66
 
67
67
  def special_keyword?(node)
68
68
  # handle strings like __FILE__
69
- (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
69
+ (node.str_type? && !node.loc?(:begin)) || node.source_range.is?('__LINE__')
70
70
  end
71
71
 
72
72
  def array_in_regexp?(node)