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
data/lib/rubocop/cli.rb CHANGED
@@ -66,7 +66,7 @@ module RuboCop
66
66
  STATUS_INTERRUPTED
67
67
  rescue Finished
68
68
  STATUS_SUCCESS
69
- rescue OptionParser::InvalidOption => e
69
+ rescue OptionParser::ParseError => e
70
70
  warn e.message
71
71
  warn 'For usage information, use --help'
72
72
  STATUS_ERROR
@@ -76,7 +76,9 @@ module RuboCop
76
76
  STATUS_ERROR
77
77
  ensure
78
78
  elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
79
- puts "Finished in #{elapsed_time} seconds" if @options[:debug] || @options[:display_time]
79
+ if @options[:debug] || @options[:display_time]
80
+ puts "Finished in #{elapsed_time.round(5)} seconds"
81
+ end
80
82
  end
81
83
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
82
84
 
@@ -164,8 +166,11 @@ module RuboCop
164
166
  set_options_to_pending_cops_reporter
165
167
  handle_editor_mode
166
168
 
167
- @config_store.options_config = @options[:config] if @options[:config]
168
- @config_store.force_default_config! if @options[:force_default_config]
169
+ @config_store.apply_options!(@options)
170
+ # Set cache root after apply_options! to ensure force_default_config is applied first.
171
+ early_cache_root = ConfigLoader.cache_root(@options[:cache_root])
172
+ ConfigLoader.cache_root = ResultCache.cache_root(@config_store, @options[:cache_root])
173
+ warn_if_cache_root_changed(early_cache_root, ConfigLoader.cache_root)
169
174
 
170
175
  handle_exiting_options
171
176
 
@@ -195,7 +200,7 @@ module RuboCop
195
200
  RuboCop::LSP.enable if @options[:editor_mode]
196
201
  end
197
202
 
198
- # rubocop:disable Metrics/CyclomaticComplexity
203
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
199
204
  def handle_exiting_options
200
205
  return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
201
206
 
@@ -203,9 +208,10 @@ module RuboCop
203
208
  run_command(:show_cops) if @options[:show_cops]
204
209
  run_command(:show_docs_url) if @options[:show_docs_url]
205
210
  run_command(:lsp) if @options[:lsp]
211
+ run_command(:mcp) if @options[:mcp]
206
212
  raise Finished
207
213
  end
208
- # rubocop:enable Metrics/CyclomaticComplexity
214
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
209
215
 
210
216
  def apply_default_formatter
211
217
  # This must be done after the options have already been processed,
@@ -224,5 +230,21 @@ module RuboCop
224
230
  def report_pending_cops
225
231
  PendingCopsReporter.warn_if_needed(@config_store.for_pwd)
226
232
  end
233
+
234
+ def warn_if_cache_root_changed(early, desired)
235
+ return if early == desired
236
+ # Normalize paths to avoid false positives from symlink resolution differences
237
+ if File.exist?(early) && File.exist?(desired) &&
238
+ File.realpath(early) == File.realpath(desired)
239
+ return
240
+ end
241
+
242
+ warn Rainbow(
243
+ "Warning: Remote configuration cache files were stored in `#{early}` " \
244
+ "because a desired cache root (`#{desired}`) was not set at the top level. " \
245
+ 'Consider setting `AllCops: CacheRootDirectory` in your toplevel configuration file, ' \
246
+ 'using the `RUBOCOP_CACHE_ROOT` environment variable, or using CLI options.'
247
+ ).yellow
248
+ end
227
249
  end
228
250
  end
@@ -34,6 +34,7 @@ module RuboCop
34
34
  def initialize(processed_source)
35
35
  @processed_source = processed_source
36
36
  @no_directives = !processed_source.raw_source.include?('rubocop')
37
+ @stack = []
37
38
  end
38
39
 
39
40
  def cop_enabled_at_line?(cop, line_number)
@@ -69,6 +70,7 @@ module RuboCop
69
70
  def extra_enabled_comments_with_names(extras:, names:)
