rubocop 1.81.7 → 1.82.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +21 -5
  4. data/config/obsoletion.yml +4 -0
  5. data/lib/rubocop/cli.rb +2 -1
  6. data/lib/rubocop/comment_config.rb +62 -17
  7. data/lib/rubocop/config_loader.rb +2 -1
  8. data/lib/rubocop/config_loader_resolver.rb +2 -2
  9. data/lib/rubocop/cop/autocorrect_logic.rb +2 -0
  10. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -3
  11. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  12. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  13. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  14. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  15. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  16. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  17. data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -4
  18. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  19. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  20. data/lib/rubocop/cop/layout/line_length.rb +7 -4
  21. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +5 -3
  22. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  23. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  24. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +1 -1
  25. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  26. data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
  27. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  28. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  29. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  30. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  31. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  32. data/lib/rubocop/cop/lint/self_assignment.rb +9 -1
  33. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  34. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  35. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
  36. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  37. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +0 -4
  38. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  39. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  40. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  41. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  42. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  43. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  44. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  45. data/lib/rubocop/cop/mixin/trailing_comma.rb +4 -5
  46. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  47. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  48. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  49. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  50. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -11
  51. data/lib/rubocop/cop/style/constant_visibility.rb +3 -3
  52. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  53. data/lib/rubocop/cop/style/endless_method.rb +2 -2
  54. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  55. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  56. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  57. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  58. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  59. data/lib/rubocop/cop/style/multiline_method_signature.rb +0 -4
  60. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  61. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  62. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  63. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +5 -0
  64. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  65. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  66. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  67. data/lib/rubocop/cop/util.rb +2 -3
  68. data/lib/rubocop/directive_comment.rb +46 -3
  69. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
  70. data/lib/rubocop/lsp/diagnostic.rb +12 -17
  71. data/lib/rubocop/lsp/routes.rb +9 -36
  72. data/lib/rubocop/lsp/runtime.rb +2 -2
  73. data/lib/rubocop/lsp/server.rb +2 -2
  74. data/lib/rubocop/magic_comment.rb +20 -0
  75. data/lib/rubocop/rake_task.rb +1 -1
  76. data/lib/rubocop/remote_config.rb +7 -8
  77. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  78. data/lib/rubocop/rspec/support.rb +1 -1
  79. data/lib/rubocop/target_ruby.rb +1 -1
  80. data/lib/rubocop/version.rb +1 -1
  81. data/lib/rubocop.rb +1 -0
  82. metadata +7 -6
@@ -9,17 +9,20 @@ module RuboCop
9
9
  # In the default style (require_parentheses), macro methods are allowed.
10
10
  # Additional methods can be added to the `AllowedMethods` or
11
11
  # `AllowedPatterns` list. These options are valid only in the default
12
- # style. Macros can be included by either setting `IgnoreMacros` to false
13
- # or adding specific macros to the `IncludedMacros` list.
12
+ # style. Macros can be included by either setting `IgnoreMacros` to false,
13
+ # adding specific macros to the `IncludedMacros` list, or using
14
+ # `IncludedMacroPatterns` for pattern-based matching.
14
15
  #
15
16
  # Precedence of options is as follows:
16
17
  #
17
18
  # 1. `AllowedMethods`
18
19
  # 2. `AllowedPatterns`
19
20
  # 3. `IncludedMacros`
21
+ # 4. `IncludedMacroPatterns`
20
22
  #
21
- # If a method is listed in both `IncludedMacros` and `AllowedMethods`,
22
- # then the latter takes precedence (that is, the method is allowed).
23
+ # If a method is listed in both `IncludedMacros`/`IncludedMacroPatterns`
24
+ # and `AllowedMethods`, then the latter takes precedence (that is, the
25
+ # method is allowed).
23
26
  #
24
27
  # In the alternative style (omit_parentheses), there are three additional
25
28
  # options.
@@ -148,6 +151,16 @@ module RuboCop
148
151
  # # still enforces parentheses on other methods
149
152
  # array.delete(e)
150
153
  #
