rubocop 1.57.2 → 1.62.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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +87 -15
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  8. data/lib/rubocop/cli/command/lsp.rb +2 -2
  9. data/lib/rubocop/cli.rb +6 -1
  10. data/lib/rubocop/config.rb +4 -2
  11. data/lib/rubocop/config_finder.rb +12 -2
  12. data/lib/rubocop/config_loader.rb +0 -1
  13. data/lib/rubocop/config_obsoletion.rb +11 -8
  14. data/lib/rubocop/config_validator.rb +14 -7
  15. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  16. data/lib/rubocop/cop/base.rb +17 -2
  17. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  18. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  19. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  20. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  21. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  23. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
  24. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  25. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  26. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +123 -29
  28. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  29. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  32. data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
  33. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  34. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  35. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  37. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
  40. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  41. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  43. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  44. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  45. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  46. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  47. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  48. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  49. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  50. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  51. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  52. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  53. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  54. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  55. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  56. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  57. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  58. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  59. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
  60. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  61. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  62. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  63. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  64. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  65. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  66. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  67. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  68. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  69. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
  70. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  71. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  72. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  73. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  74. data/lib/rubocop/cop/lint/void.rb +20 -2
  75. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  76. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  77. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  78. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  79. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  80. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  81. data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
  82. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  83. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  84. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  85. data/lib/rubocop/cop/registry.rb +1 -1
  86. data/lib/rubocop/cop/security/open.rb +2 -2
  87. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  88. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  89. data/lib/rubocop/cop/style/arguments_forwarding.rb +152 -21
  90. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  91. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  92. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  93. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  94. data/lib/rubocop/cop/style/class_check.rb +1 -0
  95. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  96. data/lib/rubocop/cop/style/collection_compact.rb +18 -8
  97. data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
  98. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  99. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
  100. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
  101. data/lib/rubocop/cop/style/date_time.rb +5 -4
  102. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  103. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  104. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  105. data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
  106. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  107. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  108. data/lib/rubocop/cop/style/for.rb +2 -0
  109. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  110. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  111. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  112. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  113. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  114. data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
  115. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  116. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  117. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
  118. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  119. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  120. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  121. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  122. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  123. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  124. data/lib/rubocop/cop/style/next.rb +1 -1
  125. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  126. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  127. data/lib/rubocop/cop/style/object_then.rb +5 -3
  128. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  129. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  130. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  131. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  132. data/lib/rubocop/cop/style/redundant_argument.rb +4 -3
  133. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  134. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +4 -3
  135. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  136. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  137. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  138. data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -7
  139. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
  140. data/lib/rubocop/cop/style/redundant_return.rb +7 -1
  141. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  142. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  143. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  144. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  145. data/lib/rubocop/cop/style/sample.rb +3 -4
  146. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  147. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  148. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  149. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
  150. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  151. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  152. data/lib/rubocop/cop/style/strip.rb +7 -4
  153. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  154. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  155. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  156. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  157. data/lib/rubocop/cops_documentation_generator.rb +15 -3
  158. data/lib/rubocop/directive_comment.rb +10 -8
  159. data/lib/rubocop/ext/regexp_node.rb +9 -4
  160. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  161. data/lib/rubocop/formatter/html_formatter.rb +31 -12
  162. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  163. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  164. data/lib/rubocop/formatter.rb +1 -1
  165. data/lib/rubocop/lsp/logger.rb +1 -1
  166. data/lib/rubocop/lsp/routes.rb +2 -2
  167. data/lib/rubocop/lsp/runtime.rb +1 -1
  168. data/lib/rubocop/lsp/server.rb +5 -2
  169. data/lib/rubocop/lsp/severity.rb +1 -1
  170. data/lib/rubocop/lsp.rb +29 -0
  171. data/lib/rubocop/magic_comment.rb +1 -1
  172. data/lib/rubocop/options.rb +11 -8
  173. data/lib/rubocop/path_util.rb +6 -2
  174. data/lib/rubocop/result_cache.rb +0 -1
  175. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  176. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  177. data/lib/rubocop/rspec/shared_contexts.rb +40 -15
  178. data/lib/rubocop/rspec/support.rb +2 -0
  179. data/lib/rubocop/runner.rb +10 -3
  180. data/lib/rubocop/server/cache.rb +1 -2
  181. data/lib/rubocop/server/client_command/exec.rb +0 -1
  182. data/lib/rubocop/server/server_command/exec.rb +0 -1
  183. data/lib/rubocop/target_finder.rb +84 -78
  184. data/lib/rubocop/target_ruby.rb +82 -80
  185. data/lib/rubocop/version.rb +18 -3
  186. data/lib/rubocop.rb +4 -0
  187. metadata +18 -10
  188. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -97,7 +97,9 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
