rubocop 1.50.2 → 1.59.0

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 (290) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -3
  3. data/config/default.yml +153 -16
  4. data/config/obsoletion.yml +5 -0
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
  6. data/lib/rubocop/cli/command/lsp.rb +19 -0
  7. data/lib/rubocop/cli.rb +4 -1
  8. data/lib/rubocop/config.rb +4 -0
  9. data/lib/rubocop/config_finder.rb +2 -2
  10. data/lib/rubocop/config_loader_resolver.rb +4 -3
  11. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  12. data/lib/rubocop/config_obsoletion.rb +13 -10
  13. data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
  14. data/lib/rubocop/cop/base.rb +6 -2
  15. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  16. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  17. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  18. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  19. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  20. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  21. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  22. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  23. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  24. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  25. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  26. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  28. data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
  29. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  30. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  31. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  32. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +7 -7
  33. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  34. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  35. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  36. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  37. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  38. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  39. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  40. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  41. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  42. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  43. data/lib/rubocop/cop/layout/end_alignment.rb +7 -1
  44. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  45. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
  46. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  48. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  49. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  50. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  51. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  52. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  53. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  54. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  55. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  56. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -5
  57. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  58. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  59. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  60. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  61. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  62. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  63. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  64. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  65. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  66. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  67. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  68. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  69. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  70. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  71. data/lib/rubocop/cop/lint/debugger.rb +19 -5
  72. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  73. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  74. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  75. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  76. data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
  77. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  78. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  79. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  80. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  81. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  82. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  83. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  84. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  85. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +78 -0
  86. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  87. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  88. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  89. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  90. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  91. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  92. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  93. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  94. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  95. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  96. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  97. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  98. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +63 -4
  99. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  100. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
  101. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  102. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  103. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  104. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  105. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  106. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  107. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  108. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  109. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  110. data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
  111. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  112. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  113. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  114. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  115. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  116. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  117. data/lib/rubocop/cop/lint/void.rb +92 -11
  118. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  119. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  120. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  121. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  122. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  123. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  124. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  125. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  126. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  127. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  128. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  129. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  130. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  131. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  132. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
  133. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  134. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  135. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  136. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  137. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  138. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  139. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  140. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  141. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  142. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  143. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  144. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  145. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  146. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  147. data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
  148. data/lib/rubocop/cop/style/alias.rb +9 -8
  149. data/lib/rubocop/cop/style/arguments_forwarding.rb +342 -63
  150. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  151. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  152. data/lib/rubocop/cop/style/attr.rb +11 -1
  153. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  154. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  155. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  156. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  157. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  158. data/lib/rubocop/cop/style/case_like_if.rb +4 -4
  159. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  160. data/lib/rubocop/cop/style/class_check.rb +1 -0
  161. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  162. data/lib/rubocop/cop/style/collection_compact.rb +22 -11
  163. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  164. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  165. data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
  166. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  167. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  168. data/lib/rubocop/cop/style/copyright.rb +5 -2
  169. data/lib/rubocop/cop/style/date_time.rb +5 -4
  170. data/lib/rubocop/cop/style/dir.rb +1 -1
  171. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  172. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  173. data/lib/rubocop/cop/style/documentation.rb +1 -1
  174. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  175. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  176. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  177. data/lib/rubocop/cop/style/eval_with_location.rb +8 -8
  178. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  179. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  180. data/lib/rubocop/cop/style/file_read.rb +2 -2
  181. data/lib/rubocop/cop/style/for.rb +1 -1
  182. data/lib/rubocop/cop/style/format_string.rb +24 -3
  183. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  184. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  185. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  186. data/lib/rubocop/cop/style/hash_each_methods.rb +84 -32
  187. data/lib/rubocop/cop/style/hash_except.rb +21 -9
  188. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  189. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  190. data/lib/rubocop/cop/style/identical_conditional_branches.rb +31 -5
  191. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  192. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  193. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  194. data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
  195. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
  196. data/lib/rubocop/cop/style/lambda.rb +3 -3
  197. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  198. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
  199. data/lib/rubocop/cop/style/map_to_hash.rb +10 -4
  200. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -5
  201. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  202. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  203. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  204. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  205. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  206. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  207. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  208. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  209. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  210. data/lib/rubocop/cop/style/next.rb +1 -1
  211. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  212. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  213. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  214. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  215. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  216. data/lib/rubocop/cop/style/redundant_argument.rb +9 -3
  217. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  218. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  219. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  220. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  221. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  222. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  223. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  224. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  225. data/lib/rubocop/cop/style/redundant_line_continuation.rb +9 -3
  226. data/lib/rubocop/cop/style/redundant_parentheses.rb +54 -21
  227. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  228. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  229. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  230. data/lib/rubocop/cop/style/redundant_return.rb +8 -3
  231. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  232. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  233. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  234. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  235. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  236. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  237. data/lib/rubocop/cop/style/require_order.rb +11 -5
  238. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  239. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  240. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  241. data/lib/rubocop/cop/style/sample.rb +2 -1
  242. data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
  243. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  244. data/lib/rubocop/cop/style/semicolon.rb +20 -4
  245. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  246. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  247. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  248. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  249. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  250. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
  251. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  252. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  253. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  254. data/lib/rubocop/cop/style/strip.rb +7 -4
  255. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  256. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  257. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  258. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  259. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  260. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  261. data/lib/rubocop/cop/team.rb +1 -1
  262. data/lib/rubocop/cop/util.rb +1 -1
  263. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  264. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  265. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  266. data/lib/rubocop/cop/variable_force.rb +1 -0
  267. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  268. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  269. data/lib/rubocop/file_finder.rb +4 -7
  270. data/lib/rubocop/formatter/html_formatter.rb +5 -4
  271. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  272. data/lib/rubocop/lsp/logger.rb +22 -0
  273. data/lib/rubocop/lsp/routes.rb +246 -0
  274. data/lib/rubocop/lsp/runtime.rb +99 -0
  275. data/lib/rubocop/lsp/server.rb +68 -0
  276. data/lib/rubocop/lsp/severity.rb +27 -0
  277. data/lib/rubocop/magic_comment.rb +12 -10
  278. data/lib/rubocop/options.rb +11 -1
  279. data/lib/rubocop/result_cache.rb +5 -2
  280. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  281. data/lib/rubocop/rspec/shared_contexts.rb +2 -3
  282. data/lib/rubocop/runner.rb +6 -4
  283. data/lib/rubocop/server/cache.rb +1 -0
  284. data/lib/rubocop/server/client_command/exec.rb +3 -2
  285. data/lib/rubocop/string_interpreter.rb +3 -3
  286. data/lib/rubocop/target_finder.rb +7 -3
  287. data/lib/rubocop/target_ruby.rb +12 -7
  288. data/lib/rubocop/version.rb +10 -6
  289. data/lib/rubocop.rb +19 -0
  290. metadata +54 -15
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'severity'
4
+
5
+ #
6
+ # This code is based on https://github.com/standardrb/standard.
7
+ #
8
+ # Copyright (c) 2023 Test Double, Inc.
9
+ #
10
+ # The MIT License (MIT)
11
+ #
12
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
13
+ #
14
+ module RuboCop
15
+ module Lsp
16
+ # Routes for Language Server Protocol of RuboCop.
17
+ # @api private
18
+ class Routes
19
+ def self.handle(name, &block)
20
+ define_method("handle_#{name}", &block)
21
+ end
22
+
23
+ private_class_method :handle
24
+
25
+ def initialize(server)
26
+ @server = server
27
+
28
+ @text_cache = {}
29
+ end
30
+
31
+ def for(name)
32
+ name = "handle_#{name}"
33
+ return unless respond_to?(name)
34
+
35
+ method(name)
36
+ end
37
+
38
+ handle 'initialize' do |request|
39
+ initialization_options = extract_initialization_options_from(request)
40
+
41
+ @server.configure(initialization_options)
42
+
43
+ @server.write(
44
+ id: request[:id],
45
+ result: LanguageServer::Protocol::Interface::InitializeResult.new(
46
+ capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
47
+ document_formatting_provider: true,
48
+ diagnostic_provider: LanguageServer::Protocol::Interface::DiagnosticOptions.new(
49
+ inter_file_dependencies: false,
50
+ workspace_diagnostics: false
51
+ ),
52
+ text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
53
+ change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::FULL,
54
+ open_close: true
55
+ )
56
+ )
57
+ )
58
+ )
59
+ end
60
+
61
+ handle 'initialized' do |_request|
62
+ version = RuboCop::Version::STRING
63
+
64
+ Logger.log("RuboCop #{version} language server initialized, PID #{Process.pid}")
65
+ end
66
+
67
+ handle 'shutdown' do |request|
68
+ Logger.log('Client asked to shutdown RuboCop language server.')
69
+ @server.stop do
70
+ @server.write(id: request[:id], result: nil)
71
+ Logger.log('Exiting...')
72
+ end
73
+ end
74
+
75
+ handle 'textDocument/diagnostic' do |request|
76
+ doc = request[:params][:textDocument]
77
+ result = diagnostic(doc[:uri], doc[:text])
78
+ @server.write(result)
79
+ end
80
+
81
+ handle 'textDocument/didChange' do |request|
82
+ params = request[:params]
83
+ result = diagnostic(params[:textDocument][:uri], params[:contentChanges][0][:text])
84
+ @server.write(result)
85
+ end
86
+
87
+ handle 'textDocument/didOpen' do |request|
88
+ doc = request[:params][:textDocument]
89
+ result = diagnostic(doc[:uri], doc[:text])
90
+ @server.write(result)
91
+ end
92
+
93
+ handle 'textDocument/didClose' do |request|
94
+ @text_cache.delete(request.dig(:params, :textDocument, :uri))
95
+ end
96
+
97
+ handle 'textDocument/formatting' do |request|
98
+ uri = request[:params][:textDocument][:uri]
99
+ @server.write(id: request[:id], result: format_file(uri))
100
+ end
101
+
102
+ handle 'workspace/didChangeConfiguration' do |_request|
103
+ Logger.log('Ignoring workspace/didChangeConfiguration')
104
+ end
105
+
106
+ handle 'workspace/didChangeWatchedFiles' do |request|
107
+ changed = request[:params][:changes].any? do |change|
108
+ change[:uri].end_with?(RuboCop::ConfigFinder::DOTFILE)
109
+ end
110
+
111
+ if changed
112
+ Logger.log('Configuration file changed; restart required')
113
+ @server.stop
114
+ end
115
+ end
116
+
117
+ handle 'workspace/executeCommand' do |request|
118
+ case (command = request[:params][:command])
119
+ when 'rubocop.formatAutocorrects'
120
+ label = 'Format with RuboCop autocorrects'
121
+ when 'rubocop.formatAutocorrectsAll'
122
+ label = 'Format all with RuboCop autocorrects'
123
+ else
124
+ handle_unsupported_method(request, command)
125
+ return
126
+ end
127
+
128
+ uri = request[:params][:arguments][0][:uri]
129
+ @server.write(
130
+ id: request[:id],
131
+ method: 'workspace/applyEdit',
132
+ params: {
133
+ label: label,
134
+ edit: {
135
+ changes: {
136
+ uri => format_file(uri, command: command)
137
+ }
138
+ }
139
+ }
140
+ )
141
+ end
142
+
143
+ handle 'textDocument/willSave' do |_request|
144
+ # Nothing to do
145
+ end
146
+
147
+ handle 'textDocument/didSave' do |_request|
148
+ # Nothing to do
149
+ end
150
+
151
+ handle '$/cancelRequest' do |_request|
152
+ # Can't cancel anything because single-threaded
153
+ end
154
+
155
+ handle '$/setTrace' do |_request|
156
+ # No-op, we log everything
157
+ end
158
+
159
+ def handle_unsupported_method(request, method = request[:method])
160
+ @server.write(
161
+ id: request[:id],
162
+ error: LanguageServer::Protocol::Interface::ResponseError.new(
163
+ code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
164
+ message: "Unsupported Method: #{method}"
165
+ )
166
+ )
167
+ Logger.log("Unsupported Method: #{method}")
168
+ end
169
+
170
+ def handle_method_missing(request)
171
+ return unless request.key?(:id)
172
+
173
+ @server.write(id: request[:id], result: nil)
174
+ end
175
+
176
+ private
177
+
178
+ def extract_initialization_options_from(request)
179
+ safe_autocorrect = request.dig(:params, :initializationOptions, :safeAutocorrect)
180
+
181
+ {
182
+ safe_autocorrect: safe_autocorrect.nil? || safe_autocorrect == true,
183
+ lint_mode: request.dig(:params, :initializationOptions, :lintMode) == true,
184
+ layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true
185
+ }
186
+ end
187
+
188
+ def format_file(file_uri, command: nil)
189
+ unless (text = @text_cache[file_uri])
190
+ Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
191
+
192
+ return []
193
+ end
194
+
195
+ new_text = @server.format(remove_file_protocol_from(file_uri), text, command: command)
196
+
197
+ return [] if new_text == text
198
+
199
+ [
200
+ newText: new_text,
201
+ range: {
202
+ start: { line: 0, character: 0 },
203
+ end: { line: text.count("\n") + 1, character: 0 }
204
+ }
205
+ ]
206
+ end
207
+
208
+ def diagnostic(file_uri, text)
209
+ @text_cache[file_uri] = text
210
+ offenses = @server.offenses(remove_file_protocol_from(file_uri), text)
211
+ diagnostics = offenses.map { |offense| to_diagnostic(offense) }
212
+
213
+ {
214
+ method: 'textDocument/publishDiagnostics',
215
+ params: {
216
+ uri: file_uri,
217
+ diagnostics: diagnostics
218
+ }
219
+ }
220
+ end
221
+
222
+ def remove_file_protocol_from(uri)
223
+ uri.delete_prefix('file://')
224
+ end
225
+
226
+ def to_diagnostic(offense)
227
+ code = offense[:cop_name]
228
+ message = offense[:message]
229
+ loc = offense[:location]
230
+ rubocop_severity = offense[:severity]
231
+ severity = Severity.find_by(rubocop_severity)
232
+
233
+ {
234
+ code: code, message: message, range: to_range(loc), severity: severity, source: 'rubocop'
235
+ }
236
+ end
237
+
238
+ def to_range(location)
239
+ {
240
+ start: { character: location[:start_column] - 1, line: location[:start_line] - 1 },
241
+ end: { character: location[:last_column] - 1, line: location[:last_line] - 1 }
242
+ }
243
+ end
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/standardrb/standard.
5
+ #
6
+ # Copyright (c) 2023 Test Double, Inc.
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Lsp
14
+ # Runtime for Language Server Protocol of RuboCop.
15
+ # @api private
16
+ class Runtime
17
+ attr_writer :safe_autocorrect, :lint_mode, :layout_mode
18
+
19
+ def initialize(config_store)
20
+ @config_store = config_store
21
+ @logged_paths = []
22
+ @safe_autocorrect = true
23
+ @lint_mode = false
24
+ @layout_mode = false
25
+ end
26
+
27
+ # This abuses the `--stdin` option of rubocop and reads the formatted text
28
+ # from the `options[:stdin]` that rubocop mutates. This depends on
29
+ # `parallel: false` as well as the fact that RuboCop doesn't otherwise dup
30
+ # or reassign that options object. Risky business!
31
+ #
32
+ # Reassigning `options[:stdin]` is done here:
33
+ # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cop/team.rb#L131
34
+ # Printing `options[:stdin]`
35
+ # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cli/command/execute_runner.rb#L95
36
+ # Setting `parallel: true` would break this here:
37
+ # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/runner.rb#L72
38
+ def format(path, text, command:)
39
+ safe_autocorrect = if command
40
+ command == 'rubocop.formatAutocorrects'
41
+ else
42
+ @safe_autocorrect
43
+ end
44
+
45
+ formatting_options = {
46
+ stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: safe_autocorrect
47
+ }
48
+ formatting_options[:only] = config_only_options if @lint_mode || @layout_mode
49
+
50
+ redirect_stdout { run_rubocop(formatting_options, path) }
51
+
52
+ formatting_options[:stdin]
53
+ end
54
+
55
+ def offenses(path, text)
56
+ diagnostic_options = {
57
+ stdin: text, force_exclusion: true, formatters: ['json'], format: 'json'
58
+ }
59
+ diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
60
+
61
+ json = redirect_stdout { run_rubocop(diagnostic_options, path) }
62
+ results = JSON.parse(json, symbolize_names: true)
63
+
64
+ if results[:files].empty?
65
+ unless @logged_paths.include?(path)
66
+ Logger.log "Ignoring file, per configuration: #{path}"
67
+ @logged_paths << path
68
+ end
69
+ return []
70
+ end
71
+
72
+ results.dig(:files, 0, :offenses)
73
+ end
74
+
75
+ private
76
+
77
+ def config_only_options
78
+ only_options = []
79
+ only_options << 'Lint' if @lint_mode
80
+ only_options << 'Layout' if @layout_mode
81
+ only_options
82
+ end
83
+
84
+ def redirect_stdout(&block)
85
+ stdout = StringIO.new
86
+
87
+ RuboCop::Server::Helper.redirect(stdout: stdout, &block)
88
+
89
+ stdout.string
90
+ end
91
+
92
+ def run_rubocop(options, path)
93
+ runner = RuboCop::Runner.new(options, @config_store)
94
+
95
+ runner.run([path])
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'language_server-protocol'
4
+ require_relative 'logger'
5
+ require_relative 'routes'
6
+ require_relative 'runtime'
7
+
8
+ #
9
+ # This code is based on https://github.com/standardrb/standard.
10
+ #
11
+ # Copyright (c) 2023 Test Double, Inc.
12
+ #
13
+ # The MIT License (MIT)
14
+ #
15
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
16
+ #
17
+ module RuboCop
18
+ module Lsp
19
+ # Language Server Protocol of RuboCop.
20
+ # @api private
21
+ class Server
22
+ def initialize(config_store)
23
+ @reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
24
+ @writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
25
+ @runtime = RuboCop::Lsp::Runtime.new(config_store)
26
+ @routes = Routes.new(self)
27
+ end
28
+
29
+ def start
30
+ @reader.read do |request|
31
+ if !request.key?(:method)
32
+ @routes.handle_method_missing(request)
33
+ elsif (route = @routes.for(request[:method]))
34
+ route.call(request)
35
+ else
36
+ @routes.handle_unsupported_method(request)
37
+ end
38
+ rescue StandardError => e
39
+ Logger.log("Error #{e.class} #{e.message[0..100]}")
40
+ Logger.log(e.backtrace.inspect)
41
+ end
42
+ end
43
+
44
+ def write(response)
45
+ @writer.write(response)
46
+ end
47
+
48
+ def format(path, text, command:)
49
+ @runtime.format(path, text, command: command)
50
+ end
51
+
52
+ def offenses(path, text)
53
+ @runtime.offenses(path, text)
54
+ end
55
+
56
+ def configure(options)
57
+ @runtime.safe_autocorrect = options[:safe_autocorrect]
58
+ @runtime.lint_mode = options[:lint_mode]
59
+ @runtime.layout_mode = options[:layout_mode]
60
+ end
61
+
62
+ def stop(&block)
63
+ at_exit(&block) if block
64
+ exit
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Lsp
5
+ # Severity for Language Server Protocol of RuboCop.
6
+ # @api private
7
+ class Severity
8
+ SEVERITIES = {
9
+ fatal: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
10
+ error: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
11
+ warning: LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING,
12
+ convention: LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION,
13
+ refactor: LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT,
14
+ info: LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT
15
+ }.freeze
16
+
17
+ def self.find_by(rubocop_severity)
18
+ if (severity = SEVERITIES[rubocop_severity.to_sym])
19
+ return severity
20
+ end
21
+
22
+ Logger.log("Unknown severity: #{rubocop_severity}")
23
+ LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT
24
+ end
25
+ end
26
+ end
27
+ end
@@ -7,7 +7,7 @@ module RuboCop
7
7
  class MagicComment
