rubocop 1.63.5 → 1.64.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/config/default.yml +18 -2
  4. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  5. data/lib/rubocop/config.rb +2 -3
  6. data/lib/rubocop/cop/base.rb +6 -13
  7. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  8. data/lib/rubocop/cop/documentation.rb +16 -6
  9. data/lib/rubocop/cop/force.rb +12 -0
  10. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  11. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  12. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  13. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  14. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -3
  15. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  16. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  17. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -1
  18. data/lib/rubocop/cop/style/copyright.rb +15 -10
  19. data/lib/rubocop/cop/style/documentation.rb +24 -24
  20. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  21. data/lib/rubocop/cop/style/hash_syntax.rb +18 -0
  22. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  23. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  24. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  25. data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -1
  26. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +90 -0
  27. data/lib/rubocop/cop/style/super_arguments.rb +156 -0
  28. data/lib/rubocop/cop/style/symbol_proc.rb +32 -5
  29. data/lib/rubocop/cop/team.rb +2 -0
  30. data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
  31. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  32. data/lib/rubocop/lockfile.rb +1 -1
  33. data/lib/rubocop/lsp/routes.rb +8 -10
  34. data/lib/rubocop/lsp.rb +9 -2
  35. data/lib/rubocop/version.rb +1 -1
  36. data/lib/rubocop.rb +2 -0
  37. metadata +10 -8
@@ -95,6 +95,17 @@ module RuboCop
95
95
  # end
96
96
  # end
97
97
  #
98
+ # @example AllowedMethods: ['method_missing', 'respond_to_missing?']
99
+ #
100
+ # # good
101
+ # class Foo
102
+ # def method_missing(name, *args)
103
+ # end
104
+ #
105
+ # def respond_to_missing?(symbol, include_private)
106
+ # end
107
+ # end
108
+ #
98
109
  class DocumentationMethod < Base
99
110
  include DocumentationComment
100
111
  include DefNode
@@ -119,6 +130,7 @@ module RuboCop
119
130
  def check(node)
120
131
  return if non_public?(node) && !require_for_non_public_methods?
121
132
  return if documentation_comment?(node)
133
+ return if method_allowed?(node)
122
134
 
123
135
  add_offense(node)
124
136
  end
@@ -126,6 +138,14 @@ module RuboCop
126
138
  def require_for_non_public_methods?
127
139
  cop_config['RequireForNonPublicMethods']
128
140
  end
141
+
142
+ def method_allowed?(node)
143
+ allowed_methods.include?(node.method_name)
144
+ end
145
+
146
+ def allowed_methods
147
+ @allowed_methods ||= cop_config.fetch('AllowedMethods', []).map(&:to_sym)
148
+ end
129
149
  end
130
150
  end
131
151
  end
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # * never - forces use of explicit hash literal value
30
30
  # * either - accepts both shorthand and explicit use of hash literal value
31
31
  # * consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
32
+ # * either_consistent - accepts both shorthand and explicit use of hash literal value,
33
+ # but they must be consistent
32
34
  #
33
35
  # @example EnforcedStyle: ruby19 (default)
34
36
  # # bad
@@ -110,6 +112,22 @@ module RuboCop
110
112
  # # good - can't omit `baz`
111
113
  # {foo: foo, bar: baz}
112
114
  #
115
+ # @example EnforcedShorthandSyntax: either_consistent
116
+ #
117
+ # # good - `foo` and `bar` values can be omitted, but they are consistent, so it's accepted
118
+ # {foo: foo, bar: bar}
119
+ #
120
+ # # bad - `bar` value can be omitted
121
+ # {foo:, bar: bar}
122
+ #
123
+ # # bad - mixed syntaxes
124
+ # {foo:, bar: baz}
125
+ #
126
+ # # good
127
+ # {foo:, bar:}
128
+ #
129
+ # # good - can't omit `baz`
130
+ # {foo: foo, bar: baz}
113
131
  class HashSyntax < Base
114
132
  include ConfigurableEnforcedStyle
115
133
  include HashShorthandSyntax