70
71
  each_directive do |directive|
71
72
  next unless comment_only_line?(directive.line_number)
73
+ next if directive.push? || directive.pop?
72
74
 
73
75
  if directive.enabled_all?
74
76
  handle_enable_all(directive, names, extras)
@@ -93,16 +95,24 @@ module RuboCop
93
95
  end
94
96
  end
95
97
 
96
- def analyze # rubocop:todo Metrics/AbcSize
98
+ def analyze # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
97
99
  return {} if @no_directives
98
100
 
99
101
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
100
102
  inject_disabled_cops_directives(analyses)
101
103
 
102
104
  each_directive do |directive|
103
- directive.cop_names.each do |cop_name|
104
- cop_name = qualified_cop_name(cop_name)
105
- analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
105
+ if directive.push?
106
+ resolved = resolve_push_cops(directive)
107
+ @stack.push(snapshot_cops(analyses, resolved.values.flatten))
108
+ apply_push(analyses, resolved, directive.line_number)
109
+ elsif directive.pop?
110
+ pop_state(analyses, directive.line_number) if @stack.any?
111
+ else
112
+ directive.cop_names.each do |cop_name|
113
+ cop_name = qualified_cop_name(cop_name)
114
+ analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
115
+ end
106
116
  end
107
117
  end
108
118
 
@@ -112,6 +122,49 @@ module RuboCop
112
122
  end
113
123
  end
114
124
 
125
+ def snapshot_cops(analyses, cop_names)
126
+ cop_names.to_h { |name| [name, analyses[name].dup] }
127
+ end
128
+
129
+ def resolve_push_cops(directive)
130
+ directive.push_args.transform_values do |names|
131
+ names.flat_map { |name| expand_cop_name(name) }
132
+ end
133
+ end
134
+
135
+ def expand_cop_name(name)
136
+ registry = Cop::Registry.global
137
+ cops = registry.department?(name) ? registry.names_for_department(name) : [name]
138
+ cops.map { |c| qualified_cop_name(c) }
139
+ end
140
+
141
+ def apply_push(analyses, resolved_cops, line)
142
+ resolved_cops.each do |op, cops|
143
+ cops.each { |cop| apply_cop_op(analyses, op, cop, line) }
144
+ end
145
+ end
146
+
147
+ def apply_cop_op(analyses, operation, cop, line)
148
+ analysis = analyses[cop]
149
+ if operation == '-' && !analysis.start_line_number
150
+ analyses[cop] = CopAnalysis.new(analysis.line_ranges, line)
151
+ elsif operation == '+' && analysis.start_line_number
152
+ analyses[cop] =
153
+ CopAnalysis.new(analysis.line_ranges + [analysis.start_line_number..line], nil)
154
+ end
155
+ end
156
+
157
+ def pop_state(analyses, line)
158
+ saved = @stack.pop
159
+ saved.each do |cop, old|
160
+ cur = analyses[cop]
161
+ new_range = cur.start_line_number ? [cur.start_line_number..(line - 1)] : []
162
+ ranges = cur.line_ranges + new_range
163
+ new_start = old.start_line_number ? line : nil
164
+ analyses[cop] = CopAnalysis.new(ranges, new_start)
165
+ end
166
+ end
167
+
115
168
  def inject_disabled_cops_directives(analyses)
116
169
  registry.disabled(config).each do |cop|
117
170
  analyses[cop.cop_name] = analyze_cop(
@@ -136,29 +189,21 @@ module RuboCop
136
189
  return analysis unless directive.disabled?
137
190
 
138
191
  line = directive.line_number
139
- start_line = analysis.start_line_number
140
-
141
- CopAnalysis.new(analysis.line_ranges + [(line..line)], start_line)
192
+ CopAnalysis.new(analysis.line_ranges + [(line..line)], analysis.start_line_number)
142
193
  end
143
194
 
144
195
  def analyze_disabled(analysis, directive)
145
196
  line = directive.line_number
146
197
  start_line = analysis.start_line_number
147
-
148
- # Cop already disabled on this line, so we end the current disabled
149
- # range before we start a new range.
150
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], line) if start_line
151
-
152
- CopAnalysis.new(analysis.line_ranges, line)
198
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
199
+ CopAnalysis.new(new_ranges, line)
153
200
  end