8
8
  # IRB's pattern for matching magic comment tokens.
9
9
  # @see https://github.com/ruby/ruby/blob/b4a55c1/lib/irb/magic-file.rb#L5
10
- TOKEN = /[[:alnum:]\-_]+/.freeze
10
+ TOKEN = '(?<token>[[:alnum:]\-_]+)'
11
11
  KEYWORDS = {
12
12
  encoding: '(?:en)?coding',
13
13
  frozen_string_literal: 'frozen[_-]string[_-]literal',
@@ -129,7 +129,7 @@ module RuboCop
129
129
  # @return [String] if pattern matched
130
130
  # @return [nil] otherwise
131
131
  def extract(pattern)
132
- @comment[pattern, 1]
132
+ @comment[pattern, :token]
133
133
  end
134
134
 
135
135
  # Parent to Vim and Emacs magic comment handling.
@@ -157,10 +157,10 @@ module RuboCop
157
157
  # @return [String] extracted value if it is found
158
158
  # @return [nil] otherwise
159
159
  def match(keyword)
160
- pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*(#{TOKEN})\z/
160
+ pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*#{TOKEN}\z/
161
161
 
162
162
  tokens.each do |token|
163
- next unless (value = token[pattern, 1])
163
+ next unless (value = token[pattern, :token])
164
164
 
165
165
  return value.downcase
166
166
  end
@@ -188,7 +188,7 @@ module RuboCop
188
188
  # @see https://www.gnu.org/software/emacs/manual/html_node/emacs/Specify-Coding.html
189
189
  # @see https://github.com/ruby/ruby/blob/3f306dc/parse.y#L6873-L6892 Emacs handling in parse.y
190
190
  class EmacsComment < EditorComment
191
- REGEXP = /-\*-(.+)-\*-/.freeze
191
+ REGEXP = /-\*-(?<token>.+)-\*-/.freeze
192
192
  FORMAT = '# -*- %s -*-'
193
193
  SEPARATOR = ';'
194
194
  OPERATOR = ':'
@@ -216,7 +216,7 @@ module RuboCop
216
216
  #
217
217
  # comment.encoding # => 'ascii-8bit'
218
218
  class VimComment < EditorComment
219
- REGEXP = /#\s*vim:\s*(.+)/.freeze
219
+ REGEXP = /#\s*vim:\s*(?<token>.+)/.freeze
220
220
  FORMAT = '# vim: %s'
221
221
  SEPARATOR = ', '
222
222
  OPERATOR = '='
@@ -259,9 +259,11 @@ module RuboCop
259
259
  # comment2.frozen_string_literal # => nil
260
260
  # comment2.encoding # => 'utf-8'
261
261
  class SimpleComment < MagicComment
262
+ FSTRING_LITERAL_COMMENT = 'frozen_string_literal:\s*(true|false)'
263
+
262
264
  # Match `encoding` or `coding`
263
265
  def encoding
264
- extract(/\A\s*\#.*\b#{KEYWORDS[:encoding]}: (#{TOKEN})/io)
266
+ extract(/\A\s*\#\s*(#{FSTRING_LITERAL_COMMENT})?\s*#{KEYWORDS[:encoding]}: (#{TOKEN})/io)
265
267
  end
266
268
 
267
269
  # Rewrite the comment without a given token type
@@ -283,15 +285,15 @@ module RuboCop
283
285
  # Case-insensitive and dashes/underscores are acceptable.
284
286
  # @see https://github.com/ruby/ruby/blob/78b95b4/parse.y#L7134-L7138
285
287
  def extract_frozen_string_literal
286
- extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*(#{TOKEN})\s*\z/io)
288
+ extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io)
287
289
  end
288
290
 
289
291
  def extract_shareable_constant_value
290
- extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*(#{TOKEN})\s*\z/io)
292
+ extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io)
291
293
  end
292
294
 
293
295
  def extract_typed
294
- extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*(#{TOKEN})\s*\z/io)
296
+ extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*#{TOKEN}\s*\z/io)
295
297
  end
296
298
  end
297
299
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
  'root of the project. RuboCop will use this path to determine which ' \
17
17
  'cops are enabled (via eg. Include/Exclude), and so that certain cops ' \
18
18
  'like Naming/FileName can be checked.'
19
- EXITING_OPTIONS = %i[version verbose_version show_cops show_docs_url].freeze
19
+ EXITING_OPTIONS = %i[version verbose_version show_cops show_docs_url lsp].freeze
20
20
  DEFAULT_MAXIMUM_EXCLUSION_ITEMS = 15
21
21
 
22
22
  def initialize
@@ -49,12 +49,14 @@ module RuboCop
49
49
 
50
50
  private
51
51
 
52
+ # rubocop:disable Metrics/AbcSize
52
53
  def define_options
53
54
  OptionParser.new do |opts|
54
55
  opts.banner = rainbow.wrap('Usage: rubocop [options] [file1, file2, ...]').bright
55
56
 
56
57
  add_check_options(opts)
57
58
  add_cache_options(opts)
59
+ add_lsp_option(opts)
58
60
  add_server_options(opts)
59
61
  add_output_options(opts)
60
62
  add_autocorrection_options(opts)
@@ -66,6 +68,7 @@ module RuboCop
66
68
  add_profile_options(opts) if RUBY_ENGINE == 'ruby' && !Platform.windows?
67
69
  end
68
70
  end
71
+ # rubocop:enable Metrics/AbcSize
69
72
 
70
73
  def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
71
74
  section(opts, 'Basic Options') do # rubocop:disable Metrics/BlockLength
@@ -205,6 +208,12 @@ module RuboCop
205
208
  end
206
209
  end
207
210
 
211
+ def add_lsp_option(opts)
212
+ section(opts, 'LSP Option') do
213
+ option(opts, '--lsp')
214
+ end
215
+ end
216
+
208
217
  def add_server_options(opts)
209
218
  section(opts, 'Server Options') do
210
219
  option(opts, '--[no-]server')
@@ -620,6 +629,7 @@ module RuboCop
620
629
  stop_server: 'Stop server process.',
621
630
  server_status: 'Show server status.',
622
631
  no_detach: 'Run the server process in the foreground.',
632
+ lsp: 'Start a language server listening on STDIN.',
623
633
  raise_cop_error: ['Raise cop-related errors with cause and location.',
624
634
  'This is used to prevent cops from failing silently.',
625
635
  'Default is false.'],
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'digest/sha1'
4
- require 'etc'
5
4
  require 'find'
6
5
  require 'zlib'
7
6
  require_relative 'cache_config'
@@ -83,7 +82,7 @@ module RuboCop
83
82
  config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
84
83
  end
85
84
 
86
- attr :path
85
+ attr_reader :path
87
86
 
88
87
  def initialize(file, team, options, config_store, cache_root = nil)
89
88
  cache_root ||= File.join(options[:cache_root], 'rubocop_cache') if options[:cache_root]
@@ -202,6 +201,10 @@ module RuboCop
202
201
  lib_root = File.join(File.dirname(__FILE__), '..')
203
202
  exe_root = File.join(lib_root, '..', 'exe')
204
203
 
204
+ # Make sure to use an absolute path to prevent errors on Windows
205
+ # when traversing the relative paths with symlinks.
206
+ exe_root = File.absolute_path(exe_root)
207
+
205
208
  # These are all the files we have `require`d plus everything in the
206
209
  # exe directory. A change to any of them could affect the cop output
207
210
  # so we include them in the cache hash.
@@ -6,7 +6,7 @@ require 'tempfile'
6
6
  module CopHelper
7
7
  extend RSpec::SharedContext
8
8
 
9
- let(:ruby_version) { 2.6 }
9
+ let(:ruby_version) { RuboCop::TargetRuby::DEFAULT_VERSION }
10
10
  let(:rails_version) { false }
11
11
 
12
12
  def inspect_source(source, file = nil)
@@ -11,6 +11,8 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
11
11
  # Make sure to expand all symlinks in the path first. Otherwise we may
12
12
  # get mismatched pathnames when loading config files later on.
13
13
  tmpdir = File.realpath(tmpdir)
14
+ # Make upwards search for .rubocop.yml files stop at this directory.
15
+ RuboCop::FileFinder.root_level = tmpdir
14
16
 
15
17
  virtual_home = File.expand_path(File.join(tmpdir, 'home'))
16
18
  Dir.mkdir(virtual_home)
@@ -21,9 +23,6 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
21
23
  root = example.metadata[:root]
22
24
  working_dir = root ? File.join(base_dir, 'work', root) : File.join(base_dir, 'work')
23
25
 
24
- # Make upwards search for .rubocop.yml files stop at this directory.
25
- RuboCop::FileFinder.root_level = working_dir
26
-
27
26
  begin
28
27
  FileUtils.mkdir_p(working_dir)
29
28
 
@@ -20,7 +20,7 @@ module RuboCop
20
20
  message = 'Infinite loop detected'
21
21
  message += " in #{path}" if path
22
22
  message += " and caused by #{root_cause}" if root_cause
23
- super message
23
+ super(message)
24
24
  end
25
25
  end
26
26
 
@@ -421,10 +421,10 @@ module RuboCop
421
421
  end
422
422
 
423
423
  def considered_failure?(offense)
424
- # For :autocorrect level, any offense - corrected or not - is a failure.
425
424
  return false if offense.disabled?
426
425
 
427
- return true if @options[:fail_level] == :autocorrect
426
+ # For :autocorrect level, any correctable offense is a failure, regardless of severity
427
+ return true if @options[:fail_level] == :autocorrect && offense.correctable?
428
428
 
429
429
  !offense.corrected? && offense.severity >= minimum_severity_to_fail
430
430
  end
@@ -461,7 +461,9 @@ module RuboCop
461
461
  @minimum_severity_to_fail ||= begin
462
462
  # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
463
463
  name = @options[:fail_level] || :refactor
464
- RuboCop::Cop::Severity.new(name)
464
+
465
+ # autocorrect is a fake level - use the default
466
+ RuboCop::Cop::Severity.new(name == :autocorrect ? :refactor : name)
465
467
  end
466
468
  end
467
469
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fileutils'
3
4
  require 'pathname'
4
5
  require_relative '../cache_config'
5
6
  require_relative '../config_finder'
@@ -18,10 +18,11 @@ module RuboCop
18
18
  def run
19
19
  ensure_server!
20
20
  Cache.status_path.delete if Cache.status_path.file?
21
+ read_stdin = ARGV.include?('-s') || ARGV.include?('--stdin')
21
22
  send_request(
22
23
  command: 'exec',
23
24
  args: ARGV.dup,
24
- body: $stdin.tty? ? '' : $stdin.read
25
+ body: read_stdin ? $stdin.read : ''
25
26
  )
26
27
  warn stderr unless stderr.empty?
27
28
  status
@@ -31,7 +32,7 @@ module RuboCop
31
32
 
32
33
  def ensure_server!
33
34
  if incompatible_version?
34
- puts 'RuboCop version incompatibility found, RuboCop server restarting...'
35
+ warn 'RuboCop version incompatibility found, RuboCop server restarting...'
35
36
  ClientCommand::Stop.new.run
36
37
  elsif check_running_server
37
38
  return