rubocop 1.69.2 → 1.75.4
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/LICENSE.txt +1 -1
- data/README.md +4 -4
- data/config/default.yml +183 -41
- data/config/internal_affairs.yml +20 -0
- data/config/obsoletion.yml +3 -1
- data/lib/rubocop/cli/command/execute_runner.rb +3 -3
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/comment_config.rb +2 -2
- data/lib/rubocop/config.rb +52 -10
- data/lib/rubocop/config_loader.rb +52 -9
- data/lib/rubocop/config_loader_resolver.rb +36 -10
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
- data/lib/rubocop/config_obsoletion.rb +46 -2
- data/lib/rubocop/config_validator.rb +25 -14
- data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +8 -4
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
- data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +230 -0
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
- data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
- data/lib/rubocop/cop/internal_affairs.rb +6 -16
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/class_structure.rb +9 -9
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +28 -1
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +7 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/line_length.rb +9 -4
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -11
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -5
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
- data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +7 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
- data/lib/rubocop/cop/lint/debugger.rb +3 -3
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
- data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
- data/lib/rubocop/cop/lint/float_comparison.rb +6 -8
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +117 -9
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +2 -2
- data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -3
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
- data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
- data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/syntax.rb +4 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +2 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +12 -9
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +9 -1
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/mixin/alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +13 -13
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
- data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
- data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
- data/lib/rubocop/cop/mixin/range_help.rb +15 -3
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
- data/lib/rubocop/cop/mixin/string_help.rb +2 -2
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +16 -4
- data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +64 -8
- data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
- data/lib/rubocop/cop/naming/variable_name.rb +51 -6
- data/lib/rubocop/cop/registry.rb +9 -6
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
- data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +44 -28
- data/lib/rubocop/cop/style/array_first_last.rb +18 -2
- data/lib/rubocop/cop/style/array_intersect.rb +39 -28
- data/lib/rubocop/cop/style/block_delimiters.rb +9 -21
- data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +2 -1
- data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
- data/lib/rubocop/cop/style/comparable_between.rb +75 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +20 -6
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +4 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -3
- data/lib/rubocop/cop/style/empty_else.rb +4 -2
- data/lib/rubocop/cop/style/empty_literal.rb +5 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +163 -18
- data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
- data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +8 -4
- data/lib/rubocop/cop/style/for.rb +1 -0
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- data/lib/rubocop/cop/style/guard_clause.rb +2 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
- data/lib/rubocop/cop/style/hash_except.rb +24 -148
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
- data/lib/rubocop/cop/style/hash_slice.rb +80 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
- data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +15 -11
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
- data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
- data/lib/rubocop/cop/style/it_assignment.rb +36 -0
- data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
- data/lib/rubocop/cop/style/lambda.rb +1 -0
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/map_into_array.rb +5 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
- data/lib/rubocop/cop/style/map_to_set.rb +3 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -16
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_else.rb +2 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
- data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
- data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/next.rb +44 -0
- data/lib/rubocop/cop/style/object_then.rb +14 -15
- data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/proc.rb +2 -2
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +14 -12
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +59 -2
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
- data/lib/rubocop/cop/style/redundant_each.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
- data/lib/rubocop/cop/style/redundant_format.rb +257 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
- data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -16
- data/lib/rubocop/cop/style/redundant_parentheses.rb +48 -16
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +1 -0
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +20 -5
- data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +4 -3
- data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
- data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
- data/lib/rubocop/cop/style/string_concatenation.rb +2 -2
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/string_methods.rb +1 -1
- data/lib/rubocop/cop/style/super_arguments.rb +66 -19
- data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +11 -2
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
- data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
- data/lib/rubocop/cop/util.rb +12 -5
- data/lib/rubocop/cop/utils/format_string.rb +10 -5
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +10 -3
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
- data/lib/rubocop/cop/variable_force.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +31 -16
- data/lib/rubocop/directive_comment.rb +45 -11
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +189 -0
- data/lib/rubocop/lsp/logger.rb +2 -2
- data/lib/rubocop/lsp/routes.rb +7 -23
- data/lib/rubocop/lsp/runtime.rb +18 -50
- data/lib/rubocop/lsp/server.rb +0 -2
- data/lib/rubocop/lsp/stdin_runner.rb +85 -0
- data/lib/rubocop/magic_comment.rb +8 -0
- data/lib/rubocop/options.rb +28 -12
- data/lib/rubocop/path_util.rb +15 -8
- data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +46 -0
- data/lib/rubocop/rake_task.rb +4 -1
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/cop_helper.rb +13 -1
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/rspec/shared_contexts.rb +38 -1
- data/lib/rubocop/rspec/support.rb +4 -2
- data/lib/rubocop/runner.rb +10 -7
- data/lib/rubocop/server/cache.rb +47 -11
- data/lib/rubocop/server/cli.rb +2 -2
- data/lib/rubocop/target_finder.rb +7 -2
- data/lib/rubocop/target_ruby.rb +16 -1
- data/lib/rubocop/version.rb +30 -8
- data/lib/rubocop.rb +16 -1
- data/lib/ruby_lsp/rubocop/addon.rb +75 -0
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
- metadata +59 -16
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -3,21 +3,22 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# Handles validation of configuration, for example cop names, parameter
|
5
5
|
# names, and Ruby versions.
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
6
7
|
class ConfigValidator
|
7
8
|
extend SimpleForwardable
|
8
9
|
|
9
10
|
# @api private
|
10
11
|
COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
|
11
|
-
Enabled].freeze
|
12
|
+
Enabled Reference References].freeze
|
12
13
|
# @api private
|
13
14
|
INTERNAL_PARAMS = %w[Description StyleGuide
|
14
15
|
VersionAdded VersionChanged VersionRemoved
|
15
|
-
Reference Safe SafeAutoCorrect].freeze
|
16
|
+
Reference References Safe SafeAutoCorrect].freeze
|
16
17
|
# @api private
|
17
18
|
NEW_COPS_VALUES = %w[pending disable enable].freeze
|
18
19
|
|
19
20
|
# @api private
|
20
|
-
CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect].to_set.freeze
|
21
|
+
CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect References].to_set.freeze
|
21
22
|
CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
|
22
23
|
CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
|
23
24
|
private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
|
@@ -41,8 +42,9 @@ module RuboCop
|
|
41
42
|
ConfigLoader.default_configuration.key?(key)
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
+
validate_parameter_shape(valid_cop_names)
|
45
46
|
|
47
|
+
check_obsoletions
|
46
48
|
alert_about_unrecognized_cops(invalid_cop_names)
|
47
49
|
validate_new_cops_parameter
|
48
50
|
validate_parameter_names(valid_cop_names)
|
@@ -64,12 +66,6 @@ module RuboCop
|
|
64
66
|
target_ruby.version
|
65
67
|
end
|
66
68
|
|
67
|
-
def validate_section_presence(name)
|
68
|
-
return unless @config.key?(name) && @config[name].nil?
|
69
|
-
|
70
|
-
raise ValidationError, "empty section #{name} found in #{smart_loaded_path}"
|
71
|
-
end
|
72
|
-
|
73
69
|
private
|
74
70
|
|
75
71
|
attr_reader :target_ruby
|
@@ -122,6 +118,7 @@ module RuboCop
|
|
122
118
|
invalid_cop_names.each do |name|
|
123
119
|
# There could be a custom cop with this name. If so, don't warn
|
124
120
|
next if Cop::Registry.global.contains_cop_matching?([name])
|
121
|
+
next if ConfigObsoletion.deprecated_cop_name?(name)
|
125
122
|
|
126
123
|
# Special case for inherit_mode, which is a directive that we keep in
|
127
124
|
# the configuration (even though it's not a cop), because it's easier
|
@@ -177,9 +174,22 @@ module RuboCop
|
|
177
174
|
raise ValidationError, message
|
178
175
|
end
|
179
176
|
|
177
|
+
def validate_parameter_shape(valid_cop_names)
|
178
|
+
valid_cop_names.each do |name|
|
179
|
+
if @config[name].nil?
|
180
|
+
raise ValidationError, "empty section #{name.inspect} found in #{smart_loaded_path}"
|
181
|
+
elsif !@config[name].is_a?(Hash)
|
182
|
+
raise ValidationError, <<~MESSAGE
|
183
|
+
The configuration for #{name.inspect} in #{smart_loaded_path} is not a Hash.
|
184
|
+
|
185
|
+
Found: #{@config[name].inspect}
|
186
|
+
MESSAGE
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
180
191
|
def validate_parameter_names(valid_cop_names)
|
181
192
|
valid_cop_names.each do |name|
|
182
|
-
validate_section_presence(name)
|
183
193
|
each_invalid_parameter(name) do |param, supported_params|
|
184
194
|
warn Rainbow(<<~MESSAGE).yellow
|
185
195
|
Warning: #{name} does not support #{param} parameter.
|
@@ -250,8 +260,7 @@ module RuboCop
|
|
250
260
|
end
|
251
261
|
end
|
252
262
|
|
253
|
-
# rubocop:disable Metrics/
|
254
|
-
def check_cop_config_value(hash, parent = nil)
|
263
|
+
def check_cop_config_value(hash, parent = nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
255
264
|
hash.each do |key, value|
|
256
265
|
check_cop_config_value(value, key) if value.is_a?(Hash)
|
257
266
|
|
@@ -261,6 +270,8 @@ module RuboCop
|
|
261
270
|
supposed_values = 'a boolean'
|
262
271
|
elsif key == 'AutoCorrect' && !CONFIG_CHECK_AUTOCORRECTS.include?(value)
|
263
272
|
supposed_values = '`always`, `contextual`, `disabled`, or a boolean'
|
273
|
+
elsif key == 'References'
|
274
|
+
supposed_values = 'an array of strings'
|
264
275
|
else
|
265
276
|
next
|
266
277
|
end
|
@@ -268,7 +279,6 @@ module RuboCop
|
|
268
279
|
raise ValidationError, param_error_message(parent, key, value, supposed_values)
|
269
280
|
end
|
270
281
|
end
|
271
|
-
# rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
272
282
|
|
273
283
|
# FIXME: Handling colors in exception messages like this is ugly.
|
274
284
|
def param_error_message(parent, key, value, supposed_values)
|
@@ -277,4 +287,5 @@ module RuboCop
|
|
277
287
|
"is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
|
278
288
|
end
|
279
289
|
end
|
290
|
+
# rubocop:enable Metrics/ClassLength
|
280
291
|
end
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def string_continuation?(node)
|
105
|
-
|
105
|
+
node.type?(:str, :dstr, :xstr) && node.source.match?(/\\\s*$/)
|
106
106
|
end
|
107
107
|
|
108
108
|
def multiline_string?(node)
|
data/lib/rubocop/cop/base.rb
CHANGED
@@ -261,6 +261,12 @@ module RuboCop
|
|
261
261
|
@config.target_ruby_version
|
262
262
|
end
|
263
263
|
|
264
|
+
# Returns a gems locked versions (i.e. from Gemfile.lock or gems.locked)
|
265
|
+
# @returns [Gem::Version | nil] The locked gem version, or nil if the gem is not present.
|
266
|
+
def target_gem_version(gem_name)
|
267
|
+
@config.gem_versions_in_target && @config.gem_versions_in_target[gem_name]
|
268
|
+
end
|
269
|
+
|
264
270
|
def parser_engine
|
265
271
|
@config.parser_engine
|
266
272
|
end
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
|
67
67
|
def conditional_declaration?(nodes)
|
68
68
|
parent = nodes[0].each_ancestor.find { |ancestor| !ancestor.begin_type? }
|
69
|
-
return false unless parent&.
|
69
|
+
return false unless parent&.type?(:if, :when)
|
70
70
|
|
71
71
|
root_conditional_node = parent.if_type? ? parent : parent.parent
|
72
72
|
nodes.all? { |node| within_conditional?(node, root_conditional_node) }
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Use `config.cop_enabled?('Department/CopName')` instead of
|
7
|
+
# traversing the config hash.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # `for_cop(...)['Enabled']
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# config.for_cop('Department/CopName')['Enabled']
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# config.cop_enabled?('Department/CopName')
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # when keeping a cop's config in a local and then checking the `Enabled` key
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# cop_config = config.for_cop('Department/CopName')
|
23
|
+
# cop_config['Enabled'] && cop_config['Foo']
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# config.for_enabled_cop('Department/CopName')['Foo']
|
27
|
+
#
|
28
|
+
class CopEnabled < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
|
32
|
+
MSG_HASH = 'Consider replacing uses of `%<hash_name>s` with `config.for_enabled_cop`.'
|
33
|
+
|
34
|
+
RESTRICT_ON_SEND = [:[]].freeze
|
35
|
+
|
36
|
+
# @!method for_cop_enabled?(node)
|
37
|
+
def_node_matcher :for_cop_enabled?, <<~PATTERN
|
38
|
+
(send
|
39
|
+
(send
|
40
|
+
${(send nil? :config) (ivar :@config)} :for_cop
|
41
|
+
$(str _)) :[]
|
42
|
+
(str "Enabled"))
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
# @!method config_enabled_lookup?(node)
|
46
|
+
def_node_matcher :config_enabled_lookup?, <<~PATTERN
|
47
|
+
(send
|
48
|
+
{(lvar $_) (ivar $_) (send nil? $_)} :[]
|
49
|
+
(str "Enabled"))
|
50
|
+
PATTERN
|
51
|
+
|
52
|
+
def on_send(node)
|
53
|
+
if (config_var, cop_name = for_cop_enabled?(node))
|
54
|
+
handle_for_cop(node, config_var, cop_name)
|
55
|
+
elsif (config_var = config_enabled_lookup?(node))
|
56
|
+
return unless config_var.end_with?('_config')
|
57
|
+
|
58
|
+
handle_hash(node, config_var)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def handle_for_cop(node, config_var, cop_name)
|
65
|
+
source = node.source
|
66
|
+
quote = cop_name.loc.begin.source
|
67
|
+
cop_name = cop_name.value
|
68
|
+
|
69
|
+
replacement = "#{config_var.source}.cop_enabled?(#{quote}#{cop_name}#{quote})"
|
70
|
+
message = format(MSG, source: source, replacement: replacement)
|
71
|
+
|
72
|
+
add_offense(node, message: message) do |corrector|
|
73
|
+
corrector.replace(node, replacement)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle_hash(node, config_var)
|
78
|
+
message = format(MSG_HASH, hash_name: config_var)
|
79
|
+
|
80
|
+
add_offense(node, message: message)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -50,10 +50,12 @@ module RuboCop
|
|
50
50
|
}.freeze
|
51
51
|
|
52
52
|
EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
|
53
|
-
/\A(auto[- ]?)?
|
53
|
+
/\A(auto[- ]?)?corrects?/ => 'does not correct',
|
54
|
+
/\band (auto[- ]?)?corrects/ => 'but does not correct'
|
54
55
|
}.freeze
|
55
56
|
|
56
57
|
EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
|
58
|
+
/\bbut (does not|doesn't) (auto[- ]?)?correct/ => 'and autocorrects',
|
57
59
|
/\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
|
58
60
|
}.freeze
|
59
61
|
|
@@ -67,7 +69,7 @@ module RuboCop
|
|
67
69
|
# @!method offense_example(node)
|
68
70
|
def_node_matcher :offense_example, <<~PATTERN
|
69
71
|
(block
|
70
|
-
(send _ {:it :specify} $...)
|
72
|
+
(send _ {:it :specify :xit :fit} $...)
|
71
73
|
_args
|
72
74
|
`(send nil? %RESTRICT_ON_SEND ...)
|
73
75
|
)
|
@@ -90,8 +92,10 @@ module RuboCop
|
|
90
92
|
description_text = string_contents(current_description)
|
91
93
|
return unless (new_description = correct_description(description_text, description_map))
|
92
94
|
|
95
|
+
quote = current_description.dstr_type? ? '"' : "'"
|
96
|
+
|
93
97
|
add_offense(current_description, message: message) do |corrector|
|
94
|
-
corrector.replace(current_description, "
|
98
|
+
corrector.replace(current_description, "#{quote}#{new_description}#{quote}")
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
@@ -106,7 +110,7 @@ module RuboCop
|
|
106
110
|
end
|
107
111
|
|
108
112
|
def string_contents(node)
|
109
|
-
node.
|
113
|
+
node.type?(:str, :dstr) ? node.value : node.source
|
110
114
|
end
|
111
115
|
end
|
112
116
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# When a node location may not exist, `Node#loc?` or `Node#loc_is?`
|
7
|
+
# can be used instead of calling `Node#respond_to?` before using
|
8
|
+
# the value.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# node.loc.respond_to?(:begin) && node.loc.begin
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# node.loc?(:begin)
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# node.loc.respond_to?(:begin) && node.loc.begin.is?('(')
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# node.loc_is?(:begin, '(')
|
22
|
+
#
|
23
|
+
# # bad
|
24
|
+
# node.loc.respond_to?(:begin) && node.loc.begin.source == '('
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# node.loc_is?(:begin, '(')
|
28
|
+
#
|
29
|
+
class LocationExists < Base
|
30
|
+
extend AutoCorrector
|
31
|
+
|
32
|
+
MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
|
33
|
+
|
34
|
+
# @!method replaceable_with_loc_is(node)
|
35
|
+
def_node_matcher :replaceable_with_loc_is, <<~PATTERN
|
36
|
+
(and
|
37
|
+
(call
|
38
|
+
(call $_receiver :loc) :respond_to?
|
39
|
+
$(sym _location))
|
40
|
+
{
|
41
|
+
(call
|
42
|
+
(call
|
43
|
+
(call _receiver :loc) _location) :is?
|
44
|
+
$(str _))
|
45
|
+
(call
|
46
|
+
(call
|
47
|
+
(call
|
48
|
+
(call _receiver :loc) _location) :source) :==
|
49
|
+
$(str _))
|
50
|
+
})
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
# @!method replaceable_with_loc(node)
|
54
|
+
def_node_matcher :replaceable_with_loc, <<~PATTERN
|
55
|
+
(and
|
56
|
+
(call
|
57
|
+
(call $_receiver :loc) :respond_to?
|
58
|
+
$(sym _location))
|
59
|
+
(call
|
60
|
+
(call _receiver :loc) _location))
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
def on_and(node)
|
64
|
+
replace_with_loc(node) || replace_with_loc_is(node)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def replace_with_loc(node)
|
70
|
+
replaceable_with_loc(node) do |receiver, location|
|
71
|
+
if node.parent&.assignment?
|
72
|
+
register_offense(node, replace_assignment(receiver, location))
|
73
|
+
else
|
74
|
+
register_offense(node, replacement(receiver, "loc?(#{location.source})"))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def replace_with_loc_is(node)
|
80
|
+
replaceable_with_loc_is(node) do |receiver, location, value|
|
81
|
+
replacement = replacement(receiver, "loc_is?(#{location.source}, #{value.source})")
|
82
|
+
register_offense(node, replacement)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def register_offense(node, replacement)
|
87
|
+
message = format(MSG, replacement: replacement, source: node.source)
|
88
|
+
|
89
|
+
add_offense(node, message: message) do |corrector|
|
90
|
+
corrector.replace(node, replacement)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def replacement(receiver, rest)
|
95
|
+
"#{replace_receiver(receiver)}#{rest}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def replace_assignment(receiver, location)
|
99
|
+
prefix = replace_receiver(receiver)
|
100
|
+
|
101
|
+
"#{prefix}loc#{dot(receiver)}#{location.value} if #{prefix}loc?(#{location.source})"
|
102
|
+
end
|
103
|
+
|
104
|
+
def replace_receiver(receiver)
|
105
|
+
return '' unless receiver
|
106
|
+
|
107
|
+
"#{receiver.source}#{dot(receiver)}"
|
108
|
+
end
|
109
|
+
|
110
|
+
def dot(node)
|
111
|
+
node.parent.loc.dot.source
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -22,7 +22,7 @@ module RuboCop
|
|
22
22
|
|
23
23
|
def on_send(node)
|
24
24
|
return unless (parent = node.parent)
|
25
|
-
return unless parent.
|
25
|
+
return unless parent.call_type? && parent.method?(:expression)
|
26
26
|
return unless parent.receiver.receiver
|
27
27
|
|
28
28
|
offense = node.loc.selector.join(parent.source_range.end)
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
corrector.replace(offense, 'source_range')
|
32
32
|
end
|
33
33
|
end
|
34
|
+
alias on_csend on_send
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
@@ -27,8 +27,8 @@ module RuboCop
|
|
27
27
|
# @!method arguments_first_or_last?(node)
|
28
28
|
def_node_matcher :arguments_first_or_last?, <<~PATTERN
|
29
29
|
{
|
30
|
-
(
|
31
|
-
(
|
30
|
+
(call (call !nil? :arguments) ${:first :last})
|
31
|
+
(call (call !nil? :arguments) :[] (int ${0 -1}))
|
32
32
|
}
|
33
33
|
PATTERN
|
34
34
|
|
@@ -47,6 +47,7 @@ module RuboCop
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
+
alias on_csend on_send
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
class NodePatternGroups
|
7
|
+
# AST Processor for NodePattern ASTs, for use with `InternalAffairs/NodePatternGroups`.
|
8
|
+
#
|
9
|
+
# Looks for sequences and subsequences where the first item is a `node_type` node,
|
10
|
+
# and converts them to `node_sequence` nodes (not a true `Rubocop::AST::NodePattern`
|
11
|
+
# node type).
|
12
|
+
#
|
13
|
+
# The resulting AST will be walked by `InternalAffairs::NodePatternGroups::ASTWalker`
|
14
|
+
# in order to find node types in a `union` node that can be rewritten as a node group.
|
15
|
+
#
|
16
|
+
# NOTE: The `on_*` methods in this class relate not to the normal node types but
|
17
|
+
# rather to the Node Pattern node types. Not every node type is handled.
|
18
|
+
#
|
19
|
+
class ASTProcessor
|
20
|
+
include ::AST::Processor::Mixin
|
21
|
+
|
22
|
+
def handler_missing(node)
|
23
|
+
node.updated(nil, process_children(node))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Look for `sequence` and `subsequence` nodes that contain a `node_type` node as
|
27
|
+
# their first child. These are rewritten as `node_sequence` nodes so that it is
|
28
|
+
# possible to compare nodes while looking for replacement candidates for node groups.
|
29
|
+
# This is necessary so that extended patterns can be matched and replaced.
|
30
|
+
# ie. `{(send _ :foo ...) (csend _ :foo ...)}` can become `(call _ :foo ...)`
|
31
|
+
def on_sequence(node)
|
32
|
+
first_child = node.child
|
33
|
+
|
34
|
+
if first_child.type == :node_type
|
35
|
+
children = [first_child.child, *process_children(node, 1..)]
|
36
|
+
|
37
|
+
# The `node_sequence` node contains the `node_type` symbol as its first child,
|
38
|
+
# followed by all the other nodes contained in the `sequence` node.
|
39
|
+
# The location is copied from the sequence, so that the entire sequence can
|
40
|
+
# eventually be corrected in the cop.
|
41
|
+
n(:node_sequence, children, location: node.location)
|
42
|
+
else
|
43
|
+
node.updated(nil, process_children(node))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
alias on_subsequence on_sequence
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def n(type, children = [], properties = {})
|
51
|
+
NodePattern::Node.new(type, children, properties)
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_children(node, range = 0..-1)
|
55
|
+
node.children[range].map do |child|
|
56
|
+
child.is_a?(::AST::Node) ? process(child) : child
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# rubocop:disable InternalAffairs/RedundantSourceRange -- node here is a `NodePattern::Node`
|
7
|
+
class NodePatternGroups
|
8
|
+
# Walks an AST that has been processed by `InternalAffairs::NodePatternGroups::Processor`
|
9
|
+
# in order to find `node_type` and `node_sequence` nodes that can be replaced with a node
|
10
|
+
# group in `InternalAffairs/NodePatternGroups`.
|
11
|
+
#
|
12
|
+
# Calling `ASTWalker#walk` sets `node_groups` with an array of `NodeGroup` structs
|
13
|
+
# that contain metadata about nodes that can be replaced, including location data. That
|
14
|
+
# metadata is used by the cop to register offenses and perform corrections.
|
15
|
+
class ASTWalker
|
16
|
+
# Struct to contain data about parts of a node pattern that can be replaced
|
17
|
+
NodeGroup = Struct.new(
|
18
|
+
:name, # The name of the node group that will be inserted
|
19
|
+
:union, # The entire `union` node
|
20
|
+
:node_types, # An array of `node_type` nodes that will be removed
|
21
|
+
:sequence?, # The pattern matches a node type with given attributes
|
22
|
+
:start_index, # The index in the union of the first node type to remove
|
23
|
+
:offense_range, # The range to mark an offense on
|
24
|
+
:ranges, # Range of each element to remove, since they may not be adjacent
|
25
|
+
:pipe, # Is the union delimited by pipes?
|
26
|
+
:other_elements?, # Does the union have other elements other than those to remove?
|
27
|
+
keyword_init: true
|
28
|
+
)
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
reset!
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset!
|
35
|
+
@node_groups = []
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :node_groups
|
39
|
+
|
40
|
+
# Recursively walk the AST in a depth-first manner.
|
41
|
+
# Only `union` nodes are handled further.
|
42
|
+
def walk(node)
|
43
|
+
return if node.nil?
|
44
|
+
|
45
|
+
on_union(node) if node.type == :union
|
46
|
+
|
47
|
+
node.child_nodes.each do |child|
|
48
|
+
walk(child)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Search `union` nodes for `node_type` and `node_sequence` nodes that can be
|
53
|
+
# collapsed into a node group.
|
54
|
+
# * `node_type` nodes are nodes with no further configuration (ie. `send`)
|
55
|
+
# * `node_sequence` nodes are nodes with further configuration (ie. `(send ...)`)
|
56
|
+
#
|
57
|
+
# Each group of types that can be collapsed will have a `NodeGroup` record added
|
58
|
+
# to `node_groups`, which is then used by the cop.
|
59
|
+
def on_union(node)
|
60
|
+
all_node_types = each_child_node(node, :node_type, :node_sequence).to_a
|
61
|
+
|
62
|
+
each_node_group(all_node_types) do |group_name, node_types|
|
63
|
+
next unless sequences_match?(node_types)
|
64
|
+
|
65
|
+
node_groups << node_group_data(
|
66
|
+
group_name, node, node_types,
|
67
|
+
all_node_types.index(node_types.first),
|
68
|
+
(node.children - node_types).any?
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def each_child_node(node, *types)
|
76
|
+
return to_enum(__method__, node, *types) unless block_given?
|
77
|
+
|
78
|
+
node.children.each do |child|
|
79
|
+
yield child if types.empty? || types.include?(child.type)
|
80
|
+
end
|
81
|
+
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def each_node_group(types_to_check)
|
86
|
+
# Find all node groups where all of the members are present in the union
|
87
|
+
type_names = types_to_check.map(&:child)
|
88
|
+
|
89
|
+
NODE_GROUPS.select { |_, group| group & type_names == group }.each_key do |name|
|
90
|
+
nodes = get_relevant_nodes(types_to_check, name)
|
91
|
+
|
92
|
+
yield name, nodes
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_relevant_nodes(node_types, group_name)
|
97
|
+
node_types.each_with_object([]) do |node_type, arr|
|
98
|
+
next unless NODE_GROUPS[group_name].include?(node_type.child)
|
99
|
+
|
100
|
+
arr << node_type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def node_group_data(name, union, node_types, start_index, other)
|
105
|
+
NodeGroup.new(
|
106
|
+
name: name,
|
107
|
+
union: union,
|
108
|
+
node_types: node_types,
|
109
|
+
sequence?: node_types.first.type == :node_sequence,
|
110
|
+
start_index: start_index,
|
111
|
+
pipe: union.source_range.source['|'],
|
112
|
+
other_elements?: other
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def sequences_match?(types)
|
117
|
+
# Ensure all given types have the same type and the same sequence
|
118
|
+
# ie. `(send ...)` and `(csend ...) is a match
|
119
|
+
# `(send)` and `(csend ...)` is not a match
|
120
|
+
# `send` and `(csend ...)` is not a match
|
121
|
+
|
122
|
+
types.each_cons(2).all? do |left, right|
|
123
|
+
left.type == right.type && left.children[1..] == right.children[1..]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
# rubocop:enable InternalAffairs/RedundantSourceRange
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|