154
+ # @example IncludedMacroPatterns: ["^assert", "^refute"]
155
+ #
156
+ # # bad
157
+ # assert_equal 'test', x
158
+ # refute_nil value
159
+ #
160
+ # # good
161
+ # assert_equal('test', x)
162
+ # refute_nil(value)
163
+ #
151
164
  # @example AllowParenthesesInMultilineCall: false (default)
152
165
  #
153
166
  # # bad
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for usage of `Module` methods returning arrays that can be replaced
7
+ # with equivalent predicates.
8
+ #
9
+ # Calling a method returning an array then checking if an element is inside
10
+ # it is much slower than using an equivalent predicate method. For example,
11
+ # `instance_methods.include?` will return an array of all public and protected
12
+ # instance methods in the module, then check if a given method is inside that
13
+ # array, while `method_defined?` will do direct method lookup, which is much
14
+ # faster and consumes less memory.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # Array.instance_methods.include?(:size)
19
+ # Array.instance_methods.member?(:size)
20
+ # Array.instance_methods(true).include?(:size)
21
+ #
22
+ # Array.instance_methods(false).include?(:find)
23
+ #
24
+ # # good
25
+ # Array.method_defined?(:size)
26
+ #
27
+ # Array.method_defined?(:find, false)
28
+ #
29
+ class ModuleMemberExistenceCheck < Base
30
+ extend AutoCorrector
31
+
32
+ MSG = 'Use `%<replacement>s` instead.'
33
+
34
+ RESTRICT_ON_SEND = %i[instance_methods].freeze
35
+
36
+ # @!method instance_methods_inclusion?(node)
37
+ def_node_matcher :instance_methods_inclusion?, <<~PATTERN
38
+ (call
39
+ (call _ :instance_methods _?)
40
+ {:include? :member?}
41
+ _)
42
+ PATTERN
43
+
44
+ def on_send(node) # rubocop:disable Metrics/AbcSize
45
+ return unless (parent = node.parent)
46
+ return unless instance_methods_inclusion?(parent)
47
+ return unless simple_method_argument?(node) && simple_method_argument?(parent)
48
+
49
+ offense_range = node.location.selector.join(parent.source_range.end)
50
+ replacement =
51
+ if node.first_argument.nil? || node.first_argument.true_type?
52
+ "method_defined?(#{parent.first_argument.source})"
53
+ else
54
+ "method_defined?(#{parent.first_argument.source}, #{node.first_argument.source})"
55
+ end
56
+
57
+ add_offense(offense_range, message: format(MSG, replacement: replacement)) do |corrector|
58
+ corrector.replace(offense_range, replacement)
59
+ end
60
+ end
61
+ alias on_csend on_send
62
+
63
+ private
64
+
65
+ def simple_method_argument?(node)
66
+ return false if node.splat_argument? || node.block_argument?
67
+ return false if node.first_argument&.hash_type?
68
+
69
+ true
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -85,10 +85,6 @@ module RuboCop
85
85
  def definition_width(node)
86
86
  node.source_range.begin.join(node.arguments.source_range.end).length
87
87
  end
88
-
89
- def max_line_length
90
- config.for_cop('Layout/LineLength')['Max'] || 120
91
- end
92
88
  end
93
89
  end
94
90
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # one, two = *foo
17
- # a, b = foo()
17
+ # a, b = foo
18
18
  # a, b = b, a
19
19
  #
20
20
  # a = 1
@@ -223,7 +223,7 @@ module RuboCop
223
223
  # __FILE__ is treated as a StrNode but has no begin
224
224
  if node.str_type? && loc.respond_to?(:begin) && loc.begin.nil?
225
225
  "'#{node.source}'"
226
- elsif node.sym_type? && loc.begin.nil?
226
+ elsif node.sym_type? && !node.loc?(:begin)
227
227
  ":#{node.source}"
228
228
  else
229
229
  node.source
@@ -37,6 +37,7 @@ module RuboCop
37
37
  # array.sum(0)
38
38
  # exit(true)
39
39
  # exit!(false)
40
+ # string.to_i(10)
40
41
  # string.split(" ")
41
42
  # "first\nsecond".split(" ")
42
43
  # string.chomp("\n")
@@ -49,6 +50,7 @@ module RuboCop
49
50
  # array.sum