154
201
 
155
202
  def analyze_rest(analysis, directive)
156
203
  line = directive.line_number
157
204
  start_line = analysis.start_line_number
158
-
159
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], nil) if start_line
160
-
161
- CopAnalysis.new(analysis.line_ranges, nil)
205
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
206
+ CopAnalysis.new(new_ranges, nil)
162
207
  end
163
208
 
164
209
  def cop_line_ranges(analysis)
@@ -217,6 +217,9 @@ module RuboCop
217
217
  for_all_cops['StringLiteralsFrozenByDefault']
218
218
  end
219
219
 
220
+ # Returns true if the file matches any include pattern. If a block is given, the block is called
221
+ # to determine if the pattern is relevant (true returned by the block) or should be skipped
222
+ # (false returned).
220
223
  def file_to_include?(file)
221
224
  relative_file_path = path_relative_to_config(file)
222
225
 
@@ -228,11 +231,9 @@ module RuboCop
228
231
  absolute_file_path = File.expand_path(file)
229
232
 
230
233
  patterns_to_include.any? do |pattern|
231
- if block_given?
232
- yield pattern, relative_file_path, absolute_file_path
233
- else
234
- match_path?(pattern, relative_file_path) || match_path?(pattern, absolute_file_path)
235
- end
234
+ next if block_given? && !yield(pattern)
235
+
236
+ match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path)
236
237
  end
237
238
  end
238
239
 
@@ -242,10 +243,7 @@ module RuboCop
242
243
  # `bundler-console` conveys `Bundler::Console`).
243
244
  return true if File.extname(file) == '.gemspec'
244
245
 
245
- file_to_include?(file) do |pattern, relative_path, absolute_path|
246
- /[A-Z]/.match?(pattern.to_s) &&
247
- (match_path?(pattern, relative_path) || match_path?(pattern, absolute_path))
248
- end
246
+ file_to_include?(file) { |pattern| /[A-Z]/.match?(pattern.to_s) }
249
247
  end
250
248
 
251
249
  # Returns true if there's a chance that an Include pattern matches hidden
@@ -286,7 +284,7 @@ module RuboCop
286
284
  loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
287
285
  File.expand_path(File.dirname(loaded_path))
288
286
  else
289
- Dir.pwd
287
+ PathUtil.pwd
290
288
  end
291
289
  end
292
290
 
@@ -345,6 +343,12 @@ module RuboCop
345
343
 
346
344
  private
347
345
 
346
+ def match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path)
347
+ should_use_absolute_path = absolute?(pattern.to_s) || pattern.to_s.start_with?('..') ||
348
+ relative_file_path.start_with?('..')
349
+ match_path?(pattern, should_use_absolute_path ? absolute_file_path : relative_file_path)
350
+ end
351
+
348
352
  # @return [Float, nil] The Rails version as a `major.minor` Float.
349
353
  def target_rails_version_from_bundler_lock_file
350
354
  @target_rails_version_from_bundler_lock_file ||= read_rails_version_from_bundler_lock_file
@@ -30,7 +30,7 @@ module RuboCop
30
30
  private
31
31
 
32
32
  def find_project_root
33
- pwd = Dir.pwd
33
+ pwd = PathUtil.pwd
34
34
  gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd)
35
35
  return unless gems_file
36
36
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'erb'
4
4
  require 'yaml'
5
+ require_relative 'cache_config'
5
6
  require_relative 'config_finder'
6
7
 
7
8
  module RuboCop
@@ -24,12 +25,16 @@ module RuboCop
24
25
 
25
26
  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
26
27
  :ignore_unrecognized_cops