97
97
  'Version Changed'
98
98
  ]
99
99
  autocorrect = if cop.support_autocorrect?
100
- "Yes#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}"
100
+ context = cop.new.always_autocorrect? ? 'Always' : 'Command-line only'
101
+
102
+ "#{context}#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}"
101
103
  else
102
104
  'No'
103
105
  end
@@ -251,9 +253,18 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
251
253
  "\ninclude::../partials/#{filename}[]\n"
252
254
  end
253
255
 
256
+ # rubocop:disable Metrics/MethodLength
254
257
  def print_cops_of_department(department)
255
258
  selected_cops = cops_of_department(department)
256
- content = +"= #{department}\n"
259
+ content = +<<~HEADER
260
+ ////
261
+ Do NOT edit this file by hand directly, as it is automatically generated.
262
+
263
+ Please make any necessary changes to the cop documentation within the source files themselves.
264
+ ////
265
+
266
+ = #{department}
267
+ HEADER
257
268
  selected_cops.each { |cop| content << print_cop_with_doc(cop) }
258
269
  content << footer_for_department(department)
259
270
  file_name = "#{docs_path}/#{department_to_basename(department)}.adoc"
@@ -262,11 +273,12 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
262
273
  file.write("#{content.strip}\n")
263
274
  end
264
275
  end
276
+ # rubocop:enable Metrics/MethodLength
265
277
 
266
278
  def print_cop_with_doc(cop) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
267
279
  cop_config = config.for_cop(cop)
268
280
  non_display_keys = %w[
269
- Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
281
+ AutoCorrect Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
270
282
  VersionChanged
271
283
  ]
272
284
  pars = cop_config.reject { |k| non_display_keys.include? k }
@@ -6,9 +6,11 @@ module RuboCop
6
6
  # cops it contains.
7
7
  class DirectiveComment
8
8
  # @api private
9
- REDUNDANT_DIRECTIVE_COP_DEPARTMENT = 'Lint'
9
+ LINT_DEPARTMENT = 'Lint'
10
10
  # @api private
11
- REDUNDANT_DIRECTIVE_COP = "#{REDUNDANT_DIRECTIVE_COP_DEPARTMENT}/RedundantCopDisableDirective"
11
+ LINT_REDUNDANT_DIRECTIVE_COP = "#{LINT_DEPARTMENT}/RedundantCopDisableDirective"
12
+ # @api private
13
+ LINT_SYNTAX_COP = "#{LINT_DEPARTMENT}/Syntax"
12
14
  # @api private
13
15
  COP_NAME_PATTERN = '([A-Z]\w+/)*(?:[A-Z]\w+)'
14
16
  # @api private
@@ -118,9 +120,10 @@ module RuboCop
118
120
  end
119
121
 
120
122
  def parsed_cop_names
121
- splitted_cops_string.map do |name|
123
+ cops = splitted_cops_string.map do |name|
122
124
  department?(name) ? cop_names_for_department(name) : name
123
125
  end.flatten
126
+ cops - [LINT_SYNTAX_COP]
124
127
  end
125
128
 
126
129
  def department?(name)
@@ -128,17 +131,16 @@ module RuboCop
128
131
  end
129
132
 
130
133
  def all_cop_names
131
- exclude_redundant_directive_cop(cop_registry.names)
134
+ exclude_lint_department_cops(cop_registry.names)
132
135
  end