50
51
  # exit
51
52
  # exit!
53
+ # string.to_i
52
54
  # string.split
53
55
  # "first second".split
54
56
  # string.chomp
@@ -80,8 +80,7 @@ module RuboCop
80
80
  end
81
81
 
82
82
  def string_literal?(node)
83
- node.loc.respond_to?(:begin) && node.loc.respond_to?(:end) &&
84
- node.loc.begin && node.loc.end
83
+ node.loc?(:begin) && node.loc?(:end)
85
84
  end
86
85
 
87
86
  def start_with_percent_q_variant?(string)
@@ -75,6 +75,11 @@ module RuboCop
75
75
  new_argument.gsub!('\"', '"')
76
76
  quote = "'"
77
77
  elsif new_argument.include?("\\'")
78
+ # Add a backslash before single quotes preceded by an even number of backslashes.
79
+ # An even number (including zero) of backslashes before a quote means the quote itself
80
+ # is not escaped.
81
+ # Otherwise an odd number means the quote is already escaped so this doesn't touch it.
82
+ new_argument.gsub!(/(?<!\\)((?:\\\\)*)'/) { "#{::Regexp.last_match(1)}\\'" }
78
83
  quote = "'"
79
84
  elsif new_argument.include?('\'')
80
85
  new_argument.gsub!("'", "\\\\'")
@@ -26,17 +26,17 @@ module RuboCop
26
26
  #
27
27
  # [source,ruby]
28
28
  # ----
29
- # class MyString < String; end
30
- # strings = [MyString.new('test'), 'test']
31
- # strings.sort.last.class #=> String
32
- # strings.max.class #=> MyString
29
+ # class MyString < String; end
30
+ # strings = [MyString.new('test'), 'test']
31
+ # strings.sort.last.class #=> String
32
+ # strings.max.class #=> MyString
33
33
  # ----
34
34
  #
35
35
  # [source,ruby]
36
36
  # ----
37
- # words = %w(dog horse mouse)
38
- # words.sort_by { |word| word.length }.last #=> 'mouse'
39
- # words.max_by { |word| word.length } #=> 'horse'
37
+ # words = %w(dog horse mouse)
38
+ # words.sort_by { |word| word.length }.last #=> 'mouse'
39
+ # words.max_by { |word| word.length } #=> 'horse'
40
40
  # ----
41
41
  #
42
42
  # @example
@@ -109,7 +109,7 @@ module RuboCop
109
109
 
110
110
  def_args.zip(super_args).each do |def_arg, super_arg|
111
111
  next if positional_arg_same?(def_arg, super_arg)
112
- next if positional_rest_arg_same(def_arg, super_arg)
112
+ next if positional_rest_arg_same?(def_arg, super_arg)
113
113
  next if keyword_arg_same?(def_arg, super_arg)
114
114
  next if keyword_rest_arg_same?(def_arg, super_arg)
115
115
  next if block_arg_same?(def_node, super_node, def_arg, super_arg)
@@ -147,7 +147,7 @@ module RuboCop
147
147
  def_arg.name == super_arg.children.first
148
148
  end
149
149
 
150
- def positional_rest_arg_same(def_arg, super_arg)
150
+ def positional_rest_arg_same?(def_arg, super_arg)
151
151
  return false unless def_arg.restarg_type?
152
152
  # anonymous forwarding
153
153
  return true if def_arg.name.nil? && super_arg.forwarded_restarg_type?
@@ -7,26 +7,26 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # a, b, _ = foo()
11
- # a, b, _, = foo()
12
- # a, _, _ = foo()
13
- # a, _, _, = foo()
10
+ # a, b, _ = foo
11
+ # a, b, _, = foo
12
+ # a, _, _ = foo
13
+ # a, _, _, = foo
14
14
  #
15
15
  # # good
16
- # a, b, = foo()
17
- # a, = foo()
18
- # *a, b, _ = foo()
16
+ # a, b, = foo
17
+ # a, = foo
18
+ # *a, b, _ = foo
19
19
  # # => We need to know to not include 2 variables in a
20
- # a, *b, _ = foo()
21
- # # => The correction `a, *b, = foo()` is a syntax error
20
+ # a, *b, _ = foo
21
+ # # => The correction `a, *b, = foo` is a syntax error
22
22
  #
23
23
  # @example AllowNamedUnderscoreVariables: true (default)
24
24
  # # good
25
- # a, b, _something = foo()
25
+ # a, b, _something = foo
26
26
  #
27
27
  # @example AllowNamedUnderscoreVariables: false
28
28
  # # bad
29
- # a, b, _something = foo()
29
+ # a, b, _something = foo
30
30
  #
31
31
  class TrailingUnderscoreVariable < Base
32
32
  include SurroundingSpace
@@ -117,10 +117,9 @@ module RuboCop
117
117
  # with calls chained to the end of it.
118
118
  def first_part_of_call_chain(node)
119
119
  while node
120
- case node.type
121
- when :send
120
+ if node.call_type?
122
121
  node = node.receiver
123
- when :block
122
+ elsif node.any_block_type?
124
123
  node = node.send_node
125
124
  else
126
125
  break
@@ -14,11 +14,17 @@ module RuboCop
14
14
  # @api private
15
15
  COP_NAME_PATTERN = '([A-Za-z]\w+/)*(?:[A-Za-z]\w+)'
16
16
  # @api private
17
+ COP_NAME_PATTERN_NC = '(?:[A-Za-z]\w+/)*[A-Za-z]\w+'
18
+ # @api private
19
+ COP_NAMES_PATTERN_NC = "(?:#{COP_NAME_PATTERN_NC} , )*#{COP_NAME_PATTERN_NC}"
20
+ # @api private
17
21
  COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}"