@@ -112,9 +112,11 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def message(node, keyword)
115
- message_template = node.elsif? ? MSG_FOR_ELSIF : MSG
116
-
117
- format(message_template, keyword: keyword)
115
+ if node.elsif?
116
+ MSG_FOR_ELSIF
117
+ else
118
+ format(MSG, keyword: keyword)
119
+ end
118
120
  end
119
121
 
120
122
  def return_boolean_value?(condition)
@@ -57,7 +57,7 @@ module RuboCop
57
57
  def_node_matcher :each_block_with_push?, <<-PATTERN
58
58
  [
59
59
  ^({begin kwbegin} ...)
60
- ({block numblock} (send _ :each) _
60
+ ({block numblock} (send !{nil? self} :each) _
61
61
  (send (lvar _) {:<< :push :append} _))
62
62
  ]
63
63
  PATTERN
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def always_multiline?
78
- @config.for_cop('Style/OneLineConditional')['AlwaysCorrectToMultiline']
78
+ cop_config['AlwaysCorrectToMultiline']
79
79
  end
80
80
 
81
81
  def cannot_replace_to_ternary?(node)
@@ -74,6 +74,7 @@ module RuboCop
74
74
  kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
75
  tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
76
  ].freeze
77
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
77
78
 
78
79
  def on_new_investigation
79
80
  return unless processed_source.ast
@@ -137,7 +138,7 @@ module RuboCop
137
138
  # do_something \
138
139
  # argument
139
140
  def method_with_argument?(current_token, next_token)
140
- return false if current_token.type != :tIDENTIFIER && current_token.type != :kRETURN
141
+ return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
141
142
 
142
143
  ARGUMENT_TYPES.include?(next_token.type)