133
136
 
134
137
  def cop_names_for_department(department)
135
138
  names = cop_registry.names_for_department(department)
136
- has_redundant_directive_cop = department == REDUNDANT_DIRECTIVE_COP_DEPARTMENT
137
- has_redundant_directive_cop ? exclude_redundant_directive_cop(names) : names
139
+ department == LINT_DEPARTMENT ? exclude_lint_department_cops(names) : names
138
140
  end
139
141
 
140
- def exclude_redundant_directive_cop(cops)
141
- cops - [REDUNDANT_DIRECTIVE_COP]
142
+ def exclude_lint_department_cops(cops)
143
+ cops - [LINT_REDUNDANT_DIRECTIVE_COP, LINT_SYNTAX_COP]
142
144
  end
143
145
  end
144
146
  end
@@ -54,10 +54,7 @@ module RuboCop
54
54
  return enum_for(__method__, named: named) unless block_given?
55
55
 
56
56
  parsed_tree&.traverse do |event, exp, _index|
57
- yield(exp) if event == :enter &&
58
- named == exp.respond_to?(:name) &&
59
- exp.respond_to?(:capturing?) &&
60
- exp.capturing?
57
+ yield(exp) if named_capturing?(exp, event, named)
61
58
  end
62
59
 
63
60
  self
@@ -65,6 +62,14 @@ module RuboCop
65
62
 
66
63
  private
67
64
 
65
+ def named_capturing?(exp, event, named)
66
+ event == :enter &&
67
+ named == exp.respond_to?(:name) &&
68
+ !exp.text.start_with?('(?<=') &&
69
+ exp.respond_to?(:capturing?) &&
70
+ exp.capturing?
71
+ end
72
+
68
73
  def with_interpolations_blanked
69
74
  # Ignore the trailing regopt node
70
75
  children[0...-1].map do |child|
@@ -30,7 +30,8 @@ module RuboCop
30
30
  @files_with_offenses ||= {}
31
31
  end
32
32
 
33
- def file_started(_file, _file_info)
33
+ def file_started(_file, options)
34
+ @config_for_pwd = options[:config_store].for_pwd
34
35
  @exclude_limit_option = @options[:exclude_limit]
35
36
  @exclude_limit = Integer(@exclude_limit_option ||
36
37
  RuboCop::Options::DEFAULT_MAXIMUM_EXCLUSION_ITEMS)
@@ -115,9 +116,13 @@ module RuboCop
115
116
  def set_max(cfg, cop_name)
116
117
  return unless cfg[:exclude_limit]
117
118
 
118
- # In case auto_gen_only_exclude is set, only modify the maximum if the
119
- # files are not excluded one by one.
120
- if !@options[:auto_gen_only_exclude] || @files_with_offenses[cop_name].size > @exclude_limit
119
+ max_set_in_user_config =
120
+ @config_for_pwd.for_cop(cop_name)['Max'] != default_config(cop_name)['Max']
121
+ if !max_set_in_user_config &&
122
+ # In case auto_gen_only_exclude is set, only modify the maximum if the files are not
123
+ # excluded one by one.
124
+ (!@options[:auto_gen_only_exclude] ||
125
+ @files_with_offenses[cop_name].size > @exclude_limit)
121
126
  cfg.merge!(cfg[:exclude_limit])
122
127
  end
123
128
 
@@ -192,8 +197,8 @@ module RuboCop
192
197
  # 'Enabled' option will be put into file only if exclude
193
198
  # limit is exceeded.
194
199
  rejected_keys = ['Enabled']
195
- rejected_keys << 'EnforcedStyle' unless auto_gen_enforced_style?
196
- cfg.reject { |key| rejected_keys.include?(key) }
200
+ rejected_keys << /\AEnforcedStyle\w*/ unless auto_gen_enforced_style?
201
+ cfg.reject { |key| include_or_match?(rejected_keys, key) }
197
202
  end
198
203
 
199
204
  def output_offending_files(output_buffer, cfg, cop_name)
@@ -262,6 +267,12 @@ module RuboCop
262
267
  def no_exclude_limit?
