rubocop 1.86.1 → 1.87.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/config/default.yml +15 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +27 -1
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +3 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +6 -7
- data/lib/rubocop/comment_config.rb +12 -15
- data/lib/rubocop/config_loader.rb +17 -2
- data/lib/rubocop/config_loader_resolver.rb +11 -3
- data/lib/rubocop/config_store.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
- data/lib/rubocop/cop/base.rb +8 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -4
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +14 -5
- data/lib/rubocop/cop/layout/end_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +13 -1
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +26 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +36 -4
- data/lib/rubocop/cop/lint/constant_resolution.rb +5 -5
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +5 -5
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +3 -8
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +18 -7
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +8 -0
- data/lib/rubocop/cop/registry.rb +42 -25
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +10 -1
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +8 -0
- data/lib/rubocop/cop/style/copyright.rb +21 -10
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/file_write.rb +18 -16
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +12 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +15 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +6 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +16 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +3 -3
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- data/lib/rubocop/cop/team.rb +86 -35
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -1
- data/lib/rubocop/lsp/runtime.rb +1 -2
- data/lib/rubocop/options.rb +26 -4
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rspec/shared_contexts.rb +21 -0
- data/lib/rubocop/runner.rb +123 -57
- data/lib/rubocop/target_finder.rb +13 -6
- data/lib/rubocop/version.rb +20 -2
- data/lib/rubocop.rb +8 -96
- metadata +8 -3
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
|
64
64
|
|
|
65
65
|
MSG = 'Convert `if` nested inside `else` to `elsif`.'
|
|
66
66
|
|
|
67
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
67
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
68
68
|
def on_if(node)
|
|
69
69
|
return if node.ternary? || node.unless?
|
|
70
70
|
|
|
@@ -72,6 +72,7 @@ module RuboCop
|
|
|
72
72
|
|
|
73
73
|
return unless else_branch&.if_type? && else_branch.if?
|
|
74
74
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
|
75
|
+
return if comments_between_else_and_if?(node, else_branch)
|
|
75
76
|
|
|
76
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
|
77
78
|
next if part_of_ignored_node?(node)
|
|
@@ -80,7 +81,7 @@ module RuboCop
|
|
|
80
81
|
ignore_node(node)
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
84
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
84
85
|
|
|
85
86
|
private
|
|
86
87
|
|
|
@@ -135,6 +136,18 @@ module RuboCop
|
|
|
135
136
|
range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
|
|
136
137
|
end
|
|
137
138
|
|
|
139
|
+
def comments_between_else_and_if?(node, else_branch)
|
|
140
|
+
return false if else_branch.modifier_form?
|
|
141
|
+
|
|
142
|
+
else_end = node.loc.else.end_pos
|
|
143
|
+
if_begin = else_branch.loc.keyword.begin_pos
|
|
144
|
+
|
|
145
|
+
processed_source.comments.any? do |comment|
|
|
146
|
+
comment_pos = comment.source_range.begin_pos
|
|
147
|
+
comment_pos > else_end && comment_pos < if_begin
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
138
151
|
def allow_if_modifier_in_else_branch?(else_branch)
|
|
139
152
|
allow_if_modifier? && else_branch&.modifier_form?
|
|
140
153
|
end
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
# Required capitalization can be set with the `DirectiveCapitalization` and
|
|
11
11
|
# `ValueCapitalization` configuration keys.
|
|
12
12
|
#
|
|
13
|
-
# NOTE: If one of these
|
|
13
|
+
# NOTE: If one of these configurations is set to nil, any capitalization is allowed.
|
|
14
14
|
#
|
|
15
15
|
# @example EnforcedStyle: snake_case (default)
|
|
16
16
|
# # The `snake_case` style will enforce that the frozen string literal
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
|
6
6
|
# Enforces the use of `max` or `min` instead of comparison for greater or less.
|
|
7
7
|
#
|
|
8
8
|
# NOTE: It can be used if you want to present limit or threshold in Ruby 2.7+.
|
|
9
|
-
#
|
|
9
|
+
# It is slow though. So autocorrection will apply generic `max` or `min`:
|
|
10
10
|
#
|
|
11
11
|
# [source,ruby]
|
|
12
12
|
# ----
|
|
@@ -13,6 +13,12 @@ module RuboCop
|
|
|
13
13
|
# array, while `method_defined?` will do direct method lookup, which is much
|
|
14
14
|
# faster and consumes less memory.
|
|
15
15
|
#
|
|
16
|
+
# NOTE: `constants.include?` is not handled by this cop because
|
|
17
|
+
# `Module#const_defined?` has different lookup behavior than
|
|
18
|
+
# `Module#constants` - `const_defined?` searches up to `Object`
|
|
19
|
+
# (top-level constants like `String`, `Integer`, etc.) while
|
|
20
|
+
# `constants` does not, which can cause behavior changes after autocorrection.
|
|
21
|
+
#
|
|
16
22
|
# @example
|
|
17
23
|
# # bad
|
|
18
24
|
# Array.instance_methods.include?(:size)
|
|
@@ -28,14 +34,12 @@ module RuboCop
|
|
|
28
34
|
#
|
|
29
35
|
# # bad
|
|
30
36
|
# Array.class_variables.include?(:foo)
|
|
31
|
-
# Array.constants.include?(:foo)
|
|
32
37
|
# Array.private_instance_methods.include?(:foo)
|
|
33
38
|
# Array.protected_instance_methods.include?(:foo)
|
|
34
39
|
# Array.public_instance_methods.include?(:foo)
|
|
35
40
|
#
|
|
36
41
|
# # good
|
|
37
42
|
# Array.class_variable_defined?(:foo)
|
|
38
|
-
# Array.const_defined?(:foo)
|
|
39
43
|
# Array.private_method_defined?(:foo)
|
|
40
44
|
# Array.protected_method_defined?(:foo)
|
|
41
45
|
# Array.public_method_defined?(:foo)
|
|
@@ -55,7 +59,6 @@ module RuboCop
|
|
|
55
59
|
|
|
56
60
|
METHOD_REPLACEMENTS = {
|
|
57
61
|
class_variables: :class_variable_defined?,
|
|
58
|
-
constants: :const_defined?,
|
|
59
62
|
instance_methods: :method_defined?,
|
|
60
63
|
private_instance_methods: :private_method_defined?,
|
|
61
64
|
protected_instance_methods: :protected_method_defined?,
|
|
@@ -99,6 +99,7 @@ module RuboCop
|
|
|
99
99
|
end
|
|
100
100
|
return unless key
|
|
101
101
|
return if accumulator_used_in_expressions?(block_node, key, value)
|
|
102
|
+
return if nested_match?(key) || nested_match?(value)
|
|
102
103
|
|
|
103
104
|
register_offense(node, block_node, key, value)
|
|
104
105
|
end
|
|
@@ -108,6 +109,21 @@ module RuboCop
|
|
|
108
109
|
references_variable?(key, acc_name) || references_variable?(value, acc_name)
|
|
109
110
|
end
|
|
110
111
|
|
|
112
|
+
def nested_match?(node)
|
|
113
|
+
node.each_node(:call).any? do |send_node|
|
|
114
|
+
next false unless RESTRICT_ON_SEND.include?(send_node.method_name)
|
|
115
|
+
|
|
116
|
+
inner_block = send_node.block_node
|
|
117
|
+
next false unless inner_block
|
|
118
|
+
|
|
119
|
+
if send_node.method?(:each_with_object)
|
|
120
|
+
each_with_object_to_hash?(inner_block)
|
|
121
|
+
else
|
|
122
|
+
inject_to_hash?(inner_block)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
111
127
|
def accumulator_name(block_node)
|
|
112
128
|
index = block_node.method?(:each_with_object) ? 1 : 0
|
|
113
129
|
block_node.argument_list[index].name
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for the instantiation of array using redundant `Array` constructor.
|
|
7
|
-
# Autocorrect replaces
|
|
6
|
+
# Checks for the instantiation of an array using a redundant `Array` constructor.
|
|
7
|
+
# Autocorrect replaces it with an array literal which is the simplest and fastest.
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
10
10
|
#
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Avoid redundant `::` prefix on constant.
|
|
6
|
+
# Avoid redundant `::` prefix on a constant.
|
|
7
7
|
#
|
|
8
|
-
# How Ruby searches
|
|
8
|
+
# How Ruby searches constants is a bit complicated, and it can often be difficult to
|
|
9
9
|
# understand from the code whether the `::` is intended or not. Where `Module.nesting`
|
|
10
10
|
# is empty, there is no need to prepend `::`, so it would be nice to consistently
|
|
11
11
|
# avoid such meaningless `::` prefix to avoid confusion.
|
|
12
12
|
#
|
|
13
|
-
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled
|
|
14
|
-
# conflicting rules.
|
|
15
|
-
# `Lint/ConstantResolution` cop which is disabled by default.
|
|
13
|
+
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled,
|
|
14
|
+
# to prevent conflicting rules. This is because it respects user configurations
|
|
15
|
+
# that want to enable `Lint/ConstantResolution` cop which is disabled by default.
|
|
16
16
|
#
|
|
17
17
|
# @example
|
|
18
18
|
# # bad
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.
|
|
7
|
-
# Autocorrect replaces
|
|
6
|
+
# Checks for the instantiation of a regexp using a redundant `Regexp.new` or `Regexp.compile`.
|
|
7
|
+
# Autocorrect replaces it with a regexp literal which is the simplest and fastest.
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
10
10
|
#
|
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
|
59
59
|
|
|
60
60
|
def initialize(config = nil, options = nil)
|
|
61
61
|
super
|
|
62
|
-
@allowed_send_nodes =
|
|
62
|
+
@allowed_send_nodes = Set.new.compare_by_identity
|
|
63
63
|
@local_variables_scopes = Hash.new { |hash, key| hash[key] = [] }.compare_by_identity
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -187,7 +187,7 @@ module RuboCop
|
|
|
187
187
|
def allow_self(node)
|
|
188
188
|
return unless node.send_type? && node.self_receiver?
|
|
189
189
|
|
|
190
|
-
@allowed_send_nodes
|
|
190
|
+
@allowed_send_nodes.add(node)
|
|
191
191
|
end
|
|
192
192
|
|
|
193
193
|
def add_lhs_to_local_variables_scopes(rhs, lhs)
|
|
@@ -5,8 +5,8 @@ module RuboCop
|
|
|
5
5
|
module Style
|
|
6
6
|
# Enforces using `//` or `%r` around regular expressions.
|
|
7
7
|
#
|
|
8
|
-
# NOTE: The following `%r` cases using a regexp starts with a blank or `=`
|
|
9
|
-
# as a method argument allowed to prevent syntax errors.
|
|
8
|
+
# NOTE: The following `%r` cases using a regexp that starts with a blank or `=`
|
|
9
|
+
# as a method argument are allowed to prevent syntax errors.
|
|
10
10
|
#
|
|
11
11
|
# [source,ruby]
|
|
12
12
|
# ----
|
|
@@ -98,7 +98,16 @@ module RuboCop
|
|
|
98
98
|
MSG_USE_SLASHES = 'Use `//` around regular expression.'
|
|
99
99
|
MSG_USE_PERCENT_R = 'Use `%r` around regular expression.'
|
|
100
100
|
|
|
101
|
+
PAIR_DELIMITER_PATTERNS = {
|
|
102
|
+
['(', ')'] => /\\.|[()]/,
|
|
103
|
+
['[', ']'] => /\\.|[\[\]]/,
|
|
104
|
+
['{', '}'] => /\\.|[{}]/,
|
|
105
|
+
['<', '>'] => /\\.|[<>]/
|
|
106
|
+
}.freeze
|
|
107
|
+
|
|
101
108
|
def on_regexp(node)
|
|
109
|
+
return if slash_literal?(node) && percent_r_delimiters_conflict?(node)
|
|
110
|
+
|
|
102
111
|
message = if slash_literal?(node)
|
|
103
112
|
MSG_USE_PERCENT_R unless allowed_slash_literal?(node)
|
|
104
113
|
else
|
|
@@ -115,6 +124,26 @@ module RuboCop
|
|
|
115
124
|
|
|
116
125
|
private
|
|
117
126
|
|
|
127
|
+
def percent_r_delimiters_conflict?(node)
|
|
128
|
+
opening, closing = preferred_delimiters
|
|
129
|
+
return false unless (pattern = PAIR_DELIMITER_PATTERNS[[opening, closing]])
|
|
130
|
+
|
|
131
|
+
!balanced_delimiters?(node_body(node), opening, closing, pattern)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def balanced_delimiters?(text, opening, closing, pattern)
|
|
135
|
+
depth = 0
|
|
136
|
+
text.scan(pattern) do |match|
|
|
137
|
+
if match == opening
|
|
138
|
+
depth += 1
|
|
139
|
+
elsif match == closing
|
|
140
|
+
depth -= 1
|
|
141
|
+
return false if depth.negative?
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
depth.zero?
|
|
145
|
+
end
|
|
146
|
+
|
|
118
147
|
def allowed_slash_literal?(node)
|
|
119
148
|
(style == :slashes && !contains_disallowed_slash?(node)) || allowed_mixed_slash?(node)
|
|
120
149
|
end
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of `rescue` in its modifier form is added for following
|
|
6
|
+
# Checks for uses of `rescue` in its modifier form. It is added for the following
|
|
7
7
|
# reasons:
|
|
8
8
|
#
|
|
9
9
|
# * The syntax of modifier form `rescue` can be misleading because it
|
|
10
10
|
# might lead us to believe that `rescue` handles the given exception
|
|
11
|
-
# but it actually
|
|
11
|
+
# but it actually rescues all exceptions to return the given rescue
|
|
12
12
|
# block. In this case, value returned by handle_error or
|
|
13
13
|
# SomeException.
|
|
14
14
|
#
|
|
15
15
|
# * Modifier form `rescue` would rescue all the exceptions. It would
|
|
16
|
-
# silently skip all
|
|
16
|
+
# silently skip all exceptions or errors and handle the error.
|
|
17
17
|
# Example: If `NoMethodError` is raised, modifier form rescue would
|
|
18
18
|
# handle the exception.
|
|
19
19
|
#
|
|
@@ -65,7 +65,10 @@ module RuboCop
|
|
|
65
65
|
|
|
66
66
|
message = format(MSG, conditional_type: node.keyword)
|
|
67
67
|
add_offense(if_branch.loc.keyword, message: message) do |corrector|
|
|
68
|
+
next if ignored_node?(node)
|
|
69
|
+
|
|
68
70
|
autocorrect(corrector, node, if_branch)
|
|
71
|
+
ignore_node(if_branch)
|
|
69
72
|
end
|
|
70
73
|
end
|
|
71
74
|
|
|
@@ -115,9 +118,8 @@ module RuboCop
|
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
def correct_node(corrector, node)
|
|
118
|
-
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
121
|
+
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
119
122
|
corrector.replace(node.condition, chainable_condition(node))
|
|
120
|
-
ignore_node(node)
|
|
121
123
|
end
|
|
122
124
|
|
|
123
125
|
def correct_for_guard_condition_style(corrector, node, if_branch)
|
|
@@ -61,6 +61,8 @@ module RuboCop
|
|
|
61
61
|
corrector.remove(range_with_surrounding_space(parent.loc.end, newlines: false))
|
|
62
62
|
elsif (class_node = parent.parent).body.nil?
|
|
63
63
|
corrector.remove(range_for_empty_class_body(class_node, parent))
|
|
64
|
+
elsif unparenthesized_struct_new?(parent)
|
|
65
|
+
wrap_unparenthesized_call_with_do(corrector, parent)
|
|
64
66
|
else
|
|
65
67
|
corrector.insert_after(parent, ' do')
|
|
66
68
|
end
|
|
@@ -73,6 +75,17 @@ module RuboCop
|
|
|
73
75
|
range_by_whole_lines(class_node.loc.end, include_final_newline: true)
|
|
74
76
|
end
|
|
75
77
|
end
|
|
78
|
+
|
|
79
|
+
def unparenthesized_struct_new?(parent)
|
|
80
|
+
parent.send_type? && parent.arguments.any? && !parent.parenthesized?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def wrap_unparenthesized_call_with_do(corrector, parent)
|
|
84
|
+
args_source = parent.arguments.map(&:source).join(', ')
|
|
85
|
+
range = parent.loc.selector.end.join(parent.source_range.end)
|
|
86
|
+
|
|
87
|
+
corrector.replace(range, "(#{args_source}) do")
|
|
88
|
+
end
|
|
76
89
|
end
|
|
77
90
|
end
|
|
78
91
|
end
|
|
@@ -260,10 +260,10 @@ module RuboCop
|
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
def begin_pos_for_replacement(node)
|
|
263
|
-
|
|
263
|
+
send_node = node.send_node
|
|
264
264
|
|
|
265
|
-
if
|
|
266
|
-
|
|
265
|
+
if send_node.parenthesized? && send_node.arguments.empty?
|
|
266
|
+
send_node.loc.begin.begin_pos
|
|
267
267
|
else
|
|
268
268
|
node.loc.begin.begin_pos
|
|
269
269
|
end
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Newcomers to
|
|
6
|
+
# Newcomers to Ruby applications may write top-level methods,
|
|
7
7
|
# when ideally they should be organized in appropriate classes or modules.
|
|
8
8
|
# This cop looks for definitions of top-level methods and warns about them.
|
|
9
9
|
#
|
|
10
|
-
# However for
|
|
10
|
+
# However, for Ruby scripts it is perfectly fine to use top-level methods.
|
|
11
11
|
# Hence this cop is disabled by default.
|
|
12
12
|
#
|
|
13
13
|
# @example
|
|
@@ -14,11 +14,11 @@ module RuboCop
|
|
|
14
14
|
#
|
|
15
15
|
# `forbid_mixed_logical_operators` style forbids the use of more than one type
|
|
16
16
|
# of logical operators. This makes the `unless` condition easier to read
|
|
17
|
-
# because either all conditions need to be met or any condition
|
|
17
|
+
# because either all conditions need to be met or any condition needs to be met
|
|
18
18
|
# in order for the expression to be truthy or falsey.
|
|
19
19
|
#
|
|
20
|
-
# `forbid_logical_operators` style forbids any use of logical
|
|
21
|
-
# This makes it even
|
|
20
|
+
# `forbid_logical_operators` style forbids any use of logical operators.
|
|
21
|
+
# This makes it even easier to read the `unless` condition as
|
|
22
22
|
# there is only one condition in the expression.
|
|
23
23
|
#
|
|
24
24
|
# @example EnforcedStyle: forbid_mixed_logical_operators (default)
|
|
@@ -16,6 +16,11 @@ module RuboCop
|
|
|
16
16
|
# # good
|
|
17
17
|
# x += 1 while x < 10
|
|
18
18
|
#
|
|
19
|
+
# # good
|
|
20
|
+
# while x < 10
|
|
21
|
+
# y += 1 if x.odd?
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
19
24
|
# # bad
|
|
20
25
|
# until x > 10
|
|
21
26
|
# x += 1
|
|
@@ -24,6 +29,11 @@ module RuboCop
|
|
|
24
29
|
# # good
|
|
25
30
|
# x += 1 until x > 10
|
|
26
31
|
#
|
|
32
|
+
# # good
|
|
33
|
+
# until x > 10
|
|
34
|
+
# y += 1 unless x.even?
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
27
37
|
# # bad
|
|
28
38
|
# x += 100 while x < 500 # a long comment that makes code too long if it were a single line
|
|
29
39
|
#
|
|
@@ -45,6 +55,12 @@ module RuboCop
|
|
|
45
55
|
end
|
|
46
56
|
end
|
|
47
57
|
alias on_until on_while
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def non_eligible_body?(body)
|
|
62
|
+
body&.conditional? || super
|
|
63
|
+
end
|
|
48
64
|
end
|
|
49
65
|
end
|
|
50
66
|
end
|
data/lib/rubocop/cop/team.rb
CHANGED
|
@@ -11,6 +11,9 @@ module RuboCop
|
|
|
11
11
|
# (unless autocorrections happened).
|
|
12
12
|
# rubocop:disable Metrics/ClassLength
|
|
13
13
|
class Team
|
|
14
|
+
InvestigationResult = Struct.new(:report, :corrector)
|
|
15
|
+
private_constant :InvestigationResult
|
|
16
|
+
|
|
14
17
|
# @return [Team]
|
|
15
18
|
def self.new(cop_or_classes, config, options = {})
|
|
16
19
|
# Support v0 api:
|
|
@@ -89,31 +92,25 @@ module RuboCop
|
|
|
89
92
|
|
|
90
93
|
# @return [Commissioner::InvestigationReport]
|
|
91
94
|
def investigate(processed_source, offset: 0, original: processed_source)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# To speed things up, run autocorrecting cops by themselves, and only
|
|
97
|
-
# run the other cops when no corrections are left
|
|
98
|
-
on_duty = roundup_relevant_cops(processed_source)
|
|
95
|
+
result = investigate_with_corrector(processed_source, offset: offset, original: original)
|
|
96
|
+
autocorrect(processed_source, result.corrector)
|
|
97
|
+
result.report
|
|
98
|
+
end
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
# @return [Array<Offense>]
|
|
101
|
+
def investigate_fragments(fragments, original:)
|
|
102
|
+
@updated_source_file = false
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
report = report.merge(investigate_partial(other_cops, processed_source,
|
|
109
|
-
offset: offset, original: original))
|
|
110
|
-
end
|
|
104
|
+
offenses, errors, warnings, corrector =
|
|
105
|
+
fragments.each_with_object([[], [], [], nil]) do |fragment, data|
|
|
106
|
+
investigate_fragment(fragment, original, data)
|
|
107
|
+
end
|
|
111
108
|
|
|
112
|
-
|
|
109
|
+
autocorrect(original, corrector)
|
|
110
|
+
@errors = errors
|
|
111
|
+
@warnings = warnings
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
ensure
|
|
116
|
-
@ready = false
|
|
113
|
+
offenses
|
|
117
114
|
end
|
|
118
115
|
|
|
119
116
|
# @deprecated
|
|
@@ -136,14 +133,13 @@ module RuboCop
|
|
|
136
133
|
|
|
137
134
|
private
|
|
138
135
|
|
|
139
|
-
def autocorrect(processed_source,
|
|
136
|
+
def autocorrect(processed_source, corrector)
|
|
140
137
|
@updated_source_file = false
|
|
141
138
|
return unless autocorrect?
|
|
142
|
-
return
|
|
139
|
+
return unless corrector
|
|
140
|
+
return if corrector.empty?
|
|
143
141
|
|
|
144
|
-
new_source =
|
|
145
|
-
|
|
146
|
-
return unless new_source
|
|
142
|
+
new_source = corrector.rewrite
|
|
147
143
|
|
|
148
144
|
if @options[:stdin]
|
|
149
145
|
# holds source read in from stdin, when --stdin option is used
|
|
@@ -174,6 +170,54 @@ module RuboCop
|
|
|
174
170
|
commissioner.investigate(processed_source, offset: offset, original: original)
|
|
175
171
|
end
|
|
176
172
|
|
|
173
|
+
def investigate_with_corrector(processed_source, offset:, original:)
|
|
174
|
+
be_ready
|
|
175
|
+
|
|
176
|
+
# The autocorrection process may have to be repeated multiple times
|
|
177
|
+
# until there are no corrections left to perform
|
|
178
|
+
# To speed things up, run autocorrecting cops by themselves, and only
|
|
179
|
+
# run the other cops when no corrections are left
|
|
180
|
+
on_duty = roundup_relevant_cops(processed_source)
|
|
181
|
+
|
|
182
|
+
autocorrect_cops, other_cops = on_duty.partition(&:autocorrect?)
|
|
183
|
+
report = investigate_partial(autocorrect_cops, processed_source,
|
|
184
|
+
offset: offset, original: original)
|
|
185
|
+
|
|
186
|
+
corrector = collated_corrector(report, offset: offset, original: original)
|
|
187
|
+
|
|
188
|
+
unless corrector
|
|
189
|
+
# If we corrected some errors, another round of inspection will be
|
|
190
|
+
# done, and any other offenses will be caught then, so only need
|
|
191
|
+
# to check other_cops if no correction was done
|
|
192
|
+
report = report.merge(investigate_partial(other_cops, processed_source,
|
|
193
|
+
offset: offset, original: original))
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
process_errors(processed_source.path, report.errors)
|
|
197
|
+
|
|
198
|
+
InvestigationResult.new(report, corrector)
|
|
199
|
+
ensure
|
|
200
|
+
@ready = false
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def investigate_fragment(fragment, original, data)
|
|
204
|
+
offenses, errors, warnings, corrector = data
|
|
205
|
+
result = investigate_with_corrector(
|
|
206
|
+
fragment[:processed_source],
|
|
207
|
+
offset: fragment[:offset],
|
|
208
|
+
original: original
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
offenses.concat(result.report.offenses)
|
|
212
|
+
if result.corrector
|
|
213
|
+
corrector ||= Corrector.new(original)
|
|
214
|
+
merge_corrector!(corrector, result.corrector, offset: 0)
|
|
215
|
+
data[3] = corrector
|
|
216
|
+
end
|
|
217
|
+
errors.concat(@errors)
|
|
218
|
+
warnings.concat(@warnings)
|
|
219
|
+
end
|
|
220
|
+
|
|
177
221
|
# @return [Array<cop>]
|
|
178
222
|
def roundup_relevant_cops(processed_source)
|
|
179
223
|
cops.select do |cop|
|
|
@@ -200,28 +244,35 @@ module RuboCop
|
|
|
200
244
|
cop.class.support_target_rails_version?(cop.target_rails_version)
|
|
201
245
|
end
|
|
202
246
|
|
|
203
|
-
def
|
|
247
|
+
def collated_corrector(report, offset:, original:)
|
|
248
|
+
return unless autocorrect?
|
|
249
|
+
return if report.processed_source.parser_error
|
|
250
|
+
|
|
204
251
|
corrector = collate_corrections(report, offset: offset, original: original)
|
|
205
252
|
|
|
206
|
-
corrector
|
|
253
|
+
corrector unless corrector.empty?
|
|
207
254
|
end
|
|
208
255
|
|
|
209
256
|
def collate_corrections(report, offset:, original:)
|
|
210
257
|
corrector = Corrector.new(original)
|
|
211
258
|
|
|
212
259
|
each_corrector(report) do |to_merge|
|
|
213
|
-
|
|
214
|
-
if corrector.source_buffer == to_merge.source_buffer
|
|
215
|
-
corrector.merge!(to_merge)
|
|
216
|
-
else
|
|
217
|
-
corrector.import!(to_merge, offset: offset)
|
|
218
|
-
end
|
|
219
|
-
end
|
|
260
|
+
merge_corrector!(corrector, to_merge, offset: offset)
|
|
220
261
|
end
|
|
221
262
|
|
|
222
263
|
corrector
|
|
223
264
|
end
|
|
224
265
|
|
|
266
|
+
def merge_corrector!(corrector, to_merge, offset:)
|
|
267
|
+
suppress_clobbering do
|
|
268
|
+
if corrector.source_buffer == to_merge.source_buffer
|
|
269
|
+
corrector.merge!(to_merge)
|
|
270
|
+
else
|
|
271
|
+
corrector.import!(to_merge, offset: offset)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
225
276
|
def each_corrector(report)
|
|
226
277
|
skips = Set.new
|
|
227
278
|
report.cop_reports.each do |cop_report|
|
|
@@ -21,11 +21,19 @@ module RuboCop
|
|
|
21
21
|
def initialize(patterns)
|
|
22
22
|
@strings = Set.new
|
|
23
23
|
@patterns = []
|
|
24
|
+
@match_cache = {}
|
|
24
25
|
partition_patterns(patterns)
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def match?(path)
|
|
28
|
-
|
|
29
|
+
# `FilePatterns.from` memoizes one instance per pattern array (by identity),
|
|
30
|
+
# so this cache is shared across every cop using the same Include/Exclude
|
|
31
|
+
# list. Patterns are immutable within a run, so caching by path is safe.
|
|
32
|
+
cached = @match_cache[path]
|
|
33
|
+
return cached unless cached.nil?
|
|
34
|
+
|
|
35
|
+
@match_cache[path] =
|
|
36
|
+
@strings.include?(path) || @patterns.any? { |pattern| PathUtil.match_path?(pattern, path) }
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
private
|
|
@@ -131,6 +131,9 @@ module RuboCop
|
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
def set_max(cfg, cop_name)
|
|
134
|
+
exclude_limits = RuboCop::ExcludeLimit.read_limits(cop_name)
|
|
135
|
+
cfg[:exclude_limit] = exclude_limits unless exclude_limits.empty?
|
|
136
|
+
|
|
134
137
|
return unless cfg[:exclude_limit]
|
|
135
138
|
|
|
136
139
|
cfg.merge!(cfg[:exclude_limit]) if should_set_max?(cop_name)
|
|
@@ -192,7 +195,7 @@ module RuboCop
|
|
|
192
195
|
next unless value.is_a?(Array)
|
|
193
196
|
next if value.empty?
|
|
194
197
|
|
|
195
|
-
value.map
|
|
198
|
+
value = value.map { |v| v.nil? ? '~' : v } # Change nil back to ~ as in the YAML file.
|
|
196
199
|
output_buffer.puts "# #{param}: #{value.uniq.join(', ')}"
|
|
197
200
|
end
|
|
198
201
|
end
|
data/lib/rubocop/lsp/runtime.rb
CHANGED
|
@@ -23,7 +23,6 @@ module RuboCop
|
|
|
23
23
|
RuboCop::LSP.enable
|
|
24
24
|
|
|
25
25
|
@runner = RuboCop::Lsp::StdinRunner.new(config_store)
|
|
26
|
-
@cop_registry = RuboCop::Cop::Registry.global.to_h
|
|
27
26
|
|
|
28
27
|
@safe_autocorrect = true
|
|
29
28
|
@lint_mode = false
|
|
@@ -63,7 +62,7 @@ module RuboCop
|
|
|
63
62
|
document_encoding,
|
|
64
63
|
offense,
|
|
65
64
|
path,
|
|
66
|
-
|
|
65
|
+
RuboCop::Cop::Registry.global.find_by_cop_name(offense.cop_name),
|
|
67
66
|
processed_source
|
|
68
67
|
).to_lsp_diagnostic(config)
|
|
69
68
|
end
|