rubocop 1.75.8 → 1.81.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.
- checksums.yaml +4 -4
- data/README.md +20 -16
- data/config/default.yml +117 -26
- data/config/obsoletion.yml +6 -3
- data/exe/rubocop +1 -8
- data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
- data/lib/rubocop/cli.rb +18 -3
- data/lib/rubocop/config_loader.rb +4 -39
- data/lib/rubocop/config_store.rb +5 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +35 -6
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +30 -4
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/lint/void.rb +7 -0
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +127 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +98 -34
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_format.rb +18 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +25 -8
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +25 -24
- data/lib/rubocop/lsp/routes.rb +65 -9
- data/lib/rubocop/lsp/runtime.rb +2 -2
- data/lib/rubocop/lsp/server.rb +2 -2
- data/lib/rubocop/lsp/stdin_runner.rb +0 -16
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/result_cache.rb +14 -12
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/runner.rb +6 -4
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/target_finder.rb +9 -9
- data/lib/rubocop/target_ruby.rb +10 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +12 -1
- data/lib/ruby_lsp/rubocop/addon.rb +25 -10
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +22 -8
@@ -20,7 +20,6 @@ module RuboCop
|
|
20
20
|
# # do a different thing...
|
21
21
|
# end
|
22
22
|
class UnlessElse < Base
|
23
|
-
include RangeHelp
|
24
23
|
extend AutoCorrector
|
25
24
|
|
26
25
|
MSG = 'Do not use `unless` with `else`. Rewrite these with the positive case first.'
|
@@ -29,25 +28,27 @@ module RuboCop
|
|
29
28
|
return unless node.unless? && node.else?
|
30
29
|
|
31
30
|
add_offense(node) do |corrector|
|
32
|
-
body_range = range_between_condition_and_else(node, node.condition)
|
33
|
-
else_range = range_between_else_and_end(node)
|
34
|
-
|
35
31
|
next if part_of_ignored_node?(node)
|
36
32
|
|
37
33
|
corrector.replace(node.loc.keyword, 'if')
|
38
|
-
|
39
|
-
|
34
|
+
|
35
|
+
body_range = range_between_condition_and_else(node)
|
36
|
+
else_range = range_between_else_and_end(node)
|
37
|
+
|
38
|
+
corrector.swap(body_range, else_range)
|
40
39
|
end
|
41
40
|
|
42
41
|
ignore_node(node)
|
43
42
|
end
|
44
43
|
|
45
|
-
def range_between_condition_and_else(node
|
46
|
-
|
44
|
+
def range_between_condition_and_else(node)
|
45
|
+
range = node.loc.begin ? node.loc.begin.end : node.condition.source_range
|
46
|
+
|
47
|
+
range.end.join(node.loc.else.begin)
|
47
48
|
end
|
48
49
|
|
49
50
|
def range_between_else_and_end(node)
|
50
|
-
|
51
|
+
node.loc.else.end.join(node.loc.end.begin)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
@@ -71,6 +71,16 @@ module RuboCop
|
|
71
71
|
name && @source.include?('{')
|
72
72
|
end
|
73
73
|
|
74
|
+
def variable_width?
|
75
|
+
!!width&.start_with?('*')
|
76
|
+
end
|
77
|
+
|
78
|
+
def variable_width_argument_number
|
79
|
+
return unless variable_width?
|
80
|
+
|
81
|
+
width == '*' ? 1 : width.match(DIGIT_DOLLAR)['arg_number'].to_i
|
82
|
+
end
|
83
|
+
|
74
84
|
# Number of arguments required for the format sequence
|
75
85
|
def arity
|
76
86
|
@source.scan('*').count + 1
|
@@ -71,6 +71,8 @@ module RuboCop
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
BRANCH_NODES = %i[if case case_match rescue].freeze
|
75
|
+
|
74
76
|
def variable_table
|
75
77
|
@variable_table ||= VariableTable.new(self)
|
76
78
|
end
|
@@ -236,11 +238,16 @@ module RuboCop
|
|
236
238
|
end
|
237
239
|
|
238
240
|
def process_loop(node)
|
239
|
-
if
|
241
|
+
if node.post_condition_loop?
|
240
242
|
# See the comment at the end of file for this behavior.
|
241
243
|
condition_node, body_node = *node
|
242
244
|
process_node(body_node)
|
243
245
|
process_node(condition_node)
|
246
|
+
elsif node.for_type?
|
247
|
+
# In `for item in items` the rightmost expression is evaluated first.
|
248
|
+
process_node(node.collection)
|
249
|
+
process_node(node.variable)
|
250
|
+
process_node(node.body) if node.body
|
244
251
|
else
|
245
252
|
process_children(node)
|
246
253
|
end
|
@@ -296,7 +303,7 @@ module RuboCop
|
|
296
303
|
variable_table.accessible_variables.each { |variable| variable.reference!(node) }
|
297
304
|
end
|
298
305
|
|
299
|
-
# Mark
|
306
|
+
# Mark last assignments which are referenced in the same loop
|
300
307
|
# as referenced by ignoring AST order since they would be referenced
|
301
308
|
# in next iteration.
|
302
309
|
def mark_assignments_as_referenced_in_loop(node)
|
@@ -308,13 +315,12 @@ module RuboCop
|
|
308
315
|
# would be skipped here.
|
309
316
|
next unless variable
|
310
317
|
|
311
|
-
variable.assignments.
|
312
|
-
|
313
|
-
assignment_node.equal?(assignment.node)
|
314
|
-
end
|
315
|
-
|
316
|
-
assignment.reference!(node)
|
318
|
+
loop_assignments = variable.assignments.select do |assignment|
|
319
|
+
assignment_nodes_in_loop.include?(assignment.node)
|
317
320
|
end
|
321
|
+
next unless loop_assignments.any?
|
322
|
+
|
323
|
+
reference_assignments(loop_assignments, node)
|
318
324
|
end
|
319
325
|
end
|
320
326
|
|
@@ -354,6 +360,17 @@ module RuboCop
|
|
354
360
|
end
|
355
361
|
end
|
356
362
|
|
363
|
+
def reference_assignments(loop_assignments, loop_node)
|
364
|
+
# If inside a branching statement, mark all as referenced.
|
365
|
+
# Otherwise, mark only the last assignment as referenced.
|
366
|
+
# Note that `rescue` must be considered as branching because of
|
367
|
+
# the `retry` keyword.
|
368
|
+
loop_assignments.each do |assignment|
|
369
|
+
assignment.reference!(loop_node) if assignment.node.each_ancestor(*BRANCH_NODES).any?
|
370
|
+
end
|
371
|
+
loop_assignments.last&.reference!(loop_node)
|
372
|
+
end
|
373
|
+
|
357
374
|
def scanned_node?(node)
|
358
375
|
scanned_nodes.include?(node)
|
359
376
|
end
|
@@ -7,6 +7,7 @@ require 'yard'
|
|
7
7
|
# @api private
|
8
8
|
class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
9
9
|
include ::RuboCop::Cop::Documentation
|
10
|
+
|
10
11
|
CopData = Struct.new(
|
11
12
|
:cop, :description, :example_objects, :safety_objects, :see_objects, :config, keyword_init: true
|
12
13
|
)
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Formatter
|
5
5
|
# This formatter displays a YAML configuration file where all cops that
|
6
6
|
# detected any offenses are configured to not detect the offense.
|
7
|
-
class DisabledConfigFormatter < BaseFormatter
|
7
|
+
class DisabledConfigFormatter < BaseFormatter # rubocop:disable Metrics/ClassLength
|
8
8
|
include PathUtil
|
9
9
|
|
10
10
|
HEADING = <<~COMMENTS
|
@@ -17,6 +17,22 @@ module RuboCop
|
|
17
17
|
# versions of RuboCop, may require this file to be generated again.
|
18
18
|
COMMENTS
|
19
19
|
|
20
|
+
EXCLUDED_CONFIG_KEYS = %w[
|
21
|
+
AutoCorrect
|
22
|
+
Description
|
23
|
+
Enabled
|
24
|
+
Exclude
|
25
|
+
Include
|
26
|
+
Reference
|
27
|
+
References
|
28
|
+
Safe
|
29
|
+
SafeAutoCorrect
|
30
|
+
StyleGuide
|
31
|
+
VersionAdded
|
32
|
+
VersionChanged
|
33
|
+
VersionRemoved
|
34
|
+
].freeze
|
35
|
+
|
20
36
|
@config_to_allow_offenses = {}
|
21
37
|
@detected_styles = {}
|
22
38
|
|
@@ -163,10 +179,7 @@ module RuboCop
|
|
163
179
|
end
|
164
180
|
|
165
181
|
def cop_config_params(default_cfg, cfg)
|
166
|
-
default_cfg.keys -
|
167
|
-
%w[Description StyleGuide Reference References Enabled Exclude Safe
|
168
|
-
SafeAutoCorrect VersionAdded VersionChanged VersionRemoved] -
|
169
|
-
cfg.keys
|
182
|
+
default_cfg.keys - EXCLUDED_CONFIG_KEYS - cfg.keys
|
170
183
|
end
|
171
184
|
|
172
185
|
def output_cop_param_comments(output_buffer, params, default_cfg)
|
@@ -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(
|
20
|
-
@
|
19
|
+
def initialize(position_encoding, offense, uri, cop_class)
|
20
|
+
@position_encoding = position_encoding
|
21
21
|
@offense = offense
|
22
22
|
@uri = uri
|
23
23
|
@cop_class = cop_class
|
@@ -45,11 +45,11 @@ module RuboCop
|
|
45
45
|
range: LanguageServer::Protocol::Interface::Range.new(
|
46
46
|
start: LanguageServer::Protocol::Interface::Position.new(
|
47
47
|
line: @offense.line - 1,
|
48
|
-
character: highlighted.begin_pos
|
48
|
+
character: to_position_character(highlighted.begin_pos)
|
49
49
|
),
|
50
50
|
end: LanguageServer::Protocol::Interface::Position.new(
|
51
51
|
line: @offense.line - 1,
|
52
|
-
character: highlighted.end_pos
|
52
|
+
character: to_position_character(highlighted.end_pos)
|
53
53
|
)
|
54
54
|
),
|
55
55
|
data: {
|
@@ -79,7 +79,7 @@ module RuboCop
|
|
79
79
|
LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
|
80
80
|
end
|
81
81
|
|
82
|
-
# rubocop:disable
|
82
|
+
# rubocop:disable Metrics/MethodLength
|
83
83
|
def autocorrect_action
|
84
84
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
85
85
|
title: "Autocorrect #{@offense.cop_name}",
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
is_preferred: true
|
99
99
|
)
|
100
100
|
end
|
101
|
-
# rubocop:enable
|
101
|
+
# rubocop:enable Metrics/MethodLength
|
102
102
|
|
103
103
|
# rubocop:disable Metrics/MethodLength
|
104
104
|
def offense_replacements
|
@@ -107,11 +107,11 @@ module RuboCop
|
|
107
107
|
range: LanguageServer::Protocol::Interface::Range.new(
|
108
108
|
start: LanguageServer::Protocol::Interface::Position.new(
|
109
109
|
line: range.line - 1,
|
110
|
-
character: range.column
|
110
|
+
character: to_position_character(range.column)
|
111
111
|
),
|
112
112
|
end: LanguageServer::Protocol::Interface::Position.new(
|
113
113
|
line: range.last_line - 1,
|
114
|
-
character: range.last_column
|
114
|
+
character: to_position_character(range.last_column)
|
115
115
|
)
|
116
116
|
),
|
117
117
|
new_text: replacement
|
@@ -120,7 +120,7 @@ module RuboCop
|
|
120
120
|
end
|
121
121
|
# rubocop:enable Metrics/MethodLength
|
122
122
|
|
123
|
-
# rubocop:disable
|
123
|
+
# rubocop:disable Metrics/MethodLength
|
124
124
|
def disable_line_action
|
125
125
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
126
126
|
title: "Disable #{@offense.cop_name} for this line",
|
@@ -138,7 +138,7 @@ module RuboCop
|
|
138
138
|
)
|
139
139
|
)
|
140
140
|
end
|
141
|
-
# rubocop:enable
|
141
|
+
# rubocop:enable Metrics/MethodLength
|
142
142
|
|
143
143
|
def line_disable_comment
|
144
144
|
new_text = if @offense.source_line.include?(' # rubocop:disable ')
|
@@ -149,7 +149,7 @@ module RuboCop
|
|
149
149
|
|
150
150
|
eol = LanguageServer::Protocol::Interface::Position.new(
|
151
151
|
line: @offense.line - 1,
|
152
|
-
character:
|
152
|
+
character: to_position_character
|
153
153
|
)
|
154
154
|
|
155
155
|
# TODO: fails for multiline strings - may be preferable to use block
|
@@ -162,19 +162,6 @@ module RuboCop
|
|
162
162
|
[inline_comment]
|
163
163
|
end
|
164
164
|
|
165
|
-
def length_of_line(line)
|
166
|
-
if @document_encoding == Encoding::UTF_16LE
|
167
|
-
line_length = 0
|
168
|
-
line.codepoints.each do |codepoint|
|
169
|
-
line_length += 1
|
170
|
-
line_length += 1 if codepoint > RubyLsp::Document::Scanner::SURROGATE_PAIR_START
|
171
|
-
end
|
172
|
-
line_length
|
173
|
-
else
|
174
|
-
line.length
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
165
|
def correctable?
|
179
166
|
!@offense.corrector.nil?
|
180
167
|
end
|
@@ -184,6 +171,20 @@ module RuboCop
|
|
184
171
|
uri.scheme = 'file' if uri.scheme.nil?
|
185
172
|
uri
|
186
173
|
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
|
187
188
|
end
|
188
189
|
end
|
189
190
|
end
|
data/lib/rubocop/lsp/routes.rb
CHANGED
@@ -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
|
18
|
+
class Routes # rubocop:disable Metrics/ClassLength
|
19
19
|
CONFIGURATION_FILE_PATTERNS = [
|
20
20
|
RuboCop::ConfigFinder::DOTFILE,
|
21
21
|
RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
|
@@ -42,6 +42,7 @@ 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]
|
45
46
|
|
46
47
|
@server.configure(initialization_options)
|
47
48
|
|
@@ -51,9 +52,10 @@ module RuboCop
|
|
51
52
|
capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
|
52
53
|
document_formatting_provider: true,
|
53
54
|
text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
|
54
|
-
change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::
|
55
|
+
change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::INCREMENTAL,
|
55
56
|
open_close: true
|
56
|
-
)
|
57
|
+
),
|
58
|
+
position_encoding: @position_encoding
|
57
59
|
)
|
58
60
|
)
|
59
61
|
)
|
@@ -76,7 +78,12 @@ module RuboCop
|
|
76
78
|
|
77
79
|
handle 'textDocument/didChange' do |request|
|
78
80
|
params = request[:params]
|
79
|
-
|
81
|
+
file_uri = params[:textDocument][:uri]
|
82
|
+
text = @text_cache[file_uri]
|
83
|
+
params[:contentChanges].each do |content|
|
84
|
+
text = change_text(text, content[:text], content[:range])
|
85
|
+
end
|
86
|
+
result = diagnostic(file_uri, text)
|
80
87
|
@server.write(result)
|
81
88
|
end
|
82
89
|
|
@@ -179,14 +186,26 @@ module RuboCop
|
|
179
186
|
|
180
187
|
def extract_initialization_options_from(request)
|
181
188
|
safe_autocorrect = request.dig(:params, :initializationOptions, :safeAutocorrect)
|
189
|
+
position_encodings = request.dig(:params, :capabilities, :general, :positionEncodings)
|
182
190
|
|
183
191
|
{
|
184
192
|
safe_autocorrect: safe_autocorrect.nil? || safe_autocorrect == true,
|
185
193
|
lint_mode: request.dig(:params, :initializationOptions, :lintMode) == true,
|
186
|
-
layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true
|
194
|
+
layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true,
|
195
|
+
position_encoding: position_encoding(position_encodings)
|
187
196
|
}
|
188
197
|
end
|
189
198
|
|
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
|
+
|
190
209
|
def format_file(file_uri, command: nil)
|
191
210
|
unless (text = @text_cache[file_uri])
|
192
211
|
Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
|
@@ -194,7 +213,7 @@ module RuboCop
|
|
194
213
|
return []
|
195
214
|
end
|
196
215
|
|
197
|
-
new_text = @server.format(
|
216
|
+
new_text = @server.format(convert_file_uri_to_path(file_uri), text, command: command)
|
198
217
|
|
199
218
|
return [] if new_text == text
|
200
219
|
|
@@ -214,13 +233,50 @@ module RuboCop
|
|
214
233
|
method: 'textDocument/publishDiagnostics',
|
215
234
|
params: {
|
216
235
|
uri: file_uri,
|
217
|
-
diagnostics: @server.offenses(
|
236
|
+
diagnostics: @server.offenses(convert_file_uri_to_path(file_uri),
|
237
|
+
text, @position_encoding)
|
218
238
|
}
|
219
239
|
}
|
220
240
|
end
|
221
241
|
|
222
|
-
def
|
223
|
-
|
242
|
+
def change_text(orig_text, text, range)
|
243
|
+
return text unless range
|
244
|
+
|
245
|
+
start_pos = text_pos(orig_text, range[:start])
|
246
|
+
end_pos = text_pos(orig_text, range[:end])
|
247
|
+
orig_text[start_pos...end_pos] = text
|
248
|
+
orig_text
|
249
|
+
end
|
250
|
+
|
251
|
+
def text_pos(text, range)
|
252
|
+
line = range[:line]
|
253
|
+
char = range[:character]
|
254
|
+
pos = 0
|
255
|
+
text.each_line.with_index do |l, i|
|
256
|
+
if i == line
|
257
|
+
pos += line_pos(l, char)
|
258
|
+
return pos
|
259
|
+
end
|
260
|
+
pos += l.size
|
261
|
+
end
|
262
|
+
pos
|
263
|
+
end
|
264
|
+
|
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
|
+
def convert_file_uri_to_path(uri)
|
279
|
+
URI.decode_www_form_component(uri.delete_prefix('file://'))
|
224
280
|
end
|
225
281
|
end
|
226
282
|
end
|
data/lib/rubocop/lsp/runtime.rb
CHANGED
@@ -44,14 +44,14 @@ module RuboCop
|
|
44
44
|
@runner.formatted_source
|
45
45
|
end
|
46
46
|
|
47
|
-
def offenses(path, text,
|
47
|
+
def offenses(path, text, position_encoding, 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
|
-
|
54
|
+
position_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
|
data/lib/rubocop/lsp/server.rb
CHANGED
@@ -51,8 +51,8 @@ module RuboCop
|
|
51
51
|
@runtime.format(path, text, command: command)
|
52
52
|
end
|
53
53
|
|
54
|
-
def offenses(path, text)
|
55
|
-
@runtime.offenses(path, text)
|
54
|
+
def offenses(path, text, position_encoding)
|
55
|
+
@runtime.offenses(path, text, position_encoding)
|
56
56
|
end
|
57
57
|
|
58
58
|
def configure(options)
|
@@ -40,7 +40,6 @@ module RuboCop
|
|
40
40
|
super(@options, config_store)
|
41
41
|
end
|
42
42
|
|
43
|
-
# rubocop:disable Metrics/MethodLength
|
44
43
|
def run(path, contents, options, prism_result: nil)
|
45
44
|
@options = options.merge(DEFAULT_RUBOCOP_OPTIONS)
|
46
45
|
@options[:stdin] = contents
|
@@ -54,22 +53,7 @@ module RuboCop
|
|
54
53
|
super([path])
|
55
54
|
|
56
55
|
raise Interrupt if aborting?
|
57
|
-
rescue RuboCop::Runner::InfiniteCorrectionLoop => e
|
58
|
-
if defined?(::RubyLsp::Requests::Formatting::Error)
|
59
|
-
raise ::RubyLsp::Requests::Formatting::Error, e.message
|
60
|
-
end
|
61
|
-
|
62
|
-
raise e
|
63
|
-
rescue RuboCop::ValidationError => e
|
64
|
-
raise ConfigurationError, e.message
|
65
|
-
rescue StandardError => e
|
66
|
-
if defined?(::RubyLsp::Requests::Formatting::Error)
|
67
|
-
raise ::RubyLsp::Requests::Support::InternalRuboCopError, e
|
68
|
-
end
|
69
|
-
|
70
|
-
raise e
|
71
56
|
end
|
72
|
-
# rubocop:enable Metrics/MethodLength
|
73
57
|
|
74
58
|
def formatted_source
|
75
59
|
@options[:stdin]
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# Reports information about pending cops that are not explicitly configured.
|
5
|
+
#
|
6
|
+
# This class is responsible for displaying warnings when new cops have been added to RuboCop
|
7
|
+
# but have not yet been enabled or disabled in the user's configuration.
|
8
|
+
# It provides a centralized way to determine whether such warnings should be shown,
|
9
|
+
# based on global flags or configuration settings.
|
10
|
+
class PendingCopsReporter
|
11
|
+
class << self
|
12
|
+
PENDING_BANNER = <<~BANNER
|
13
|
+
The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
|
14
|
+
|
15
|
+
Please also note that you can opt-in to new cops by default by adding this to your config:
|
16
|
+
AllCops:
|
17
|
+
NewCops: enable
|
18
|
+
BANNER
|
19
|
+
|
20
|
+
attr_accessor :disable_pending_cops, :enable_pending_cops
|
21
|
+
|
22
|
+
def warn_if_needed(config)
|
23
|
+
return if possible_new_cops?(config)
|
24
|
+
|
25
|
+
pending_cops = pending_cops_only_qualified(config.pending_cops)
|
26
|
+
warn_on_pending_cops(pending_cops) unless pending_cops.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def pending_cops_only_qualified(pending_cops)
|
32
|
+
pending_cops.select { |cop| Cop::Registry.qualified_cop?(cop.name) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def possible_new_cops?(config)
|
36
|
+
disable_pending_cops || enable_pending_cops ||
|
37
|
+
config.disabled_new_cops? || config.enabled_new_cops?
|
38
|
+
end
|
39
|
+
|
40
|
+
def warn_on_pending_cops(pending_cops)
|
41
|
+
warn Rainbow(PENDING_BANNER).yellow
|
42
|
+
|
43
|
+
pending_cops.each { |cop| warn_pending_cop cop }
|
44
|
+
|
45
|
+
warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
|
46
|
+
end
|
47
|
+
|
48
|
+
def warn_pending_cop(cop)
|
49
|
+
version = cop.metadata['VersionAdded'] || 'N/A'
|
50
|
+
|
51
|
+
warn Rainbow("#{cop.name}: # new in #{version}").yellow
|
52
|
+
warn Rainbow(' Enabled: true').yellow
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
# Provides functionality for caching RuboCop runs.
|
10
10
|
# @api private
|
11
11
|
class ResultCache
|
12
|
-
NON_CHANGING = %i[color format formatters out debug fail_level
|
12
|
+
NON_CHANGING = %i[color format formatters out debug display_time fail_level
|
13
13
|
fix_layout autocorrect safe_autocorrect autocorrect_all
|
14
14
|
cache fail_fast stdin parallel].freeze
|
15
15
|
|
@@ -198,20 +198,22 @@ module RuboCop
|
|
198
198
|
end
|
199
199
|
|
200
200
|
def rubocop_extra_features
|
201
|
-
|
202
|
-
|
201
|
+
@rubocop_extra_features ||= begin
|
202
|
+
lib_root = File.join(File.dirname(__FILE__), '..')
|
203
|
+
exe_root = File.join(lib_root, '..', 'exe')
|
203
204
|
|
204
|
-
|
205
|
-
|
206
|
-
|
205
|
+
# Make sure to use an absolute path to prevent errors on Windows
|
206
|
+
# when traversing the relative paths with symlinks.
|
207
|
+
exe_root = File.absolute_path(exe_root)
|
207
208
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
209
|
+
# These are all the files we have `require`d plus everything in the
|
210
|
+
# exe directory. A change to any of them could affect the cop output
|
211
|
+
# so we include them in the cache hash.
|
212
|
+
source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
|
213
|
+
source_files -= ResultCache.rubocop_required_features # Rely on gem versions
|
213
214
|
|
214
|
-
|
215
|
+
source_files
|
216
|
+
end
|
215
217
|
end
|
216
218
|
|
217
219
|
# Return a hash of the options given at invocation, minus the ones that have
|
@@ -72,9 +72,15 @@ module RuboCop
|
|
72
72
|
#
|
73
73
|
# expect_no_corrections
|
74
74
|
#
|
75
|
-
# If your code has variables of different lengths, you can use
|
76
|
-
#
|
77
|
-
#
|
75
|
+
# If your code has variables of different lengths, you can use the
|
76
|
+
# following markers to format your template by passing the variables as a
|
77
|
+
# keyword arguments:
|
78
|
+
#
|
79
|
+
# - `%{foo}`: Interpolates `foo`
|
80
|
+
# - `^{foo}`: Inserts `'^' * foo.size` for dynamic offense range length
|
81
|
+
# - `_{foo}`: Inserts `' ' * foo.size` for dynamic offense range indentation
|
82
|
+
#
|
83
|
+
# You can also abbreviate offense messages with `[...]`.
|
78
84
|
#
|
79
85
|
# %w[raise fail].each do |keyword|
|
80
86
|
# expect_offense(<<~RUBY, keyword: keyword)
|