18
22
  # @api private
19
23
  COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})"
20
24
  # @api private
21
- AVAILABLE_MODES = %w[disable enable todo].freeze
25
+ PUSH_POP_ARGS_PATTERN = "([+\\-]#{COP_NAME_PATTERN_NC}(?:\\s+[+\\-]#{COP_NAME_PATTERN_NC})*)"
26
+ # @api private
27
+ AVAILABLE_MODES = %w[disable enable todo push pop].freeze
22
28
  # @api private
23
29
  DIRECTIVE_MARKER_PATTERN = '# rubocop : '
24
30
  # @api private
@@ -27,7 +33,7 @@ module RuboCop
27
33
  DIRECTIVE_HEADER_PATTERN = "#{DIRECTIVE_MARKER_PATTERN}((?:#{AVAILABLE_MODES.join('|')}))\\b"
28
34
  # @api private
29
35
  DIRECTIVE_COMMENT_REGEXP = Regexp.new(
30
- "#{DIRECTIVE_HEADER_PATTERN} #{COPS_PATTERN}"
36
+ "#{DIRECTIVE_HEADER_PATTERN}(?:\\s+#{COPS_PATTERN}|\\s+#{PUSH_POP_ARGS_PATTERN})?"
31
37
  .gsub(' ', '\s*')
32
38
  )
33
39
  # @api private
@@ -58,6 +64,7 @@ module RuboCop
58
64
  # Checks if the comment is malformed as a `# rubocop:` directive
59
65
  def malformed?
60
66
  return true if !start_with_marker? || @match_data.nil?
67
+ return true if missing_cop_name?
61
68
 
62
69
  tail = @match_data.post_match.lstrip
63
70
  !(tail.empty? || tail.start_with?(TRAILING_COMMENT_MARKER))
@@ -65,6 +72,8 @@ module RuboCop
65
72
 
66
73
  # Checks if the directive comment is missing a cop name
67
74
  def missing_cop_name?
75
+ return false if push? || pop?
76
+
68
77
  MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP.match?(comment.text)
69
78
  end
70
79
 
@@ -88,7 +97,13 @@ module RuboCop
88
97
 
89
98
  # Returns match captures to directive comment pattern
90
99
  def match_captures
91
- @match_captures ||= @match_data&.captures
100
+ @match_captures ||= @match_data && begin
101
+ captures = @match_data.captures
102
+ mode = captures[0]
103
+ # COPS_PATTERN is at captures[1], PUSH_POP_ARGS_PATTERN is at captures[4]
104
+ cops = captures[1] || captures[4]
105
+ [mode, cops]
106
+ end
92
107
  end
