rubocop 1.69.2 → 1.71.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +36 -2
- data/lib/rubocop/cli/command/execute_runner.rb +3 -3
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +13 -4
- data/lib/rubocop/config_loader.rb +4 -0
- data/lib/rubocop/config_loader_resolver.rb +14 -3
- data/lib/rubocop/config_validator.rb +18 -8
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
- data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
- data/lib/rubocop/cop/layout/class_structure.rb +7 -7
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
- data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +23 -5
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +17 -30
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
- data/lib/rubocop/cop/lint/syntax.rb +4 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
- data/lib/rubocop/cop/lint/void.rb +3 -2
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +8 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
- data/lib/rubocop/cop/mixin/comments_help.rb +2 -0
- data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_subset.rb +170 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +26 -16
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -2
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
- data/lib/rubocop/cop/style/array_first_last.rb +18 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -19
- data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
- data/lib/rubocop/cop/style/collection_methods.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
- data/lib/rubocop/cop/style/empty_else.rb +4 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +8 -4
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_except.rb +9 -148
- data/lib/rubocop/cop/style/hash_slice.rb +65 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
- data/lib/rubocop/cop/style/it_assignment.rb +36 -0
- data/lib/rubocop/cop/style/map_to_set.rb +3 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/missing_else.rb +2 -0
- data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
- data/lib/rubocop/cop/style/mutable_constant.rb +2 -2
- data/lib/rubocop/cop/style/object_then.rb +13 -15
- data/lib/rubocop/cop/style/open_struct_use.rb +4 -4
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +6 -4
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -4
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
- data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
- data/lib/rubocop/cop/style/string_methods.rb +1 -1
- data/lib/rubocop/cop/style/super_arguments.rb +63 -15
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
- data/lib/rubocop/cop/util.rb +9 -2
- data/lib/rubocop/cops_documentation_generator.rb +13 -13
- data/lib/rubocop/directive_comment.rb +9 -8
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +189 -0
- data/lib/rubocop/lsp/logger.rb +2 -2
- data/lib/rubocop/lsp/routes.rb +7 -23
- data/lib/rubocop/lsp/runtime.rb +15 -49
- data/lib/rubocop/lsp/stdin_runner.rb +83 -0
- data/lib/rubocop/options.rb +2 -1
- data/lib/rubocop/path_util.rb +11 -8
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -1
- data/lib/rubocop/runner.rb +5 -6
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/target_ruby.rb +15 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -0
- data/lib/ruby_lsp/rubocop/addon.rb +78 -0
- data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
- metadata +17 -8
@@ -23,6 +23,10 @@ module RuboCop
|
|
23
23
|
# `define_method`, therefore, `super` used within these blocks will be allowed.
|
24
24
|
# This approach might result in false negatives, yet ensuring safe detection takes precedence.
|
25
25
|
#
|
26
|
+
# NOTE: When forwarding the same arguments but replacing the block argument with a new inline
|
27
|
+
# block, it is not necessary to explicitly list the non-block arguments. As such, an offense
|
28
|
+
# will be registered in this case.
|
29
|
+
#
|
26
30
|
# @example
|
27
31
|
# # bad
|
28
32
|
# def method(*args, **kwargs)
|
@@ -44,6 +48,16 @@ module RuboCop
|
|
44
48
|
# super()
|
45
49
|
# end
|
46
50
|
#
|
51
|
+
# # bad - forwarding with overridden block
|
52
|
+
# def method(*args, **kwargs, &block)
|
53
|
+
# super(*args, **kwargs) { do_something }
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good - implicitly passing all non-block arguments
|
57
|
+
# def method(*args, **kwargs, &block)
|
58
|
+
# super { do_something }
|
59
|
+
# end
|
60
|
+
#
|
47
61
|
# # good - assigning to the block variable before calling super
|
48
62
|
# def method(&block)
|
49
63
|
# # Assigning to the block variable would pass the old value to super,
|
@@ -58,44 +72,75 @@ module RuboCop
|
|
58
72
|
ASSIGN_TYPES = %i[or_asgn lvasgn].freeze
|
59
73
|
|
60
74
|
MSG = 'Call `super` without arguments and parentheses when the signature is identical.'
|
75
|
+
MSG_INLINE_BLOCK = 'Call `super` without arguments and parentheses when all positional ' \
|
76
|
+
'and keyword arguments are forwarded.'
|
61
77
|
|
62
78
|
def on_super(super_node)
|
63
|
-
def_node = super_node
|
79
|
+
return unless (def_node = find_def_node(super_node))
|
80
|
+
|
81
|
+
def_node_args = def_node.arguments.argument_list
|
82
|
+
super_args = preprocess_super_args(super_node.arguments)
|
83
|
+
|
84
|
+
return unless arguments_identical?(def_node, super_node, def_node_args, super_args)
|
85
|
+
|
86
|
+
# If the number of arguments to the def node and super node are different here,
|
87
|
+
# it's because the block argument is not forwarded.
|
88
|
+
message = def_node_args.size == super_args.size ? MSG : MSG_INLINE_BLOCK
|
89
|
+
add_offense(super_node, message: message) do |corrector|
|
90
|
+
corrector.replace(super_node, 'super')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def find_def_node(super_node)
|
97
|
+
super_node.ancestors.find do |node|
|
64
98
|
# When defining dynamic methods, implicitly calling `super` is not possible.
|
65
99
|
# Since there is a possibility of delegation to `define_method`,
|
66
100
|
# `super` used within the block is always allowed.
|
67
|
-
break if node.block_type?
|
101
|
+
break if node.block_type? && !block_sends_to_super?(super_node, node)
|
68
102
|
|
69
103
|
break node if DEF_TYPES.include?(node.type)
|
70
104
|
end
|
71
|
-
return unless def_node
|
72
|
-
return unless arguments_identical?(def_node, def_node.arguments.argument_list,
|
73
|
-
super_node.arguments)
|
74
|
-
|
75
|
-
add_offense(super_node) { |corrector| corrector.replace(super_node, 'super') }
|
76
105
|
end
|
77
106
|
|
78
|
-
private
|
79
|
-
|
80
107
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
81
|
-
def arguments_identical?(def_node, def_args, super_args)
|
82
|
-
|
83
|
-
return false if def_args.size != super_args.size
|
108
|
+
def arguments_identical?(def_node, super_node, def_args, super_args)
|
109
|
+
return false if argument_list_size_differs?(def_args, super_args, super_node)
|
84
110
|
|
85
111
|
def_args.zip(super_args).each do |def_arg, super_arg|
|
86
112
|
next if positional_arg_same?(def_arg, super_arg)
|
87
113
|
next if positional_rest_arg_same(def_arg, super_arg)
|
88
114
|
next if keyword_arg_same?(def_arg, super_arg)
|
89
115
|
next if keyword_rest_arg_same?(def_arg, super_arg)
|
90
|
-
next if block_arg_same?(def_node, def_arg, super_arg)
|
116
|
+
next if block_arg_same?(def_node, super_node, def_arg, super_arg)
|
91
117
|
next if forward_arg_same?(def_arg, super_arg)
|
92
118
|
|
93
119
|
return false
|
94
120
|
end
|
121
|
+
|
95
122
|
true
|
96
123
|
end
|
97
124
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
98
125
|
|
126
|
+
def argument_list_size_differs?(def_args, super_args, super_node)
|
127
|
+
# If the def node has a block argument and the super node has an explicit block,
|
128
|
+
# the number of arguments is the same, so ignore the def node block arg.
|
129
|
+
def_args_size = def_args.size
|
130
|
+
def_args_size -= 1 if def_args.any?(&:blockarg_type?) && block_sends_to_super?(super_node)
|
131
|
+
|
132
|
+
def_args_size != super_args.size
|
133
|
+
end
|
134
|
+
|
135
|
+
def block_sends_to_super?(super_node, parent_node = super_node.parent)
|
136
|
+
# Checks if the send node of a block is the given super node,
|
137
|
+
# or a method chain containing it.
|
138
|
+
return false unless parent_node
|
139
|
+
return false unless parent_node.type?(:block, :numblock)
|
140
|
+
|
141
|
+
parent_node.send_node.each_node(:super).any?(super_node)
|
142
|
+
end
|
143
|
+
|
99
144
|
def positional_arg_same?(def_arg, super_arg)
|
100
145
|
return false unless def_arg.arg_type? || def_arg.optarg_type?
|
101
146
|
return false unless super_arg.lvar_type?
|
@@ -133,8 +178,11 @@ module RuboCop
|
|
133
178
|
def_arg.name == lvar_node.children.first
|
134
179
|
end
|
135
180
|
|
136
|
-
def block_arg_same?(def_node, def_arg, super_arg)
|
137
|
-
return false unless def_arg.blockarg_type?
|
181
|
+
def block_arg_same?(def_node, super_node, def_arg, super_arg)
|
182
|
+
return false unless def_arg.blockarg_type?
|
183
|
+
return true if block_sends_to_super?(super_node)
|
184
|
+
return false unless super_arg.block_pass_type?
|
185
|
+
|
138
186
|
# anonymous forwarding
|
139
187
|
return true if (block_pass_child = super_arg.children.first).nil? && def_arg.name.nil?
|
140
188
|
|
@@ -7,12 +7,15 @@ module RuboCop
|
|
7
7
|
# The supported styles are:
|
8
8
|
#
|
9
9
|
# * `consistent_comma`: Requires a comma after the last argument,
|
10
|
-
# for all parenthesized method calls with arguments.
|
10
|
+
# for all parenthesized multi-line method calls with arguments.
|
11
11
|
# * `comma`: Requires a comma after the last argument, but only for
|
12
12
|
# parenthesized method calls where each argument is on its own line.
|
13
13
|
# * `no_comma`: Requires that there is no comma after the last
|
14
14
|
# argument.
|
15
15
|
#
|
16
|
+
# Regardless of style, trailing commas are not allowed in
|
17
|
+
# single-line method calls.
|
18
|
+
#
|
16
19
|
# @example EnforcedStyleForMultiline: consistent_comma
|
17
20
|
# # bad
|
18
21
|
# method(1, 2,)
|
@@ -85,6 +85,12 @@ module RuboCop
|
|
85
85
|
NONCOMMUTATIVE_OPERATORS = %i[===].freeze
|
86
86
|
PROGRAM_NAMES = %i[$0 $PROGRAM_NAME].freeze
|
87
87
|
RESTRICT_ON_SEND = RuboCop::AST::Node::COMPARISON_OPERATORS
|
88
|
+
ENFORCE_YODA_STYLES = %i[
|
89
|
+
require_for_all_comparison_operators require_for_equality_operators_only
|
90
|
+
].freeze
|
91
|
+
EQUALITY_ONLY_STYLES = %i[
|
92
|
+
forbid_for_equality_operators_only require_for_equality_operators_only
|
93
|
+
].freeze
|
88
94
|
|
89
95
|
# @!method file_constant_equal_program_name?(node)
|
90
96
|
def_node_matcher :file_constant_equal_program_name?, <<~PATTERN
|
@@ -105,13 +111,11 @@ module RuboCop
|
|
105
111
|
private
|
106
112
|
|
107
113
|
def enforce_yoda?
|
108
|
-
style
|
109
|
-
style == :require_for_equality_operators_only
|
114
|
+
ENFORCE_YODA_STYLES.include?(style)
|
110
115
|
end
|
111
116
|
|
112
117
|
def equality_only?
|
113
|
-
style
|
114
|
-
style == :require_for_equality_operators_only
|
118
|
+
EQUALITY_ONLY_STYLES.include?(style)
|
115
119
|
end
|
116
120
|
|
117
121
|
def yoda_compatible_condition?(node)
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -193,11 +193,18 @@ module RuboCop
|
|
193
193
|
enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
|
194
194
|
end
|
195
195
|
|
196
|
+
def parse_regexp(text)
|
197
|
+
Regexp::Parser.parse(text)
|
198
|
+
rescue Regexp::Parser::Error
|
199
|
+
# Upon encountering an invalid regular expression,
|
200
|
+
# we aim to proceed and identify any remaining potential offenses.
|
201
|
+
nil
|
202
|
+
end
|
203
|
+
|
196
204
|
private
|
197
205
|
|
198
206
|
def compatible_external_encoding_for?(src)
|
199
|
-
src
|
200
|
-
src.force_encoding(Encoding.default_external).valid_encoding?
|
207
|
+
src.dup.force_encoding(Encoding.default_external).valid_encoding?
|
201
208
|
end
|
202
209
|
|
203
210
|
def include_or_equal?(source, target)
|
@@ -18,7 +18,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
18
18
|
description: ->(data) { "#{data.description}\n" },
|
19
19
|
safety: ->(data) { safety_object(data.safety_objects, data.cop) },
|
20
20
|
examples: ->(data) { examples(data.example_objects, data.cop) },
|
21
|
-
configuration: ->(data) { configurations(data.cop.department, data.
|
21
|
+
configuration: ->(data) { configurations(data.cop.department, data.cop, data.config) },
|
22
22
|
references: ->(data) { references(data.cop, data.see_objects) }
|
23
23
|
}.freeze
|
24
24
|
|
@@ -180,17 +180,17 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
180
180
|
content
|
181
181
|
end
|
182
182
|
|
183
|
-
def configurations(department,
|
184
|
-
return '' if pars.empty?
|
185
|
-
|
183
|
+
def configurations(department, cop, cop_config)
|
186
184
|
header = ['Name', 'Default value', 'Configurable values']
|
187
|
-
configs =
|
185
|
+
configs = cop_config
|
188
186
|
.each_key
|
189
187
|
.reject { |key| key.start_with?('Supported') }
|
190
188
|
.reject { |key| key.start_with?('AllowMultipleStyles') }
|
189
|
+
return '' if configs.empty?
|
190
|
+
|
191
191
|
content = configs.map do |name|
|
192
|
-
configurable = configurable_values(
|
193
|
-
default = format_table_value(
|
192
|
+
configurable = configurable_values(cop_config, name)
|
193
|
+
default = format_table_value(cop_config[name])
|
194
194
|
|
195
195
|
[configuration_name(department, name), default, configurable]
|
196
196
|
end
|
@@ -206,17 +206,17 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
206
206
|
end
|
207
207
|
|
208
208
|
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
209
|
-
def configurable_values(
|
209
|
+
def configurable_values(cop_config, name)
|
210
210
|
case name
|
211
211
|
when /^Enforced/
|
212
212
|
supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
|
213
|
-
format_table_value(
|
213
|
+
format_table_value(cop_config[supported_style_name])
|
214
214
|
when 'IndentationWidth'
|
215
215
|
'Integer'
|
216
216
|
when 'Database'
|
217
|
-
format_table_value(
|
217
|
+
format_table_value(cop_config['SupportedDatabases'])
|
218
218
|
else
|
219
|
-
case
|
219
|
+
case cop_config[name]
|
220
220
|
when String
|
221
221
|
'String'
|
222
222
|
when Integer
|
@@ -319,7 +319,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
319
319
|
AutoCorrect Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
|
320
320
|
VersionChanged
|
321
321
|
]
|
322
|
-
|
322
|
+
parameters = cop_config.reject { |k| non_display_keys.include? k }
|
323
323
|
description = 'No documentation'
|
324
324
|
example_objects = safety_objects = see_objects = []
|
325
325
|
cop_code(cop) do |code_object|
|
@@ -329,7 +329,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
329
329
|
see_objects = code_object.tags('see')
|
330
330
|
end
|
331
331
|
data = CopData.new(cop: cop, description: description, example_objects: example_objects,
|
332
|
-
safety_objects: safety_objects, see_objects: see_objects, config:
|
332
|
+
safety_objects: safety_objects, see_objects: see_objects, config: parameters)
|
333
333
|
cops_body(data)
|
334
334
|
end
|
335
335
|
|
@@ -88,10 +88,15 @@ module RuboCop
|
|
88
88
|
@cop_names ||= all_cops? ? all_cop_names : parsed_cop_names
|
89
89
|
end
|
90
90
|
|
91
|
+
# Returns an array of cops for this directive comment, without resolving departments
|
92
|
+
def raw_cop_names
|
93
|
+
@raw_cop_names ||= (cops || '').split(/,\s*/)
|
94
|
+
end
|
95
|
+
|
91
96
|
# Returns array of specified in this directive department names
|
92
97
|
# when all department disabled
|
93
98
|
def department_names
|
94
|
-
|
99
|
+
raw_cop_names.select { |cop| department?(cop) }
|
95
100
|
end
|
96
101
|
|
97
102
|
# Checks if directive departments include cop
|
@@ -101,11 +106,11 @@ module RuboCop
|
|
101
106
|
|
102
107
|
# Checks if cop department has already used in directive comment
|
103
108
|
def overridden_by_department?(cop)
|
104
|
-
in_directive_department?(cop) &&
|
109
|
+
in_directive_department?(cop) && raw_cop_names.include?(cop)
|
105
110
|
end
|
106
111
|
|
107
112
|
def directive_count
|
108
|
-
|
113
|
+
raw_cop_names.count
|
109
114
|
end
|
110
115
|
|
111
116
|
# Returns line number for directive
|
@@ -115,12 +120,8 @@ module RuboCop
|
|
115
120
|
|
116
121
|
private
|
117
122
|
|
118
|
-
def splitted_cops_string
|
119
|
-
(cops || '').split(/,\s*/)
|
120
|
-
end
|
121
|
-
|
122
123
|
def parsed_cop_names
|
123
|
-
cops =
|
124
|
+
cops = raw_cop_names.map do |name|
|
124
125
|
department?(name) ? cop_names_for_department(name) : name
|
125
126
|
end.flatten
|
126
127
|
cops - [LINT_SYNTAX_COP]
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'severity'
|
4
|
+
|
5
|
+
#
|
6
|
+
# This code is based on https://github.com/standardrb/standard.
|
7
|
+
#
|
8
|
+
# Copyright (c) 2023 Test Double, Inc.
|
9
|
+
#
|
10
|
+
# The MIT License (MIT)
|
11
|
+
#
|
12
|
+
# https://github.com/standardrb/standard/blob/main/LICENSE.txt
|
13
|
+
#
|
14
|
+
module RuboCop
|
15
|
+
module LSP
|
16
|
+
# Diagnostic for Language Server Protocol of RuboCop.
|
17
|
+
# @api private
|
18
|
+
class Diagnostic
|
19
|
+
def initialize(document_encoding, offense, uri, cop_class)
|
20
|
+
@document_encoding = document_encoding
|
21
|
+
@offense = offense
|
22
|
+
@uri = uri
|
23
|
+
@cop_class = cop_class
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_lsp_code_actions
|
27
|
+
code_actions = []
|
28
|
+
|
29
|
+
code_actions << autocorrect_action if correctable?
|
30
|
+
code_actions << disable_line_action
|
31
|
+
|
32
|
+
code_actions
|
33
|
+
end
|
34
|
+
|
35
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
36
|
+
def to_lsp_diagnostic(config)
|
37
|
+
highlighted = @offense.highlighted_area
|
38
|
+
|
39
|
+
LanguageServer::Protocol::Interface::Diagnostic.new(
|
40
|
+
message: message,
|
41
|
+
source: 'RuboCop',
|
42
|
+
code: @offense.cop_name,
|
43
|
+
code_description: code_description(config),
|
44
|
+
severity: severity,
|
45
|
+
range: LanguageServer::Protocol::Interface::Range.new(
|
46
|
+
start: LanguageServer::Protocol::Interface::Position.new(
|
47
|
+
line: @offense.line - 1,
|
48
|
+
character: highlighted.begin_pos
|
49
|
+
),
|
50
|
+
end: LanguageServer::Protocol::Interface::Position.new(
|
51
|
+
line: @offense.line - 1,
|
52
|
+
character: highlighted.end_pos
|
53
|
+
)
|
54
|
+
),
|
55
|
+
data: {
|
56
|
+
correctable: correctable?,
|
57
|
+
code_actions: to_lsp_code_actions
|
58
|
+
}
|
59
|
+
)
|
60
|
+
end
|
61
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def message
|
66
|
+
message = @offense.message
|
67
|
+
message += "\n\nThis offense is not autocorrectable.\n" unless correctable?
|
68
|
+
message
|
69
|
+
end
|
70
|
+
|
71
|
+
def severity
|
72
|
+
Severity.find_by(@offense.severity.name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def code_description(config)
|
76
|
+
return unless @cop_class
|
77
|
+
return unless (doc_url = @cop_class.documentation_url(config))
|
78
|
+
|
79
|
+
LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
|
80
|
+
end
|
81
|
+
|
82
|
+
# rubocop:disable Layout/LineLength, Metrics/MethodLength
|
83
|
+
def autocorrect_action
|
84
|
+
LanguageServer::Protocol::Interface::CodeAction.new(
|
85
|
+
title: "Autocorrect #{@offense.cop_name}",
|
86
|
+
kind: LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX,
|
87
|
+
edit: LanguageServer::Protocol::Interface::WorkspaceEdit.new(
|
88
|
+
document_changes: [
|
89
|
+
LanguageServer::Protocol::Interface::TextDocumentEdit.new(
|
90
|
+
text_document: LanguageServer::Protocol::Interface::OptionalVersionedTextDocumentIdentifier.new(
|
91
|
+
uri: ensure_uri_scheme(@uri.to_s).to_s,
|
92
|
+
version: nil
|
93
|
+
),
|
94
|
+
edits: correctable? ? offense_replacements : []
|
95
|
+
)
|
96
|
+
]
|
97
|
+
),
|
98
|
+
is_preferred: true
|
99
|
+
)
|
100
|
+
end
|
101
|
+
# rubocop:enable Layout/LineLength, Metrics/MethodLength
|
102
|
+
|
103
|
+
# rubocop:disable Metrics/MethodLength
|
104
|
+
def offense_replacements
|
105
|
+
@offense.corrector.as_replacements.map do |range, replacement|
|
106
|
+
LanguageServer::Protocol::Interface::TextEdit.new(
|
107
|
+
range: LanguageServer::Protocol::Interface::Range.new(
|
108
|
+
start: LanguageServer::Protocol::Interface::Position.new(
|
109
|
+
line: range.line - 1,
|
110
|
+
character: range.column
|
111
|
+
),
|
112
|
+
end: LanguageServer::Protocol::Interface::Position.new(
|
113
|
+
line: range.last_line - 1,
|
114
|
+
character: range.last_column
|
115
|
+
)
|
116
|
+
),
|
117
|
+
new_text: replacement
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
# rubocop:enable Metrics/MethodLength
|
122
|
+
|
123
|
+
# rubocop:disable Layout/LineLength, Metrics/MethodLength
|
124
|
+
def disable_line_action
|
125
|
+
LanguageServer::Protocol::Interface::CodeAction.new(
|
126
|
+
title: "Disable #{@offense.cop_name} for this line",
|
127
|
+
kind: LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX,
|
128
|
+
edit: LanguageServer::Protocol::Interface::WorkspaceEdit.new(
|
129
|
+
document_changes: [
|
130
|
+
LanguageServer::Protocol::Interface::TextDocumentEdit.new(
|
131
|
+
text_document: LanguageServer::Protocol::Interface::OptionalVersionedTextDocumentIdentifier.new(
|
132
|
+
uri: ensure_uri_scheme(@uri.to_s).to_s,
|
133
|
+
version: nil
|
134
|
+
),
|
135
|
+
edits: line_disable_comment
|
136
|
+
)
|
137
|
+
]
|
138
|
+
)
|
139
|
+
)
|
140
|
+
end
|
141
|
+
# rubocop:enable Layout/LineLength, Metrics/MethodLength
|
142
|
+
|
143
|
+
def line_disable_comment
|
144
|
+
new_text = if @offense.source_line.include?(' # rubocop:disable ')
|
145
|
+
",#{@offense.cop_name}"
|
146
|
+
else
|
147
|
+
" # rubocop:disable #{@offense.cop_name}"
|
148
|
+
end
|
149
|
+
|
150
|
+
eol = LanguageServer::Protocol::Interface::Position.new(
|
151
|
+
line: @offense.line - 1,
|
152
|
+
character: length_of_line(@offense.source_line)
|
153
|
+
)
|
154
|
+
|
155
|
+
# TODO: fails for multiline strings - may be preferable to use block
|
156
|
+
# comments to disable some offenses
|
157
|
+
inline_comment = LanguageServer::Protocol::Interface::TextEdit.new(
|
158
|
+
range: LanguageServer::Protocol::Interface::Range.new(start: eol, end: eol),
|
159
|
+
new_text: new_text
|
160
|
+
)
|
161
|
+
|
162
|
+
[inline_comment]
|
163
|
+
end
|
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
|
+
def correctable?
|
179
|
+
!@offense.corrector.nil?
|
180
|
+
end
|
181
|
+
|
182
|
+
def ensure_uri_scheme(uri)
|
183
|
+
uri = URI.parse(uri)
|
184
|
+
uri.scheme = 'file' if uri.scheme.nil?
|
185
|
+
uri
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
data/lib/rubocop/lsp/logger.rb
CHANGED
data/lib/rubocop/lsp/routes.rb
CHANGED
@@ -16,6 +16,11 @@ module RuboCop
|
|
16
16
|
# Routes for Language Server Protocol of RuboCop.
|
17
17
|
# @api private
|
18
18
|
class Routes
|
19
|
+
CONFIGURATION_FILE_PATTERNS = [
|
20
|
+
RuboCop::ConfigFinder::DOTFILE,
|
21
|
+
RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
|
22
|
+
].freeze
|
23
|
+
|
19
24
|
def self.handle(name, &block)
|
20
25
|
define_method(:"handle_#{name}", &block)
|
21
26
|
end
|
@@ -96,7 +101,7 @@ module RuboCop
|
|
96
101
|
|
97
102
|
handle 'workspace/didChangeWatchedFiles' do |request|
|
98
103
|
changed = request[:params][:changes].any? do |change|
|
99
|
-
change[:uri].end_with?(
|
104
|
+
CONFIGURATION_FILE_PATTERNS.any? { |path| change[:uri].end_with?(path) }
|
100
105
|
end
|
101
106
|
|
102
107
|
if changed
|
@@ -204,14 +209,12 @@ module RuboCop
|
|
204
209
|
|
205
210
|
def diagnostic(file_uri, text)
|
206
211
|
@text_cache[file_uri] = text
|
207
|
-
offenses = @server.offenses(remove_file_protocol_from(file_uri), text)
|
208
|
-
diagnostics = offenses.map { |offense| to_diagnostic(offense) }
|
209
212
|
|
210
213
|
{
|
211
214
|
method: 'textDocument/publishDiagnostics',
|
212
215
|
params: {
|
213
216
|
uri: file_uri,
|
214
|
-
diagnostics:
|
217
|
+
diagnostics: @server.offenses(remove_file_protocol_from(file_uri), text)
|
215
218
|
}
|
216
219
|
}
|
217
220
|
end
|
@@ -219,25 +222,6 @@ module RuboCop
|
|
219
222
|
def remove_file_protocol_from(uri)
|
220
223
|
uri.delete_prefix('file://')
|
221
224
|
end
|
222
|
-
|
223
|
-
def to_diagnostic(offense)
|
224
|
-
code = offense[:cop_name]
|
225
|
-
message = offense[:message]
|
226
|
-
loc = offense[:location]
|
227
|
-
rubocop_severity = offense[:severity]
|
228
|
-
severity = Severity.find_by(rubocop_severity)
|
229
|
-
|
230
|
-
{
|
231
|
-
code: code, message: message, range: to_range(loc), severity: severity, source: 'rubocop'
|
232
|
-
}
|
233
|
-
end
|
234
|
-
|
235
|
-
def to_range(location)
|
236
|
-
{
|
237
|
-
start: { character: location[:start_column] - 1, line: location[:start_line] - 1 },
|
238
|
-
end: { character: location[:last_column], line: location[:last_line] - 1 }
|
239
|
-
}
|
240
|
-
end
|
241
225
|
end
|
242
226
|
end
|
243
227
|
end
|