143
144
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Detects the use of the `public_send` method with a literal method name argument.
7
+ # Since the `send` method can be used to call private methods, by default,
8
+ # only the `public_send` method is detected.
9
+ #
10
+ # @safety
11
+ # This cop is not safe because it can incorrectly detect based on the receiver.
12
+ # Additionally, when `AllowSend` is set to `true`, it cannot determine whether
13
+ # the `send` method being detected is calling a private method.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # obj.public_send(:method_name)
18
+ # obj.public_send('method_name')
19
+ #
20
+ # # good
21
+ # obj.method_name
22
+ #
23
+ # @example AllowSend: true (default)
24
+ # # good
25
+ # obj.send(:method_name)
26
+ # obj.send('method_name')
27
+ # obj.__send__(:method_name)
28
+ # obj.__send__('method_name')
29
+ #
30
+ # @example AllowSend: false
31
+ # # bad
32
+ # obj.send(:method_name)
33
+ # obj.send('method_name')
34
+ # obj.__send__(:method_name)
35
+ # obj.__send__('method_name')
36
+ #
37
+ # # good
38
+ # obj.method_name
39
+ #
40
+ class SendWithLiteralMethodName < Base
41
+ extend AutoCorrector
42
+
43
+ MSG = 'Use `%<method_name>s` method call directly instead.'
44
+ RESTRICT_ON_SEND = %i[public_send send __send__].freeze
45
+ STATIC_METHOD_NAME_NODE_TYPES = %i[sym str].freeze
46
+ METHOD_NAME_PATTERN = /\A[a-zA-Z_][a-zA-Z0-9_]*[!?=]?\z/.freeze
47
+ RESERVED_WORDS = %i[
48
+ BEGIN END alias and begin break case class def defined? do else elsif end ensure
49
+ false for if in module next nil not or redo rescue retry return self super then true
50
+ undef unless until when while yield
51
+ ].freeze
52
+
53
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
54
+ def on_send(node)
55
+ return if allow_send? && !node.method?(:public_send)
56
+ return unless (first_argument = node.first_argument)
57
+ return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
58
+
59
+ offense_range = offense_range(node)
60
+ method_name = first_argument.value
61
+ return if !METHOD_NAME_PATTERN.match?(method_name) || RESERVED_WORDS.include?(method_name)
62
+
63
+ add_offense(offense_range, message: format(MSG, method_name: method_name)) do |corrector|
64
+ if node.arguments.one?
65
+ corrector.replace(offense_range, method_name)
66
+ else
67
+ corrector.replace(node.loc.selector, method_name)
68
+ corrector.remove(removal_argument_range(first_argument, node.arguments[1]))
69
+ end
70
+ end
71
+ end
72
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
73
+
74
+ private
75
+
76
+ def allow_send?
77
+ !!cop_config['AllowSend']
78
+ end
79
+
80
+ def offense_range(node)
81
+ node.loc.selector.join(node.source_range.end)
82
+ end
83
+
84
+ def removal_argument_range(first_argument, second_argument)
85
+ first_argument.source_range.begin.join(second_argument.source_range.begin)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for redundant argument forwarding when calling super
7
+ # with arguments identical to the method definition.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # def method(*args, **kwargs)
12
+ # super(*args, **kwargs)
13
+ # end
14
+ #
15
+ # # good - implicitly passing all arguments
16
+ # def method(*args, **kwargs)
17
+ # super
18
+ # end
19
+ #
20
+ # # good - forwarding a subset of the arguments
21
+ # def method(*args, **kwargs)
22
+ # super(*args)
23
+ # end
24
+ #
25
+ # # good - forwarding no arguments
26
+ # def method(*args, **kwargs)
27
+ # super()
28
+ # end
29
+ #
30
+ # # good - assigning to the block variable before calling super
31
+ # def method(&block)
32
+ # # Assigning to the block variable would pass the old value to super,
33
+ # # under this circumstance the block must be referenced explicitly.
34
+ # block ||= proc { 'fallback behavior' }
35
+ # super(&block)
36
+ # end
37
+ class SuperArguments < Base
38
+ extend AutoCorrector
39
+
40
+ DEF_TYPES = %i[def defs].freeze
41
+ ASSIGN_TYPES = %i[or_asgn lvasgn].freeze
42
+
43
+ MSG = 'Call `super` without arguments and parentheses when the signature is identical.'
44
+
45
+ def on_super(super_node)
46
+ def_node = super_node.ancestors.find do |node|
47
+ # You can't implicitly call super when dynamically defining methods
48
+ break if define_method?(node)
49
+
50
+ break node if DEF_TYPES.include?(node.type)
51
+ end
52
+ return unless def_node
53
+ return unless arguments_identical?(def_node, def_node.arguments.argument_list,
54
+ super_node.arguments)
55
+
56
+ add_offense(super_node) { |corrector| corrector.replace(super_node, 'super') }
57
+ end
58
+
59
+ private
60
+
61
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
62
+ def arguments_identical?(def_node, def_args, super_args)
63
+ super_args = preprocess_super_args(super_args)
64
+ return false if def_args.size != super_args.size
65
+
66
+ def_args.zip(super_args).each do |def_arg, super_arg|
67
+ next if positional_arg_same?(def_arg, super_arg)
68
+ next if positional_rest_arg_same(def_arg, super_arg)
69
+ next if keyword_arg_same?(def_arg, super_arg)
70
+ next if keyword_rest_arg_same?(def_arg, super_arg)
71
+ next if block_arg_same?(def_node, def_arg, super_arg)
72
+ next if forward_arg_same?(def_arg, super_arg)
73
+
74
+ return false
75
+ end
76
+ true
77
+ end
78
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
79
+
80
+ def positional_arg_same?(def_arg, super_arg)
81
+ return false unless def_arg.arg_type? || def_arg.optarg_type?
82
+ return false unless super_arg.lvar_type?
83
+
84
+ def_arg.name == super_arg.children.first
85
+ end
86
+
87
+ def positional_rest_arg_same(def_arg, super_arg)
88
+ return false unless def_arg.restarg_type?
89
+ # anonymous forwarding
90
+ return true if def_arg.name.nil? && super_arg.forwarded_restarg_type?
91
+ return false unless super_arg.splat_type?
92
+ return false unless (lvar_node = super_arg.children.first).lvar_type?
93
+
94
+ def_arg.name == lvar_node.children.first
95
+ end
96
+
97
+ def keyword_arg_same?(def_arg, super_arg)
98
+ return false unless def_arg.kwarg_type? || def_arg.kwoptarg_type?
99
+ return false unless (pair_node = super_arg).pair_type?
100
+ return false unless (sym_node = pair_node.key).sym_type?
101
+ return false unless (lvar_node = pair_node.value).lvar_type?
102
+ return false unless sym_node.source == lvar_node.source
103
+
104
+ def_arg.name == sym_node.value
105
+ end
106
+
107
+ def keyword_rest_arg_same?(def_arg, super_arg)
108
+ return false unless def_arg.kwrestarg_type?
109
+ # anonymous forwarding
110
+ return true if def_arg.name.nil? && super_arg.forwarded_kwrestarg_type?
111
+ return false unless super_arg.kwsplat_type?
112
+ return false unless (lvar_node = super_arg.children.first).lvar_type?
113
+
114
+ def_arg.name == lvar_node.children.first
115
+ end
116
+
117
+ def block_arg_same?(def_node, def_arg, super_arg)
118
+ return false unless def_arg.blockarg_type? && super_arg.block_pass_type?
119
+ # anonymous forwarding
120
+ return true if (block_pass_child = super_arg.children.first).nil? && def_arg.name.nil?
121
+
122
+ block_arg_name = block_pass_child.children.first
123
+ def_arg.name == block_arg_name && !block_reassigned?(def_node, block_arg_name)
124
+ end
125
+
126
+ # Reassigning the block argument will still pass along the original block to super
127
+ # https://bugs.ruby-lang.org/issues/20505
128
+ def block_reassigned?(def_node, block_arg_name)
129
+ def_node.each_node(*ASSIGN_TYPES).any? do |assign_node|
130
+ assign_node.name == block_arg_name
131
+ end
132
+ end
133
+
134
+ def forward_arg_same?(def_arg, super_arg)
135
+ def_arg.forward_arg_type? && super_arg.forwarded_args_type?
136
+ end
137
+
138
+ def define_method?(node)
139
+ return false unless node.block_type?
140
+
141
+ node.method?(:define_method) || node.method?(:define_singleton_method)
142
+ end
143
+
144
+ def preprocess_super_args(super_args)
145
+ super_args.flat_map do |node|
146
+ if node.hash_type? && !node.braces?
147
+ node.children
148
+ else
149
+ node
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -120,6 +120,23 @@ module RuboCop
120
120
  # # good
