rubocop 1.88.2 → 1.90.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 +139 -16
- data/exe/rubocop +1 -1
- data/lib/rubocop/cached_data.rb +7 -2
- data/lib/rubocop/cli/command/execute_runner.rb +31 -0
- data/lib/rubocop/cli.rb +2 -4
- data/lib/rubocop/comment_config/directive_range.rb +32 -0
- data/lib/rubocop/comment_config/disable_next.rb +97 -0
- data/lib/rubocop/comment_config.rb +81 -49
- data/lib/rubocop/config.rb +76 -5
- data/lib/rubocop/config_loader.rb +1 -2
- data/lib/rubocop/config_loader_resolver.rb +1 -2
- data/lib/rubocop/config_validator.rb +39 -3
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -0
- data/lib/rubocop/cop/badge.rb +8 -0
- data/lib/rubocop/cop/base.rb +40 -6
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/corrector.rb +4 -4
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +55 -5
- data/lib/rubocop/cop/gemspec.rb +22 -0
- data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
- data/lib/rubocop/cop/generator.rb +4 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/class_structure.rb +108 -26
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -2
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +21 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +3 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/line_length.rb +84 -12
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -2
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +12 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +77 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +7 -0
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +31 -34
- data/lib/rubocop/cop/layout.rb +114 -0
- data/lib/rubocop/cop/lazy_loader.rb +41 -0
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -7
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +71 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
- data/lib/rubocop/cop/lint/argument_mismatch.rb +89 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +18 -21
- data/lib/rubocop/cop/lint/constant_resolution.rb +25 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -8
- data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +300 -22
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
- data/lib/rubocop/cop/lint/interpolation_check.rb +1 -2
- data/lib/rubocop/cop/lint/literal_as_condition.rb +8 -6
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -7
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +25 -12
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- data/lib/rubocop/cop/lint/name_typo.rb +270 -0
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +98 -19
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +47 -7
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -2
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -4
- data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +1 -2
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +38 -3
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -2
- data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -2
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +36 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +61 -7
- data/lib/rubocop/cop/lint/void.rb +18 -8
- data/lib/rubocop/cop/lint.rb +178 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics.rb +31 -0
- data/lib/rubocop/cop/migration/department_name.rb +1 -6
- data/lib/rubocop/cop/migration.rb +13 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -5
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +23 -6
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -2
- data/lib/rubocop/cop/mixin/hash_subset.rb +1 -2
- data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +7 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +51 -6
- data/lib/rubocop/cop/mixin/project_index_help.rb +140 -0
- data/lib/rubocop/cop/mixin/range_help.rb +1 -2
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +46 -4
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
- data/lib/rubocop/cop/mixin.rb +82 -77
- data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +16 -0
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -4
- data/lib/rubocop/cop/naming/method_name.rb +5 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +33 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -2
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/naming.rb +31 -0
- data/lib/rubocop/cop/offense.rb +37 -10
- data/lib/rubocop/cop/registry.rb +180 -46
- data/lib/rubocop/cop/security.rb +19 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -6
- data/lib/rubocop/cop/style/array_first_last.rb +1 -2
- data/lib/rubocop/cop/style/array_intersect.rb +24 -5
- data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +3 -6
- data/lib/rubocop/cop/style/case_like_if.rb +2 -4
- data/lib/rubocop/cop/style/class_and_module_children.rb +79 -20
- data/lib/rubocop/cop/style/combinable_loops.rb +1 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +23 -2
- data/lib/rubocop/cop/style/constant_visibility.rb +1 -2
- data/lib/rubocop/cop/style/copyright.rb +5 -1
- data/lib/rubocop/cop/style/directive_scope.rb +171 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +76 -12
- data/lib/rubocop/cop/style/documentation.rb +47 -0
- data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
- data/lib/rubocop/cop/style/endless_method.rb +0 -10
- data/lib/rubocop/cop/style/format_string_token.rb +1 -2
- data/lib/rubocop/cop/style/guard_clause.rb +1 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -4
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +8 -50
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -2
- data/lib/rubocop/cop/style/lambda.rb +4 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +22 -7
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -2
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +30 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -2
- data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +5 -0
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
- data/lib/rubocop/cop/style/negative_array_index.rb +3 -3
- data/lib/rubocop/cop/style/nil_comparison.rb +1 -2
- data/lib/rubocop/cop/style/operator_method_call.rb +1 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -4
- data/lib/rubocop/cop/style/redundant_constant_base.rb +37 -1
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +1 -2
- data/lib/rubocop/cop/style/redundant_each.rb +1 -2
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_format.rb +14 -7
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +78 -135
- data/lib/rubocop/cop/style/redundant_parentheses.rb +65 -67
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -2
- data/lib/rubocop/cop/style/redundant_return.rb +1 -2
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +11 -2
- data/lib/rubocop/cop/style/sample.rb +11 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -2
- data/lib/rubocop/cop/style/semicolon.rb +2 -4
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -5
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +18 -5
- data/lib/rubocop/cop/style/super_arguments.rb +1 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -2
- data/lib/rubocop/cop/style/time_now.rb +41 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -2
- data/lib/rubocop/cop/style.rb +312 -0
- data/lib/rubocop/cop/team.rb +59 -6
- data/lib/rubocop/cop/util.rb +2 -4
- data/lib/rubocop/cop/variable_force/variable.rb +19 -8
- data/lib/rubocop/cops_documentation_generator.rb +4 -7
- data/lib/rubocop/directive_comment.rb +39 -3
- data/lib/rubocop/feature_loader.rb +0 -6
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/html_formatter.rb +2 -4
- data/lib/rubocop/formatter/json_formatter.rb +11 -6
- data/lib/rubocop/formatter/junit_formatter.rb +26 -9
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +4 -3
- data/lib/rubocop/formatter/tap_formatter.rb +3 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -2
- data/lib/rubocop/lockfile.rb +18 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -8
- data/lib/rubocop/lsp/routes.rb +89 -22
- data/lib/rubocop/lsp/runtime.rb +4 -0
- data/lib/rubocop/lsp/server.rb +4 -0
- data/lib/rubocop/lsp/stdin_runner.rb +20 -0
- data/lib/rubocop/mcp/server.rb +1 -2
- data/lib/rubocop/options.rb +10 -6
- data/lib/rubocop/path_util.rb +1 -2
- data/lib/rubocop/pending_cops_reporter.rb +1 -6
- data/lib/rubocop/plugin/configuration_integrator.rb +6 -3
- data/lib/rubocop/project_index_loader.rb +16 -0
- data/lib/rubocop/rake_task.rb +1 -2
- data/lib/rubocop/result_cache.rb +6 -4
- data/lib/rubocop/rspec/expect_offense.rb +2 -4
- data/lib/rubocop/rspec/shared_contexts.rb +16 -2
- data/lib/rubocop/runner.rb +71 -43
- data/lib/rubocop/server/cache.rb +11 -7
- data/lib/rubocop/server/cli.rb +2 -4
- data/lib/rubocop/server.rb +14 -0
- data/lib/rubocop/target_finder.rb +4 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/todo_audit.rb +111 -0
- data/lib/rubocop/version.rb +3 -5
- data/lib/rubocop.rb +20 -626
- data/lib/ruby_lsp/rubocop/addon.rb +1 -2
- metadata +28 -5
|
@@ -30,21 +30,55 @@ module RuboCop
|
|
|
30
30
|
# foo = "1"
|
|
31
31
|
# # rubocop:enable all
|
|
32
32
|
# baz
|
|
33
|
+
#
|
|
34
|
+
# # bad
|
|
35
|
+
# foo = 1
|
|
36
|
+
# # rubocop:pop
|
|
37
|
+
#
|
|
38
|
+
# # good
|
|
39
|
+
# # rubocop:push -Style/StringLiterals
|
|
40
|
+
# foo = "1"
|
|
41
|
+
# # rubocop:pop
|
|
33
42
|
class RedundantCopEnableDirective < Base
|
|
34
43
|
include RangeHelp
|
|
35
44
|
include SurroundingSpace
|
|
36
45
|
extend AutoCorrector
|
|
37
46
|
|
|
38
47
|
MSG = 'Unnecessary enabling of %<cop>s.'
|
|
48
|
+
MSG_ORPHAN_POP = 'Unnecessary `rubocop:pop` without a matching `rubocop:push`.'
|
|
39
49
|
|
|
40
50
|
def on_new_investigation
|
|
41
|
-
return if processed_source.blank?
|
|
51
|
+
return if processed_source.blank?
|
|
42
52
|
|
|
53
|
+
source = processed_source.raw_source
|
|
54
|
+
check_extra_enables if source.include?('enable')
|
|
55
|
+
check_orphan_pops if source.include?('pop')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def check_extra_enables
|
|
43
61
|
offenses = processed_source.comment_config.extra_enabled_comments
|
|
44
62
|
offenses.each { |comment, cop_names| register_offense(comment, cop_names) }
|
|
45
63
|
end
|
|
46
64
|
|
|
47
|
-
|
|
65
|
+
def check_orphan_pops
|
|
66
|
+
push_depth = 0
|
|
67
|
+
processed_source.comments.each do |comment|
|
|
68
|
+
directive = DirectiveComment.new(comment)
|
|
69
|
+
if directive.push?
|
|
70
|
+
push_depth += 1
|
|
71
|
+
elsif directive.pop?
|
|
72
|
+
push_depth.zero? ? register_orphan_pop(directive) : push_depth -= 1
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def register_orphan_pop(directive)
|
|
78
|
+
add_offense(directive.range, message: MSG_ORPHAN_POP) do |corrector|
|
|
79
|
+
corrector.remove(range_with_surrounding_space(directive.range, side: :right))
|
|
80
|
+
end
|
|
81
|
+
end
|
|
48
82
|
|
|
49
83
|
def register_offense(comment, cop_names)
|
|
50
84
|
directive = DirectiveComment.new(comment)
|
|
@@ -55,15 +89,21 @@ module RuboCop
|
|
|
55
89
|
range_of_offense(comment, name),
|
|
56
90
|
message: format(MSG, cop: all_or_name(name))
|
|
57
91
|
) do |corrector|
|
|
58
|
-
|
|
59
|
-
corrector.remove(range_with_surrounding_space(directive.range, side: :right))
|
|
60
|
-
else
|
|
61
|
-
corrector.remove(range_with_comma(comment, name))
|
|
62
|
-
end
|
|
92
|
+
corrector.remove(removal_range(directive, comment, cop_names, name))
|
|
63
93
|
end
|
|
64
94
|
end
|
|
65
95
|
end
|
|
66
96
|
|
|
97
|
+
# When every cop on the directive is redundant the whole comment goes, `--` reason
|
|
98
|
+
# included; otherwise just the one cop is spliced out of the list.
|
|
99
|
+
def removal_range(directive, comment, cop_names, name)
|
|
100
|
+
if directive.match?(cop_names)
|
|
101
|
+
range_with_surrounding_space(directive.range_with_reason, side: :right)
|
|
102
|
+
else
|
|
103
|
+
range_with_comma(comment, name)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
67
107
|
def range_of_offense(comment, name)
|
|
68
108
|
start_pos = comment_start(comment) + cop_name_indention(comment, name)
|
|
69
109
|
range_between(start_pos, start_pos + name.size)
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
|
63
63
|
|
|
64
64
|
private
|
|
65
65
|
|
|
66
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
66
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
67
67
|
def redundant_feature?(feature_name)
|
|
68
68
|
feature_name == 'enumerator' ||
|
|
69
69
|
(target_ruby_version >= 2.1 && feature_name == 'thread') ||
|
|
@@ -73,7 +73,6 @@ module RuboCop
|
|
|
73
73
|
(target_ruby_version >= 3.2 && feature_name == 'set') ||
|
|
74
74
|
(target_ruby_version >= 4.0 && feature_name == 'pathname')
|
|
75
75
|
end
|
|
76
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
77
76
|
end
|
|
78
77
|
end
|
|
79
78
|
end
|
|
@@ -208,7 +208,7 @@ module RuboCop
|
|
|
208
208
|
add_offense(range) { |corrector| corrector.replace(range, '.') }
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
# rubocop:disable Metrics/AbcSize
|
|
211
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
212
212
|
def on_or(node)
|
|
213
213
|
conversion_with_default?(node) do |send_node|
|
|
214
214
|
range = send_node.loc.dot.begin.join(node.source_range.end)
|
|
@@ -221,7 +221,6 @@ module RuboCop
|
|
|
221
221
|
end
|
|
222
222
|
end
|
|
223
223
|
end
|
|
224
|
-
# rubocop:enable Metrics/AbcSize
|
|
225
224
|
|
|
226
225
|
private
|
|
227
226
|
|
|
@@ -139,7 +139,7 @@ module RuboCop
|
|
|
139
139
|
grandparent.array_type? && grandparent.children.size > 1
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
# rubocop:disable Metrics/AbcSize
|
|
142
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
143
143
|
def replacement_range_and_content(node)
|
|
144
144
|
variable = node.children.first
|
|
145
145
|
expression = node.source_range
|
|
@@ -157,7 +157,6 @@ module RuboCop
|
|
|
157
157
|
[node.loc.operator, '']
|
|
158
158
|
end
|
|
159
159
|
end
|
|
160
|
-
# rubocop:enable Metrics/AbcSize
|
|
161
160
|
|
|
162
161
|
def array_splat?(node)
|
|
163
162
|
node.children.first.array_type?
|
|
@@ -192,7 +192,7 @@ module RuboCop
|
|
|
192
192
|
(hash (pair (sym :exception) false))
|
|
193
193
|
PATTERN
|
|
194
194
|
|
|
195
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
195
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
196
196
|
def on_send(node)
|
|
197
197
|
return if node.arguments.any? || hash_or_set_with_block?(node)
|
|
198
198
|
|
|
@@ -208,7 +208,6 @@ module RuboCop
|
|
|
208
208
|
corrector.remove(node.loc.dot.join(node.loc.end || node.loc.selector))
|
|
209
209
|
end
|
|
210
210
|
end
|
|
211
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
212
211
|
alias on_csend on_send
|
|
213
212
|
|
|
214
213
|
private
|
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
|
33
33
|
MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
|
|
34
34
|
MSG_WITH_INDEX = 'Remove redundant `with_index`.'
|
|
35
35
|
|
|
36
|
-
# rubocop:disable Metrics/AbcSize
|
|
36
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
37
37
|
def on_block(node)
|
|
38
38
|
return unless node.receiver
|
|
39
39
|
return if node.method?(:with_index) && !node.receiver.receiver
|
|
@@ -50,7 +50,6 @@ module RuboCop
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
|
-
# rubocop:enable Metrics/AbcSize
|
|
54
53
|
|
|
55
54
|
alias on_numblock on_block
|
|
56
55
|
alias on_itblock on_block
|
|
@@ -9,6 +9,13 @@ module RuboCop
|
|
|
9
9
|
# safe navigation operator after a safe navigation operator.
|
|
10
10
|
# This cop checks for the problem outlined above.
|
|
11
11
|
#
|
|
12
|
+
# @safety
|
|
13
|
+
# This cop's autocorrection is unsafe because it changes the behavior of
|
|
14
|
+
# the code: `x&.foo.bar` raises `NoMethodError` when `x` or `x&.foo` is `nil`,
|
|
15
|
+
# whereas the corrected `x&.foo&.bar` returns `nil` instead. The autocorrection
|
|
16
|
+
# also assumes that extending safe navigation through the chain is intended,
|
|
17
|
+
# while removing the first `&.` may be what was intended instead.
|
|
18
|
+
#
|
|
12
19
|
# @example
|
|
13
20
|
#
|
|
14
21
|
# # bad
|
|
@@ -38,7 +45,7 @@ module RuboCop
|
|
|
38
45
|
}
|
|
39
46
|
PATTERN
|
|
40
47
|
|
|
41
|
-
# rubocop:disable Metrics/AbcSize
|
|
48
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
42
49
|
def on_send(node)
|
|
43
50
|
return unless require_safe_navigation?(node)
|
|
44
51
|
|
|
@@ -56,7 +63,6 @@ module RuboCop
|
|
|
56
63
|
end
|
|
57
64
|
end
|
|
58
65
|
end
|
|
59
|
-
# rubocop:enable Metrics/AbcSize
|
|
60
66
|
|
|
61
67
|
private
|
|
62
68
|
|
|
@@ -85,7 +85,7 @@ module RuboCop
|
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
88
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
89
89
|
def find_consistent_parts(grouped_operands)
|
|
90
90
|
csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
|
|
91
91
|
|
|
@@ -99,7 +99,6 @@ module RuboCop
|
|
|
99
99
|
['.', csend_in_or]
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
103
102
|
|
|
104
103
|
def already_appropriate_call?(operand, dot_op)
|
|
105
104
|
return true if operand.safe_navigation? && dot_op == '&.'
|
|
@@ -126,7 +125,7 @@ module RuboCop
|
|
|
126
125
|
end
|
|
127
126
|
end
|
|
128
127
|
|
|
129
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
128
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
130
129
|
def most_left_indices(grouped_operands)
|
|
131
130
|
indices = { csend_in_and: nil, csend_in_or: nil, send_in_and: nil, send_in_or: nil }
|
|
132
131
|
|
|
@@ -139,7 +138,6 @@ module RuboCop
|
|
|
139
138
|
|
|
140
139
|
indices.values
|
|
141
140
|
end
|
|
142
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
143
141
|
|
|
144
142
|
def operand_in_and?(node)
|
|
145
143
|
return true if node.parent.and_type?
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for `super` calls with explicit arguments that pass the wrong
|
|
7
|
+
# number of positional arguments to the overridden implementation, using
|
|
8
|
+
# the project index.
|
|
9
|
+
#
|
|
10
|
+
# The check is powered by the project-wide index, so it only runs when
|
|
11
|
+
# `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is installed.
|
|
12
|
+
# Without the index the cop does nothing.
|
|
13
|
+
#
|
|
14
|
+
# Only `super` inside a plain instance method defined directly in a class
|
|
15
|
+
# body is considered, and only when the enclosing class resolves in the
|
|
16
|
+
# index and its entire ancestry is resolved, so a superclass method coming
|
|
17
|
+
# from a gem, the standard library, or a dynamic definition never produces
|
|
18
|
+
# an offense. The overridden implementation is the first ancestor after
|
|
19
|
+
# the enclosing class in the index's method resolution order that defines
|
|
20
|
+
# the method; when it is not a plain method definition (an `attr_*` or an
|
|
21
|
+
# alias) or its definitions disagree on arity, the call is not checked.
|
|
22
|
+
# Calls that forward arguments (`*`, `**`, `...`) are skipped, and bare
|
|
23
|
+
# `super` (which forwards the current method's parameters) is not checked.
|
|
24
|
+
# Methods the index attributes to `Object`, `Kernel`, or `BasicObject`
|
|
25
|
+
# are never used as the overridden implementation, since a `def` inside
|
|
26
|
+
# a block at the top level (`Struct.new do ... end`) is indexed under
|
|
27
|
+
# `Object` even though it defines a method somewhere else entirely.
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# # Given the project defines:
|
|
31
|
+
# # class Base
|
|
32
|
+
# # def initialize(name, size); end
|
|
33
|
+
# # end
|
|
34
|
+
#
|
|
35
|
+
# # bad
|
|
36
|
+
# class Widget < Base
|
|
37
|
+
# def initialize(name)
|
|
38
|
+
# super(name)
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # good
|
|
43
|
+
# class Widget < Base
|
|
44
|
+
# def initialize(name)
|
|
45
|
+
# super(name, 0)
|
|
46
|
+
# end
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
class SuperArgumentMismatch < Base
|
|
50
|
+
include ProjectIndexHelp
|
|
51
|
+
include IndexedMethodArity
|
|
52
|
+
|
|
53
|
+
MSG = 'Wrong number of arguments to `super` ' \
|
|
54
|
+
'(given %<given>d, expected %<expected>s for `%<parent>s#%<method>s`).'
|
|
55
|
+
|
|
56
|
+
# Blocks that change what method (or scope) `super` refers to, or in
|
|
57
|
+
# which `super` is not statically resolvable.
|
|
58
|
+
CONTEXT_CHANGING_BLOCKS = %i[
|
|
59
|
+
define_method define_singleton_method class_eval class_exec
|
|
60
|
+
module_eval module_exec instance_eval instance_exec refine
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
# Methods the index attributes to the root namespaces are not
|
|
64
|
+
# trustworthy super targets: a `def` inside a block at the top level
|
|
65
|
+
# (`Struct.new do ... end`, `Class.new do ... end`) is indexed under
|
|
66
|
+
# `Object` even though it defines a method somewhere else entirely.
|
|
67
|
+
BUILTIN_ROOTS = %w[Object Kernel BasicObject].freeze
|
|
68
|
+
|
|
69
|
+
def on_super(node)
|
|
70
|
+
return unless project_index
|
|
71
|
+
|
|
72
|
+
def_node = enclosing_instance_method(node)
|
|
73
|
+
return unless def_node
|
|
74
|
+
|
|
75
|
+
shape, parent = resolved_super_shape(def_node)
|
|
76
|
+
return unless shape
|
|
77
|
+
|
|
78
|
+
min, max, has_keywords = shape
|
|
79
|
+
given = positional_argument_count(node, has_keywords)
|
|
80
|
+
return if given.nil? || arity_satisfied?(given, min, max)
|
|
81
|
+
|
|
82
|
+
add_offense(node.loc.keyword,
|
|
83
|
+
message: message(def_node.method_name, parent, given, min, max))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def message(method_name, parent, given, min, max)
|
|
89
|
+
format(MSG, given: given, expected: expected_range(min, max),
|
|
90
|
+
parent: parent.name, method: method_name)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The `def` node whose method the `super` call re-dispatches, or nil
|
|
94
|
+
# when the context is not statically known: `super` inside a
|
|
95
|
+
# singleton method, inside `define_method` or an eval/refine block,
|
|
96
|
+
# or outside any method.
|
|
97
|
+
def enclosing_instance_method(node)
|
|
98
|
+
node.each_ancestor(:any_def, :any_block, :sclass).each do |ancestor|
|
|
99
|
+
case ancestor.type
|
|
100
|
+
when :def then return ancestor
|
|
101
|
+
when :defs, :sclass then return nil
|
|
102
|
+
else
|
|
103
|
+
return nil if CONTEXT_CHANGING_BLOCKS.include?(ancestor.method_name)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# `[[min, max, has_keywords], parent]` for the implementation `super`
|
|
111
|
+
# dispatches to, or nil when the enclosing class or the overridden
|
|
112
|
+
# method is not statically known.
|
|
113
|
+
def resolved_super_shape(def_node)
|
|
114
|
+
declaration = enclosing_class_declaration(def_node)
|
|
115
|
+
return nil unless declaration
|
|
116
|
+
return nil unless fully_resolved_index_ancestry?(declaration, ignore_extend: true)
|
|
117
|
+
|
|
118
|
+
super_method_shape(declaration, def_node.method_name)
|
|
119
|
+
rescue StandardError
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The index declaration of the class whose body directly contains
|
|
124
|
+
# `def_node`, or nil when the method is not defined directly in a
|
|
125
|
+
# class body (module methods are excluded because their `super`
|
|
126
|
+
# target depends on where the module is mixed in) or the class does
|
|
127
|
+
# not resolve in the index.
|
|
128
|
+
def enclosing_class_declaration(def_node)
|
|
129
|
+
class_node = def_node.each_ancestor(:class, :module, :sclass, :any_block).first
|
|
130
|
+
return nil unless class_node&.class_type?
|
|
131
|
+
|
|
132
|
+
declaration = project_index[lexical_nesting_of(def_node).join('::')]
|
|
133
|
+
return nil unless declaration.is_a?(Rubydex::Namespace)
|
|
134
|
+
return nil unless declared_at?(declaration, class_node)
|
|
135
|
+
|
|
136
|
+
declaration
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Whether one of the declaration's definitions is the given class
|
|
140
|
+
# node, anchoring the name-based lookup to the source being
|
|
141
|
+
# inspected (a qualified identifier like `class Foo::Bar` can
|
|
142
|
+
# resolve to a namespace other than the joined nesting names).
|
|
143
|
+
def declared_at?(declaration, class_node)
|
|
144
|
+
declaration.definitions.any? do |definition|
|
|
145
|
+
location = definition.location
|
|
146
|
+
location.uri.start_with?(FILE_URI_PREFIX) &&
|
|
147
|
+
location.to_display.start_line == class_node.first_line &&
|
|
148
|
+
same_file?(location.to_file_path, processed_source.file_path)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# The shape of the first implementation of `method_name` after the
|
|
153
|
+
# enclosing class in the index's method resolution order, or nil
|
|
154
|
+
# when no indexed ancestor defines it (e.g. it comes from a gem or
|
|
155
|
+
# the standard library, which are not indexed).
|
|
156
|
+
def super_method_shape(declaration, method_name)
|
|
157
|
+
ancestors = declaration.ancestors.to_a
|
|
158
|
+
position = ancestors.index { |ancestor| ancestor.name == declaration.name }
|
|
159
|
+
return nil unless position
|
|
160
|
+
|
|
161
|
+
ancestors.drop(position + 1).each do |ancestor|
|
|
162
|
+
return nil if BUILTIN_ROOTS.include?(ancestor.name)
|
|
163
|
+
|
|
164
|
+
member = ancestor.member("#{method_name}()")
|
|
165
|
+
next unless member
|
|
166
|
+
|
|
167
|
+
# The first definer along the chain is the receiving
|
|
168
|
+
# implementation; when its shape is unknown there is nothing
|
|
169
|
+
# further to check.
|
|
170
|
+
shape = indexed_member_shape(member)
|
|
171
|
+
return shape && [shape, ancestor]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
nil
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -78,7 +78,7 @@ module RuboCop
|
|
|
78
78
|
|
|
79
79
|
minimum_target_ruby_version 2.6
|
|
80
80
|
|
|
81
|
-
# rubocop:disable Metrics/AbcSize
|
|
81
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
82
82
|
def on_rescue(node)
|
|
83
83
|
if (method, exception_classes = begin_numeric_constructor_rescue_nil(node.parent))
|
|
84
84
|
return unless expected_exception_classes_only?(exception_classes)
|
|
@@ -100,7 +100,6 @@ module RuboCop
|
|
|
100
100
|
corrector.replace(node, prefer)
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
|
-
# rubocop:enable Metrics/AbcSize
|
|
104
103
|
|
|
105
104
|
private
|
|
106
105
|
|
|
@@ -71,7 +71,9 @@ module RuboCop
|
|
|
71
71
|
send_arg && argument_match?(send_arg, def_arg)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
all_present &&
|
|
74
|
+
all_present &&
|
|
75
|
+
!extra_positional_arguments?(arguments, def_node) &&
|
|
76
|
+
!extra_keyword_arguments?(arguments, def_node)
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
# The enumerator re-invokes the method with these arguments, so passing more
|
|
@@ -99,7 +101,41 @@ module RuboCop
|
|
|
99
101
|
def_node.arguments.select { |arg| arg.type?(:arg, :optarg) }
|
|
100
102
|
end
|
|
101
103
|
|
|
102
|
-
#
|
|
104
|
+
# The enumerator re-invokes the method with these arguments, so passing
|
|
105
|
+
# unexpected keyword arguments raises `ArgumentError` at runtime.
|
|
106
|
+
def extra_keyword_arguments?(arguments, def_node)
|
|
107
|
+
return false if variadic_keyword_parameters?(def_node)
|
|
108
|
+
return false if expandable_keyword_arguments?(arguments)
|
|
109
|
+
|
|
110
|
+
(passed_keyword_arguments(arguments) - keyword_parameters(def_node)).any?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def variadic_keyword_parameters?(def_node)
|
|
114
|
+
def_node.arguments.any? { |arg| arg.type?(:kwrestarg, :forward_arg) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# A call-side keyword splat or argument forwarding can expand to any set of keywords.
|
|
118
|
+
def expandable_keyword_arguments?(arguments)
|
|
119
|
+
arguments.any? do |arg|
|
|
120
|
+
arg.forwarded_args_type? || arg.each_child_node(:kwsplat, :forwarded_kwrestarg).any?
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def passed_keyword_arguments(arguments)
|
|
125
|
+
arguments.filter_map do |arg|
|
|
126
|
+
next unless arg.hash_type?
|
|
127
|
+
|
|
128
|
+
arg.pairs.filter_map { |pair| pair.key.value if pair.key.sym_type? }
|
|
129
|
+
end.flatten
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def keyword_parameters(def_node)
|
|
133
|
+
def_node.arguments.filter_map do |arg|
|
|
134
|
+
arg.children[0] if arg.type?(:kwarg, :kwoptarg)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
103
139
|
def argument_match?(send_arg, def_arg)
|
|
104
140
|
def_arg_name = def_arg.children[0]
|
|
105
141
|
|
|
@@ -121,7 +157,6 @@ module RuboCop
|
|
|
121
157
|
send_arg.forwarded_args_type?
|
|
122
158
|
end
|
|
123
159
|
end
|
|
124
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
125
160
|
|
|
126
161
|
def keyword_hash_argument?(send_arg)
|
|
127
162
|
send_arg.hash_type? && !send_arg.braces?
|
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
|
83
83
|
}
|
|
84
84
|
PATTERN
|
|
85
85
|
|
|
86
|
-
# rubocop:disable Metrics/MethodLength
|
|
86
|
+
# rubocop:disable-next Metrics/MethodLength
|
|
87
87
|
def flow_expression?(node)
|
|
88
88
|
return report_on_flow_command?(node) if flow_command?(node)
|
|
89
89
|
|
|
@@ -102,7 +102,6 @@ module RuboCop
|
|
|
102
102
|
false
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
|
-
# rubocop:enable Metrics/MethodLength
|
|
106
105
|
|
|
107
106
|
def check_if(node)
|
|
108
107
|
if_branch = node.if_branch
|