263
268
  @options[:no_exclude_limit] == false
264
269
  end
270
+
271
+ # Returns true if the given arr include the given elm or if any of the
272
+ # given arr is a regexp that matches the given elm.
273
+ def include_or_match?(arr, elm)
274
+ arr.include?(elm) || arr.any? { |x| x.is_a?(Regexp) && x.match?(elm) }
275
+ end
265
276
  end
266
277
  end
267
278
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'cgi'
4
4
  require 'erb'
5
- require 'ostruct'
6
5
 
7
6
  module RuboCop
8
7
  module Formatter
@@ -10,6 +9,7 @@ module RuboCop
10
9
  class HTMLFormatter < BaseFormatter
11
10
  ELLIPSES = '<span class="extra-code">...</span>'
12
11
  TEMPLATE_PATH = File.expand_path('../../../assets/output.html.erb', __dir__)
12
+ CSS_PATH = File.expand_path('../../../assets/output.css.erb', __dir__)
13
13
 
14
14
  Color = Struct.new(:red, :green, :blue, :alpha) do
15
15
  def to_s
@@ -51,8 +51,8 @@ module RuboCop
51
51
  context = ERBContext.new(files, summary)
52
52
 
53
53
  template = File.read(TEMPLATE_PATH, encoding: Encoding::UTF_8)
54
- erb = ERB.new(template, trim_mode: '-')
55
- html = erb.result(context.binding)
54
+ erb = ERB.new(template)
55
+ html = erb.result(context.binding).lines.map { (_1 =~ /^\s*$/).nil? ? _1 : "\n" }.join
56
56
 
57
57
  output.write html
58
58
  end
@@ -62,14 +62,6 @@ module RuboCop
62
62
  include PathUtil
63
63
  include TextUtil
64
64
 
65
- SEVERITY_COLORS = {
66
- refactor: Color.new(0xED, 0x9C, 0x28, 1.0),
67
- convention: Color.new(0xED, 0x9C, 0x28, 1.0),
68
- warning: Color.new(0x96, 0x28, 0xEF, 1.0),
69
- error: Color.new(0xD2, 0x32, 0x2D, 1.0),
70
- fatal: Color.new(0xD2, 0x32, 0x2D, 1.0)
71
- }.freeze
72
-
73
65
  LOGO_IMAGE_PATH = File.expand_path('../../../assets/logo.png', __dir__)
74
66
 
75
67
  attr_reader :files, :summary
@@ -87,7 +79,7 @@ module RuboCop
87
79
  # rubocop:enable Lint/UselessMethodDefinition
88
80
 
89
81
  def decorated_message(offense)
90
- offense.message.gsub(/`(.+?)`/) { "<code>#{Regexp.last_match(1)}</code>" }
82
+ offense.message.gsub(/`(.+?)`/) { "<code>#{escape(Regexp.last_match(1))}</code>" }
91
83
  end
92
84
 
93
85
  def highlighted_source_line(offense)
@@ -128,6 +120,33 @@ module RuboCop
128
120
  # https://github.com/ruby/base64/blob/v0.1.1/lib/base64.rb#L27-L40
129
121
  [image].pack('m')
130
122
  end
123
+
124
+ def render_css
125
+ context = CSSContext.new
126
+ template = File.read(CSS_PATH, encoding: Encoding::UTF_8)
127
+ erb = ERB.new(template, trim_mode: '-')
128
+ erb.result(context.binding).lines.map do |line|
129
+ line == "\n" ? line : " #{line}"
130
+ end.join
131
+ end
132
+ end
133
+
134
+ # This class provides helper methods used in the ERB CSS template.
135
+ class CSSContext
136
+ SEVERITY_COLORS = {
137
+ refactor: Color.new(0xED, 0x9C, 0x28, 1.0),
138
+ convention: Color.new(0xED, 0x9C, 0x28, 1.0),
139
+ warning: Color.new(0x96, 0x28, 0xEF, 1.0),
140
+ error: Color.new(0xD2, 0x32, 0x2D, 1.0),
141
+ fatal: Color.new(0xD2, 0x32, 0x2D, 1.0)
142
+ }.freeze
143
+
144
+ # Make Kernel#binding public.
145
+ # rubocop:disable Lint/UselessMethodDefinition
146
+ def binding
147
+ super
148
+ end
149
+ # rubocop:enable Lint/UselessMethodDefinition
131
150
  end