93
108
 
94
109
  # Checks if this directive disables cops
@@ -101,6 +116,21 @@ module RuboCop
101
116
  mode == 'enable'
102
117
  end
103
118
 
119
+ # Checks if this directive is a push
120
+ def push?
121
+ mode == 'push'
122
+ end
123
+
124
+ # Checks if this directive is a pop
125
+ def pop?
126
+ mode == 'pop'
127
+ end
128
+
129
+ # Returns the push arguments as a hash of cop names with their operations
130
+ def push_args
131
+ @push_args ||= parse_push_args
132
+ end
133
+
104
134
  # Checks if this directive enables all cops
105
135
  def enabled_all?
106
136
  !disabled? && all_cops?
@@ -176,5 +206,18 @@ module RuboCop
176
206
  def exclude_lint_department_cops(cops)
177
207
  cops - [LINT_REDUNDANT_DIRECTIVE_COP, LINT_SYNTAX_COP]
178
208
  end
209
+
210
+ def parse_push_args
211
+ return {} unless push? && cops
212
+
213
+ args = {}
214
+ cops.split.each do |cop_spec|
215
+ op = cop_spec[0]
216
+ cop_name = cop_spec[1..]
217
+ args[op] ||= []
218
+ args[op] << cop_name
219
+ end
220
+ args
221
+ end
179
222
  end
180
223
  end
@@ -27,6 +27,7 @@ module RuboCop
27
27
  References
28
28
  Safe
29
29
  SafeAutoCorrect
30
+ Severity
30
31
  StyleGuide
31
32
  VersionAdded
32
33
  VersionChanged
@@ -16,8 +16,8 @@ module RuboCop
16
16
  # Diagnostic for Language Server Protocol of RuboCop.
17
17
  # @api private
18
18
  class Diagnostic
19
- def initialize(position_encoding, offense, uri, cop_class)
20
- @position_encoding = position_encoding
19
+ def initialize(document_encoding, offense, uri, cop_class)
20
+ @document_encoding = document_encoding
21
21
  @offense = offense
22
22
  @uri = uri
23
23
  @cop_class = cop_class
@@ -149,7 +149,7 @@ module RuboCop
149
149
 
150
150
  eol = LanguageServer::Protocol::Interface::Position.new(
151
151
  line: @offense.line - 1,
152
- character: to_position_character
152
+ character: to_position_character(@offense.source_line.length)
153
153
  )
154
154
 
155
155
  # TODO: fails for multiline strings - may be preferable to use block
@@ -162,6 +162,15 @@ module RuboCop
162
162
  [inline_comment]
163
163
  end
164
164
 
165
+ def to_position_character(utf8_index)
166
+ str = @offense.source_line[0, utf8_index]
167
+ if @document_encoding == Encoding::UTF_16LE || @document_encoding.nil?
168
+ str.length + str.b.count("\xf0-\xff".b)
169
+ else
170
+ str.length
171
+ end
172
+ end
173
+
165
174
  def correctable?
166
175
  !@offense.corrector.nil?
167
176
  end
@@ -171,20 +180,6 @@ module RuboCop
171
180
  uri.scheme = 'file' if uri.scheme.nil?
172
181
  uri
173
182
  end
174
-
175
- def to_position_character(utf8_index = nil)
176
- str = utf8_index ? @offense.source_line[0, utf8_index] : @offense.source_line
177
- case @position_encoding
178
- when 'utf-8', Encoding::UTF_8
179
- str.bytesize
180
- when 'utf-32', Encoding::UTF_32
181
- str.size
182
- else # 'utf-16'
183
- # utf-16 is default position encoding on LSP
184
- # https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
185
- str.size + str.count("\u{10000}-\u{10FFFF}")
186
- end
187
- end
188
183
  end
189
184
  end
190
185
  end
@@ -15,7 +15,7 @@ module RuboCop
15
15
  module LSP
16
16
  # Routes for Language Server Protocol of RuboCop.
17
17
  # @api private
