rubocop 1.69.1 → 1.70.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +19 -2
- data/lib/rubocop/cli/command/execute_runner.rb +3 -3
- 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/autocorrect_logic.rb +31 -34
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- 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/node_type_predicate.rb +4 -3
- data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +4 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -7
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
- 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 +1 -6
- 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_leading_space.rb +11 -2
- 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_method_argument_line_breaks.rb +24 -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_operators.rb +3 -3
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +11 -3
- data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +6 -14
- 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/void.rb +3 -2
- data/lib/rubocop/cop/metrics/class_length.rb +9 -9
- data/lib/rubocop/cop/metrics/method_length.rb +8 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
- data/lib/rubocop/cop/mixin/comments_help.rb +6 -1
- data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +46 -22
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- 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/block_delimiters.rb +8 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +3 -6
- 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 +1 -2
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
- data/lib/rubocop/cop/style/file_null.rb +20 -4
- data/lib/rubocop/cop/style/float_division.rb +8 -4
- data/lib/rubocop/cop/style/hash_except.rb +54 -67
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +6 -4
- data/lib/rubocop/cop/style/it_assignment.rb +36 -0
- 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 +1 -1
- data/lib/rubocop/cop/style/missing_else.rb +2 -0
- data/lib/rubocop/cop/style/multiple_comparison.rb +34 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +13 -15
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +5 -3
- 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_initialize.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +12 -9
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -4
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
- 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_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/super_arguments.rb +63 -15
- 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/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/magic_comment.rb +3 -3
- data/lib/rubocop/path_util.rb +11 -8
- data/lib/rubocop/rspec/shared_contexts.rb +4 -1
- data/lib/rubocop/runner.rb +5 -6
- data/lib/rubocop/target_ruby.rb +15 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- data/lib/ruby_lsp/rubocop/addon.rb +78 -0
- data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
- metadata +16 -8
@@ -73,7 +73,7 @@ module RuboCop
|
|
73
73
|
LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
|
74
74
|
ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
|
75
75
|
ARGUMENT_TYPES = %i[
|
76
|
-
kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
|
76
|
+
kDEF kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
|
77
77
|
tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
|
78
78
|
].freeze
|
79
79
|
ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
|
@@ -112,10 +112,13 @@ module RuboCop
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def inside_string_literal_or_method_with_argument?(range)
|
115
|
+
line_range = range_by_whole_lines(range)
|
116
|
+
|
115
117
|
processed_source.tokens.each_cons(2).any? do |token, next_token|
|
116
118
|
next if token.line == next_token.line
|
117
119
|
|
118
|
-
inside_string_literal?(range, token) ||
|
120
|
+
inside_string_literal?(range, token) ||
|
121
|
+
method_with_argument?(line_range, token, next_token)
|
119
122
|
end
|
120
123
|
end
|
121
124
|
|
@@ -129,11 +132,10 @@ module RuboCop
|
|
129
132
|
return true unless (node = find_node_for_line(range.last_line))
|
130
133
|
return false if argument_newline?(node)
|
131
134
|
|
132
|
-
source
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
parse(source.gsub("\\\n", "\n")).valid_syntax?
|
135
|
+
# Check if source is still valid without the continuation
|
136
|
+
source = processed_source.raw_source.dup
|
137
|
+
source[range.begin_pos, range.length] = "\n"
|
138
|
+
parse(source).valid_syntax?
|
137
139
|
end
|
138
140
|
|
139
141
|
def inspect_end_of_ruby_code_line_continuation
|
@@ -156,8 +158,9 @@ module RuboCop
|
|
156
158
|
#
|
157
159
|
# do_something \
|
158
160
|
# argument
|
159
|
-
def method_with_argument?(current_token, next_token)
|
161
|
+
def method_with_argument?(line_range, current_token, next_token)
|
160
162
|
return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
|
163
|
+
return false unless current_token.pos.overlaps?(line_range)
|
161
164
|
|
162
165
|
ARGUMENT_TYPES.include?(next_token.type)
|
163
166
|
end
|
@@ -181,7 +184,7 @@ module RuboCop
|
|
181
184
|
|
182
185
|
def find_node_for_line(last_line)
|
183
186
|
processed_source.ast.each_node do |node|
|
184
|
-
return node if
|
187
|
+
return node if same_line?(node, last_line)
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
@@ -166,10 +166,7 @@ module RuboCop
|
|
166
166
|
def_node_matcher :interpolation?, '[^begin ^^dstr]'
|
167
167
|
|
168
168
|
def allow_in_multiline_conditions?
|
169
|
-
|
170
|
-
return false unless parentheses_around_condition_config['Enabled']
|
171
|
-
|
172
|
-
!!parentheses_around_condition_config['AllowInMultilineConditions']
|
169
|
+
!!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
|
173
170
|
end
|
174
171
|
|
175
172
|
def check_send(begin_node, node)
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
# rubocop:disable Metrics/AbcSize
|
53
53
|
def on_lvasgn(node)
|
54
54
|
return unless (rhs = node.rhs)
|
55
|
-
return unless rhs.
|
55
|
+
return unless rhs.call_type? && method_returning_self?(rhs.method_name)
|
56
56
|
return unless (receiver = rhs.receiver)
|
57
57
|
|
58
58
|
receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
|
@@ -77,6 +77,7 @@ module RuboCop
|
|
77
77
|
corrector.remove(correction_range(node))
|
78
78
|
end
|
79
79
|
end
|
80
|
+
alias on_csend on_send
|
80
81
|
|
81
82
|
private
|
82
83
|
|
@@ -88,7 +89,7 @@ module RuboCop
|
|
88
89
|
def_node_matcher :redundant_self_assignment?, <<~PATTERN
|
89
90
|
(send
|
90
91
|
(self) _
|
91
|
-
(
|
92
|
+
(call
|
92
93
|
(send
|
93
94
|
{(self) nil?} %1) #method_returning_self?
|
94
95
|
...))
|
@@ -96,10 +97,10 @@ module RuboCop
|
|
96
97
|
|
97
98
|
# @!method redundant_nonself_assignment?(node, receiver, method_name)
|
98
99
|
def_node_matcher :redundant_nonself_assignment?, <<~PATTERN
|
99
|
-
(
|
100
|
+
(call
|
100
101
|
%1 _
|
101
|
-
(
|
102
|
-
(
|
102
|
+
(call
|
103
|
+
(call
|
103
104
|
%1 %2) #method_returning_self?
|
104
105
|
...))
|
105
106
|
PATTERN
|
@@ -323,7 +323,7 @@ module RuboCop
|
|
323
323
|
return true if unsafe_method?(method)
|
324
324
|
|
325
325
|
method.each_ancestor(:send).any? do |ancestor|
|
326
|
-
break true unless config.
|
326
|
+
break true unless config.cop_enabled?('Lint/SafeNavigationChain')
|
327
327
|
|
328
328
|
break true if unsafe_method?(ancestor)
|
329
329
|
break true if nil_methods.include?(ancestor.method_name)
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
def on_send(node)
|
69
69
|
return if allow_send? && !node.method?(:public_send)
|
70
70
|
return unless (first_argument = node.first_argument)
|
71
|
-
return unless
|
71
|
+
return unless first_argument.type?(*STATIC_METHOD_NAME_NODE_TYPES)
|
72
72
|
|
73
73
|
offense_range = offense_range(node)
|
74
74
|
method_name = first_argument.value
|
@@ -83,6 +83,7 @@ module RuboCop
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
86
|
+
alias on_csend on_send
|
86
87
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
87
88
|
|
88
89
|
private
|
@@ -68,8 +68,7 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def single_line_blocks_preferred?
|
71
|
-
|
72
|
-
redundant_line_break_config['Enabled'] && redundant_line_break_config['InspectBlocks']
|
71
|
+
@config.for_enabled_cop('Layout/RedundantLineBreak')['InspectBlocks']
|
73
72
|
end
|
74
73
|
end
|
75
74
|
end
|
@@ -134,10 +134,9 @@ module RuboCop
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def disallow_endless_method_style?
|
137
|
-
|
138
|
-
return true unless endless_method_config['Enabled']
|
137
|
+
return true unless config.cop_enabled?('Style/EndlessMethod')
|
139
138
|
|
140
|
-
|
139
|
+
config.for_cop('Style/EndlessMethod')['EnforcedStyle'] == 'disallow'
|
141
140
|
end
|
142
141
|
end
|
143
142
|
end
|
@@ -78,38 +78,67 @@ module RuboCop
|
|
78
78
|
return unless node.arguments.one?
|
79
79
|
|
80
80
|
range_node = node.first_argument
|
81
|
-
|
82
|
-
unless (message, removal_range =
|
83
|
-
|
84
|
-
|
81
|
+
offense_range = find_offense_range(node)
|
82
|
+
return unless (message, removal_range =
|
83
|
+
offense_message_with_removal_range(node, range_node, offense_range))
|
84
|
+
|
85
|
+
# Changing the range to beginningless or endless when unparenthesized
|
86
|
+
# changes the semantics of the code, and thus will not be considered
|
87
|
+
# an offense.
|
88
|
+
return if removal_range != offense_range && unparenthesized_call?(node)
|
85
89
|
|
86
|
-
add_offense(
|
90
|
+
add_offense(offense_range, message: message) do |corrector|
|
87
91
|
corrector.remove(removal_range)
|
88
92
|
end
|
89
93
|
end
|
94
|
+
alias on_csend on_send
|
90
95
|
|
91
96
|
private
|
92
97
|
|
93
|
-
def
|
98
|
+
def unparenthesized_call?(node)
|
99
|
+
node.loc.dot && !node.parenthesized?
|
100
|
+
end
|
101
|
+
|
102
|
+
def find_offense_range(node)
|
103
|
+
if node.loc.dot
|
104
|
+
node.loc.dot.join(node.source_range.end)
|
105
|
+
else
|
106
|
+
node.loc.selector
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def offense_message_with_removal_range(node, range_node, offense_range)
|
94
111
|
if range_from_zero_till_minus_one?(range_node)
|
95
|
-
[format(MSG_USELESS_RANGE, prefer:
|
112
|
+
[format(MSG_USELESS_RANGE, prefer: offense_range.source), offense_range]
|
96
113
|
elsif range_till_minus_one?(range_node)
|
97
114
|
[
|
98
|
-
|
115
|
+
offense_message_for_partial_range(node, endless(range_node), offense_range),
|
116
|
+
range_node.end
|
99
117
|
]
|
100
118
|
elsif range_from_zero?(range_node) && target_ruby_version >= 2.7
|
101
119
|
[
|
102
|
-
|
120
|
+
offense_message_for_partial_range(node, beginless(range_node), offense_range),
|
121
|
+
range_node.begin
|
103
122
|
]
|
104
123
|
end
|
105
124
|
end
|
106
125
|
|
126
|
+
def offense_message_for_partial_range(node, prefer, offense_range)
|
127
|
+
current = node.loc.dot ? arguments_source(node) : offense_range.source
|
128
|
+
prefer = "[#{prefer}]" unless node.loc.dot
|
129
|
+
format(MSG, prefer: prefer, current: current)
|
130
|
+
end
|
131
|
+
|
107
132
|
def endless(range_node)
|
108
|
-
"
|
133
|
+
"#{range_node.begin.source}#{range_node.loc.operator.source}"
|
109
134
|
end
|
110
135
|
|
111
136
|
def beginless(range_node)
|
112
|
-
"
|
137
|
+
"#{range_node.loc.operator.source}#{range_node.end.source}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def arguments_source(node)
|
141
|
+
node.first_argument.source_range.join(node.last_argument.source_range.end).source
|
113
142
|
end
|
114
143
|
end
|
115
144
|
end
|
@@ -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
|
|
@@ -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)
|
@@ -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