132
151
  end
133
152
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'pathname'
5
4
 
6
5
  module RuboCop
7
6
  module Formatter
@@ -61,8 +61,7 @@ module RuboCop
61
61
 
62
62
  column_width = total_count.to_s.length + 2
63
63
  per_cop_counts.each do |cop_name, count|
64
- output.puts "#{count.to_s.ljust(column_width)}#{cop_name}" \
65
- "#{@style_guide_links[cop_name]}\n"
64
+ output.puts "#{count.to_s.ljust(column_width)}#{cop_information(cop_name)}"
66
65
  end
67
66
  output.puts '--'
68
67
  output.puts "#{total_count} Total in #{offending_files_count} files"
@@ -78,6 +77,17 @@ module RuboCop
78
77
  def total_offense_count(offense_counts)
79
78
  offense_counts.values.sum
80
79
  end
80
+
81
+ def cop_information(cop_name)
82
+ cop = RuboCop::Cop::Registry.global.find_by_cop_name(cop_name).new
83
+
84
+ if cop.correctable?
85
+ safety = cop.safe_autocorrect? ? 'Safe' : 'Unsafe'
86
+ correctable = Rainbow(" [#{safety} Correctable]").yellow
87
+ end
88
+
89
+ "#{cop_name}#{correctable}#{@style_guide_links[cop_name]}"
90
+ end
81
91
  end
82
92
  end
83
93
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  require_relative 'formatter/emacs_style_formatter'
15
15
  require_relative 'formatter/file_list_formatter'
16
16
  require_relative 'formatter/fuubar_style_formatter'
17
- require_relative 'formatter/git_hub_actions_formatter'
17
+ require_relative 'formatter/github_actions_formatter'
18
18
  require_relative 'formatter/html_formatter'
19
19
  require_relative 'formatter/json_formatter'
20
20
  require_relative 'formatter/junit_formatter'
@@ -10,7 +10,7 @@
10
10
  # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
11
  #
12
12
  module RuboCop
13
- module Lsp
13
+ module LSP
14
14
  # Log for Language Server Protocol of RuboCop.
15
15
  # @api private
16
16
  class Logger
@@ -12,12 +12,12 @@ require_relative 'severity'
12
12
  # https://github.com/standardrb/standard/blob/main/LICENSE.txt
13
13
  #
14
14
  module RuboCop
15
- module Lsp
15
+ module LSP
16
16
  # Routes for Language Server Protocol of RuboCop.
17
17
  # @api private
18
18
  class Routes
19
19
  def self.handle(name, &block)
20
- define_method("handle_#{name}", &block)
20
+ define_method(:"handle_#{name}", &block)
21
21
  end
22
22
 
23
23
  private_class_method :handle
@@ -10,7 +10,7 @@
10
10
  # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
11
  #
12
12
  module RuboCop
13
- module Lsp
13
+ module LSP
14
14
  # Runtime for Language Server Protocol of RuboCop.
15
15
  # @api private
16
16
  class Runtime
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'language_server-protocol'
4
+ require_relative '../lsp'
4
5
  require_relative 'logger'
5
6
  require_relative 'routes'
6
7
  require_relative 'runtime'
@@ -15,14 +16,16 @@ require_relative 'runtime'
15
16
  # https://github.com/standardrb/standard/blob/main/LICENSE.txt
16
17
  #
17
18
  module RuboCop
18
- module Lsp
19
+ module LSP
19
20
  # Language Server Protocol of RuboCop.
20
21
  # @api private
21
22
  class Server
22
23
  def initialize(config_store)
24
+ RuboCop::LSP.enable
25
+
23
26
  @reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
24
27
  @writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
