rubocop 1.89.0 → 1.91.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 +309 -14
- data/config/obsoletion.yml +9 -0
- data/exe/rubocop +1 -1
- data/lib/rubocop/cached_data.rb +7 -2
- data/lib/rubocop/changed_files.rb +112 -0
- data/lib/rubocop/cli/command/execute_runner.rb +52 -1
- data/lib/rubocop/cli.rb +11 -7
- data/lib/rubocop/comment_config/directive_range.rb +34 -0
- data/lib/rubocop/comment_config/disable_next.rb +143 -0
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +50 -64
- data/lib/rubocop/config.rb +33 -5
- data/lib/rubocop/config_loader.rb +13 -6
- data/lib/rubocop/config_loader_resolver.rb +50 -9
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +19 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -0
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +49 -5
- data/lib/rubocop/cop/corrector.rb +3 -3
- data/lib/rubocop/cop/correctors.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- 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/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/class_structure.rb +102 -26
- data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
- 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/empty_lines_after_module_inclusion.rb +1 -1
- 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 +17 -4
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -5
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/line_length.rb +20 -3
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -2
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
- data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +2 -4
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
- data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +17 -11
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
- data/lib/rubocop/cop/lint/deprecated_reference.rb +11 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +113 -15
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- 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/interpolation_check.rb +1 -2
- data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -8
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -6
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +25 -12
- data/lib/rubocop/cop/lint/name_typo.rb +53 -6
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +122 -29
- 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 +1 -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 +1 -2
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -2
- data/lib/rubocop/cop/lint/unused_private_method.rb +94 -17
- 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/utils/nil_receiver_checker.rb +61 -7
- data/lib/rubocop/cop/lint/void.rb +1 -2
- data/lib/rubocop/cop/lint.rb +3 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
- data/lib/rubocop/cop/migration/department_name.rb +1 -2
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- 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/hash_alignment_styles.rb +11 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +7 -4
- data/lib/rubocop/cop/mixin/hash_subset.rb +1 -2
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- 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 +62 -6
- data/lib/rubocop/cop/mixin/range_help.rb +1 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +13 -7
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
- data/lib/rubocop/cop/mixin.rb +6 -2
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +16 -0
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- 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/rescued_exceptions_variable_name.rb +1 -2
- data/lib/rubocop/cop/offense.rb +27 -4
- data/lib/rubocop/cop/registry.rb +43 -11
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -8
- data/lib/rubocop/cop/style/array_first_last.rb +1 -2
- 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 +5 -7
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -2
- 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 +1 -2
- data/lib/rubocop/cop/style/constant_visibility.rb +6 -3
- data/lib/rubocop/cop/style/copyright.rb +1 -2
- data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/directive_scope.rb +304 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +83 -13
- data/lib/rubocop/cop/style/documentation_method.rb +1 -9
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +12 -2
- data/lib/rubocop/cop/style/endless_method.rb +31 -12
- data/lib/rubocop/cop/style/file_null.rb +2 -2
- data/lib/rubocop/cop/style/float_division.rb +10 -16
- data/lib/rubocop/cop/style/for.rb +5 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -2
- data/lib/rubocop/cop/style/guard_clause.rb +5 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
- data/lib/rubocop/cop/style/hash_lookup_method.rb +3 -0
- 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 +1 -2
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -2
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
- data/lib/rubocop/cop/style/negative_array_index.rb +2 -4
- data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
- data/lib/rubocop/cop/style/nil_comparison.rb +36 -9
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
- data/lib/rubocop/cop/style/not.rb +3 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- 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/parentheses_around_condition.rb +6 -1
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_condition.rb +6 -8
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
- data/lib/rubocop/cop/style/redundant_each.rb +1 -2
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +2 -4
- data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -5
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -2
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +6 -6
- 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 +1 -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_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +18 -5
- data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
- 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/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -2
- data/lib/rubocop/cop/style.rb +2 -1
- data/lib/rubocop/cop/team.rb +11 -3
- data/lib/rubocop/cop/util.rb +3 -5
- data/lib/rubocop/cop/variable_force/variable.rb +1 -2
- data/lib/rubocop/cops_documentation_generator.rb +26 -8
- data/lib/rubocop/directive_comment.rb +73 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- 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/sarif_formatter.rb +181 -0
- 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/formatter.rb +1 -0
- data/lib/rubocop/lockfile.rb +18 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -8
- data/lib/rubocop/lsp/routes.rb +48 -19
- data/lib/rubocop/magic_comment.rb +27 -0
- data/lib/rubocop/mcp/server.rb +1 -2
- data/lib/rubocop/options.rb +69 -7
- data/lib/rubocop/path_util.rb +2 -3
- data/lib/rubocop/plugin/configuration_integrator.rb +6 -3
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -2
- data/lib/rubocop/remote_config.rb +4 -4
- data/lib/rubocop/result_cache.rb +16 -5
- data/lib/rubocop/rspec/expect_offense.rb +2 -4
- data/lib/rubocop/rspec/shared_contexts.rb +4 -2
- data/lib/rubocop/runner.rb +90 -44
- data/lib/rubocop/server/cache.rb +1 -2
- 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/todo_audit.rb +111 -0
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/version.rb +3 -5
- data/lib/rubocop.rb +7 -1
- data/lib/ruby_lsp/rubocop/addon.rb +1 -2
- metadata +18 -6
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# The Lint/RedundantCopDisableDirective cop needs to be disabled so as
|
|
4
4
|
# to be able to provide a (bad) example of a redundant disable.
|
|
5
|
-
# rubocop:disable Lint/RedundantCopDisableDirective
|
|
5
|
+
# rubocop:disable-next Lint/RedundantCopDisableDirective -- the examples below read as real directives
|
|
6
6
|
module RuboCop
|
|
7
7
|
module Cop
|
|
8
8
|
module Lint
|
|
@@ -104,17 +104,35 @@ module RuboCop
|
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def each_redundant_disable(&block)
|
|
107
|
+
each_detached_next_directive(&block)
|
|
108
|
+
|
|
107
109
|
cop_disabled_line_ranges.each do |cop, line_ranges|
|
|
110
|
+
# A pending cop that is not enabled in this run produces no
|
|
111
|
+
# offenses, so its directives cannot be judged - they typically
|
|
112
|
+
# prepare the code for the moment the cop gets enabled.
|
|
113
|
+
next if pending_cop_not_run?(cop)
|
|
114
|
+
|
|
108
115
|
each_already_disabled(cop, line_ranges, &block)
|
|
109
116
|
each_line_range(cop, line_ranges, &block)
|
|
110
117
|
end
|
|
111
118
|
end
|
|
112
119
|
|
|
120
|
+
def pending_cop_not_run?(cop)
|
|
121
|
+
# `Config#for_cop` corrects wrongly-namespaced names, but a name that
|
|
122
|
+
# is not registered as written never suppresses anything, so it is
|
|
123
|
+
# reported as unknown rather than exempted via the corrected cop.
|
|
124
|
+
return false unless all_cop_names.include?(cop)
|
|
125
|
+
|
|
126
|
+
cop_cfg = config.for_cop(cop)
|
|
127
|
+
cop_cfg['Enabled'] == 'pending' &&
|
|
128
|
+
!processed_source.registry.enabled_pending_cop?(cop_cfg, config, cop)
|
|
129
|
+
end
|
|
130
|
+
|
|
113
131
|
def each_line_range(cop, line_ranges)
|
|
114
132
|
line_ranges.each_with_index do |line_range, line_range_index|
|
|
115
133
|
next if should_skip_line_range?(cop, line_range)
|
|
116
134
|
|
|
117
|
-
comment =
|
|
135
|
+
comment = directive_comment(line_range)
|
|
118
136
|
next if skip_directive?(comment)
|
|
119
137
|
|
|
120
138
|
next_range = line_ranges[line_range_index + 1]
|
|
@@ -127,9 +145,39 @@ module RuboCop
|
|
|
127
145
|
ignore_offense?(line_range) || expected_final_disable?(cop, line_range)
|
|
128
146
|
end
|
|
129
147
|
|
|
148
|
+
# A range opened by a `disable-next` directive starts at the statement,
|
|
149
|
+
# not at the directive comment above it, so ask the range itself.
|
|
150
|
+
def directive_comment(line_range)
|
|
151
|
+
if line_range.respond_to?(:directive)
|
|
152
|
+
line_range.directive.comment
|
|
153
|
+
else
|
|
154
|
+
processed_source.comment_at_line(line_range.begin)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# A next-statement directive with no statement attached (or misplaced
|
|
159
|
+
# at the end of a code line) affects nothing, so it is redundant by
|
|
160
|
+
# definition.
|
|
161
|
+
def each_detached_next_directive
|
|
162
|
+
processed_source.comment_config.detached_next_directives.each do |directive|
|
|
163
|
+
names = if directive.next?
|
|
164
|
+
directive.signed_args.values.flatten
|
|
165
|
+
else
|
|
166
|
+
directive.raw_cop_names
|
|
167
|
+
end
|
|
168
|
+
names.each { |cop| yield directive.comment, cop }
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
130
172
|
def skip_directive?(comment)
|
|
173
|
+
# A cop disabled in the configuration is represented by a synthetic directive that
|
|
174
|
+
# has no comment in the source, so there is nothing to report or to remove.
|
|
175
|
+
# Its range starts at `CONFIG_DISABLED_LINE_RANGE_MIN` and runs to the end of the file,
|
|
176
|
+
# but a `pop` splits it, and the pieces in between are bounded on both sides.
|
|
177
|
+
return true if comment.is_a?(CommentConfig::ConfigDisabledCopDirectiveComment)
|
|
178
|
+
|
|
131
179
|
directive = DirectiveComment.new(comment)
|
|
132
|
-
directive.push? || directive.pop?
|
|
180
|
+
directive.push? || directive.pop? || directive.next?
|
|
133
181
|
end
|
|
134
182
|
|
|
135
183
|
def find_redundant_directive(cop, comment, line_range, next_range)
|
|
@@ -142,7 +190,7 @@ module RuboCop
|
|
|
142
190
|
end
|
|
143
191
|
end
|
|
144
192
|
|
|
145
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
193
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
146
194
|
def each_already_disabled(cop, line_ranges)
|
|
147
195
|
line_ranges.each_cons(2) do |previous_range, range|
|
|
148
196
|
next if ignore_offense?(range)
|
|
@@ -152,13 +200,13 @@ module RuboCop
|
|
|
152
200
|
# whether there are offenses or not.
|
|
153
201
|
next unless followed_ranges?(previous_range, range)
|
|
154
202
|
|
|
155
|
-
comment =
|
|
203
|
+
comment = directive_comment(range)
|
|
156
204
|
|
|
157
|
-
next
|
|
158
|
-
#
|
|
159
|
-
# to disable a few select cops first and then all cops
|
|
160
|
-
# down in the code.
|
|
161
|
-
next if all_disabled?(comment)
|
|
205
|
+
# `push`/`next` signed arguments are not analyzed for redundancy
|
|
206
|
+
# (yet), and comments disabling all cops don't count since it's
|
|
207
|
+
# reasonable to disable a few select cops first and then all cops
|
|
208
|
+
# further down in the code.
|
|
209
|
+
next if comment.nil? || skip_directive?(comment) || all_disabled?(comment)
|
|
162
210
|
|
|
163
211
|
redundant =
|
|
164
212
|
if department_disabled?(cop, comment)
|
|
@@ -170,7 +218,6 @@ module RuboCop
|
|
|
170
218
|
yield comment, redundant if redundant
|
|
171
219
|
end
|
|
172
220
|
end
|
|
173
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
174
221
|
|
|
175
222
|
def find_redundant_cop(cop, range)
|
|
176
223
|
cop_offenses = offenses_to_check.select { |offense| offense.cop_name == cop }
|
|
@@ -198,7 +245,11 @@ module RuboCop
|
|
|
198
245
|
end
|
|
199
246
|
|
|
200
247
|
def range_with_offense?(range, offenses = offenses_to_check)
|
|
201
|
-
|
|
248
|
+
# An offense is covered when the disabled range overlaps any line of
|
|
249
|
+
# its span, mirroring how offenses are suppressed.
|
|
250
|
+
offenses.none? do |offense|
|
|
251
|
+
offense.line <= range.end && offense.location.last_line >= range.begin
|
|
252
|
+
end
|
|
202
253
|
end
|
|
203
254
|
|
|
204
255
|
def all_disabled?(comment)
|
|
@@ -241,17 +292,33 @@ module RuboCop
|
|
|
241
292
|
end
|
|
242
293
|
|
|
243
294
|
def add_offense_for_entire_comment(comment, cops)
|
|
244
|
-
|
|
295
|
+
directive = DirectiveComment.new(comment)
|
|
296
|
+
location = directive.range
|
|
245
297
|
cop_names = cops.sort.map { |c| describe(c) }.join(', ')
|
|
246
298
|
|
|
247
|
-
|
|
248
|
-
|
|
299
|
+
# An unknown cop may just not be loaded in this run (e.g. a custom
|
|
300
|
+
# cop whose configuration failed to load) - removing its directive
|
|
301
|
+
# would destroy something that cannot be restored, so only report.
|
|
302
|
+
# A misplaced EOL `disable-next` should be moved, not deleted.
|
|
303
|
+
message = message(cop_names, enabling: directive.enable_next?)
|
|
304
|
+
if any_unknown_cop?(cops) || misplaced_next_directive?(comment)
|
|
305
|
+
return add_offense(location, message: message)
|
|
306
|
+
end
|
|
249
307
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
308
|
+
add_offense(location, message: message) do |corrector|
|
|
309
|
+
remove_entire_comment(corrector, comment)
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def remove_entire_comment(corrector, comment)
|
|
314
|
+
# Take the `--` reason with the directive; `leave_free_comment?` keeps anything else.
|
|
315
|
+
directive_range = DirectiveComment.new(comment).range_with_reason
|
|
316
|
+
range = comment_range_with_surrounding_space(directive_range, comment.source_range)
|
|
317
|
+
|
|
318
|
+
if leave_free_comment?(comment, range)
|
|
319
|
+
corrector.replace(range, ' # ')
|
|
320
|
+
else
|
|
321
|
+
corrector.remove(range)
|
|
255
322
|
end
|
|
256
323
|
end
|
|
257
324
|
|
|
@@ -261,14 +328,35 @@ module RuboCop
|
|
|
261
328
|
ranges = cop_ranges.map { |_, r| r }
|
|
262
329
|
|
|
263
330
|
cop_ranges.each do |cop, range|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
331
|
+
add_offense_for_cop_in_list(cop, range, ranges)
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def add_offense_for_cop_in_list(cop, range, ranges)
|
|
336
|
+
cop_name = describe(cop)
|
|
337
|
+
return add_offense(range, message: message(cop_name)) if unknown_cop?(cop)
|
|
338
|
+
|
|
339
|
+
add_offense(range, message: message(cop_name)) do |corrector|
|
|
340
|
+
corrector.remove(directive_range_in_list(range, ranges))
|
|
269
341
|
end
|
|
270
342
|
end
|
|
271
343
|
|
|
344
|
+
def any_unknown_cop?(cops)
|
|
345
|
+
cops.any? { |cop| unknown_cop?(cop) }
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def misplaced_next_directive?(comment)
|
|
349
|
+
directive = DirectiveComment.new(comment)
|
|
350
|
+
(directive.disable_next? || directive.next? || directive.enable_next?) &&
|
|
351
|
+
!processed_source.comment_config.comment_only_line?(directive.line_number)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def unknown_cop?(cop)
|
|
355
|
+
return false if cop == 'all' || department_marker?(cop)
|
|
356
|
+
|
|
357
|
+
!all_cop_names.include?(cop)
|
|
358
|
+
end
|
|
359
|
+
|
|
272
360
|
def leave_free_comment?(comment, range)
|
|
273
361
|
free_comment = comment.text.gsub(range.source.strip, '')
|
|
274
362
|
|
|
@@ -303,7 +391,13 @@ module RuboCop
|
|
|
303
391
|
|
|
304
392
|
SIMILAR_COP_NAMES_CACHE = Hash.new do |hash, cop_name|
|
|
305
393
|
hash[:all_cop_names] = Registry.global.names unless hash.key?(:all_cop_names)
|
|
306
|
-
|
|
394
|
+
# A registered cop with the same base name is a better suggestion
|
|
395
|
+
# than anything spelling similarity can find - the most common
|
|
396
|
+
# mistake is qualifying a cop with the wrong department.
|
|
397
|
+
basename = "/#{cop_name.split('/').last}"
|
|
398
|
+
same_basename = hash[:all_cop_names].find { |name| name.end_with?(basename) }
|
|
399
|
+
hash[cop_name] =
|
|
400
|
+
same_basename || NameSimilarity.find_similar_name(cop_name, hash[:all_cop_names])
|
|
307
401
|
end
|
|
308
402
|
private_constant :SIMILAR_COP_NAMES_CACHE
|
|
309
403
|
|
|
@@ -316,8 +410,8 @@ module RuboCop
|
|
|
316
410
|
similar ? "`#{cop}` (did you mean `#{similar}`?)" : "`#{cop}` (unknown cop)"
|
|
317
411
|
end
|
|
318
412
|
|
|
319
|
-
def message(cop_names)
|
|
320
|
-
"Unnecessary disabling of #{cop_names}."
|
|
413
|
+
def message(cop_names, enabling: false)
|
|
414
|
+
"Unnecessary #{enabling ? 'enabling' : 'disabling'} of #{cop_names}."
|
|
321
415
|
end
|
|
322
416
|
|
|
323
417
|
def all_cop_names
|
|
@@ -344,4 +438,3 @@ module RuboCop
|
|
|
344
438
|
end
|
|
345
439
|
end
|
|
346
440
|
end
|
|
347
|
-
# rubocop:enable Lint/RedundantCopDisableDirective
|
|
@@ -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
|
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
|
45
45
|
}
|
|
46
46
|
PATTERN
|
|
47
47
|
|
|
48
|
-
# rubocop:disable Metrics/AbcSize
|
|
48
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
49
49
|
def on_send(node)
|
|
50
50
|
return unless require_safe_navigation?(node)
|
|
51
51
|
|
|
@@ -63,7 +63,6 @@ module RuboCop
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
-
# rubocop:enable Metrics/AbcSize
|
|
67
66
|
|
|
68
67
|
private
|
|
69
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
|
|