18
- class Routes # rubocop:disable Metrics/ClassLength
18
+ class Routes
19
19
  CONFIGURATION_FILE_PATTERNS = [
20
20
  RuboCop::ConfigFinder::DOTFILE,
21
21
  RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
@@ -42,7 +42,6 @@ module RuboCop
42
42
 
43
43
  handle 'initialize' do |request|
44
44
  initialization_options = extract_initialization_options_from(request)
45
- @position_encoding = initialization_options[:position_encoding]
46
45
 
47
46
  @server.configure(initialization_options)
48
47
 
@@ -54,8 +53,7 @@ module RuboCop
54
53
  text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
55
54
  change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::INCREMENTAL,
56
55
  open_close: true
57
- ),
58
- position_encoding: @position_encoding
56
+ )
59
57
  )
60
58
  )
61
59
  )
@@ -186,26 +184,14 @@ module RuboCop
186
184
 
187
185
  def extract_initialization_options_from(request)
188
186
  safe_autocorrect = request.dig(:params, :initializationOptions, :safeAutocorrect)
189
- position_encodings = request.dig(:params, :capabilities, :general, :positionEncodings)
190
187
 
191
188
  {
192
189
  safe_autocorrect: safe_autocorrect.nil? || safe_autocorrect == true,
193
190
  lint_mode: request.dig(:params, :initializationOptions, :lintMode) == true,
194
- layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true,
195
- position_encoding: position_encoding(position_encodings)
191
+ layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true
196
192
  }
197
193
  end
198
194
 
199
- def position_encoding(position_encodings)
200
- if position_encodings&.include?('utf-8')
201
- 'utf-8'
202
- elsif position_encodings&.include?('utf-32')
203
- 'utf-32'
204
- else
205
- 'utf-16'
206
- end
207
- end
208
-
209
195
  def format_file(file_uri, command: nil)
210
196
  unless (text = @text_cache[file_uri])
211
197
  Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
@@ -233,8 +219,7 @@ module RuboCop
233
219
  method: 'textDocument/publishDiagnostics',
234
220
  params: {
235
221
  uri: file_uri,
236
- diagnostics: @server.offenses(convert_file_uri_to_path(file_uri),
237
- text, @position_encoding)
222
+ diagnostics: @server.offenses(convert_file_uri_to_path(file_uri), text)
238
223
  }
239
224
  }
240
225
  end
@@ -244,8 +229,9 @@ module RuboCop
244
229
 
245
230
  start_pos = text_pos(orig_text, range[:start])
246
231
  end_pos = text_pos(orig_text, range[:end])
247
- orig_text[start_pos...end_pos] = text
248
- orig_text
232
+ text_bin = orig_text.b
233
+ text_bin[start_pos...end_pos] = text.b
234
+ text_bin.force_encoding(orig_text.encoding)
249
235
  end
250
236
 
251
237
  def text_pos(text, range)
@@ -254,27 +240,14 @@ module RuboCop
254
240
  pos = 0
255
241
  text.each_line.with_index do |l, i|
256
242
  if i == line
257
- pos += line_pos(l, char)
243
+ pos += l.encode('utf-16be').b[0, char * 2].encode('utf-8', 'utf-16be').bytesize
258
244
  return pos
259
245
  end
260
- pos += l.size
246
+ pos += l.bytesize
261
247
  end
262
248
  pos
263
249
  end
264
250
 
265
- def line_pos(line, char)
266
- case @position_encoding
267
- when 'utf-8'
268
- line.byteslice(0, char).size
269
- when 'utf-32'
270
- char
271
- else # 'utf-16'
272
- # utf-16 is default position encoding on LSP
273
- # https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
274
- line.encode('utf-16be').byteslice(0, char * 2).size
275
- end
276
- end
277
-
278
251
  def convert_file_uri_to_path(uri)
279
252
  URI.decode_www_form_component(uri.delete_prefix('file://'))
280
253
  end
@@ -44,14 +44,14 @@ module RuboCop
44
44
  @runner.formatted_source
45
45
  end
46
46
 
47
- def offenses(path, text, position_encoding, prism_result: nil)
47
+ def offenses(path, text, document_encoding = nil, prism_result: nil)
48
48
  diagnostic_options = {}