27
- attr_writer :default_configuration
28
+ attr_writer :default_configuration, :cache_root
28
29
  attr_reader :loaded_plugins, :loaded_features
29
30
 
30
31
  alias debug? debug
31
32
  alias ignore_parent_exclusion? ignore_parent_exclusion
32
33
 
34
+ def cache_root(cache_root_override = nil)
35
+ @cache_root ||= CacheConfig.root_dir_from_toplevel_config(cache_root_override)
36
+ end
37
+
33
38
  def clear_options
34
39
  @debug = nil
35
40
  @loaded_plugins = Set.new
@@ -38,6 +43,7 @@ module RuboCop
38
43
  @enable_pending_cops = nil
39
44
  @ignore_parent_exclusion = nil
40
45
  @ignore_unrecognized_cops = nil
46
+ @cache_root = nil
41
47
  FileFinder.root_level = nil
42
48
  end
43
49
 
@@ -75,7 +81,9 @@ module RuboCop
75
81
 
76
82
  puts "configuration from #{absolute_path}" if debug?
77
83
 
78
- raise(TypeError, "Malformed configuration in #{absolute_path}") unless hash.is_a?(Hash)
84
+ unless hash.is_a?(Hash)
85
+ raise(ValidationError, "Malformed configuration in #{absolute_path}")
86
+ end
79
87
 
80
88
  hash
81
89
  end
@@ -148,31 +156,22 @@ module RuboCop
148
156
  # When testing a plugin using `rubocop/rspec/support`, the plugin is loaded automatically,
149
157
  # so this API is usually not needed. It is intended to be used only when implementing tests
150
158
  # that do not use `rubocop/rspec/support`.
151
- # rubocop:disable Metrics/MethodLength
152
159
  def inject_defaults!(config_yml_path)
153
160
  if Pathname(config_yml_path).directory?
154
- # TODO: Since the warning noise is expected to be high until some time after the release,
155
- # warnings will only be issued when `RUBYOPT=-w` is specified.
156
- # To proceed step by step, the next step is to remove `$VERBOSE` and always issue warning.
157
- # Eventually, `project_root` will no longer be accepted.
158
- if $VERBOSE
159
- warn Rainbow(<<~MESSAGE).yellow, uplevel: 1
160
- Use config YAML file path instead of project root directory.
161
- e.g., `path/to/config/default.yml`
162
- MESSAGE
163
- end
164
- # NOTE: For compatibility.
165
- project_root = config_yml_path
166
- path = File.join(project_root, 'config', 'default.yml')
167
- config = load_file(path)
168
- else
169
- hash = ConfigLoader.load_yaml_configuration(config_yml_path.to_s)
170
- config = Config.new(hash, config_yml_path).tap(&:make_excludes_absolute)
161
+ warn Rainbow(<<~MESSAGE).yellow, uplevel: 1
162
+ Use config YAML file path instead of project root directory.
163
+ e.g., `path/to/config/default.yml`
164
+ MESSAGE
165
+ raise ArgumentError,
166
+ 'Passing a project root directory to `inject_defaults!` is no longer supported.'
171
167
  end
172
168
 
169
+ path = config_yml_path.to_s
170
+ hash = ConfigLoader.load_yaml_configuration(path)
171
+ config = Config.new(hash, path).tap(&:make_excludes_absolute)
172
+
173
173
  @default_configuration = ConfigLoader.merge_with_default(config, path)
174
174
  end
175
- # rubocop:enable Metrics/MethodLength
176
175
 
177
176
  # Returns the path RuboCop inferred as the root of the project. No file
178
177
  # searches will go past this directory.
@@ -45,6 +45,7 @@ module RuboCop
45
45
  base_config.each do |k, v|
46
46
  next unless v.is_a?(Hash)
47
47
 
48
+ only_base_has_include = v.key?('Include') && !hash.dig(k, 'Include')
48
49
  if hash.key?(k)
