rubocop 1.90.0 → 1.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +241 -11
- data/config/obsoletion.yml +9 -0
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +134 -0
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +23 -3
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/show_cops.rb +6 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
- data/lib/rubocop/cli.rb +11 -4
- data/lib/rubocop/comment_config/directive_range.rb +3 -1
- data/lib/rubocop/comment_config/disable_next.rb +49 -3
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +32 -53
- data/lib/rubocop/config.rb +10 -0
- data/lib/rubocop/config_loader.rb +18 -7
- data/lib/rubocop/config_loader_resolver.rb +79 -12
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +29 -3
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +57 -24
- data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
- data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- data/lib/rubocop/cop/correctors.rb +2 -2
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/class_structure.rb +9 -1
- data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +15 -10
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -4
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +71 -19
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
- data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +23 -2
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -4
- 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/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +42 -17
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
- data/lib/rubocop/cop/lint/void.rb +8 -1
- data/lib/rubocop/cop/lint.rb +1 -0
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/migration/department_name.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +5 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -2
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +31 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +29 -3
- data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
- data/lib/rubocop/cop/mixin.rb +4 -2
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- 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/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +10 -2
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +10 -2
- data/lib/rubocop/cop/style/alias.rb +18 -5
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +3 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
- data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
- data/lib/rubocop/cop/style/case_like_if.rb +9 -6
- data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
- data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/directive_scope.rb +154 -21
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +118 -18
- data/lib/rubocop/cop/style/documentation_method.rb +1 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- 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_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +15 -3
- data/lib/rubocop/cop/style/endless_method.rb +91 -11
- data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/file_null.rb +2 -2
- data/lib/rubocop/cop/style/float_division.rb +28 -14
- data/lib/rubocop/cop/style/for.rb +44 -1
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +13 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +35 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +18 -0
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
- data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +48 -8
- 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 +10 -3
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +14 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +34 -17
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
- data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +25 -5
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +9 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/sample.rb +9 -8
- data/lib/rubocop/cop/style/self_assignment.rb +12 -15
- data/lib/rubocop/cop/style/semicolon.rb +16 -5
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
- data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
- data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
- data/lib/rubocop/cop/style.rb +0 -1
- data/lib/rubocop/cop/team.rb +10 -5
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/cops_documentation_generator.rb +23 -2
- data/lib/rubocop/directive_comment.rb +37 -8
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
- data/lib/rubocop/formatter/formatter_set.rb +6 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -2
- data/lib/rubocop/formatter/json_formatter.rb +71 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/formatter.rb +1 -0
- data/lib/rubocop/lsp/runtime.rb +47 -11
- data/lib/rubocop/lsp/stdin_runner.rb +11 -5
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/magic_comment.rb +27 -0
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +184 -76
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +97 -4
- data/lib/rubocop/path_util.rb +1 -1
- data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +8 -5
- data/lib/rubocop/result_cache.rb +36 -18
- data/lib/rubocop/runner.rb +160 -49
- data/lib/rubocop/server/cache.rb +2 -2
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +9 -1
- metadata +21 -6
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for magic comments placed where Ruby silently ignores them.
|
|
7
|
+
#
|
|
8
|
+
# The `encoding` magic comment is only honored on the first line of a file,
|
|
9
|
+
# or on the second line when the first line is a shebang. Anywhere else it
|
|
10
|
+
# is silently ignored - even directly below another comment or a blank line.
|
|
11
|
+
#
|
|
12
|
+
# Other magic comments (such as `frozen_string_literal`) are honored
|
|
13
|
+
# anywhere before the first token of code, but are ignored after any code,
|
|
14
|
+
# with a warning emitted only when running Ruby with `-w`.
|
|
15
|
+
#
|
|
16
|
+
# A magic comment misplaced ahead of a shebang also renders the shebang
|
|
17
|
+
# ineffective, since a shebang is only recognized on the first line.
|
|
18
|
+
#
|
|
19
|
+
# NOTE: An `encoding` comment that is only preceded by other magic
|
|
20
|
+
# comments is not flagged by this cop; that case is handled by
|
|
21
|
+
# `Lint/OrderedMagicComments`. `shareable_constant_value` is never
|
|
22
|
+
# flagged, as Ruby intentionally allows it mid-file with block scoping.
|
|
23
|
+
#
|
|
24
|
+
# @safety
|
|
25
|
+
# This cop's autocorrection is unsafe because moving the magic comment
|
|
26
|
+
# to its effective position activates it, which changes runtime
|
|
27
|
+
# behavior (e.g. the source encoding or string mutability).
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# # bad
|
|
31
|
+
# # Documentation comment
|
|
32
|
+
# # encoding: ascii-8bit
|
|
33
|
+
# puts 'hello'
|
|
34
|
+
#
|
|
35
|
+
# # good
|
|
36
|
+
# # encoding: ascii-8bit
|
|
37
|
+
# # Documentation comment
|
|
38
|
+
# puts 'hello'
|
|
39
|
+
#
|
|
40
|
+
# # bad
|
|
41
|
+
# require 'foo'
|
|
42
|
+
# # frozen_string_literal: true
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# # frozen_string_literal: true
|
|
46
|
+
# require 'foo'
|
|
47
|
+
#
|
|
48
|
+
# # bad
|
|
49
|
+
# # frozen_string_literal: true
|
|
50
|
+
# #!/usr/bin/env ruby
|
|
51
|
+
# puts 'hello'
|
|
52
|
+
#
|
|
53
|
+
# # good
|
|
54
|
+
# #!/usr/bin/env ruby
|
|
55
|
+
# # frozen_string_literal: true
|
|
56
|
+
# puts 'hello'
|
|
57
|
+
class MisplacedMagicComment < Base
|
|
58
|
+
include RangeHelp
|
|
59
|
+
extend AutoCorrector
|
|
60
|
+
|
|
61
|
+
MSG_ENCODING = 'The `encoding` magic comment is ignored unless placed on the first ' \
|
|
62
|
+
'line (or below a shebang on the first line).'
|
|
63
|
+
MSG_AFTER_CODE = 'The `%<directive>s` magic comment is ignored after any code.'
|
|
64
|
+
MSG_ABOVE_SHEBANG = 'A magic comment above a shebang renders the shebang ineffective.'
|
|
65
|
+
|
|
66
|
+
def on_new_investigation
|
|
67
|
+
return if processed_source.buffer.source.empty?
|
|
68
|
+
|
|
69
|
+
check_magic_comment_above_shebang
|
|
70
|
+
processed_source.comments.each { |comment| check_comment(comment) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def check_comment(comment)
|
|
76
|
+
return unless magic_comment_shaped?(comment.text)
|
|
77
|
+
|
|
78
|
+
magic_comment = MagicComment.parse(comment.text)
|
|
79
|
+
return unless magic_comment.valid?
|
|
80
|
+
|
|
81
|
+
if magic_comment.encoding_specified?
|
|
82
|
+
return unless known_encoding?(magic_comment.encoding)
|
|
83
|
+
|
|
84
|
+
check_encoding_comment(comment)
|
|
85
|
+
elsif magic_comment.frozen_string_literal_specified?
|
|
86
|
+
check_top_block_comment(comment, 'frozen_string_literal')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# The Emacs and Vim regexps in `MagicComment` match anywhere inside a
|
|
91
|
+
# comment, which would flag documentation that merely quotes a magic
|
|
92
|
+
# comment (e.g. `# # -*- coding: UTF-8 -*-`). Require the magic
|
|
93
|
+
# comment to start right after the `#`.
|
|
94
|
+
def magic_comment_shaped?(text)
|
|
95
|
+
/\A#(?![^#]*#)/.match?(text)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Prose that happens to open with `Encoding:` parses as an encoding
|
|
99
|
+
# comment (`# Encoding: force given encoding` yields `force`). Ruby
|
|
100
|
+
# ignores a misplaced encoding comment entirely, so a name no encoding
|
|
101
|
+
# answers to means the line is a comment, not a directive.
|
|
102
|
+
def known_encoding?(name)
|
|
103
|
+
Encoding.find(name)
|
|
104
|
+
true
|
|
105
|
+
rescue ArgumentError
|
|
106
|
+
false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def shebang?
|
|
110
|
+
processed_source.lines.first.to_s.start_with?('#!')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# First line that may carry an effective encoding comment.
|
|
114
|
+
def effective_encoding_line
|
|
115
|
+
shebang? ? 2 : 1
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def first_code_token
|
|
119
|
+
processed_source.sorted_tokens.find { |token| !token.comment? }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def check_encoding_comment(comment)
|
|
123
|
+
return unless misplaced_encoding_position?(comment)
|
|
124
|
+
|
|
125
|
+
add_offense(comment, message: MSG_ENCODING) do |corrector|
|
|
126
|
+
correct_encoding_comment(corrector, comment)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def misplaced_encoding_position?(comment)
|
|
131
|
+
line = comment.source_range.line
|
|
132
|
+
return false if line == effective_encoding_line && comment_starts_line?(comment)
|
|
133
|
+
|
|
134
|
+
# Leave `# frozen_string_literal: true` + `# encoding: x` runs at the
|
|
135
|
+
# very top to Lint/OrderedMagicComments, which already reorders them.
|
|
136
|
+
!preceded_only_by_magic_comments?(comment)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# With an effective encoding comment already in place, moving another
|
|
140
|
+
# one in would override it. Drop an identical duplicate and leave a
|
|
141
|
+
# conflicting one for a human to resolve.
|
|
142
|
+
def correct_encoding_comment(corrector, comment)
|
|
143
|
+
effective_comment = effective_encoding_comment
|
|
144
|
+
|
|
145
|
+
if effective_comment.nil?
|
|
146
|
+
move_comment(corrector, comment, effective_encoding_line)
|
|
147
|
+
elsif comment_encoding(effective_comment) == comment_encoding(comment)
|
|
148
|
+
corrector.remove(comment_removal_range(comment))
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def comment_encoding(comment)
|
|
153
|
+
Encoding.find(MagicComment.parse(comment.text).encoding)
|
|
154
|
+
rescue ArgumentError
|
|
155
|
+
nil
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def check_top_block_comment(comment, directive)
|
|
159
|
+
return unless first_code_token
|
|
160
|
+
return unless comment.source_range.begin_pos > first_code_token.begin_pos
|
|
161
|
+
|
|
162
|
+
message = format(MSG_AFTER_CODE, directive: directive)
|
|
163
|
+
add_offense(comment, message: message) do |corrector|
|
|
164
|
+
# Both would be inserted at the top, in no reliable order. Leave
|
|
165
|
+
# this one to the next pass, once the encoding comment is in place.
|
|
166
|
+
next if encoding_comment_moving_in?
|
|
167
|
+
|
|
168
|
+
move_comment(corrector, comment, top_block_insertion_line)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def encoding_comment_moving_in?
|
|
173
|
+
return false if effective_encoding_comment
|
|
174
|
+
|
|
175
|
+
processed_source.comments.any? do |comment|
|
|
176
|
+
known_encoding_comment?(comment) && misplaced_encoding_position?(comment)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def effective_encoding_comment
|
|
181
|
+
processed_source.comments.find do |comment|
|
|
182
|
+
comment.source_range.line == effective_encoding_line &&
|
|
183
|
+
comment_starts_line?(comment) &&
|
|
184
|
+
MagicComment.parse(comment.text).encoding_specified?
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def known_encoding_comment?(comment)
|
|
189
|
+
return false unless magic_comment_shaped?(comment.text)
|
|
190
|
+
|
|
191
|
+
magic_comment = MagicComment.parse(comment.text)
|
|
192
|
+
magic_comment.encoding_specified? && known_encoding?(magic_comment.encoding)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Insert below an effective encoding comment rather than above it,
|
|
196
|
+
# which would push it off the only lines where Ruby honors it.
|
|
197
|
+
def top_block_insertion_line
|
|
198
|
+
effective_encoding_comment ? effective_encoding_line + 1 : effective_encoding_line
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def check_magic_comment_above_shebang
|
|
202
|
+
shebang_comment = processed_source.comments.find do |comment|
|
|
203
|
+
comment.source_range.line > 1 && comment.text.start_with?('#!') &&
|
|
204
|
+
comment.source_range.column.zero?
|
|
205
|
+
end
|
|
206
|
+
return unless shebang_comment
|
|
207
|
+
# Only flag when what precedes the shebang is magic comments -
|
|
208
|
+
# a `#!` comment deep inside a file is not an intended shebang.
|
|
209
|
+
return unless preceded_only_by_magic_comments?(shebang_comment)
|
|
210
|
+
|
|
211
|
+
add_offense(shebang_comment, message: MSG_ABOVE_SHEBANG)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def preceded_only_by_magic_comments?(comment)
|
|
215
|
+
(1...comment.source_range.line).all? do |line_number|
|
|
216
|
+
text = processed_source.lines[line_number - 1]
|
|
217
|
+
(line_number == 1 && text.start_with?('#!')) || MagicComment.parse(text).valid?
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def comment_starts_line?(comment)
|
|
222
|
+
processed_source.lines[comment.source_range.line - 1].lstrip.start_with?('#')
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def move_comment(corrector, comment, target_line)
|
|
226
|
+
corrector.remove(comment_removal_range(comment))
|
|
227
|
+
target_range = processed_source.buffer.line_range(target_line)
|
|
228
|
+
if comment.source_range.line < target_line
|
|
229
|
+
corrector.insert_after(target_range, "\n#{comment.text}")
|
|
230
|
+
else
|
|
231
|
+
corrector.insert_before(target_range, "#{comment.text}\n")
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def comment_removal_range(comment)
|
|
236
|
+
if comment_starts_line?(comment)
|
|
237
|
+
range_by_whole_lines(comment.source_range, include_final_newline: true)
|
|
238
|
+
else
|
|
239
|
+
range_with_surrounding_space(comment.source_range, side: :left)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rubocop:disable-next Lint/RedundantCopDisableDirective
|
|
3
|
+
# rubocop:disable-next Lint/RedundantCopDisableDirective -- the examples below read as real directives
|
|
4
4
|
module RuboCop
|
|
5
5
|
module Cop
|
|
6
6
|
module Lint
|
|
@@ -62,7 +62,7 @@ module RuboCop
|
|
|
62
62
|
each_missing_enable do |cop, line_range|
|
|
63
63
|
next if acceptable_range?(cop, line_range)
|
|
64
64
|
|
|
65
|
-
comment =
|
|
65
|
+
comment = opening_comment(line_range)
|
|
66
66
|
|
|
67
67
|
add_offense(comment, message: message(cop, comment))
|
|
68
68
|
end
|
|
@@ -73,14 +73,29 @@ module RuboCop
|
|
|
73
73
|
def each_missing_enable
|
|
74
74
|
processed_source.disabled_line_ranges.each do |cop, line_ranges|
|
|
75
75
|
line_ranges.each do |line_range|
|
|
76
|
-
# A `disable-next` scope closes itself with its statement.
|
|
77
|
-
next if
|
|
76
|
+
# A `disable-next` or `next` scope closes itself with its statement.
|
|
77
|
+
next if statement_scoped?(line_range)
|
|
78
78
|
|
|
79
79
|
yield cop, line_range
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def statement_scoped?(line_range)
|
|
85
|
+
directive = line_range.respond_to?(:directive) && line_range.directive
|
|
86
|
+
directive && (directive.disable_next? || directive.next?)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# A disable suspended by `enable-next` or `next +Cop` reopens below the
|
|
90
|
+
# statement, on a code line, so the comment that opened it has to come
|
|
91
|
+
# from the range rather than from its first line.
|
|
92
|
+
def opening_comment(line_range)
|
|
93
|
+
directive = line_range.respond_to?(:directive) && line_range.directive
|
|
94
|
+
return directive.comment if directive
|
|
95
|
+
|
|
96
|
+
processed_source.comment_at_line(line_range.begin)
|
|
97
|
+
end
|
|
98
|
+
|
|
84
99
|
def acceptable_range?(cop, line_range)
|
|
85
100
|
# This has to remain a strict inequality to handle
|
|
86
101
|
# the case when max_range is Float::INFINITY
|
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
|
95
95
|
MSG = 'Method definitions must not be nested. Use `lambda` instead.'
|
|
96
96
|
|
|
97
97
|
def on_def(node)
|
|
98
|
-
subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
|
98
|
+
subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring -- the first child differs between `def` and `defs`
|
|
99
99
|
return if node.defs_type? && allowed_subject_type?(subject)
|
|
100
100
|
|
|
101
101
|
def_ancestor = node.each_ancestor(:any_def).first
|
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
|
67
67
|
|
|
68
68
|
# NOTE: itblock is not handled because this cop is limited to Ruby <= 2.7
|
|
69
69
|
# via `maximum_target_ruby_version`, so itblock nodes (Ruby 3.4+) are never encountered.
|
|
70
|
-
def on_block(node) # rubocop:disable InternalAffairs/ItblockHandler
|
|
70
|
+
def on_block(node) # rubocop:disable InternalAffairs/ItblockHandler -- limited to Ruby <= 2.7, where `it` blocks do not exist
|
|
71
71
|
return unless node.body
|
|
72
72
|
return unless unsorted_dir_loop?(node.send_node)
|
|
73
73
|
|
|
@@ -132,7 +132,7 @@ module RuboCop
|
|
|
132
132
|
|
|
133
133
|
def handle_as_symbol(node)
|
|
134
134
|
to_method_symbol(node) do |receiver, sym_node, to_method|
|
|
135
|
-
next if receiver.nil? || !node.arguments.one?
|
|
135
|
+
next if receiver.nil? || !node.arguments.one? || node.operator_method?
|
|
136
136
|
|
|
137
137
|
message = format(
|
|
138
138
|
MSG,
|
|
@@ -46,13 +46,29 @@ module RuboCop
|
|
|
46
46
|
|
|
47
47
|
def valid_first_argument?(first_arg)
|
|
48
48
|
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg) ||
|
|
49
|
-
compound_range?(first_arg)
|
|
49
|
+
compound_range?(first_arg) || invalid_bare_argument?(first_arg)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def compound_range?(first_arg)
|
|
53
53
|
first_arg.range_type? && first_arg.parenthesized_call?
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
def invalid_bare_argument?(node)
|
|
57
|
+
node = node.children.first while node&.begin_type? && node.children.one?
|
|
58
|
+
return false unless node
|
|
59
|
+
|
|
60
|
+
keyword_operator?(node) || modifier_expression?(node)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def keyword_operator?(node)
|
|
64
|
+
(node.operator_keyword? && node.semantic_operator?) ||
|
|
65
|
+
node.rescue_type? || (node.send_type? && node.prefix_not?)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def modifier_expression?(node)
|
|
69
|
+
node.type?(:if, :while, :until) && node.modifier_form?
|
|
70
|
+
end
|
|
71
|
+
|
|
56
72
|
def chained_calls?(node)
|
|
57
73
|
first_argument = node.first_argument
|
|
58
74
|
first_argument.call_type? && (node.children.last&.children&.count || 0) > 1
|
|
@@ -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-next 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
|
|
@@ -110,7 +110,7 @@ module RuboCop
|
|
|
110
110
|
# A pending cop that is not enabled in this run produces no
|
|
111
111
|
# offenses, so its directives cannot be judged - they typically
|
|
112
112
|
# prepare the code for the moment the cop gets enabled.
|
|
113
|
-
next if pending_cop_not_run?(cop)
|
|
113
|
+
next if pending_cop_not_run?(cop) || disabled_by_preview?(cop)
|
|
114
114
|
|
|
115
115
|
each_already_disabled(cop, line_ranges, &block)
|
|
116
116
|
each_line_range(cop, line_ranges, &block)
|
|
@@ -128,6 +128,17 @@ module RuboCop
|
|
|
128
128
|
!processed_source.registry.enabled_pending_cop?(cop_cfg, config, cop)
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
+
# A cop that only the `Preview` defaults disable runs again as soon as
|
|
132
|
+
# preview is turned off, so its directives are still needed.
|
|
133
|
+
def disabled_by_preview?(cop)
|
|
134
|
+
return false unless preview? && all_cop_names.include?(cop)
|
|
135
|
+
|
|
136
|
+
preview_defaults = ConfigLoader.default_configuration[cop]&.fetch('Preview', nil)
|
|
137
|
+
return false unless preview_defaults.is_a?(Hash) && preview_defaults['Enabled'] == false
|
|
138
|
+
|
|
139
|
+
!config.cop_enabled?(cop)
|
|
140
|
+
end
|
|
141
|
+
|
|
131
142
|
def each_line_range(cop, line_ranges)
|
|
132
143
|
line_ranges.each_with_index do |line_range, line_range_index|
|
|
133
144
|
next if should_skip_line_range?(cop, line_range)
|
|
@@ -155,17 +166,29 @@ module RuboCop
|
|
|
155
166
|
end
|
|
156
167
|
end
|
|
157
168
|
|
|
158
|
-
# A
|
|
159
|
-
# of a code line)
|
|
169
|
+
# A next-statement directive with no statement attached (or misplaced
|
|
170
|
+
# at the end of a code line) affects nothing, so it is redundant by
|
|
171
|
+
# definition.
|
|
160
172
|
def each_detached_next_directive
|
|
161
173
|
processed_source.comment_config.detached_next_directives.each do |directive|
|
|
162
|
-
|
|
174
|
+
names = if directive.next?
|
|
175
|
+
directive.signed_args.values.flatten
|
|
176
|
+
else
|
|
177
|
+
directive.raw_cop_names
|
|
178
|
+
end
|
|
179
|
+
names.each { |cop| yield directive.comment, cop }
|
|
163
180
|
end
|
|
164
181
|
end
|
|
165
182
|
|
|
166
183
|
def skip_directive?(comment)
|
|
184
|
+
# A cop disabled in the configuration is represented by a synthetic directive that
|
|
185
|
+
# has no comment in the source, so there is nothing to report or to remove.
|
|
186
|
+
# Its range starts at `CONFIG_DISABLED_LINE_RANGE_MIN` and runs to the end of the file,
|
|
187
|
+
# but a `pop` splits it, and the pieces in between are bounded on both sides.
|
|
188
|
+
return true if comment.is_a?(CommentConfig::ConfigDisabledCopDirectiveComment)
|
|
189
|
+
|
|
167
190
|
directive = DirectiveComment.new(comment)
|
|
168
|
-
directive.push? || directive.pop?
|
|
191
|
+
directive.push? || directive.pop? || directive.next?
|
|
169
192
|
end
|
|
170
193
|
|
|
171
194
|
def find_redundant_directive(cop, comment, line_range, next_range)
|
|
@@ -190,11 +213,11 @@ module RuboCop
|
|
|
190
213
|
|
|
191
214
|
comment = directive_comment(range)
|
|
192
215
|
|
|
193
|
-
next
|
|
194
|
-
#
|
|
195
|
-
# to disable a few select cops first and then all cops
|
|
196
|
-
# down in the code.
|
|
197
|
-
next if all_disabled?(comment)
|
|
216
|
+
# `push`/`next` signed arguments are not analyzed for redundancy
|
|
217
|
+
# (yet), and comments disabling all cops don't count since it's
|
|
218
|
+
# reasonable to disable a few select cops first and then all cops
|
|
219
|
+
# further down in the code.
|
|
220
|
+
next if comment.nil? || skip_directive?(comment) || all_disabled?(comment)
|
|
198
221
|
|
|
199
222
|
redundant =
|
|
200
223
|
if department_disabled?(cop, comment)
|
|
@@ -280,18 +303,20 @@ module RuboCop
|
|
|
280
303
|
end
|
|
281
304
|
|
|
282
305
|
def add_offense_for_entire_comment(comment, cops)
|
|
283
|
-
|
|
306
|
+
directive = DirectiveComment.new(comment)
|
|
307
|
+
location = directive.range
|
|
284
308
|
cop_names = cops.sort.map { |c| describe(c) }.join(', ')
|
|
285
309
|
|
|
286
310
|
# An unknown cop may just not be loaded in this run (e.g. a custom
|
|
287
311
|
# cop whose configuration failed to load) - removing its directive
|
|
288
312
|
# would destroy something that cannot be restored, so only report.
|
|
289
313
|
# A misplaced EOL `disable-next` should be moved, not deleted.
|
|
314
|
+
message = message(cop_names, enabling: directive.enable_next?)
|
|
290
315
|
if any_unknown_cop?(cops) || misplaced_next_directive?(comment)
|
|
291
|
-
return add_offense(location, message: message
|
|
316
|
+
return add_offense(location, message: message)
|
|
292
317
|
end
|
|
293
318
|
|
|
294
|
-
add_offense(location, message: message
|
|
319
|
+
add_offense(location, message: message) do |corrector|
|
|
295
320
|
remove_entire_comment(corrector, comment)
|
|
296
321
|
end
|
|
297
322
|
end
|
|
@@ -333,7 +358,7 @@ module RuboCop
|
|
|
333
358
|
|
|
334
359
|
def misplaced_next_directive?(comment)
|
|
335
360
|
directive = DirectiveComment.new(comment)
|
|
336
|
-
directive.disable_next? &&
|
|
361
|
+
(directive.disable_next? || directive.next? || directive.enable_next?) &&
|
|
337
362
|
!processed_source.comment_config.comment_only_line?(directive.line_number)
|
|
338
363
|
end
|
|
339
364
|
|
|
@@ -396,8 +421,8 @@ module RuboCop
|
|
|
396
421
|
similar ? "`#{cop}` (did you mean `#{similar}`?)" : "`#{cop}` (unknown cop)"
|
|
397
422
|
end
|
|
398
423
|
|
|
399
|
-
def message(cop_names)
|
|
400
|
-
"Unnecessary disabling of #{cop_names}."
|
|
424
|
+
def message(cop_names, enabling: false)
|
|
425
|
+
"Unnecessary #{enabling ? 'enabling' : 'disabling'} of #{cop_names}."
|
|
401
426
|
end
|
|
402
427
|
|
|
403
428
|
def all_cop_names
|
|
@@ -28,6 +28,7 @@ module RuboCop
|
|
|
28
28
|
# end
|
|
29
29
|
#
|
|
30
30
|
class RedundantDirGlobSort < Base
|
|
31
|
+
include RangeHelp
|
|
31
32
|
extend AutoCorrector
|
|
32
33
|
extend TargetRubyVersion
|
|
33
34
|
|
|
@@ -46,8 +47,7 @@ module RuboCop
|
|
|
46
47
|
selector = node.loc.selector
|
|
47
48
|
|
|
48
49
|
add_offense(selector) do |corrector|
|
|
49
|
-
corrector.
|
|
50
|
-
corrector.remove(node.loc.dot)
|
|
50
|
+
autocorrect(corrector, node.loc.dot, selector)
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -67,6 +67,17 @@ module RuboCop
|
|
|
67
67
|
def sort_with_comparator?(node)
|
|
68
68
|
node.parent&.any_block_type? || node.last_argument&.block_pass_type?
|
|
69
69
|
end
|
|
70
|
+
|
|
71
|
+
def autocorrect(corrector, dot, selector)
|
|
72
|
+
range = dot.join(selector)
|
|
73
|
+
|
|
74
|
+
if processed_source.contains_comment?(range)
|
|
75
|
+
corrector.remove(dot)
|
|
76
|
+
corrector.remove(selector)
|
|
77
|
+
else
|
|
78
|
+
corrector.remove(range_with_surrounding_space(range, side: :left))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
70
81
|
end
|
|
71
82
|
end
|
|
72
83
|
end
|
|
@@ -53,12 +53,22 @@ module RuboCop
|
|
|
53
53
|
return if node.each_descendant(:dstr).any?
|
|
54
54
|
|
|
55
55
|
regexp_constructor(node) do |text|
|
|
56
|
+
next unless verbatim_string?(text)
|
|
57
|
+
|
|
56
58
|
detect_offenses_in_tree(text, parse_regexp(text.value))
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
private
|
|
61
63
|
|
|
64
|
+
# Offsets into the string's value only point at the right place in the source
|
|
65
|
+
# when the string has no escape sequences, so anything else is left alone.
|
|
66
|
+
def verbatim_string?(node)
|
|
67
|
+
return false unless node.loc?(:begin) && node.loc?(:end)
|
|
68
|
+
|
|
69
|
+
node.loc.begin.end.join(node.loc.end.begin).source == node.value
|
|
70
|
+
end
|
|
71
|
+
|
|
62
72
|
# When a character class opens with a bare `]` (e.g. `[^]]`), `regexp_parser` parses
|
|
63
73
|
# `[^]` / `[]` as an empty set and reports the closing `]` as a separate literal.
|
|
64
74
|
# Ruby treats that `]` as the end of the class, not as an unescaped bracket,
|
|
@@ -97,7 +107,7 @@ module RuboCop
|
|
|
97
107
|
location = range_at_index(node, expr.ts, pos)
|
|
98
108
|
|
|
99
109
|
add_offense(location) do |corrector|
|
|
100
|
-
corrector.replace(location,
|
|
110
|
+
corrector.replace(location, escaped_bracket(node))
|
|
101
111
|
end
|
|
102
112
|
end
|
|
103
113
|
|
|
@@ -108,6 +118,13 @@ module RuboCop
|
|
|
108
118
|
adjustment = index + offset
|
|
109
119
|
node.loc.begin.end.adjust(begin_pos: adjustment, end_pos: adjustment + 1)
|
|
110
120
|
end
|
|
121
|
+
|
|
122
|
+
# A double-quoted string turns `\]` into `]`, so its backslash needs escaping too.
|
|
123
|
+
def escaped_bracket(node)
|
|
124
|
+
return '\]' if node.regexp_type? || node.single_quoted? || node.percent_literal?(:q)
|
|
125
|
+
|
|
126
|
+
'\\\\]'
|
|
127
|
+
end
|
|
111
128
|
end
|
|
112
129
|
end
|
|
113
130
|
end
|
|
@@ -212,16 +212,23 @@ module RuboCop
|
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
def remove_local_variable_assignment_part(corrector, node)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def variable_in_loop_condition?(assignment_node, variable)
|
|
219
|
-
return false if assignment_node.each_ancestor(:any_def).any?
|
|
215
|
+
expression = node.expression
|
|
216
|
+
assignment_part = node.loc.name.begin.join(expression.source_range.begin)
|
|
220
217
|
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
# `x = 1, 2` cannot become `1, 2`, so the values become an array literal.
|
|
219
|
+
if expression.array_type? && !expression.bracketed?
|
|
220
|
+
corrector.replace(assignment_part, '[')
|
|
221
|
+
corrector.insert_after(expression, ']')
|
|
222
|
+
else
|
|
223
|
+
corrector.remove(assignment_part)
|
|
223
224
|
end
|
|
225
|
+
end
|
|
224
226
|
|
|
227
|
+
def variable_in_loop_condition?(assignment_node, variable)
|
|
228
|
+
# A method defined inside the loop has its own scope, so the loop condition
|
|
229
|
+
# can only read the variable if the loop is nearer than any method definition.
|
|
230
|
+
loop_node = assignment_node.each_ancestor(*VariableForce::LOOP_TYPES, :any_def).first
|
|
231
|
+
return false if !loop_node || loop_node.any_def_type?
|
|
225
232
|
return false unless loop_node.respond_to?(:condition)
|
|
226
233
|
|
|
227
234
|
condition_node = loop_node.condition
|
|
@@ -271,7 +271,14 @@ module RuboCop
|
|
|
271
271
|
return if node.parent.type?(:if, :case, :when, :case_match, :in_pattern)
|
|
272
272
|
return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
|
|
273
273
|
|
|
274
|
-
|
|
274
|
+
range = range_with_surrounding_space(range: void_expression_range(node), side: :left)
|
|
275
|
+
corrector.remove(range)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def void_expression_range(node)
|
|
279
|
+
return node.source_range unless node.respond_to?(:heredoc?) && node.heredoc?
|
|
280
|
+
|
|
281
|
+
node.source_range.join(node.loc.heredoc_end)
|
|
275
282
|
end
|
|
276
283
|
|
|
277
284
|
def autocorrect_nonmutating_send(corrector, node, suggestion)
|
data/lib/rubocop/cop/lint.rb
CHANGED
|
@@ -76,6 +76,7 @@ module RuboCop
|
|
|
76
76
|
register_cop :LiteralAssignmentInCondition, "#{__dir__}/lint/literal_assignment_in_condition"
|
|
77
77
|
register_cop :LiteralInInterpolation, "#{__dir__}/lint/literal_in_interpolation"
|
|
78
78
|
register_cop :Loop, "#{__dir__}/lint/loop"
|
|
79
|
+
register_cop :MisplacedMagicComment, "#{__dir__}/lint/misplaced_magic_comment"
|
|
79
80
|
register_cop :MissingCopEnableDirective, "#{__dir__}/lint/missing_cop_enable_directive"
|
|
80
81
|
register_cop :MissingSuper, "#{__dir__}/lint/missing_super"
|
|
81
82
|
register_cop :MixedCaseRange, "#{__dir__}/lint/mixed_case_range"
|
|
@@ -40,6 +40,8 @@ module RuboCop
|
|
|
40
40
|
class ClassLength < Base
|
|
41
41
|
include CodeLength
|
|
42
42
|
|
|
43
|
+
LABEL = 'Class'
|
|
44
|
+
|
|
43
45
|
def on_class(node)
|
|
44
46
|
check_code_length(node)
|
|
45
47
|
end
|
|
@@ -60,8 +62,8 @@ module RuboCop
|
|
|
60
62
|
|
|
61
63
|
private
|
|
62
64
|
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
+
def cop_label
|
|
66
|
+
LABEL
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
def find_expression_within_parent(parent)
|
|
@@ -38,6 +38,8 @@ module RuboCop
|
|
|
38
38
|
class ModuleLength < Base
|
|
39
39
|
include CodeLength
|
|
40
40
|
|
|
41
|
+
LABEL = 'Module'
|
|
42
|
+
|
|
41
43
|
def on_module(node)
|
|
42
44
|
check_code_length(node)
|
|
43
45
|
end
|
|
@@ -53,8 +55,8 @@ module RuboCop
|
|
|
53
55
|
(casgn nil? _ (any_block (send (const {nil? cbase} :Module) :new) ...))
|
|
54
56
|
PATTERN
|
|
55
57
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
+
def cop_label
|
|
59
|
+
LABEL
|
|
58
60
|
end
|
|
59
61
|
end
|
|
60
62
|
end
|