121
121
  # something.map { |s| s.upcase }
122
122
  #
123
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
124
+ # # bad
125
+ # ->(x) { x.foo }
126
+ # proc { |x| x.foo }
127
+ # Proc.new { |x| x.foo }
128
+ #
129
+ # # good
130
+ # lambda(&:foo)
131
+ # proc(&:foo)
132
+ # Proc.new(&:foo)
133
+ #
134
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
135
+ # # good
136
+ # ->(x) { x.foo }
137
+ # proc { |x| x.foo }
138
+ # Proc.new { |x| x.foo }
139
+ #
123
140
  class SymbolProc < Base
124
141
  include CommentsHelp
125
142
  include RangeHelp
@@ -129,6 +146,7 @@ module RuboCop
129
146
 
130
147
  MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` instead of a block.'
131
148
  SUPER_TYPES = %i[super zsuper].freeze
149
+ LAMBDA_OR_PROC = %i[lambda proc].freeze
132
150
 
133
151
  # @!method proc_node?(node)
134
152
  def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
@@ -151,13 +169,12 @@ module RuboCop
151
169
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
152
170
  def on_block(node)
153
171
  symbol_proc?(node) do |dispatch_node, arguments_node, method_name|
154
- # TODO: Rails-specific handling that we should probably make
155
- # configurable - https://github.com/rubocop/rubocop/issues/1485
156
- # we should allow lambdas & procs
157
- return if proc_node?(dispatch_node)
172
+ if active_support_extensions_enabled?
173
+ return if proc_node?(dispatch_node)
174
+ return if LAMBDA_OR_PROC.include?(dispatch_node.method_name)
175
+ end
158
176
  return if unsafe_hash_usage?(dispatch_node)
159
177
  return if unsafe_array_usage?(dispatch_node)
160
- return if %i[lambda proc].include?(dispatch_node.method_name)
161
178
  return if allowed_method_name?(dispatch_node.method_name)
162
179
  return if allow_if_method_has_argument?(node.send_node)
163
180
  return if node.block_type? && destructuring_block_argument?(arguments_node)
@@ -206,6 +223,8 @@ module RuboCop
206
223
  end
207
224
 
208
225
  def autocorrect_without_args(corrector, node)
226
+ autocorrect_lambda_block(corrector, node) if node.send_node.lambda_literal?
227
+
209
228
  corrector.replace(block_range_with_space(node), "(&:#{node.body.method_name})")
210
229
  end
211
230
 
@@ -218,6 +237,14 @@ module RuboCop
218
237
  corrector.remove(block_range_with_space(node))
219
238
  end
220
239
 
240
+ def autocorrect_lambda_block(corrector, node)
241
+ send_node_loc = node.send_node.loc
242
+ corrector.replace(send_node_loc.selector, 'lambda')
243
+
244
+ range = range_between(send_node_loc.selector.end_pos, node.loc.begin.end_pos - 2)
245
+ corrector.remove(range)
246
+ end
247
+
221
248
  def block_range_with_space(node)
222
249
  block_range = range_between(begin_pos_for_replacement(node), node.loc.end.end_pos)
223
250
  range_with_surrounding_space(block_range, side: :left)
@@ -240,6 +240,8 @@ module RuboCop
240
240
 
241
241
  if cause.is_a?(Warning)
242
242
  handle_warning(cause, location)
243
+ elsif cause.is_a?(Force::HookError)
244
+ handle_error(cause.cause, location, cause.joining_cop)
243
245
  else
244
246
  handle_error(cause, location, error.cop)
245
247
  end
@@ -116,20 +116,24 @@ module RuboCop
116
116
  def set_max(cfg, cop_name)
117
117
  return unless cfg[:exclude_limit]
118
118
 
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)
126
- cfg.merge!(cfg[:exclude_limit])
127
- end
119
+ cfg.merge!(cfg[:exclude_limit]) if should_set_max?(cop_name)
128
120
 
129
121
  # Remove already used exclude_limit.
130
122
  cfg.reject! { |key| key == :exclude_limit }
131
123
  end
132
124
 
125
+ def should_set_max?(cop_name)
126
+ max_set_in_user_config =
127
+ @config_for_pwd.for_cop(cop_name)['Max'] != default_config(cop_name)['Max']
128
+
129
+ max_allowed = !max_set_in_user_config && !no_exclude_limit?
130
+ return false unless max_allowed
131
+
132
+ # In case auto_gen_only_exclude is set, only modify the maximum if the files are not
133
+ # excluded one by one.
134
+ !@options[:auto_gen_only_exclude] || @files_with_offenses[cop_name].size > @exclude_limit
135
+ end
136
+
133
137
  def output_cop_comments(output_buffer, cfg, cop_name, offense_count)
134
138
  output_buffer.puts "# Offense count: #{offense_count}" if show_offense_counts?
135
139
 
@@ -27,6 +27,7 @@ module RuboCop
27
27
  '[t]ap' => 'TapFormatter',
28
28
  '[w]orst' => 'WorstOffendersFormatter'
29
29
  }.freeze
30
+ BUILTIN_FORMATTER_NAMES = BUILTIN_FORMATTERS_FOR_KEYS.keys.map { |key| key.delete('[]') }
30
31
 
31
32
  FORMATTER_APIS = %i[started finished].freeze
32
33
 
@@ -88,7 +89,12 @@ module RuboCop
88
89
  /^\[#{specified_key}\]/.match?(key) || specified_key == key.delete('[]')
89
90
  end
90
91
 
91
- raise %(No formatter for "#{specified_key}") if matching_keys.empty?
92
+ if matching_keys.empty?
93
+ similar_name = NameSimilarity.find_similar_name(specified_key, BUILTIN_FORMATTER_NAMES)
94
+ suggestion = %( Did you mean? "#{similar_name}") if similar_name
95
+
96
+ raise Rainbow(%(Formatter "#{specified_key}" not found.#{suggestion})).red
97
+ end
92
98
 
93
99
  raise %(Cannot determine formatter for "#{specified_key}") if matching_keys.size > 1
94
100
 
@@ -72,7 +72,7 @@ module RuboCop
72
72
  def parser
73
73
  return @parser if defined?(@parser)
74
74
 
75
- @parser = if @lockfile_path && bundler_lock_parser_defined?
75
+ @parser = if @lockfile_path && File.exist?(@lockfile_path) && bundler_lock_parser_defined?
76
76
  begin
77
77
  lockfile = ::Bundler.read_file(@lockfile_path)
78
78
  ::Bundler::LockfileParser.new(lockfile) if lockfile
@@ -45,10 +45,6 @@ module RuboCop
45
45
  result: LanguageServer::Protocol::Interface::InitializeResult.new(
46
46
  capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
47
47
  document_formatting_provider: true,
48
- diagnostic_provider: LanguageServer::Protocol::Interface::DiagnosticOptions.new(
49
- inter_file_dependencies: false,
50
- workspace_diagnostics: false
51
- ),
52
48
  text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
53
49
  change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::FULL,
54
50
  open_close: true
@@ -73,10 +69,6 @@ module RuboCop
73
69
  end
74
70
  end
75
71
 
76
- handle 'textDocument/diagnostic' do |request|
77
- # no-op, diagnostics are handled in textDocument/didChange
78
- end
79
-
80
72
  handle 'textDocument/didChange' do |request|
81
73
  params = request[:params]
82
74
  result = diagnostic(params[:textDocument][:uri], params[:contentChanges][0][:text])
@@ -125,6 +117,12 @@ module RuboCop
125
117
  end
126
118
 
127
119
  uri = request[:params][:arguments][0][:uri]
120
+ formatted = nil
121
+
122
+ # The `workspace/executeCommand` is an LSP method triggered by intentional user actions,
123
+ # so the user's intention for autocorrection is respected.
124
+ LSP.disable { formatted = format_file(uri, command: command) }
125
+
128
126
  @server.write(
129
127
  id: request[:id],
130
128
  method: 'workspace/applyEdit',
@@ -132,7 +130,7 @@ module RuboCop
132
130
  label: label,
133
131
  edit: {
134
132
  changes: {
135
- uri => format_file(uri, command: command)
133
+ uri => formatted
136
134
  }
137
135
  }
138
136
  }
@@ -237,7 +235,7 @@ module RuboCop
237
235
  def to_range(location)
238
236
  {
239
237
  start: { character: location[:start_column] - 1, line: location[:start_line] - 1 },
240
- end: { character: location[:last_column] - 1, line: location[:last_line] - 1 }
238
+ end: { character: location[:last_column], line: location[:last_line] - 1 }
241
239
  }
242
240
  end
243
241
  end
data/lib/rubocop/lsp.rb CHANGED
@@ -22,8 +22,15 @@ module RuboCop
22
22
  # Disable LSP.
23
23
  #
24
24
  # @return [void]
25
- def disable
26
- @enabled = false
25
+ def disable(&block)
26
+ if block
27
+ original = @enabled
28
+ @enabled = false
29
+ yield
30
+ @enabled = original
31
+ else
32
+ @enabled = false
33
+ end
27
34
  end
28
35
  end
29
36
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.63.5'
6
+ STRING = '1.64.1'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -666,6 +666,7 @@ require_relative 'rubocop/cop/style/select_by_regexp'
666
666
  require_relative 'rubocop/cop/style/self_assignment'
667
667
  require_relative 'rubocop/cop/style/semicolon'
668
668
  require_relative 'rubocop/cop/style/send'
669
+ require_relative 'rubocop/cop/style/send_with_literal_method_name'
669
670
  require_relative 'rubocop/cop/style/signal_exception'
670
671
  require_relative 'rubocop/cop/style/single_argument_dig'
671
672
  require_relative 'rubocop/cop/style/single_line_block_params'
@@ -682,6 +683,7 @@ require_relative 'rubocop/cop/style/string_literals_in_interpolation'
682
683
  require_relative 'rubocop/cop/style/string_methods'
683
684
  require_relative 'rubocop/cop/style/strip'
684
685
  require_relative 'rubocop/cop/style/struct_inheritance'
686
+ require_relative 'rubocop/cop/style/super_arguments'
685
687
  require_relative 'rubocop/cop/style/super_with_args_parentheses'
686
688
  require_relative 'rubocop/cop/style/swap_values'
687
689
  require_relative 'rubocop/cop/style/symbol_array'