49
50
  v = merge(v, hash[k],
50
51
  cop_name: k, file: file, debug: debug,
@@ -52,7 +53,7 @@ module RuboCop
52
53
  inherit_mode: determine_inherit_mode(hash, k))
53
54
  end
54
55
  hash[k] = v
55
- fix_include_paths(base_config.loaded_path, hash, path, k, v) if v.key?('Include')
56
+ fix_include_paths(base_config.loaded_path, hash, path, k, v) if only_base_has_include
56
57
  end
57
58
  end
58
59
  end
@@ -246,7 +247,7 @@ module RuboCop
246
247
  def inherited_file(path, inherit_from, file)
247
248
  if PathUtil.remote_file?(inherit_from)
248
249
  # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`.
249
- RemoteConfig.new(inherit_from, File.dirname(path))
250
+ RemoteConfig.new(inherit_from, ConfigLoader.cache_root)
250
251
  elsif Pathname.new(inherit_from).absolute?
251
252
  # An absolute path to a config, e.g. `inherit_from: /Users/me/rubocop.yml`.
252
253
  # The path may come from `inherit_gem` option, where a gem name is expanded
@@ -256,7 +257,7 @@ module RuboCop
256
257
  elsif file.is_a?(RemoteConfig)
257
258
  # A path relative to a URL, e.g. `inherit_from: configs/default.yml`
258
259
  # in a config included with `inherit_from: http://example.com/rubocop.yml`
259
- file.inherit_from_remote(inherit_from, path)
260
+ file.inherit_from_remote(inherit_from)
260
261
  else
261
262
  # A local relative path, e.g. `inherit_from: default.yml`
262
263
  print 'Inheriting ' if ConfigLoader.debug?
@@ -295,10 +296,11 @@ module RuboCop
295
296
  begin
296
297
  gem = Bundler.load.specs[gem_name].first
297
298
  gem_path = gem.full_gem_path if gem
298
- rescue Bundler::GemfileNotFound
299
- # No Gemfile found. Bundler may be loaded manually
300
- rescue Bundler::GitError
301
- # The Gemfile exists but contains an uninstalled git source
299
+ rescue StandardError
300
+ # The Gemfile has a problem, which could be one of:
301
+ # - No Gemfile found. Bundler may be loaded manually
302
+ # - The Gemfile exists but contains an uninstalled git source
303
+ # - The Gemfile exists but cannot be loaded for some other reason
302
304
  end
303
305
  end
304
306
 
@@ -39,8 +39,10 @@ module RuboCop
39
39
  end
40
40
 
41
41
  def plugin_loaded?
42
- # Plugins loaded via `require` are included in `loaded_features`.
43
- config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
42
+ # Plugins loaded via `plugins` are Plugin objects with an `about.name` attribute.
43
+ # Plugins loaded via `require` are included in `loaded_features` as strings.
44
+ config.loaded_plugins.any? { |plugin| plugin.about.name == gem } ||
45
+ config.loaded_features.include?(gem)
44
46
  end
45
47
  end
46
48
  end
@@ -25,6 +25,11 @@ module RuboCop
25
25
  @validated = true
26
26
  end
27
27
 
28
+ def apply_options!(options)
29
+ self.options_config = options[:config] if options[:config]
30
+ force_default_config! if options[:force_default_config]
31
+ end
32
+
28
33
  def options_config=(options_config)
29
34
  loaded_config = ConfigLoader.load_file(options_config)
30
35
  @options_config = ConfigLoader.merge_with_default(loaded_config, options_config)
@@ -44,7 +49,7 @@ module RuboCop
44
49
  end
45
50
 
46
51
  def for_pwd
47
- for_dir(Dir.pwd)
52
+ for_dir(PathUtil.pwd)
48
53
  end
49
54
 
50
55
  # If type (file/dir) is known beforehand,
@@ -9,7 +9,7 @@ module RuboCop
9
9
 
10
10
  # @api private
11
11
  COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
12
- Enabled Reference References].freeze
12
+ Enabled Reference References Safe SafeAutoCorrect].freeze
13
13
  # @api private
