rubocop 1.91.0 → 1.92.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/README.md +1 -1
- data/config/default.yml +3 -1
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +35 -13
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +2 -2
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/show_cops.rb +6 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
- data/lib/rubocop/cli.rb +3 -2
- data/lib/rubocop/comment_config.rb +17 -8
- data/lib/rubocop/config_loader.rb +6 -3
- data/lib/rubocop/config_loader_resolver.rb +37 -12
- data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
- data/lib/rubocop/config_validator.rb +11 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/base.rb +42 -21
- data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
- data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/class_structure.rb +9 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +52 -18
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
- data/lib/rubocop/cop/lint/void.rb +8 -1
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/mixin/alignment.rb +4 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
- data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
- data/lib/rubocop/cop/mixin.rb +2 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +7 -0
- data/lib/rubocop/cop/style/alias.rb +18 -5
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +4 -1
- data/lib/rubocop/cop/style/attr.rb +3 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
- data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
- data/lib/rubocop/cop/style/case_like_if.rb +6 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +67 -6
- data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/float_division.rb +22 -2
- data/lib/rubocop/cop/style/for.rb +40 -2
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +9 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +32 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +18 -0
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
- data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
- data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
- data/lib/rubocop/cop/style/not.rb +10 -5
- data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +9 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/sample.rb +9 -8
- data/lib/rubocop/cop/style/self_assignment.rb +12 -15
- data/lib/rubocop/cop/style/semicolon.rb +16 -5
- data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
- data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
- data/lib/rubocop/cop/team.rb +10 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/formatter_set.rb +4 -0
- data/lib/rubocop/formatter/json_formatter.rb +71 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/lsp/runtime.rb +47 -11
- data/lib/rubocop/lsp/stdin_runner.rb +11 -5
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +184 -76
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +45 -10
- data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
- data/lib/rubocop/remote_config.rb +4 -1
- data/lib/rubocop/result_cache.rb +20 -13
- data/lib/rubocop/runner.rb +109 -41
- data/lib/rubocop/server/cache.rb +2 -2
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -5
|
@@ -121,7 +121,6 @@ module RuboCop
|
|
|
121
121
|
tokens[1]&.type == :tSTRING_DBEG && tokens[2]&.semicolon?
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
|
|
125
124
|
def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
|
|
126
125
|
range = source_range(processed_source.buffer, line, column)
|
|
127
126
|
|
|
@@ -134,13 +133,11 @@ module RuboCop
|
|
|
134
133
|
# See: https://github.com/rubocop/rubocop/issues/10791
|
|
135
134
|
if token_before_semicolon&.regexp_dots?
|
|
136
135
|
node = find_node(range_nodes, token_before_semicolon)
|
|
136
|
+
corrector.wrap(node, '(', ')') if node
|
|
137
137
|
elsif token_before_semicolon&.type == :tLABEL
|
|
138
|
-
|
|
139
|
-
space = node.parent.loc.selector.end.join(node.source_range.begin)
|
|
140
|
-
corrector.remove(space)
|
|
138
|
+
parenthesize_arguments(corrector, value_omission_hash(token_before_semicolon))
|
|
141
139
|
end
|
|
142
140
|
|
|
143
|
-
corrector.wrap(node, '(', ')') if node
|
|
144
141
|
corrector.remove(range)
|
|
145
142
|
end
|
|
146
143
|
end
|
|
@@ -161,6 +158,20 @@ module RuboCop
|
|
|
161
158
|
end
|
|
162
159
|
end
|
|
163
160
|
|
|
161
|
+
def value_omission_hash(token_before_semicolon)
|
|
162
|
+
find_node(value_omission_pair_nodes, token_before_semicolon)&.parent
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def parenthesize_arguments(corrector, hash_node)
|
|
166
|
+
return unless hash_node
|
|
167
|
+
|
|
168
|
+
call = hash_node.parent
|
|
169
|
+
before_arguments = args_begin(call).begin.join(call.first_argument.source_range.begin)
|
|
170
|
+
|
|
171
|
+
corrector.replace(before_arguments, '(')
|
|
172
|
+
corrector.insert_after(call.last_argument, ')')
|
|
173
|
+
end
|
|
174
|
+
|
|
164
175
|
def expressions_per_line(exprs)
|
|
165
176
|
# create a map matching lines to the number of expressions on them
|
|
166
177
|
exprs_lines = exprs.map(&:last_line)
|
|
@@ -35,6 +35,7 @@ module RuboCop
|
|
|
35
35
|
#
|
|
36
36
|
class SingleLineMethods < Base
|
|
37
37
|
include Alignment
|
|
38
|
+
include EndlessMethodBodyHelp
|
|
38
39
|
extend AutoCorrector
|
|
39
40
|
|
|
40
41
|
MSG = 'Avoid single-line method definitions.'
|
|
@@ -67,10 +68,14 @@ module RuboCop
|
|
|
67
68
|
return false if target_ruby_version < 3.0
|
|
68
69
|
return false if disallow_endless_method_style?
|
|
69
70
|
return false unless body_node
|
|
70
|
-
return false if body_node.
|
|
71
|
-
NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
|
|
71
|
+
return false if body_node.parent.assignment_method?
|
|
72
72
|
|
|
73
|
-
!body_node
|
|
73
|
+
!unsupported_endless_method_body?(body_node) && endless_method_body?(body_node)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def unsupported_endless_method_body?(body_node)
|
|
77
|
+
body_node.basic_conditional? ||
|
|
78
|
+
NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
|
|
74
79
|
end
|
|
75
80
|
|
|
76
81
|
def correct_to_multiline(corrector, node)
|
|
@@ -89,8 +94,8 @@ module RuboCop
|
|
|
89
94
|
|
|
90
95
|
def correct_to_endless(corrector, node)
|
|
91
96
|
receiver = "#{node.receiver.source}." if node.receiver
|
|
92
|
-
arguments = node.arguments.any? ? node.arguments.source : '()'
|
|
93
97
|
body_source = method_body_source(node.body)
|
|
98
|
+
arguments = endless_arguments(node)
|
|
94
99
|
replacement = "def #{receiver}#{node.method_name}#{arguments} = #{body_source}"
|
|
95
100
|
|
|
96
101
|
corrector.replace(node, replacement)
|
|
@@ -138,6 +143,13 @@ module RuboCop
|
|
|
138
143
|
!method_body.arguments.empty? && !method_body.comparison_method?
|
|
139
144
|
end
|
|
140
145
|
|
|
146
|
+
def endless_arguments(node)
|
|
147
|
+
arguments = node.arguments
|
|
148
|
+
return '()' if arguments.none?
|
|
149
|
+
|
|
150
|
+
arguments.loc.begin ? arguments.source : "(#{arguments.source})"
|
|
151
|
+
end
|
|
152
|
+
|
|
141
153
|
def disallow_endless_method_style?
|
|
142
154
|
return true unless config.cop_enabled?('Style/EndlessMethod')
|
|
143
155
|
|
|
@@ -50,7 +50,33 @@ module RuboCop
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def redundant_parentheses?(node)
|
|
53
|
-
style == :require_no_parentheses && parentheses?(node)
|
|
53
|
+
return false unless style == :require_no_parentheses && parentheses?(node)
|
|
54
|
+
|
|
55
|
+
arguments = node.block_node.arguments
|
|
56
|
+
!arguments_require_parentheses?(arguments) && !comment_inside_parentheses?(arguments)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def arguments_require_parentheses?(arguments)
|
|
60
|
+
arguments.each_descendant(:any_block, :hash).any? do |node|
|
|
61
|
+
!node.hash_type? || node.braces?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def comment_inside_parentheses?(arguments)
|
|
66
|
+
!leading_padding(arguments).source.strip.empty? ||
|
|
67
|
+
!trailing_padding(arguments).source.strip.empty?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def leading_padding(arguments)
|
|
71
|
+
first_argument = arguments.children.first
|
|
72
|
+
|
|
73
|
+
arguments.loc.begin.end.join(first_argument.source_range.begin)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def trailing_padding(arguments)
|
|
77
|
+
last_argument = arguments.children.last
|
|
78
|
+
|
|
79
|
+
last_argument.source_range.end.join(arguments.loc.end.begin)
|
|
54
80
|
end
|
|
55
81
|
|
|
56
82
|
def message(_node)
|
|
@@ -62,10 +88,8 @@ module RuboCop
|
|
|
62
88
|
end
|
|
63
89
|
|
|
64
90
|
def unwanted_parentheses_corrector(corrector, node)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
corrector.replace(args_loc.begin, '')
|
|
68
|
-
corrector.remove(args_loc.end)
|
|
91
|
+
corrector.remove(node.loc.begin.join(leading_padding(node)))
|
|
92
|
+
corrector.remove(trailing_padding(node).join(node.loc.end))
|
|
69
93
|
end
|
|
70
94
|
|
|
71
95
|
def stabby_lambda_with_args?(node)
|
|
@@ -160,7 +160,9 @@ module RuboCop
|
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
def adjust_str_literal(part)
|
|
163
|
-
if
|
|
163
|
+
if file_keyword?(part)
|
|
164
|
+
"\#{#{part.source}}"
|
|
165
|
+
elsif single_quoted?(part)
|
|
164
166
|
part.value.gsub(/(\\|"|#\{|#@|#\$)/, '\\\\\&')
|
|
165
167
|
elsif double_quoted?(part)
|
|
166
168
|
# Reuse the source as written - rebuilding it from the value via
|
|
@@ -178,12 +180,16 @@ module RuboCop
|
|
|
178
180
|
end
|
|
179
181
|
end
|
|
180
182
|
|
|
183
|
+
def file_keyword?(str_node)
|
|
184
|
+
str_node.source == '__FILE__' && !str_node.parent.dstr_type?
|
|
185
|
+
end
|
|
186
|
+
|
|
181
187
|
def single_quoted?(str_node)
|
|
182
|
-
str_node.source.start_with?("'")
|
|
188
|
+
str_node.loc.begin && str_node.source.start_with?("'")
|
|
183
189
|
end
|
|
184
190
|
|
|
185
191
|
def double_quoted?(str_node)
|
|
186
|
-
str_node.source.start_with?('"')
|
|
192
|
+
str_node.loc.begin && str_node.source.start_with?('"')
|
|
187
193
|
end
|
|
188
194
|
|
|
189
195
|
def mode
|
|
@@ -76,6 +76,9 @@ module RuboCop
|
|
|
76
76
|
|
|
77
77
|
def on_super(super_node)
|
|
78
78
|
return unless (def_node = find_def_node(super_node))
|
|
79
|
+
# Zsuper passes a destructured argument as the original value, while
|
|
80
|
+
# `argument_list` flattens it into its parts.
|
|
81
|
+
return if def_node.arguments.any?(&:mlhs_type?)
|
|
79
82
|
|
|
80
83
|
def_node_args = def_node.arguments.argument_list
|
|
81
84
|
super_args = preprocess_super_args(super_node.arguments)
|
|
@@ -142,9 +142,11 @@ module RuboCop
|
|
|
142
142
|
include RangeHelp
|
|
143
143
|
include AllowedMethods
|
|
144
144
|
include AllowedPattern
|
|
145
|
+
include PatternMatchingHelp
|
|
145
146
|
extend AutoCorrector
|
|
146
147
|
|
|
147
148
|
MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` instead of a block.'
|
|
149
|
+
MSG_LAMBDA_LITERAL = 'Use `lambda(&:%<method>s)` instead of %<original>s.'
|
|
148
150
|
SUPER_TYPES = %i[super zsuper].freeze
|
|
149
151
|
LAMBDA_OR_PROC = %i[lambda proc].freeze
|
|
150
152
|
|
|
@@ -174,6 +176,8 @@ module RuboCop
|
|
|
174
176
|
return if proc_node?(dispatch_node)
|
|
175
177
|
return if LAMBDA_OR_PROC.include?(dispatch_node.method_name)
|
|
176
178
|
end
|
|
179
|
+
# A pattern accepts a lambda literal, but not `lambda(&:foo)`.
|
|
180
|
+
return if in_pattern?(node)
|
|
177
181
|
return if unsafe_hash_usage?(dispatch_node)
|
|
178
182
|
return if unsafe_array_usage?(dispatch_node)
|
|
179
183
|
return if allowed_method_name?(dispatch_node.method_name)
|
|
@@ -207,12 +211,26 @@ module RuboCop
|
|
|
207
211
|
end
|
|
208
212
|
|
|
209
213
|
def register_offense(node, method_name, block_method_name)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
range = if node.send_node.lambda_literal?
|
|
215
|
+
node.source_range
|
|
216
|
+
else
|
|
217
|
+
node.loc.begin.begin.join(node.loc.end.end)
|
|
218
|
+
end
|
|
219
|
+
message = message(node, method_name, block_method_name)
|
|
214
220
|
|
|
215
|
-
add_offense(range, message: message)
|
|
221
|
+
add_offense(range, message: message) do |corrector|
|
|
222
|
+
autocorrect(corrector, node)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def message(node, method_name, block_method_name)
|
|
227
|
+
if node.send_node.lambda_literal?
|
|
228
|
+
original = node.single_line? ? "`#{node.source}`" : 'a lambda literal with a block'
|
|
229
|
+
|
|
230
|
+
format(MSG_LAMBDA_LITERAL, method: method_name, original: original)
|
|
231
|
+
else
|
|
232
|
+
format(MSG, method: method_name, block_method: block_method_name)
|
|
233
|
+
end
|
|
216
234
|
end
|
|
217
235
|
|
|
218
236
|
def autocorrect(corrector, node)
|
|
@@ -58,6 +58,7 @@ module RuboCop
|
|
|
58
58
|
include SafeAssignment
|
|
59
59
|
include ConfigurableEnforcedStyle
|
|
60
60
|
include SurroundingSpace
|
|
61
|
+
include ReparsedEquivalence
|
|
61
62
|
extend AutoCorrector
|
|
62
63
|
|
|
63
64
|
VARIABLE_TYPES = AST::Node::VARIABLES
|
|
@@ -101,7 +102,8 @@ module RuboCop
|
|
|
101
102
|
condition = node.condition
|
|
102
103
|
|
|
103
104
|
return nil if parenthesized?(condition) &&
|
|
104
|
-
(safe_assignment?(condition) || unsafe_autocorrect?(condition)
|
|
105
|
+
(safe_assignment?(condition) || unsafe_autocorrect?(condition) ||
|
|
106
|
+
verified_by_reparse([condition]).empty?)
|
|
105
107
|
|
|
106
108
|
if parenthesized?(condition)
|
|
107
109
|
correct_parenthesized(corrector, condition)
|
|
@@ -218,6 +220,26 @@ module RuboCop
|
|
|
218
220
|
end
|
|
219
221
|
end
|
|
220
222
|
|
|
223
|
+
# Whatever binds looser than the ternary operator (`n += 1`, `a rescue b`,
|
|
224
|
+
# a nested ternary, `yield a`, several statements, ...) changes
|
|
225
|
+
# meaning without the parentheses, so their removal is verified by
|
|
226
|
+
# reparsing.
|
|
227
|
+
def apply_reparse_correction(corrector, condition)
|
|
228
|
+
correct_parenthesized(corrector, condition)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# The removed parentheses are the only expected difference.
|
|
232
|
+
def normalize_reparsed_ast(node)
|
|
233
|
+
return node unless node.is_a?(::Parser::AST::Node)
|
|
234
|
+
|
|
235
|
+
children = node.children.map { |child| normalize_reparsed_ast(child) }
|
|
236
|
+
if node.begin_type? && children.one? && children.first.is_a?(::Parser::AST::Node)
|
|
237
|
+
children.first
|
|
238
|
+
else
|
|
239
|
+
node.updated(nil, children)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
221
243
|
def correct_unparenthesized(corrector, condition)
|
|
222
244
|
corrector.wrap(condition, '(', ')')
|
|
223
245
|
end
|
|
@@ -35,19 +35,20 @@ module RuboCop
|
|
|
35
35
|
|
|
36
36
|
MSG = 'Do not use trailing `_`s in parallel assignment. Prefer `%<code>s`.'
|
|
37
37
|
UNDERSCORE = '_'
|
|
38
|
+
ARRAY_OPENING = '['
|
|
38
39
|
DISALLOW = %i[lvasgn splat].freeze
|
|
39
40
|
private_constant :DISALLOW
|
|
40
41
|
|
|
41
42
|
def on_masgn(node)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ranges.each do |range|
|
|
43
|
+
unneeded_ranges(node).each do |range, replacement|
|
|
44
|
+
closing = replacement == ARRAY_OPENING ? ']' : ''
|
|
45
45
|
good_code = node.source
|
|
46
46
|
offset = range.begin_pos - node.source_range.begin_pos
|
|
47
|
-
good_code[offset, range.size] =
|
|
47
|
+
good_code[offset, range.size] = replacement
|
|
48
48
|
|
|
49
|
-
add_offense(range, message: format(MSG, code: good_code)) do |corrector|
|
|
50
|
-
corrector.
|
|
49
|
+
add_offense(range, message: format(MSG, code: "#{good_code}#{closing}")) do |corrector|
|
|
50
|
+
corrector.replace(range, replacement)
|
|
51
|
+
corrector.insert_after(node, closing) unless closing.empty?
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
end
|
|
@@ -115,9 +116,12 @@ module RuboCop
|
|
|
115
116
|
|
|
116
117
|
return unused_range(node, mlhs_node) if unused_variables_only?(first_offense, variables)
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
range = if Util.parentheses?(mlhs_node)
|
|
120
|
+
range_for_parentheses(first_offense, mlhs_node)
|
|
121
|
+
else
|
|
122
|
+
range_between(first_offense.source_range.begin_pos, node.loc.operator.begin_pos)
|
|
123
|
+
end
|
|
124
|
+
[range, '']
|
|
121
125
|
end
|
|
122
126
|
|
|
123
127
|
def children_offenses(variables)
|
|
@@ -129,17 +133,17 @@ module RuboCop
|
|
|
129
133
|
end
|
|
130
134
|
|
|
131
135
|
def unused_range(node, mlhs_node)
|
|
132
|
-
start_range = mlhs_node.source_range.begin_pos
|
|
133
|
-
|
|
134
136
|
# `node` can be an `mlhs` when recursing into a nested destructuring
|
|
135
|
-
# group
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
# group. Removing the group could leave a dangling comma or put
|
|
138
|
+
# something after a splat, so it is collapsed into a single `_`,
|
|
139
|
+
# which the parent group handles in turn.
|
|
140
|
+
return [mlhs_node.source_range, UNDERSCORE] unless node.masgn_type?
|
|
141
|
+
|
|
142
|
+
rhs = node.rhs
|
|
143
|
+
range = range_between(mlhs_node.source_range.begin_pos, rhs.source_range.begin_pos)
|
|
144
|
+
|
|
145
|
+
# `_, _ = 1, 2` cannot become `1, 2`, so the values become an array literal.
|
|
146
|
+
[range, rhs.array_type? && !rhs.bracketed? ? ARRAY_OPENING : '']
|
|
143
147
|
end
|
|
144
148
|
|
|
145
149
|
def range_for_parentheses(offense, left)
|
|
@@ -104,7 +104,7 @@ module RuboCop
|
|
|
104
104
|
valid_yoda?(node)
|
|
105
105
|
|
|
106
106
|
add_offense(node) do |corrector|
|
|
107
|
-
corrector
|
|
107
|
+
autocorrect(corrector, node)
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
|
|
@@ -138,22 +138,37 @@ module RuboCop
|
|
|
138
138
|
format(MSG, source: node.source)
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
def
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
def autocorrect(corrector, node)
|
|
142
|
+
if constant_portion?(node.first_argument)
|
|
143
|
+
move_argument_to_front(corrector, node)
|
|
144
|
+
else
|
|
145
|
+
move_receiver_to_back(corrector, node)
|
|
146
|
+
end
|
|
146
147
|
end
|
|
147
148
|
|
|
148
149
|
def constant_portion?(node)
|
|
149
150
|
node.recursive_literal? || node.const_type?
|
|
150
151
|
end
|
|
151
152
|
|
|
152
|
-
def
|
|
153
|
-
|
|
153
|
+
def move_argument_to_front(corrector, node)
|
|
154
|
+
receiver = node.receiver
|
|
155
|
+
|
|
156
|
+
replacement = "#{node.first_argument.source} #{reverse_comparison(node)} "
|
|
157
|
+
|
|
158
|
+
corrector.insert_before(receiver, replacement)
|
|
159
|
+
corrector.remove(receiver.source_range.end.join(node.source_range.end))
|
|
154
160
|
end
|
|
155
161
|
|
|
156
|
-
def
|
|
162
|
+
def move_receiver_to_back(corrector, node)
|
|
163
|
+
argument = node.first_argument
|
|
164
|
+
|
|
165
|
+
corrector.remove(node.source_range.begin.join(argument.source_range.begin))
|
|
166
|
+
corrector.insert_after(argument, " #{reverse_comparison(node)} #{node.receiver.source}")
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def reverse_comparison(node)
|
|
170
|
+
operator = node.method_name
|
|
171
|
+
|
|
157
172
|
REVERSE_COMPARISON.fetch(operator.to_s, operator)
|
|
158
173
|
end
|
|
159
174
|
|
|
@@ -43,6 +43,9 @@ module RuboCop
|
|
|
43
43
|
MSG = 'Non-literal operand (`%<source>s`) should be first.'
|
|
44
44
|
|
|
45
45
|
RESTRICT_ON_SEND = %i[* + & | ^].freeze
|
|
46
|
+
ARGUMENT_ONLY_TYPES = %i[
|
|
47
|
+
splat block_pass forwarded_args forwarded_restarg forwarded_kwrestarg
|
|
48
|
+
].freeze
|
|
46
49
|
|
|
47
50
|
def on_new_investigation
|
|
48
51
|
@offended_nodes = nil
|
|
@@ -68,13 +71,19 @@ module RuboCop
|
|
|
68
71
|
private
|
|
69
72
|
|
|
70
73
|
def yoda_expression_constant?(lhs, rhs)
|
|
71
|
-
constant_portion?(lhs) && !constant_portion?(rhs)
|
|
74
|
+
constant_portion?(lhs) && !constant_portion?(rhs) && operand?(rhs)
|
|
72
75
|
end
|
|
73
76
|
|
|
74
77
|
def constant_portion?(node)
|
|
75
78
|
node.type?(:numeric, :const)
|
|
76
79
|
end
|
|
77
80
|
|
|
81
|
+
def operand?(node)
|
|
82
|
+
return false if node.hash_type? && !node.braces?
|
|
83
|
+
|
|
84
|
+
!node.type?(*ARGUMENT_ONLY_TYPES)
|
|
85
|
+
end
|
|
86
|
+
|
|
78
87
|
def supported_operators
|
|
79
88
|
@supported_operators ||= Array(cop_config['SupportedOperators']).freeze
|
|
80
89
|
end
|
data/lib/rubocop/cop/team.rb
CHANGED
|
@@ -178,7 +178,7 @@ module RuboCop
|
|
|
178
178
|
elsif defer_corrections
|
|
179
179
|
@updated_source = new_source
|
|
180
180
|
else
|
|
181
|
-
|
|
181
|
+
RuboCop::Util.replace_file_contents(processed_source.file_path, new_source)
|
|
182
182
|
end
|
|
183
183
|
end
|
|
184
184
|
|
|
@@ -342,20 +342,25 @@ module RuboCop
|
|
|
342
342
|
end
|
|
343
343
|
|
|
344
344
|
def each_corrector(report)
|
|
345
|
-
|
|
345
|
+
applied = []
|
|
346
346
|
report.cop_reports.each do |cop_report|
|
|
347
|
-
|
|
347
|
+
cop_class = cop_report.cop.class
|
|
348
348
|
corrector = cop_report.corrector
|
|
349
349
|
|
|
350
350
|
next if corrector.nil? || corrector.empty?
|
|
351
|
-
next if
|
|
351
|
+
next if applied.any? { |other| autocorrect_incompatible?(cop_class, other) }
|
|
352
352
|
|
|
353
353
|
yield corrector
|
|
354
354
|
|
|
355
|
-
|
|
355
|
+
applied << cop_class
|
|
356
356
|
end
|
|
357
357
|
end
|
|
358
358
|
|
|
359
|
+
def autocorrect_incompatible?(cop_class, other)
|
|
360
|
+
cop_class.autocorrect_incompatible_with.include?(other) ||
|
|
361
|
+
other.autocorrect_incompatible_with.include?(cop_class)
|
|
362
|
+
end
|
|
363
|
+
|
|
359
364
|
def suppress_clobbering
|
|
360
365
|
yield
|
|
361
366
|
rescue ::Parser::ClobberingError
|
|
@@ -67,7 +67,8 @@ module RuboCop
|
|
|
67
67
|
|
|
68
68
|
break if !assignment.branch || assignment.branch == reference.branch
|
|
69
69
|
|
|
70
|
-
unless assignment.branch.may_run_incompletely?
|
|
70
|
+
unless assignment.branch.may_run_incompletely? ||
|
|
71
|
+
exception_may_reach?(assignment.branch, node)
|
|
71
72
|
(consumed_branches ||= Set.new) << assignment.branch
|
|
72
73
|
end
|
|
73
74
|
end
|
|
@@ -83,6 +84,18 @@ module RuboCop
|
|
|
83
84
|
covers?(conditional, reference_node) && !covers?(conditional.condition, reference_node)
|
|
84
85
|
end
|
|
85
86
|
|
|
87
|
+
# A branch nested in the main body of `begin` can be cut short by an exception
|
|
88
|
+
# too. An earlier assignment in it is visible to a reference in the `rescue` or
|
|
89
|
+
# `ensure` clause, or after a `rescue` that handles the exception.
|
|
90
|
+
def exception_may_reach?(branch, reference_node)
|
|
91
|
+
branch.each_ancestor.any? do |ancestor|
|
|
92
|
+
next false unless ancestor.may_run_incompletely?
|
|
93
|
+
next false if covers?(ancestor.child_node, reference_node)
|
|
94
|
+
|
|
95
|
+
ancestor.control_node.rescue_type? || covers?(ancestor.control_node, reference_node)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
86
99
|
def modifier_conditional_of(node)
|
|
87
100
|
node.each_ancestor(:if, :while, :until).find do |conditional|
|
|
88
101
|
conditional.modifier_form? && covers?(conditional.condition, node)
|
|
@@ -35,6 +35,7 @@ module RuboCop
|
|
|
35
35
|
# * `#file_started`
|
|
36
36
|
# * `#file_finished`
|
|
37
37
|
# * `#file_started`
|
|
38
|
+
# * `#file_problems` (only when a cop crashed or warned on the file)
|
|
38
39
|
# * `#file_finished`
|
|
39
40
|
# * `#finished`
|
|
40
41
|
#
|
|
@@ -88,6 +89,27 @@ module RuboCop
|
|
|
88
89
|
# @return [void]
|
|
89
90
|
def file_started(file, options); end
|
|
90
91
|
|
|
92
|
+
# @api public
|
|
93
|
+
#
|
|
94
|
+
# Invoked before `#file_finished` for a file that a cop crashed on or
|
|
95
|
+
# raised a warning for, or whose corrections went into an infinite loop.
|
|
96
|
+
# Optional: a formatter implementing the API by duck typing is skipped
|
|
97
|
+
# when it doesn't define it.
|
|
98
|
+
#
|
|
99
|
+
# @param file [String]
|
|
100
|
+
# the file path
|
|
101
|
+
#
|
|
102
|
+
# @param errors [Array(String)]
|
|
103
|
+
# the error messages as they're printed, without colors. A cop that
|
|
104
|
+
# crashes on every node of a kind has a message for each, naming the
|
|
105
|
+
# line and column.
|
|
106
|
+
#
|
|
107
|
+
# @param warnings [Array(String)]
|
|
108
|
+
# the warning messages, in the same form
|
|
109
|
+
#
|
|
110
|
+
# @return [void]
|
|
111
|
+
def file_problems(file, errors, warnings); end
|
|
112
|
+
|
|
91
113
|
# @api public
|
|
92
114
|
#
|
|
93
115
|
# Invoked at the end of inspecting each files.
|
|
@@ -49,6 +49,10 @@ module RuboCop
|
|
|
49
49
|
each { |f| f.file_started(file, options) }
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def file_problems(file, errors, warnings)
|
|
53
|
+
each { |f| f.file_problems(file, errors, warnings) if f.respond_to?(:file_problems) }
|
|
54
|
+
end
|
|
55
|
+
|
|
52
56
|
def file_finished(file, offenses)
|
|
53
57
|
each { |f| f.file_finished(file, offenses) }
|
|
54
58
|
offenses
|