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
|
@@ -175,10 +175,19 @@ module RuboCop
|
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
def ancestor_namespaces(node)
|
|
178
|
-
node
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
.
|
|
178
|
+
ancestors = node.each_ancestor(:class, :module).reverse_each
|
|
179
|
+
|
|
180
|
+
ancestors.with_object([]) do |ancestor, namespaces|
|
|
181
|
+
append_namespaces(namespaces, ancestor.identifier)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Compact definitions (e.g. `module A::B`) contribute every path segment,
|
|
186
|
+
# and an absolute one (e.g. `module ::A::B`) discards the enclosing namespaces.
|
|
187
|
+
def append_namespaces(namespaces, identifier)
|
|
188
|
+
namespaces.clear if identifier.absolute?
|
|
189
|
+
namespaces.concat(identifier_namespaces(identifier))
|
|
190
|
+
namespaces << identifier.short_name
|
|
182
191
|
end
|
|
183
192
|
|
|
184
193
|
def unconditional_definition?(node)
|
|
@@ -188,14 +197,11 @@ module RuboCop
|
|
|
188
197
|
end
|
|
189
198
|
|
|
190
199
|
def definition_name(node)
|
|
191
|
-
|
|
200
|
+
namespaces = ancestor_namespaces(node)
|
|
201
|
+
append_namespaces(namespaces, node.identifier)
|
|
202
|
+
constant = namespaces.pop
|
|
192
203
|
|
|
193
|
-
|
|
194
|
-
fully_qualified_name_for([], identifier.short_name)
|
|
195
|
-
else
|
|
196
|
-
namespaces = ancestor_namespaces(node) + identifier_namespaces(identifier)
|
|
197
|
-
fully_qualified_name_for(namespaces, identifier.short_name)
|
|
198
|
-
end
|
|
204
|
+
fully_qualified_name_for(namespaces, constant)
|
|
199
205
|
end
|
|
200
206
|
|
|
201
207
|
def identifier_namespaces(identifier)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rubocop:disable Lint/RedundantCopDisableDirective
|
|
4
|
-
# rubocop:disable Style/DoubleCopDisableDirective
|
|
5
3
|
module RuboCop
|
|
6
4
|
module Cop
|
|
7
5
|
module Lint
|
|
@@ -23,12 +21,11 @@ module RuboCop
|
|
|
23
21
|
# # good
|
|
24
22
|
# # rubocop:disable all
|
|
25
23
|
#
|
|
26
|
-
# # bad
|
|
24
|
+
# # bad - only the first directive takes effect
|
|
27
25
|
# # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
|
|
28
26
|
#
|
|
29
27
|
# # good
|
|
30
|
-
# # rubocop:disable Layout/LineLength
|
|
31
|
-
# # rubocop:disable Style/Encoding
|
|
28
|
+
# # rubocop:disable Layout/LineLength, Style/Encoding
|
|
32
29
|
#
|
|
33
30
|
# # bad
|
|
34
31
|
# # rubocop:wrongmode Layout/LineLength
|
|
@@ -42,29 +39,139 @@ module RuboCop
|
|
|
42
39
|
# # good
|
|
43
40
|
# # rubocop:disable Layout/LineLength -- comment
|
|
44
41
|
#
|
|
42
|
+
# # bad
|
|
43
|
+
# # rucocop:disable Layout/LineLength
|
|
44
|
+
#
|
|
45
|
+
# # good
|
|
46
|
+
# # rubocop:disable Layout/LineLength
|
|
47
|
+
#
|
|
48
|
+
# # bad
|
|
49
|
+
# # rubocop:disable Layout/LineLenght
|
|
50
|
+
#
|
|
51
|
+
# # good
|
|
52
|
+
# # rubocop:disable Layout/LineLength
|
|
53
|
+
#
|
|
45
54
|
class CopDirectiveSyntax < Base
|
|
55
|
+
extend AutoCorrector
|
|
56
|
+
|
|
46
57
|
COMMON_MSG = 'Malformed directive comment detected.'
|
|
47
58
|
|
|
48
59
|
MISSING_MODE_NAME_MSG = 'The mode name is missing.'
|
|
49
|
-
INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `todo`, `push`, or `pop`.' # rubocop:disable Layout/LineLength
|
|
60
|
+
INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `disable-next`, `enable-next`, `todo`, `todo-next`, `next`, `push`, or `pop`.' # rubocop:disable Layout/LineLength -- the message lists every mode and does not wrap
|
|
50
61
|
MISSING_COP_NAME_MSG = 'The cop name is missing.'
|
|
62
|
+
MULTIPLE_DIRECTIVES_MSG = 'Only the first directive on a line takes effect. ' \
|
|
63
|
+
'List the cop names in a single directive instead.'
|
|
51
64
|
MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
|
|
52
65
|
'Comment in the directive must start with `--`.'
|
|
66
|
+
INVALID_SIGNED_ARGS_MSG = '`push` and `next` arguments must be `+`- or `-`-prefixed ' \
|
|
67
|
+
'cop names, and `pop` takes no arguments.'
|
|
68
|
+
NEXT_DIRECTIVE_AT_EOL_MSG = 'A `-next` directive must be on its own line, above the ' \
|
|
69
|
+
'statement it applies to.'
|
|
70
|
+
INVALID_KEYWORD_MSG = 'The directive keyword must be `rubocop`, not `%<keyword>s`.'
|
|
71
|
+
UNKNOWN_COP_MSG = 'Unknown cop name `%<name>s`%<suggestion>s.'
|
|
72
|
+
|
|
73
|
+
# A comment that looks like an attempted directive: any keyword
|
|
74
|
+
# followed by a colon and a valid mode name.
|
|
75
|
+
NEAR_MISS_KEYWORD_REGEXP = /
|
|
76
|
+
\A\#+\s*(?<keyword>[A-Za-z][\w-]*)\s*:\s*
|
|
77
|
+
(?:#{DirectiveComment::MODES_PATTERN})\b
|
|
78
|
+
/x.freeze
|
|
53
79
|
|
|
54
80
|
def on_new_investigation
|
|
55
81
|
processed_source.comments.each do |comment|
|
|
56
82
|
directive_comment = DirectiveComment.new(comment)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
if directive_comment.start_with_marker?
|
|
84
|
+
check_directive(comment, directive_comment)
|
|
85
|
+
elsif (keyword = near_miss_keyword(comment))
|
|
86
|
+
message = format("#{COMMON_MSG} #{INVALID_KEYWORD_MSG}", keyword: keyword)
|
|
87
|
+
add_offense(comment, message: message)
|
|
88
|
+
end
|
|
62
89
|
end
|
|
63
90
|
end
|
|
64
91
|
|
|
65
92
|
private
|
|
66
93
|
|
|
67
|
-
|
|
94
|
+
def check_directive(comment, directive_comment)
|
|
95
|
+
if (directives = multiple_directives(comment, directive_comment))
|
|
96
|
+
add_offense(comment, message: "#{COMMON_MSG} #{MULTIPLE_DIRECTIVES_MSG}") do |corrector|
|
|
97
|
+
merge_directives(corrector, comment, directives)
|
|
98
|
+
end
|
|
99
|
+
elsif directive_comment.malformed?
|
|
100
|
+
add_offense(comment, message: offense_message(directive_comment))
|
|
101
|
+
elsif misplaced_next_directive?(directive_comment)
|
|
102
|
+
add_offense(comment, message: NEXT_DIRECTIVE_AT_EOL_MSG)
|
|
103
|
+
elsif (name = unknown_cop_name(directive_comment))
|
|
104
|
+
add_offense(comment, message: unknown_cop_message(directive_comment, name))
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Everything after the first directive in a comment is trailing text as
|
|
109
|
+
# far as the parser is concerned, so a second directive written on the
|
|
110
|
+
# same line disables nothing at all. A valid `--` reason may mention a
|
|
111
|
+
# directive as plain text, which should not be treated as another one.
|
|
112
|
+
def multiple_directives(comment, directive_comment)
|
|
113
|
+
matches = comment.text.to_enum(:scan, DirectiveComment::DIRECTIVE_COMMENT_REGEXP)
|
|
114
|
+
.map { Regexp.last_match }
|
|
115
|
+
matches = filter_reason_matches(matches, directive_comment)
|
|
116
|
+
|
|
117
|
+
matches if matches.size > 1
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def filter_reason_matches(matches, directive_comment)
|
|
121
|
+
return matches unless directive_comment.reason
|
|
122
|
+
|
|
123
|
+
[matches.first, *matches.drop(1).reject { |match| match.post_match.match?(/\S/) }]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def merge_directives(corrector, comment, directives)
|
|
127
|
+
return unless directives_adjacent?(comment, directives)
|
|
128
|
+
return unless (mode = merged_mode(directives))
|
|
129
|
+
return unless (cops = merged_cops(directives))
|
|
130
|
+
|
|
131
|
+
corrector.replace(comment, "# rubocop:#{mode} #{cops.join(', ')}")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# `all` covers every cop already, so folding it into a list of names
|
|
135
|
+
# would be a rewrite rather than a merge.
|
|
136
|
+
def merged_cops(directives)
|
|
137
|
+
cops = directives.flat_map { |match| match[2].to_s.split(',').map(&:strip) }
|
|
138
|
+
cops = cops.reject(&:empty?).uniq
|
|
139
|
+
cops unless cops.empty? || cops.include?('all')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Anything written between the directives is a `--` reason or prose,
|
|
143
|
+
# and merging around it would either move it or drop it.
|
|
144
|
+
def directives_adjacent?(comment, directives)
|
|
145
|
+
text = comment.text
|
|
146
|
+
bounds = directives.map { |match| match.end(0) }
|
|
147
|
+
.zip(directives.map { |match| match.begin(0) }[1..] + [text.length])
|
|
148
|
+
bounds.all? { |from, to| text[from...to].strip.empty? }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# `todo` is an alias of `disable`, so those two combine. Anything else
|
|
152
|
+
# (an `enable` beside a `disable`, or directives of different scopes)
|
|
153
|
+
# means different things per directive and can't be folded into one.
|
|
154
|
+
def merged_mode(directives)
|
|
155
|
+
modes = directives.map { |match| match[1] }.uniq
|
|
156
|
+
return modes.first if modes.size == 1
|
|
157
|
+
return modes.first if (modes - %w[disable todo]).empty?
|
|
158
|
+
|
|
159
|
+
nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# An EOL next-statement directive is not honored - it must fail
|
|
163
|
+
# loudly instead of silently doing nothing.
|
|
164
|
+
def misplaced_next_directive?(directive_comment)
|
|
165
|
+
next_statement_directive?(directive_comment) &&
|
|
166
|
+
!processed_source.comment_config.comment_only_line?(directive_comment.line_number)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def next_statement_directive?(directive_comment)
|
|
170
|
+
directive_comment.disable_next? || directive_comment.enable_next? ||
|
|
171
|
+
directive_comment.next?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# rubocop:disable-next Metrics/MethodLength
|
|
68
175
|
def offense_message(directive_comment)
|
|
69
176
|
comment = directive_comment.comment
|
|
70
177
|
after_marker = comment.text.sub(DirectiveComment::DIRECTIVE_MARKER_REGEXP, '')
|
|
@@ -75,16 +182,59 @@ module RuboCop
|
|
|
75
182
|
INVALID_MODE_NAME_MSG
|
|
76
183
|
elsif directive_comment.missing_cop_name?
|
|
77
184
|
MISSING_COP_NAME_MSG
|
|
185
|
+
elsif directive_comment.invalid_signed_args?
|
|
186
|
+
INVALID_SIGNED_ARGS_MSG
|
|
78
187
|
else
|
|
79
188
|
MALFORMED_COP_NAMES_MSG
|
|
80
189
|
end
|
|
81
190
|
|
|
82
191
|
"#{COMMON_MSG} #{additional_msg}"
|
|
83
192
|
end
|
|
84
|
-
|
|
193
|
+
|
|
194
|
+
def near_miss_keyword(comment)
|
|
195
|
+
match = comment.text.match(NEAR_MISS_KEYWORD_REGEXP)
|
|
196
|
+
return unless match
|
|
197
|
+
|
|
198
|
+
keyword = match[:keyword]
|
|
199
|
+
return if keyword == 'rubocop'
|
|
200
|
+
|
|
201
|
+
keyword if similar_to_rubocop?(keyword)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def similar_to_rubocop?(keyword)
|
|
205
|
+
return true if keyword.casecmp?('rubocop')
|
|
206
|
+
# `DidYouMean` is not always available - see `NameSimilarity`.
|
|
207
|
+
return false unless defined?(DidYouMean::Levenshtein)
|
|
208
|
+
|
|
209
|
+
DidYouMean::Levenshtein.distance(keyword.downcase, 'rubocop') <= 2
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def unknown_cop_name(directive_comment)
|
|
213
|
+
return if directive_comment.pop? || directive_comment.all_cops?
|
|
214
|
+
|
|
215
|
+
registry = directive_comment.cop_registry
|
|
216
|
+
directive_names(directive_comment).find do |name|
|
|
217
|
+
next false if registry.department?(name)
|
|
218
|
+
|
|
219
|
+
qualified = registry.qualified_cop_name(name, nil, warn: false)
|
|
220
|
+
!registry.contains_cop_matching?([qualified])
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def directive_names(directive_comment)
|
|
225
|
+
if directive_comment.push? || directive_comment.next?
|
|
226
|
+
directive_comment.signed_args.values.flatten
|
|
227
|
+
else
|
|
228
|
+
directive_comment.raw_cop_names
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def unknown_cop_message(directive_comment, name)
|
|
233
|
+
similar = NameSimilarity.find_similar_name(name, directive_comment.cop_registry.names)
|
|
234
|
+
suggestion = similar ? " (did you mean `#{similar}`?)" : ''
|
|
235
|
+
format(UNKNOWN_COP_MSG, name: name, suggestion: suggestion)
|
|
236
|
+
end
|
|
85
237
|
end
|
|
86
238
|
end
|
|
87
239
|
end
|
|
88
240
|
end
|
|
89
|
-
# rubocop:enable Lint/RedundantCopDisableDirective
|
|
90
|
-
# rubocop:enable Style/DoubleCopDisableDirective
|
|
@@ -150,10 +150,19 @@ module RuboCop
|
|
|
150
150
|
false
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
+
# Enumerated in a single pass that stops at the first non-deprecated
|
|
154
|
+
# definition, since materializing every definition of a declaration
|
|
155
|
+
# that is almost never deprecated dominates the cop's cost.
|
|
153
156
|
def deprecated?(declaration)
|
|
154
|
-
|
|
157
|
+
any = false
|
|
155
158
|
|
|
156
|
-
definitions.
|
|
159
|
+
declaration.definitions.each do |definition|
|
|
160
|
+
return false unless definition.deprecated?
|
|
161
|
+
|
|
162
|
+
any = true
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
any
|
|
157
166
|
end
|
|
158
167
|
|
|
159
168
|
# References from a definition that is itself documented as deprecated
|
|
@@ -19,7 +19,22 @@ module RuboCop
|
|
|
19
19
|
# file is wrapped in a conditional, so a platform-specific redefinition in
|
|
20
20
|
# another file may still be reported. Aliasing the method to itself (see above)
|
|
21
21
|
# before redefining marks the redefinition as intentional and is respected
|
|
22
|
-
# across files.
|
|
22
|
+
# across files. With `AllCops/ActiveSupportExtensionsEnabled: true`, Active
|
|
23
|
+
# Support's redefinition markers (`silence_redefinition_of_method` and
|
|
24
|
+
# `redefine_method`) are honored the same way.
|
|
25
|
+
#
|
|
26
|
+
# NOTE: Methods defined with `define_method` are not recorded in the project
|
|
27
|
+
# index, so a duplicate whose other definition uses `define_method` cannot
|
|
28
|
+
# be detected across files.
|
|
29
|
+
#
|
|
30
|
+
# Cross-file duplicates whose other definition lives in a file matching one
|
|
31
|
+
# of the `AllowedCrossFilePaths` patterns are not reported. This suits files
|
|
32
|
+
# that redefine application methods but are never loaded together with them,
|
|
33
|
+
# such as standalone scripts. Patterns are matched with the same glob (or
|
|
34
|
+
# regexp) semantics as `Exclude`, against the other file's path relative to
|
|
35
|
+
# the directory of the `.rubocop.yml` that configures the cop; absolute
|
|
36
|
+
# patterns are matched against the absolute path. Offenses inside such files
|
|
37
|
+
# themselves are best silenced with an ordinary per-cop `Exclude`.
|
|
23
38
|
#
|
|
24
39
|
# @example
|
|
25
40
|
#
|
|
@@ -129,6 +144,24 @@ module RuboCop
|
|
|
129
144
|
# delegate :foo, to: :bar
|
|
130
145
|
# end
|
|
131
146
|
#
|
|
147
|
+
# # good - Active Support's redefinition markers signal an intentional
|
|
148
|
+
# # redefinition of a method defined in another file
|
|
149
|
+
# silence_redefinition_of_method :foo
|
|
150
|
+
# def foo
|
|
151
|
+
# 1
|
|
152
|
+
# end
|
|
153
|
+
#
|
|
154
|
+
# @example AllowedCrossFilePaths: ['script/**/*'] (default: [])
|
|
155
|
+
# # Cross-file duplicates whose other definition lives in a file
|
|
156
|
+
# # matching one of the patterns are not reported.
|
|
157
|
+
#
|
|
158
|
+
# # good - assuming `AppHelper#format` is also defined in
|
|
159
|
+
# # `script/backfill.rb`, which is never loaded with this file
|
|
160
|
+
# class AppHelper
|
|
161
|
+
# def format
|
|
162
|
+
# end
|
|
163
|
+
# end
|
|
164
|
+
#
|
|
132
165
|
# @example DelegatingMethods: ['delegate', 'expose'] (default: ['delegate'])
|
|
133
166
|
# # A project's own `delegate`-shaped macros can be registered so the
|
|
134
167
|
# # methods they define are recognized (with
|
|
@@ -160,13 +193,14 @@ module RuboCop
|
|
|
160
193
|
super
|
|
161
194
|
@definitions = {}
|
|
162
195
|
@scopes = Hash.new { |hash, key| hash[key] = [] }
|
|
163
|
-
@
|
|
196
|
+
@intentionally_redefined = Set.new
|
|
164
197
|
end
|
|
165
198
|
|
|
166
199
|
def on_new_investigation
|
|
167
|
-
# The self-alias trick
|
|
168
|
-
# the file that uses
|
|
169
|
-
|
|
200
|
+
# The self-alias trick and Active Support's redefinition markers declare
|
|
201
|
+
# an intentional redefinition only within the file that uses them, so the
|
|
202
|
+
# tracked names do not carry over.
|
|
203
|
+
@intentionally_redefined = Set.new
|
|
170
204
|
super
|
|
171
205
|
end
|
|
172
206
|
|
|
@@ -199,7 +233,7 @@ module RuboCop
|
|
|
199
233
|
return unless name && original_name
|
|
200
234
|
|
|
201
235
|
if name == original_name
|
|
202
|
-
|
|
236
|
+
track_intentional_redefinition(node, name)
|
|
203
237
|
return
|
|
204
238
|
end
|
|
205
239
|
return if node.ancestors.any?(&:if_type?)
|
|
@@ -241,6 +275,15 @@ module RuboCop
|
|
|
241
275
|
)
|
|
242
276
|
PATTERN
|
|
243
277
|
|
|
278
|
+
# Matches Active Support's markers of an intentional method redefinition:
|
|
279
|
+
# `silence_redefinition_of_method :name` suppresses Ruby's redefinition
|
|
280
|
+
# warning for a subsequent definition of `name`, and
|
|
281
|
+
# `redefine_method(:name) { ... }` both silences the warning and redefines.
|
|
282
|
+
# @!method active_support_redefinition_marker(node)
|
|
283
|
+
def_node_matcher :active_support_redefinition_marker, <<~PATTERN
|
|
284
|
+
(send nil? {:silence_redefinition_of_method :redefine_method} ({sym str} $_) ...)
|
|
285
|
+
PATTERN
|
|
286
|
+
|
|
244
287
|
# @!method sym_name(node)
|
|
245
288
|
def_node_matcher :sym_name, '(sym $_name)'
|
|
246
289
|
|
|
@@ -263,7 +306,7 @@ module RuboCop
|
|
|
263
306
|
|
|
264
307
|
if name && original_name
|
|
265
308
|
if name == original_name
|
|
266
|
-
|
|
309
|
+
track_intentional_redefinition(node, name)
|
|
267
310
|
return
|
|
268
311
|
end
|
|
269
312
|
return if inside_condition?(node)
|
|
@@ -283,6 +326,12 @@ module RuboCop
|
|
|
283
326
|
return if inside_condition?(node)
|
|
284
327
|
|
|
285
328
|
names.each { |name| found_instance_method(node, name) }
|
|
329
|
+
elsif (name = active_support_redefinition_marker(node))
|
|
330
|
+
# `redefine_method` takes a block; scope resolution must start from the
|
|
331
|
+
# block node, since `parent_module_name` cannot see through a block
|
|
332
|
+
# ancestor that is not a module constructor.
|
|
333
|
+
track_intentional_redefinition(node.block_node || node, name) if
|
|
334
|
+
active_support_extensions_enabled?
|
|
286
335
|
end
|
|
287
336
|
end
|
|
288
337
|
|
|
@@ -386,7 +435,7 @@ module RuboCop
|
|
|
386
435
|
|
|
387
436
|
def anon_block_scope_id(anon_block)
|
|
388
437
|
parent = anon_block.parent
|
|
389
|
-
return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def)
|
|
438
|
+
return unless parent&.type?(:any_block, :begin, :call, :casgn, :ivasgn, :any_def)
|
|
390
439
|
|
|
391
440
|
if (receiver = scope_receiver(parent, anon_block))
|
|
392
441
|
"#{receiver.source}.#{parent.method_name}"
|
|
@@ -441,27 +490,39 @@ module RuboCop
|
|
|
441
490
|
if scope && !@scopes[scope].include?(key)
|
|
442
491
|
@definitions[key] = node
|
|
443
492
|
@scopes[scope] << key
|
|
444
|
-
elsif intentional_cross_file_redefinition?(node, method_name, key)
|
|
493
|
+
elsif intentional_cross_file_redefinition?(node, method_name, key) ||
|
|
494
|
+
allowed_cross_file_redefinition?(node, key)
|
|
445
495
|
@definitions[key] = node
|
|
446
496
|
else
|
|
447
497
|
add_offense(location(node), message: message_for_dup(node, method_name, key))
|
|
448
498
|
end
|
|
449
499
|
end
|
|
450
500
|
|
|
501
|
+
# `AllowedCrossFilePaths` also covers duplicates detected without the index,
|
|
502
|
+
# when the cop instance carries definitions over from an earlier file of the
|
|
503
|
+
# same run.
|
|
504
|
+
def allowed_cross_file_redefinition?(node, key)
|
|
505
|
+
other_path = @definitions[key].source_range.source_buffer.name
|
|
506
|
+
return false if other_path == node.source_range.source_buffer.name
|
|
507
|
+
|
|
508
|
+
allowed_cross_file_path?(other_path)
|
|
509
|
+
end
|
|
510
|
+
|
|
451
511
|
# The self-alias trick (`alias foo foo` or `alias_method :foo, :foo` right before
|
|
452
512
|
# a `def`) suppresses Ruby's method redefinition warning, signaling an intentional
|
|
453
|
-
# redefinition of a method defined in another file.
|
|
513
|
+
# redefinition of a method defined in another file. Active Support's redefinition
|
|
514
|
+
# markers (tracked when `ActiveSupportExtensionsEnabled` is on) signal the same.
|
|
454
515
|
def intentional_cross_file_redefinition?(node, method_name, key)
|
|
455
|
-
@
|
|
516
|
+
@intentionally_redefined.include?(method_name) &&
|
|
456
517
|
@definitions[key].source_range.source_buffer.name !=
|
|
457
518
|
node.source_range.source_buffer.name
|
|
458
519
|
end
|
|
459
520
|
|
|
460
|
-
def
|
|
521
|
+
def track_intentional_redefinition(node, name)
|
|
461
522
|
scope = node.parent_module_name
|
|
462
523
|
return unless scope
|
|
463
524
|
|
|
464
|
-
@
|
|
525
|
+
@intentionally_redefined << "#{humanize_scope(scope)}#{name}"
|
|
465
526
|
end
|
|
466
527
|
|
|
467
528
|
def method_key(node, method_name)
|
|
@@ -544,7 +605,7 @@ module RuboCop
|
|
|
544
605
|
|
|
545
606
|
def check_cross_file_duplicate(node, method_name)
|
|
546
607
|
return unless project_index
|
|
547
|
-
return if @
|
|
608
|
+
return if @intentionally_redefined.include?(method_name)
|
|
548
609
|
return if node.each_ancestor(:any_def).any?
|
|
549
610
|
return unless (prior = cross_file_prior_definition(method_name))
|
|
550
611
|
|
|
@@ -559,12 +620,27 @@ module RuboCop
|
|
|
559
620
|
|
|
560
621
|
definitions = definitions_in_other_files(
|
|
561
622
|
indexed_definitions(match[:owner], match[:separator], match[:name])
|
|
562
|
-
)
|
|
623
|
+
).reject { |definition| allowed_cross_file_path?(definition.location.to_file_path) }
|
|
563
624
|
return if definitions.empty? || cross_file_self_alias_trick?(definitions)
|
|
625
|
+
return if cross_file_redefinition_marker?(definitions, match[:name])
|
|
564
626
|
|
|
565
627
|
first_indexed_definition(definitions)
|
|
566
628
|
end
|
|
567
629
|
|
|
630
|
+
# Cross-file duplicates whose other definition site matches one of the
|
|
631
|
+
# `AllowedCrossFilePaths` patterns are skipped (e.g. standalone scripts that
|
|
632
|
+
# are never loaded together with the code they redefine). Patterns are
|
|
633
|
+
# matched like `Exclude` patterns, against the path relative to the
|
|
634
|
+
# directory of the config file that configures the cop; absolute patterns
|
|
635
|
+
# are matched against the absolute path.
|
|
636
|
+
def allowed_cross_file_path?(path)
|
|
637
|
+
patterns = cop_config.fetch('AllowedCrossFilePaths', [])
|
|
638
|
+
return false if patterns.empty?
|
|
639
|
+
|
|
640
|
+
relative = config.path_relative_to_config(path)
|
|
641
|
+
patterns.any? { |pattern| match_path?(pattern, relative) || match_path?(pattern, path) }
|
|
642
|
+
end
|
|
643
|
+
|
|
568
644
|
def indexed_definitions(owner, separator, name)
|
|
569
645
|
namespace = separator == '.' ? "#{owner}::<#{owner.split('::').last}>" : owner
|
|
570
646
|
|
|
@@ -601,6 +677,28 @@ module RuboCop
|
|
|
601
677
|
others.any? { |definition| alias_paths.include?(definition.location.to_file_path) }
|
|
602
678
|
end
|
|
603
679
|
|
|
680
|
+
# An Active Support redefinition marker alongside one of the definitions in
|
|
681
|
+
# another file marks the redefinition there as intentional, like the
|
|
682
|
+
# self-alias trick. The index does not record the marker's method-name
|
|
683
|
+
# argument, so the other file's source is searched for a marker naming
|
|
684
|
+
# the method.
|
|
685
|
+
def cross_file_redefinition_marker?(definitions, name)
|
|
686
|
+
return false unless active_support_extensions_enabled?
|
|
687
|
+
|
|
688
|
+
definitions.map { |definition| definition.location.to_file_path }.uniq.any? do |path|
|
|
689
|
+
redefinition_marker_in_file?(path, name)
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def redefinition_marker_in_file?(path, name)
|
|
694
|
+
return false unless File.readable?(path)
|
|
695
|
+
|
|
696
|
+
escaped = Regexp.escape(name)
|
|
697
|
+
marker = /\b(?:silence_redefinition_of_method|redefine_method)\s*\(?\s*
|
|
698
|
+
(?::#{escaped}|(["'])#{escaped}\1)(?![\w=!?])/x
|
|
699
|
+
File.read(path).scrub.match?(marker)
|
|
700
|
+
end
|
|
701
|
+
|
|
604
702
|
def first_indexed_definition(definitions)
|
|
605
703
|
definitions.find { |definition| !definition.is_a?(Rubydex::MethodAliasDefinition) }
|
|
606
704
|
end
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
|
63
63
|
class EmptyBlock < Base
|
|
64
64
|
MSG = 'Empty block detected.'
|
|
65
65
|
|
|
66
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
66
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- an empty block has no parameters to number
|
|
67
67
|
return if node.body
|
|
68
68
|
return if allow_empty_lambdas? && node.lambda_or_proc?
|
|
69
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
|
28
28
|
FOR_METHOD = ' Or, if they were intended to be separate method ' \
|
|
29
29
|
'arguments, separate them with a comma.'
|
|
30
30
|
|
|
31
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
31
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
32
32
|
def on_dstr(node)
|
|
33
33
|
each_bad_cons(node) do |lhs_node, rhs_node|
|
|
34
34
|
range = lhs_node.source_range.join(rhs_node.source_range)
|
|
@@ -52,7 +52,6 @@ module RuboCop
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
56
55
|
|
|
57
56
|
private
|
|
58
57
|
|
|
@@ -80,7 +80,7 @@ module RuboCop
|
|
|
80
80
|
alternative: alternative)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
83
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
84
84
|
def ineffective_modifier(node, ignored_methods = nil, modifier = nil, &block)
|
|
85
85
|
node.each_child_node do |child|
|
|
86
86
|
case child.type
|
|
@@ -97,7 +97,6 @@ module RuboCop
|
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
101
100
|
|
|
102
101
|
def access_modifier?(node)
|
|
103
102
|
node.bare_access_modifier? && !node.method?(:module_function)
|
|
@@ -41,7 +41,7 @@ module RuboCop
|
|
|
41
41
|
|
|
42
42
|
private
|
|
43
43
|
|
|
44
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
44
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
45
45
|
def check(node)
|
|
46
46
|
return if node.parent&.regexp_type?
|
|
47
47
|
return unless /(?<!\\)#\{.*\}/.match?(node.source)
|
|
@@ -51,7 +51,6 @@ module RuboCop
|
|
|
51
51
|
|
|
52
52
|
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
|
53
53
|
end
|
|
54
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
55
54
|
|
|
56
55
|
def autocorrect(corrector, node)
|
|
57
56
|
starting_token, ending_token = if node.source.include?('"')
|
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
|
48
48
|
add_offense(node.lhs) do |corrector|
|
|
49
49
|
# Don't autocorrect `'foo' && return` because having `return` as
|
|
50
50
|
# the leftmost node can lead to a void value expression syntax error.
|
|
51
|
-
next if node.rhs
|
|
51
|
+
next if void_value_expression?(node.rhs)
|
|
52
52
|
|
|
53
53
|
corrector.replace(node, node.rhs.source)
|
|
54
54
|
end
|
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
|
60
60
|
add_offense(node.lhs) do |corrector|
|
|
61
61
|
# Don't autocorrect `'foo' && return` because having `return` as
|
|
62
62
|
# the leftmost node can lead to a void value expression syntax error.
|
|
63
|
-
next if node.rhs
|
|
63
|
+
next if void_value_expression?(node.rhs)
|
|
64
64
|
|
|
65
65
|
corrector.replace(node, node.rhs.source)
|
|
66
66
|
end
|
|
@@ -88,7 +88,7 @@ module RuboCop
|
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
# rubocop:disable Metrics/AbcSize
|
|
91
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
92
92
|
def on_while_post(node)
|
|
93
93
|
return if node.condition.source == 'true'
|
|
94
94
|
|
|
@@ -102,7 +102,6 @@ module RuboCop
|
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
|
-
# rubocop:enable Metrics/AbcSize
|
|
106
105
|
|
|
107
106
|
def on_until(node)
|
|
108
107
|
return if node.condition.source == 'false'
|
|
@@ -118,7 +117,7 @@ module RuboCop
|
|
|
118
117
|
end
|
|
119
118
|
end
|
|
120
119
|
|
|
121
|
-
# rubocop:disable Metrics/AbcSize
|
|
120
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
122
121
|
def on_until_post(node)
|
|
123
122
|
return if node.condition.source == 'false'
|
|
124
123
|
|
|
@@ -132,7 +131,6 @@ module RuboCop
|
|
|
132
131
|
end
|
|
133
132
|
end
|
|
134
133
|
end
|
|
135
|
-
# rubocop:enable Metrics/AbcSize
|
|
136
134
|
|
|
137
135
|
def on_case(case_node)
|
|
138
136
|
if (cond = case_node.condition)
|
|
@@ -177,6 +175,12 @@ module RuboCop
|
|
|
177
175
|
|
|
178
176
|
private
|
|
179
177
|
|
|
178
|
+
def void_value_expression?(node)
|
|
179
|
+
node = node.children.last while node&.begin_type?
|
|
180
|
+
|
|
181
|
+
node&.type?(:return, :break, :next)
|
|
182
|
+
end
|
|
183
|
+
|
|
180
184
|
def check_for_literal(node)
|
|
181
185
|
cond = condition(node)
|
|
182
186
|
if cond.literal?
|
|
@@ -250,7 +254,7 @@ module RuboCop
|
|
|
250
254
|
end
|
|
251
255
|
end
|
|
252
256
|
|
|
253
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
257
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
254
258
|
def correct_if_node(node, cond)
|
|
255
259
|
result = condition_evaluation?(node, cond)
|
|
256
260
|
|
|
@@ -281,7 +285,6 @@ module RuboCop
|
|
|
281
285
|
ignore_node(node)
|
|
282
286
|
end
|
|
283
287
|
end
|
|
284
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
285
288
|
end
|
|
286
289
|
end
|
|
287
290
|
end
|