14
14
  INTERNAL_PARAMS = %w[Description StyleGuide
15
15
  VersionAdded VersionChanged VersionRemoved
@@ -35,8 +35,8 @@ module RuboCop
35
35
  # `false` is the same as `disabled` for backward compatibility.
36
36
  return false if ['disabled', false].include?(cop_config['AutoCorrect'])
37
37
 
38
- # When LSP is enabled, it is considered as editing source code,
39
- # and autocorrection with `AutoCorrect: contextual` will not be performed.
38
+ # When LSP is enabled or the `--editor-mode` option is on, it is considered as editing
39
+ # source code, and autocorrection with `AutoCorrect: contextual` will not be performed.
40
40
  return false if contextual_autocorrect? && LSP.enabled?
41
41
 
42
42
  # :safe_autocorrect is a derived option based on several command-line
@@ -90,11 +90,13 @@ module RuboCop
90
90
  end
91
91
 
92
92
  def line_with_eol_comment_too_long?(range)
93
+ return false unless max_line_length
94
+
93
95
  (range.source_line + eol_comment).length > max_line_length
94
96
  end
95
97
 
96
98
  def surrounding_heredoc?(node)
97
- node.type?(:str, :dstr, :xstr) && node.heredoc?
99
+ node.any_str_type? && node.heredoc?
98
100
  end
99
101
 
100
102
  def heredoc_range(node)
@@ -106,7 +108,7 @@ module RuboCop
106
108
  end
107
109
 
108
110
  def string_continuation?(node)
109
- node.type?(:str, :dstr, :xstr) && node.source.match?(/\\\s*$/)
111
+ node.any_str_type? && node.source.match?(/\\\s*$/)
110
112
  end
111
113
 
112
114
  def multiline_string?(node)
@@ -133,6 +135,8 @@ module RuboCop
133
135
  end
134
136
 
135
137
  def max_line_length
138
+ return unless config.cop_enabled?('Layout/LineLength')
139
+
136
140
  config.for_cop('Layout/LineLength')['Max'] || 120
137
141
  end
138
142
 
@@ -7,48 +7,48 @@ module RuboCop
7
7
  # ref, or tag) are either required or forbidden.
8
8
  #
9
9
  # @example EnforcedStyle: required (default)
10
- # # bad
11
- # gem 'rubocop'
10
+ # # bad
11
+ # gem 'rubocop'
12
12
  #
13
- # # good
14
- # gem 'rubocop', '~> 1.12'
13
+ # # good
14
+ # gem 'rubocop', '~> 1.12'
15
15
  #
16
- # # good
17
- # gem 'rubocop', '>= 1.10.0'
16
+ # # good
17
+ # gem 'rubocop', '>= 1.10.0'
18
18
  #
19
- # # good
20
- # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
19
+ # # good
20
+ # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
21
21
  #
22
- # # good
23
- # gem 'rubocop', branch: 'feature-branch'
22
+ # # good
23
+ # gem 'rubocop', branch: 'feature-branch'
24
24
  #
25
- # # good
26
- # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
25
+ # # good
26
+ # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
27
27
  #
28
- # # good
29
- # gem 'rubocop', tag: 'v1.17.0'
28
+ # # good
29
+ # gem 'rubocop', tag: 'v1.17.0'
30
30
  #
31
31
  # @example EnforcedStyle: forbidden
32
- # # good
33
- # gem 'rubocop'
32
+ # # good
33
+ # gem 'rubocop'
34
34
  #
35
- # # bad
36
- # gem 'rubocop', '~> 1.12'
35
+ # # bad
36
+ # gem 'rubocop', '~> 1.12'
37
37
  #
38
- # # bad
39
- # gem 'rubocop', '>= 1.10.0'
38
+ # # bad
39
+ # gem 'rubocop', '>= 1.10.0'
40
40
  #
41
- # # bad
42
- # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
41
+ # # bad
42
+ # gem 'rubocop', '>= 1.5.0', '< 1.10.0'
43
43
  #
44
- # # bad
45
- # gem 'rubocop', branch: 'feature-branch'
44
+ # # bad
45
+ # gem 'rubocop', branch: 'feature-branch'
46
46
  #
47
- # # bad
48
- # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
47
+ # # bad
48
+ # gem 'rubocop', ref: '74b5bfbb2c4b6fd6cdbbc7254bd7084b36e0c85b'
49
49
  #
50
- # # bad
51
- # gem 'rubocop', tag: 'v1.17.0'
50
+ # # bad
51
+ # gem 'rubocop', tag: 'v1.17.0'
52
52
  #
53
53
  class GemVersion < Base
54
54
  include ConfigurableEnforcedStyle
@@ -43,8 +43,7 @@ module RuboCop
43
43
  def on_new_investigation
44
44
  return if processed_source.blank?
45
45
 
46
- gem_declarations(processed_source.ast)
47
- .each_cons(2) do |previous, current|
46
+ gem_declarations(processed_source.ast).each_cons(2) do |previous, current|
48
47
  next unless consecutive_lines?(previous, current)
49
48
  next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
50
49
 
@@ -16,6 +16,9 @@ module RuboCop
16
16
  return unless node
17
17
 
18
18
  @processed_source = processed_source
19
+ # Disable autocorrection for tabs as it requires special handling
20
+ return if using_tabs?
21
+
19
22
  expr = node.respond_to?(:loc) ? node.source_range : node
20
23
  return if block_comment_within?(expr)
21
24
 
@@ -30,11 +33,12 @@ module RuboCop
30
33
  @processed_source = processed_source
31
34
  whitespace = whitespace_range(node)
32
35
  column = alignment_column(align_to)
36
+ indentation = indentation_string(column)
33
37
 
34
38
  if whitespace.source.strip.empty?
35
- corrector.replace(whitespace, ' ' * column)
39
+ corrector.replace(whitespace, indentation)
36
40
  else
37
- corrector.insert_after(whitespace, "\n#{' ' * column}")
41
+ corrector.insert_after(whitespace, "\n#{indentation}")
38
42
  end
39
43
  end
40
44
 
@@ -57,7 +61,7 @@ module RuboCop
57
61
  def inside_string_ranges(node)
58
62
  return [] unless node.is_a?(Parser::AST::Node)
59
63
 
60
- node.each_node(:str, :dstr, :xstr).filter_map { |n| inside_string_range(n) }
64
+ node.each_node(:any_str).filter_map { |n| inside_string_range(n) }
61
65
  end
62
66
 
63
67
  def inside_string_range(node)
@@ -76,9 +80,7 @@ module RuboCop
76
80
  # nil.
77
81
  # - The source map of `__FILE__` responds to neither :begin nor :end.
78
82
  def delimited_string_literal?(node)
79
- loc = node.location
80
-
81
- loc.respond_to?(:begin) && loc.begin && loc.respond_to?(:end) && loc.end
83
+ node.loc?(:begin) && node.loc?(:end)
82
84
  end
83
85
 
84
86
  def block_comment_within?(expr)
@@ -122,6 +124,20 @@ module RuboCop
122
124
  align_to.column
123
125
  end
124
126
  end
127
+
128
+ def indentation_string(column)
129
+ if using_tabs?
130
+ "\t" * column
131
+ else
132
+ ' ' * column
133
+ end
134
+ end
135
+
136
+ def using_tabs?
137
+ config = processed_source.config
138
+ indentation_style = config.for_cop('Layout/IndentationStyle')['EnforcedStyle']
139
+ indentation_style == 'tabs'
140
+ end
125
141
  end
126
142
  end
127
143
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
 
17
17
  def negated_condition(node)
18
18
  condition = node.condition
19
- condition = condition.children.first while condition.begin_type?
19
+ condition = condition.children.last while condition.begin_type?
20
20
  condition
21
21
  end
22
22
  end