49
49
  diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
50
50
 
51
51
  @runner.run(path, text, diagnostic_options, prism_result: prism_result)
52
52
  @runner.offenses.map do |offense|
53
53
  Diagnostic.new(
54
- position_encoding, offense, path, @cop_registry[offense.cop_name]&.first
54
+ document_encoding, offense, path, @cop_registry[offense.cop_name]&.first
55
55
  ).to_lsp_diagnostic(@runner.config_for_working_directory)
56
56
  end
57
57
  end
@@ -51,8 +51,8 @@ module RuboCop
51
51
  @runtime.format(path, text, command: command)
52
52
  end
53
53
 
54
- def offenses(path, text, position_encoding)
55
- @runtime.offenses(path, text, position_encoding)
54
+ def offenses(path, text)
55
+ @runtime.offenses(path, text)
56
56
  end
57
57
 
58
58
  def configure(options)
@@ -11,6 +11,7 @@ module RuboCop
11
11
  KEYWORDS = {
12
12
  encoding: '(?:en)?coding',
13
13
  frozen_string_literal: 'frozen[_-]string[_-]literal',
14
+ rbs_inline: 'rbs_inline',
14
15
  shareable_constant_value: 'shareable[_-]constant[_-]value',
15
16
  typed: 'typed'
16
17
  }.freeze
@@ -36,6 +37,7 @@ module RuboCop
36
37
  def any?
37
38
  frozen_string_literal_specified? ||
38
39
  encoding_specified? ||
40
+ rbs_inline_specified? ||
39
41
  shareable_constant_value_specified? ||
40
42
  typed_specified?
41
43
  end
@@ -60,6 +62,10 @@ module RuboCop
60
62
  [true, false].include?(frozen_string_literal)
61
63
  end
62
64
 
65
+ def valid_rbs_inline_value?
66
+ %w[enabled disabled].include?(extract_rbs_inline_value)
67
+ end
68
+
63
69
  def valid_shareable_constant_value?
64
70
  %w[none literal experimental_everything experimental_copy].include?(shareable_constant_value)
65
71
  end
@@ -105,6 +111,10 @@ module RuboCop
105
111
  specified?(encoding)
106
112
  end
107
113
 
114
+ def rbs_inline_specified?
115
+ valid_rbs_inline_value?
116
+ end
117
+
108
118
  # Was the Sorbet `typed` sigil specified?
109
119
  #
110
120
  # @return [Boolean]
@@ -203,6 +213,9 @@ module RuboCop
203
213
  match(KEYWORDS[:frozen_string_literal])
204
214
  end
205
215
 
216
+ # Emacs comments cannot specify RBS::inline behavior.
217
+ def extract_rbs_inline_value; end
218
+
206
219
  def extract_shareable_constant_value
207
220
  match(KEYWORDS[:shareable_constant_value])
208
221
  end
@@ -242,6 +255,9 @@ module RuboCop
242
255
  # Vim comments cannot specify frozen string literal behavior.
243
256
  def frozen_string_literal; end
244
257
 
258
+ # Vim comments cannot specify RBS::inline behavior.
259
+ def extract_rbs_inline_value; end
260
+
245
261
  # Vim comments cannot specify shareable constant values behavior.
246
262
  def shareable_constant_value; end
247
263
 
@@ -296,6 +312,10 @@ module RuboCop
296
312
  extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io)
297
313
  end
298
314
 
315
+ def extract_rbs_inline_value
316
+ extract(/\A\s*#\s*#{KEYWORDS[:rbs_inline]}:\s*#{TOKEN}\s*\z/io)
317
+ end
318
+
299
319
  def extract_shareable_constant_value
300
320
  extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io)
301
321
  end
@@ -75,7 +75,7 @@ module RuboCop
75
75
  def setup_subtasks(name, *args, &task_block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
76
76
  namespace(name) do
77
77
  # rubocop:todo Naming/InclusiveLanguage
78
- task(:auto_correct, *args) do
78
+ task(:auto_correct, *args) do |_, task_args|
79
79
  require 'rainbow'
80
80
  warn Rainbow(
81
81
  'rubocop:auto_correct task is deprecated; ' \