25
- @runtime = RuboCop::Lsp::Runtime.new(config_store)
28
+ @runtime = RuboCop::LSP::Runtime.new(config_store)
26
29
  @routes = Routes.new(self)
27
30
  end
28
31
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RuboCop
4
- module Lsp
4
+ module LSP
5
5
  # Severity for Language Server Protocol of RuboCop.
6
6
  # @api private
7
7
  class Severity
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # The RuboCop's built-in LSP module.
5
+ module LSP
6
+ module_function
7
+
8
+ # Returns true when LSP is enabled, false when disabled.
9
+ #
10
+ # @return [Boolean]
11
+ def enabled?
12
+ @enabled ||= false
13
+ end
14
+
15
+ # Enable LSP.
16
+ #
17
+ # @return [void]
18
+ def enable
19
+ @enabled = true
20
+ end
21
+
22
+ # Disable LSP.
23
+ #
24
+ # @return [void]
25
+ def disable
26
+ @enabled = false
27
+ end
28
+ end
29
+ end
@@ -268,7 +268,7 @@ module RuboCop
268
268
 
269
269
  # Rewrite the comment without a given token type
270
270
  def without(type)
271
- if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/)
271
+ if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/io)
272
272
  ''
273
273
  else
274
274
  @comment
@@ -95,6 +95,7 @@ module RuboCop
95
95
  option(opts, '--ignore-unrecognized-cops')
96
96
  option(opts, '--force-default-config')
97
97
  option(opts, '-s', '--stdin FILE')
98
+ option(opts, '--editor-mode')
98
99
  option(opts, '-P', '--[no-]parallel')
99
100
  option(opts, '--raise-cop-error')
100
101
  add_severity_option(opts)
@@ -364,15 +365,12 @@ module RuboCop
364
365
  raise OptionArgumentError, '-C/--cache argument must be true or false'
365
366
  end
366
367
 
367
- if display_only_fail_level_offenses_with_autocorrect?
368
- raise OptionArgumentError, '--autocorrect cannot be used with ' \
369
- '--display-only-fail-level-offenses.'
370
- end
371
368
  validate_auto_gen_config
372
369
  validate_autocorrect
373
370
  validate_display_only_failed
374
371
  validate_display_only_failed_and_display_only_correctable
375
372
  validate_display_only_correctable_and_autocorrect
373
+ validate_lsp_and_editor_mode
376
374
  disable_parallel_when_invalid_option_combo
377
375
 
378
376
  return if incompatible_options.size <= 1
@@ -420,6 +418,13 @@ module RuboCop
420
418
  format('--display-only-failed cannot be used together with other display options.')
421
419
  end
422
420
 
421
+ def validate_lsp_and_editor_mode
422
+ return if !@options.key?(:lsp) || !@options.key?(:editor_mode)
423
+
424
+ raise OptionArgumentError,
425
+ format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
426
+ end
427
+
423
428
  def validate_autocorrect
424
429
  if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
425
430
  message = Rainbow(<<~MESSAGE).red
@@ -460,10 +465,6 @@ module RuboCop
460
465
  (@options[:only] & %w[Lint/RedundantCopDisableDirective RedundantCopDisableDirective]).any?
461
466
  end
462
467
 
463
- def display_only_fail_level_offenses_with_autocorrect?
464
- @options.key?(:display_only_fail_level_offenses) && @options.key?(:autocorrect)
465
- end
466
-
467
468
  def except_syntax?
468
469
  @options.key?(:except) && (@options[:except] & %w[Lint/Syntax Syntax]).any?
469
470
  end
@@ -617,6 +618,8 @@ module RuboCop
617
618
  'parallel. Default is true.'],
618
619
  stdin: ['Pipe source from STDIN, using FILE in offense',
619
620
  'reports. This is useful for editor integration.'],
621
+ editor_mode: ['Optimize real-time feedback in editors,',
622
+ 'adjusting behaviors for editing experience.'],
620
623
  init: 'Generate a .rubocop.yml file in the current directory.',
621
624
  server: ['If a server process has not been started yet, start',
622
625
  'the server process and execute inspection with server.',
@@ -44,7 +44,7 @@ module RuboCop
44
44
  end
45
45
  end
46
46
 
47
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
47
+ # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
48
48
  def match_path?(pattern, path)
49
49
  case pattern
50
50
  when String
@@ -52,6 +52,10 @@ module RuboCop
52
52
  if pattern == path
53
53
  true
54
54
  elsif glob?(pattern)
55
+ # File name matching doesn't really work with relative patterns that start with "..". We
56
+ # get around that problem by converting the pattern to an absolute path.
57
+ pattern = File.expand_path(pattern) if pattern.start_with?('..')
58
+
55
59
  File.fnmatch?(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
56
60
  end
57
61
 
@@ -66,7 +70,7 @@ module RuboCop
66
70
  end
67
71
  end
68
72
  end
69
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
73
+ # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
70
74
 
71
75
  # Returns true for an absolute Unix or Windows path.
72
76
  def absolute?(path)
@@ -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'
@@ -6,7 +6,11 @@ require 'tempfile'
6
6
  module CopHelper
7
7
  extend RSpec::SharedContext
8
8
 
9
- let(:ruby_version) { RuboCop::TargetRuby::DEFAULT_VERSION }
9
+ let(:ruby_version) do
10
+ # The minimum version Prism can parse is 3.3.
11
+ ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : RuboCop::TargetRuby::DEFAULT_VERSION
12
+ end
13
+ let(:parser_engine) { ENV.fetch('PARSER_ENGINE', :parser_whitequark).to_sym }
10
14
  let(:rails_version) { false }
11
15
 
12
16
  def inspect_source(source, file = nil)
@@ -28,7 +32,9 @@ module CopHelper
28
32
  file = file.path
29
33
  end
30
34
 
31
- processed_source = RuboCop::ProcessedSource.new(source, ruby_version, file)
35
+ processed_source = RuboCop::ProcessedSource.new(
36
+ source, ruby_version, file, parser_engine: parser_engine
37
+ )
32
38
  processed_source.config = configuration
33
39
  processed_source.registry = registry
34
40
  processed_source
@@ -126,7 +126,7 @@ module RuboCop
126
126
  @offenses
127
127
  end
128
128
 
129
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
129
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
130
130
  def expect_correction(correction, loop: true, source: nil)
131
131
  if source
132
132
  expected_annotations = parse_annotations(source, raise_error: false)
@@ -148,7 +148,6 @@ module RuboCop
148
148
 
149
149
  break corrected_source unless loop
150
150
  break corrected_source if @last_corrector.empty?
151
- break corrected_source if corrected_source == @processed_source.buffer.source
152
151
 
153
152
  if iteration > RuboCop::Runner::MAX_ITERATIONS
154
153
  raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
@@ -163,19 +162,20 @@ module RuboCop
163
162
 
164
163
  expect(new_source).to eq(correction)
165
164
  end
166
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
165
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
167
166
 
168
167
  def expect_no_corrections
169
168
  raise '`expect_no_corrections` must follow `expect_offense`' unless @processed_source
170
169
 
171
170
  return if @last_corrector.empty?
172
171
 
173
- # In order to print a nice diff, e.g. what source got corrected to,
174
- # we need to run the actual corrections
175
-
172
+ # This is just here for a pretty diff if the source actually got changed
176
173
  new_source = @last_corrector.rewrite
177
-
178
174
  expect(new_source).to eq(@processed_source.buffer.source)
175
+
176
+ # There is an infinite loop if a corrector is present that did not make
177
+ # any changes. It will cause the same offense/correction on the next loop.
178
+ raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
179
179
  end
180
180
 
181
181
  def expect_no_offenses(source, file = nil)
@@ -212,7 +212,7 @@ module RuboCop
212
212
 
213
213
  # Parsed representation of code annotated with the `^^^ Message` style
214
214
  class AnnotatedSource
215
- ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) /.freeze
215
+ ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
216
216
  ABBREV = "[...]\n"
217
217
 
218
218
  # @param annotated_source [String] string passed to the matchers