rubocop 1.50.2 → 1.62.1
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 +7 -5
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +196 -28
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
- data/lib/rubocop/cli/command/lsp.rb +19 -0
- data/lib/rubocop/cli.rb +10 -2
- data/lib/rubocop/config.rb +8 -2
- data/lib/rubocop/config_finder.rb +14 -4
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_loader_resolver.rb +4 -3
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +13 -10
- data/lib/rubocop/config_validator.rb +14 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
- data/lib/rubocop/cop/base.rb +23 -4
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
- data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
- data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
- data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +19 -5
- data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
- data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
- data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +34 -5
- data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
- data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
- data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
- data/lib/rubocop/cop/lint/useless_times.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +97 -11
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +8 -3
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
- data/lib/rubocop/cop/migration/department_name.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/string_help.rb +4 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
- data/lib/rubocop/cop/naming/constant_name.rb +2 -3
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
- data/lib/rubocop/cop/style/alias.rb +9 -8
- data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/attr.rb +11 -1
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/begin_block.rb +1 -2
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
- data/lib/rubocop/cop/style/case_like_if.rb +5 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +32 -12
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
- data/lib/rubocop/cop/style/copyright.rb +5 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/dir_empty.rb +8 -14
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
- data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/file_read.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +3 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
- data/lib/rubocop/cop/style/guard_clause.rb +28 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
- data/lib/rubocop/cop/style/hash_except.rb +21 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- 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 +34 -5
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
- data/lib/rubocop/cop/style/lambda.rb +3 -3
- data/lib/rubocop/cop/style/lambda_call.rb +5 -0
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +24 -9
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
- data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +32 -8
- data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_return.rb +14 -3
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
- data/lib/rubocop/cop/style/require_order.rb +11 -5
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
- data/lib/rubocop/cop/style/sample.rb +3 -4
- data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +20 -4
- data/lib/rubocop/cop/style/signal_exception.rb +1 -1
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_array.rb +35 -15
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
- data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/cops_documentation_generator.rb +16 -4
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/ext/regexp_parser.rb +4 -1
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +35 -14
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/logger.rb +22 -0
- data/lib/rubocop/lsp/routes.rb +246 -0
- data/lib/rubocop/lsp/runtime.rb +99 -0
- data/lib/rubocop/lsp/server.rb +71 -0
- data/lib/rubocop/lsp/severity.rb +27 -0
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +13 -11
- data/lib/rubocop/options.rb +22 -9
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/result_cache.rb +5 -2
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +8 -8
- data/lib/rubocop/rspec/shared_contexts.rb +42 -18
- data/lib/rubocop/rspec/support.rb +2 -0
- data/lib/rubocop/runner.rb +15 -6
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/server/client_command/exec.rb +3 -3
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/string_interpreter.rb +3 -3
- data/lib/rubocop/target_finder.rb +91 -81
- data/lib/rubocop/target_ruby.rb +85 -78
- data/lib/rubocop/version.rb +27 -8
- data/lib/rubocop.rb +19 -0
- metadata +56 -14
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -10,13 +10,17 @@ module RuboCop
|
|
10
10
|
|
11
11
|
AUTO_GENERATED_FILE = '.rubocop_todo.yml'
|
12
12
|
YAML_OPTIONAL_DOC_START = /\A---(\s+#|\s*\z)/.freeze
|
13
|
+
PLACEHOLDER = '###rubocop:inherit_here'
|
13
14
|
|
14
15
|
PHASE_1 = 'Phase 1 of 2: run Layout/LineLength cop'
|
15
16
|
PHASE_2 = 'Phase 2 of 2: run all cops'
|
16
17
|
|
17
18
|
PHASE_1_OVERRIDDEN = '(skipped because the default Layout/LineLength:Max is overridden)'
|
18
19
|
PHASE_1_DISABLED = '(skipped because Layout/LineLength is disabled)'
|
19
|
-
|
20
|
+
PHASE_1_SKIPPED_ONLY_COPS =
|
21
|
+
'(skipped because a list of cops is passed to the `--only` flag)'
|
22
|
+
PHASE_1_SKIPPED_ONLY_EXCLUDE =
|
23
|
+
'(skipped because only excludes will be generated due to `--auto-gen-only-exclude` flag)'
|
20
24
|
|
21
25
|
def run
|
22
26
|
add_formatter
|
@@ -28,12 +32,14 @@ module RuboCop
|
|
28
32
|
private
|
29
33
|
|
30
34
|
def maybe_run_line_length_cop
|
31
|
-
if
|
35
|
+
if only_exclude?
|
36
|
+
skip_line_length_cop(PHASE_1_SKIPPED_ONLY_EXCLUDE)
|
37
|
+
elsif !line_length_enabled?(@config_store.for_pwd)
|
32
38
|
skip_line_length_cop(PHASE_1_DISABLED)
|
33
39
|
elsif !same_max_line_length?(@config_store.for_pwd, ConfigLoader.default_configuration)
|
34
40
|
skip_line_length_cop(PHASE_1_OVERRIDDEN)
|
35
41
|
elsif options_has_only_flag?
|
36
|
-
skip_line_length_cop(
|
42
|
+
skip_line_length_cop(PHASE_1_SKIPPED_ONLY_COPS)
|
37
43
|
else
|
38
44
|
run_line_length_cop
|
39
45
|
end
|
@@ -64,6 +70,10 @@ module RuboCop
|
|
64
70
|
@options[:only]
|
65
71
|
end
|
66
72
|
|
73
|
+
def only_exclude?
|
74
|
+
@options[:auto_gen_only_exclude]
|
75
|
+
end
|
76
|
+
|
67
77
|
# Do an initial run with only Layout/LineLength so that cops that
|
68
78
|
# depend on Layout/LineLength:Max get the correct value for that
|
69
79
|
# parameter.
|
@@ -125,15 +135,19 @@ module RuboCop
|
|
125
135
|
|
126
136
|
def existing_configuration(config_file)
|
127
137
|
File.read(config_file, encoding: Encoding::UTF_8)
|
128
|
-
.sub(/^inherit_from: *[^\n]+/,
|
129
|
-
.sub(/^inherit_from: *(\n *- *[^\n]+)+/,
|
138
|
+
.sub(/^inherit_from: *[^\n]+/, PLACEHOLDER)
|
139
|
+
.sub(/^inherit_from: *(\n *- *[^\n]+)+/, PLACEHOLDER)
|
130
140
|
end
|
131
141
|
|
132
142
|
def write_config_file(file_name, file_string, rubocop_yml_contents)
|
133
143
|
lines = /\S/.match?(rubocop_yml_contents) ? rubocop_yml_contents.split("\n", -1) : []
|
134
|
-
|
135
|
-
|
136
|
-
|
144
|
+
unless rubocop_yml_contents&.include?(PLACEHOLDER)
|
145
|
+
doc_start_index = lines.index { |line| YAML_OPTIONAL_DOC_START.match?(line) } || -1
|
146
|
+
lines.insert(doc_start_index + 1, PLACEHOLDER)
|
147
|
+
end
|
148
|
+
File.write(file_name, lines.join("\n")
|
149
|
+
.sub(/#{PLACEHOLDER}\n*/o, "inherit_from:#{file_string}\n\n")
|
150
|
+
.sub(/\n\n+\Z/, "\n"))
|
137
151
|
end
|
138
152
|
|
139
153
|
def relative_path_to_todo_from_options_config
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../lsp/server'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
class CLI
|
7
|
+
module Command
|
8
|
+
# Start Language Server Protocol of RuboCop.
|
9
|
+
# @api private
|
10
|
+
class LSP < Base
|
11
|
+
self.command_name = :lsp
|
12
|
+
|
13
|
+
def run
|
14
|
+
RuboCop::LSP::Server.new(@config_store).start
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rubocop/cli.rb
CHANGED
@@ -11,8 +11,8 @@ module RuboCop
|
|
11
11
|
STATUS_ERROR = 2
|
12
12
|
STATUS_INTERRUPTED = Signal.list['INT'] + 128
|
13
13
|
DEFAULT_PARALLEL_OPTIONS = %i[
|
14
|
-
color debug display_style_guide display_time display_only_fail_level_offenses
|
15
|
-
display_only_failed except extra_details fail_level fix_layout format
|
14
|
+
color config debug display_style_guide display_time display_only_fail_level_offenses
|
15
|
+
display_only_failed editor_mode except extra_details fail_level fix_layout format
|
16
16
|
ignore_disable_comments lint only only_guide_cops require safe
|
17
17
|
autocorrect safe_autocorrect autocorrect_all
|
18
18
|
].freeze
|
@@ -151,6 +151,7 @@ module RuboCop
|
|
151
151
|
|
152
152
|
def act_on_options
|
153
153
|
set_options_to_config_loader
|
154
|
+
handle_editor_mode
|
154
155
|
|
155
156
|
@config_store.options_config = @options[:config] if @options[:config]
|
156
157
|
@config_store.force_default_config! if @options[:force_default_config]
|
@@ -174,14 +175,21 @@ module RuboCop
|
|
174
175
|
ConfigLoader.ignore_unrecognized_cops = @options[:ignore_unrecognized_cops]
|
175
176
|
end
|
176
177
|
|
178
|
+
def handle_editor_mode
|
179
|
+
RuboCop::LSP.enable if @options[:editor_mode]
|
180
|
+
end
|
181
|
+
|
182
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
177
183
|
def handle_exiting_options
|
178
184
|
return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
|
179
185
|
|
180
186
|
run_command(:version) if @options[:version] || @options[:verbose_version]
|
181
187
|
run_command(:show_cops) if @options[:show_cops]
|
182
188
|
run_command(:show_docs_url) if @options[:show_docs_url]
|
189
|
+
run_command(:lsp) if @options[:lsp]
|
183
190
|
raise Finished
|
184
191
|
end
|
192
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
185
193
|
|
186
194
|
def apply_default_formatter
|
187
195
|
# This must be done after the options have already been processed,
|
data/lib/rubocop/config.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pathname'
|
4
|
-
|
5
3
|
# FIXME: Moving Rails department code to RuboCop Rails will remove
|
6
4
|
# the following rubocop:disable comment.
|
7
5
|
# rubocop:disable Metrics/ClassLength
|
@@ -246,6 +244,10 @@ module RuboCop
|
|
246
244
|
end
|
247
245
|
end
|
248
246
|
|
247
|
+
def parser_engine
|
248
|
+
@parser_engine ||= for_all_cops.fetch('ParserEngine', :parser_whitequark).to_sym
|
249
|
+
end
|
250
|
+
|
249
251
|
def target_rails_version
|
250
252
|
@target_rails_version ||=
|
251
253
|
if for_all_cops['TargetRailsVersion']
|
@@ -284,6 +286,10 @@ module RuboCop
|
|
284
286
|
end
|
285
287
|
end
|
286
288
|
|
289
|
+
def inspect # :nodoc:
|
290
|
+
"#<#{self.class.name}:#{object_id} @loaded_path=#{loaded_path}>"
|
291
|
+
end
|
292
|
+
|
287
293
|
private
|
288
294
|
|
289
295
|
def target_rails_version_from_bundler_lock_file
|
@@ -17,8 +17,8 @@ module RuboCop
|
|
17
17
|
attr_writer :project_root
|
18
18
|
|
19
19
|
def find_config_path(target_dir)
|
20
|
-
find_project_dotfile(target_dir) ||
|
21
|
-
DEFAULT_FILE
|
20
|
+
find_project_dotfile(target_dir) || find_project_root_dot_config ||
|
21
|
+
find_user_dotfile || find_user_xdg_config || DEFAULT_FILE
|
22
22
|
end
|
23
23
|
|
24
24
|
# Returns the path RuboCop inferred as the root of the project. No file
|
@@ -41,19 +41,29 @@ module RuboCop
|
|
41
41
|
find_file_upwards(DOTFILE, target_dir, project_root)
|
42
42
|
end
|
43
43
|
|
44
|
+
def find_project_root_dot_config
|
45
|
+
return unless project_root
|
46
|
+
|
47
|
+
dotfile = File.join(project_root, '.config', DOTFILE)
|
48
|
+
return dotfile if File.exist?(dotfile)
|
49
|
+
|
50
|
+
xdg_config = File.join(project_root, '.config', 'rubocop', XDG_CONFIG)
|
51
|
+
xdg_config if File.exist?(xdg_config)
|
52
|
+
end
|
53
|
+
|
44
54
|
def find_user_dotfile
|
45
55
|
return unless ENV.key?('HOME')
|
46
56
|
|
47
57
|
file = File.join(Dir.home, DOTFILE)
|
48
58
|
|
49
|
-
|
59
|
+
file if File.exist?(file)
|
50
60
|
end
|
51
61
|
|
52
62
|
def find_user_xdg_config
|
53
63
|
xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config'))
|
54
64
|
xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG)
|
55
65
|
|
56
|
-
|
66
|
+
xdg_config if File.exist?(xdg_config)
|
57
67
|
end
|
58
68
|
|
59
69
|
def expand_path(path)
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
inherit_mode: determine_inherit_mode(hash, k))
|
34
34
|
end
|
35
35
|
hash[k] = v
|
36
|
-
fix_include_paths(base_config.loaded_path, hash, k, v) if v.key?('Include')
|
36
|
+
fix_include_paths(base_config.loaded_path, hash, path, k, v) if v.key?('Include')
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -42,12 +42,13 @@ module RuboCop
|
|
42
42
|
# base configuration are relative to the directory where the base configuration file is. For the
|
43
43
|
# derived configuration, we need to make those paths relative to where the derived configuration
|
44
44
|
# file is.
|
45
|
-
def fix_include_paths(base_config_path, hash, key, value)
|
45
|
+
def fix_include_paths(base_config_path, hash, path, key, value)
|
46
46
|
return unless File.basename(base_config_path).start_with?('.rubocop')
|
47
47
|
|
48
48
|
base_dir = File.dirname(base_config_path)
|
49
|
+
derived_dir = File.dirname(path)
|
49
50
|
hash[key]['Include'] = value['Include'].map do |include_path|
|
50
|
-
PathUtil.relative_path(File.join(base_dir, include_path),
|
51
|
+
PathUtil.relative_path(File.join(base_dir, include_path), derived_dir)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def violated?
|
22
|
-
config[cop]&.key?(parameter)
|
22
|
+
applies_to_current_ruby_version? && config[cop]&.key?(parameter)
|
23
23
|
end
|
24
24
|
|
25
25
|
def warning?
|
@@ -28,6 +28,14 @@ module RuboCop
|
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
+
def applies_to_current_ruby_version?
|
32
|
+
minimum_ruby_version = metadata['minimum_ruby_version']
|
33
|
+
|
34
|
+
return true unless minimum_ruby_version
|
35
|
+
|
36
|
+
config.target_ruby_version >= minimum_ruby_version
|
37
|
+
end
|
38
|
+
|
31
39
|
def alternative
|
32
40
|
metadata['alternative']
|
33
41
|
end
|
@@ -15,6 +15,8 @@ module RuboCop
|
|
15
15
|
'changed_parameters' => ChangedParameter,
|
16
16
|
'changed_enforced_styles' => ChangedEnforcedStyles
|
17
17
|
}.freeze
|
18
|
+
LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant
|
19
|
+
private_constant :LOAD_RULES_CACHE
|
18
20
|
|
19
21
|
attr_reader :rules, :warnings
|
20
22
|
|
@@ -48,16 +50,17 @@ module RuboCop
|
|
48
50
|
# Default rules for obsoletions are in config/obsoletion.yml
|
49
51
|
# Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
|
50
52
|
def load_rules # rubocop:disable Metrics/AbcSize
|
51
|
-
rules = self.class.files
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
rules = LOAD_RULES_CACHE[self.class.files] ||=
|
54
|
+
self.class.files.each_with_object({}) do |filename, hash|
|
55
|
+
hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
|
56
|
+
case first
|
57
|
+
when Hash
|
58
|
+
first.merge(second)
|
59
|
+
when Array
|
60
|
+
first.concat(second)
|
61
|
+
end
|
58
62
|
end
|
59
63
|
end
|
60
|
-
end
|
61
64
|
|
62
65
|
cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
|
63
66
|
parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
|
@@ -68,11 +71,11 @@ module RuboCop
|
|
68
71
|
# Cop rules are keyed by the name of the original cop
|
69
72
|
def load_cop_rules(rules)
|
70
73
|
rules.flat_map do |rule_type, data|
|
71
|
-
data.
|
74
|
+
data.filter_map do |cop_name, configuration|
|
72
75
|
next unless configuration # allow configurations to be disabled with `CopName: ~`
|
73
76
|
|
74
77
|
COP_RULE_CLASSES[rule_type].new(@config, cop_name, configuration)
|
75
|
-
end
|
78
|
+
end
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pathname'
|
4
|
-
|
5
3
|
module RuboCop
|
6
4
|
# Handles validation of configuration, for example cop names, parameter
|
7
5
|
# names, and Ruby versions.
|
@@ -20,6 +18,7 @@ module RuboCop
|
|
20
18
|
# @api private
|
21
19
|
CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect].to_set.freeze
|
22
20
|
CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
|
21
|
+
CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
|
23
22
|
private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
|
24
23
|
|
25
24
|
def_delegators :@config, :smart_loaded_path, :for_all_cops
|
@@ -250,23 +249,31 @@ module RuboCop
|
|
250
249
|
end
|
251
250
|
end
|
252
251
|
|
252
|
+
# rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
253
253
|
def check_cop_config_value(hash, parent = nil)
|
254
254
|
hash.each do |key, value|
|
255
255
|
check_cop_config_value(value, key) if value.is_a?(Hash)
|
256
256
|
|
257
257
|
next unless CONFIG_CHECK_KEYS.include?(key) && value.is_a?(String)
|
258
258
|
|
259
|
-
|
259
|
+
if key == 'Enabled' && !CONFIG_CHECK_DEPARTMENTS.include?(value)
|
260
|
+
supposed_values = 'a boolean'
|
261
|
+
elsif key == 'AutoCorrect' && !CONFIG_CHECK_AUTOCORRECTS.include?(value)
|
262
|
+
supposed_values = '`always`, `contextual`, `disabled`, or a boolean'
|
263
|
+
else
|
264
|
+
next
|
265
|
+
end
|
260
266
|
|
261
|
-
raise ValidationError,
|
267
|
+
raise ValidationError, param_error_message(parent, key, value, supposed_values)
|
262
268
|
end
|
263
269
|
end
|
270
|
+
# rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
264
271
|
|
265
272
|
# FIXME: Handling colors in exception messages like this is ugly.
|
266
|
-
def
|
273
|
+
def param_error_message(parent, key, value, supposed_values)
|
267
274
|
"#{Rainbow('').reset}" \
|
268
|
-
"Property #{Rainbow(key).yellow} of
|
269
|
-
"is supposed to be
|
275
|
+
"Property #{Rainbow(key).yellow} of #{Rainbow(parent).yellow} cop " \
|
276
|
+
"is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
|
270
277
|
end
|
271
278
|
end
|
272
279
|
end
|
@@ -32,7 +32,12 @@ module RuboCop
|
|
32
32
|
# allow turning off autocorrect on a cop by cop basis
|
33
33
|
return true unless cop_config
|
34
34
|
|
35
|
-
|
35
|
+
# `false` is the same as `disabled` for backward compatibility.
|
36
|
+
return false if ['disabled', false].include?(cop_config['AutoCorrect'])
|
37
|
+
|
38
|
+
# When LSP is enabled, it is considered as editing source code,
|
39
|
+
# and autocorrection with `AutoCorrect: contextual` will not be performed.
|
40
|
+
return false if contextual_autocorrect? && LSP.enabled?
|
36
41
|
|
37
42
|
# :safe_autocorrect is a derived option based on several command-line
|
38
43
|
# arguments - see RuboCop::Options#add_autocorrection_options
|
@@ -82,7 +87,9 @@ module RuboCop
|
|
82
87
|
node.array_type? && node.percent_literal?
|
83
88
|
end
|
84
89
|
|
85
|
-
percent_array.map(&:source_range).find
|
90
|
+
percent_array.map(&:source_range).find do |range|
|
91
|
+
offense_range.begin_pos > range.begin_pos && range.overlaps?(offense_range)
|
92
|
+
end
|
86
93
|
end
|
87
94
|
|
88
95
|
def range_of_first_line(range)
|
data/lib/rubocop/cop/base.rb
CHANGED
@@ -53,7 +53,7 @@ module RuboCop
|
|
53
53
|
# List of cops that should not try to autocorrect at the same
|
54
54
|
# time as this cop
|
55
55
|
#
|
56
|
-
# @return [Array<RuboCop::Cop::
|
56
|
+
# @return [Array<RuboCop::Cop::Base>]
|
57
57
|
#
|
58
58
|
# @api public
|
59
59
|
def self.autocorrect_incompatible_with
|
@@ -232,6 +232,10 @@ module RuboCop
|
|
232
232
|
@config.target_ruby_version
|
233
233
|
end
|
234
234
|
|
235
|
+
def parser_engine
|
236
|
+
@config.parser_engine
|
237
|
+
end
|
238
|
+
|
235
239
|
def target_rails_version
|
236
240
|
@config.target_rails_version
|
237
241
|
end
|
@@ -254,7 +258,7 @@ module RuboCop
|
|
254
258
|
|
255
259
|
# There should be very limited reasons for a Cop to do it's own parsing
|
256
260
|
def parse(source, path = nil)
|
257
|
-
ProcessedSource.new(source, target_ruby_version, path)
|
261
|
+
ProcessedSource.new(source, target_ruby_version, path, parser_engine: parser_engine)
|
258
262
|
end
|
259
263
|
|
260
264
|
# @api private
|
@@ -284,7 +288,7 @@ module RuboCop
|
|
284
288
|
# @api private
|
285
289
|
def self.callbacks_needed
|
286
290
|
@callbacks_needed ||= public_instance_methods.select do |m|
|
287
|
-
m.
|
291
|
+
m.start_with?(/on_|after_/) &&
|
288
292
|
!Base.method_defined?(m) # exclude standard "callbacks" like 'on_begin_investigation'
|
289
293
|
end
|
290
294
|
end
|
@@ -305,6 +309,21 @@ module RuboCop
|
|
305
309
|
@current_original = original
|
306
310
|
end
|
307
311
|
|
312
|
+
# @api private
|
313
|
+
def always_autocorrect?
|
314
|
+
# `true` is the same as `'always'` for backward compatibility.
|
315
|
+
['always', true].include?(cop_config.fetch('AutoCorrect', 'always'))
|
316
|
+
end
|
317
|
+
|
318
|
+
# @api private
|
319
|
+
def contextual_autocorrect?
|
320
|
+
cop_config.fetch('AutoCorrect', 'always') == 'contextual'
|
321
|
+
end
|
322
|
+
|
323
|
+
def inspect # :nodoc:
|
324
|
+
"#<#{self.class.name}:#{object_id} @config=#{@config} @options=#{@options}>"
|
325
|
+
end
|
326
|
+
|
308
327
|
private
|
309
328
|
|
310
329
|
### Reserved for Cop::Cop
|
@@ -385,7 +404,7 @@ module RuboCop
|
|
385
404
|
def use_corrector(range, corrector)
|
386
405
|
if autocorrect?
|
387
406
|
attempt_correction(range, corrector)
|
388
|
-
elsif corrector &&
|
407
|
+
elsif corrector && (always_autocorrect? || (contextual_autocorrect? && !LSP.enabled?))
|
389
408
|
:uncorrected
|
390
409
|
else
|
391
410
|
:unsupported
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Bundler
|
6
|
+
# A Gem group, or a set of groups, should be listed only once in a Gemfile.
|
7
|
+
#
|
8
|
+
# For example, if the values of `source`, `git`, `platforms`, or `path`
|
9
|
+
# surrounding `group` are different, no offense will be registered:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# -----
|
13
|
+
# platforms :ruby do
|
14
|
+
# group :default do
|
15
|
+
# gem 'openssl'
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# platforms :jruby do
|
20
|
+
# group :default do
|
21
|
+
# gem 'jruby-openssl'
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# -----
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# # bad
|
28
|
+
# group :development do
|
29
|
+
# gem 'rubocop'
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# group :development do
|
33
|
+
# gem 'rubocop-rails'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # bad (same set of groups declared twice)
|
37
|
+
# group :development, :test do
|
38
|
+
# gem 'rubocop'
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# group :test, :development do
|
42
|
+
# gem 'rspec'
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# group :development do
|
47
|
+
# gem 'rubocop'
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# group :development, :test do
|
51
|
+
# gem 'rspec'
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# # good
|
55
|
+
# gem 'rubocop', groups: [:development, :test]
|
56
|
+
# gem 'rspec', groups: [:development, :test]
|
57
|
+
#
|
58
|
+
class DuplicatedGroup < Base
|
59
|
+
include RangeHelp
|
60
|
+
|
61
|
+
MSG = 'Gem group `%<group_name>s` already defined on line ' \
|
62
|
+
'%<line_of_first_occurrence>d of the Gemfile.'
|
63
|
+
SOURCE_BLOCK_NAMES = %i[source git platforms path].freeze
|
64
|
+
|
65
|
+
# @!method group_declarations(node)
|
66
|
+
def_node_search :group_declarations, '(send nil? :group ...)'
|
67
|
+
|
68
|
+
def on_new_investigation
|
69
|
+
return if processed_source.blank?
|
70
|
+
|
71
|
+
duplicated_group_nodes.each do |nodes|
|
72
|
+
nodes[1..].each do |node|
|
73
|
+
group_name = node.arguments.map(&:source).join(', ')
|
74
|
+
|
75
|
+
register_offense(node, group_name, nodes.first.first_line)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def duplicated_group_nodes
|
83
|
+
group_declarations = group_declarations(processed_source.ast)
|
84
|
+
group_keys = group_declarations.group_by do |node|
|
85
|
+
source_key = find_source_key(node)
|
86
|
+
group_attributes = group_attributes(node).sort.join
|
87
|
+
|
88
|
+
"#{source_key}#{group_attributes}"
|
89
|
+
end
|
90
|
+
|
91
|
+
group_keys.values.select { |nodes| nodes.size > 1 }
|
92
|
+
end
|
93
|
+
|
94
|
+
def register_offense(node, group_name, line_of_first_occurrence)
|
95
|
+
line_range = node.loc.column...node.loc.last_column
|
96
|
+
offense_location = source_range(processed_source.buffer, node.first_line, line_range)
|
97
|
+
message = format(
|
98
|
+
MSG,
|
99
|
+
group_name: group_name,
|
100
|
+
line_of_first_occurrence: line_of_first_occurrence
|
101
|
+
)
|
102
|
+
add_offense(offense_location, message: message)
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_source_key(node)
|
106
|
+
source_block = node.each_ancestor(:block).find do |block_node|
|
107
|
+
SOURCE_BLOCK_NAMES.include?(block_node.method_name)
|
108
|
+
end
|
109
|
+
|
110
|
+
return unless source_block
|
111
|
+
|
112
|
+
"#{source_block.method_name}#{source_block.send_node.first_argument&.source}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def group_attributes(node)
|
116
|
+
node.arguments.map do |argument|
|
117
|
+
if argument.hash_type?
|
118
|
+
argument.pairs.map(&:source).sort.join(', ')
|
119
|
+
else
|
120
|
+
argument.respond_to?(:value) ? argument.value.to_s : argument.source
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
150
150
|
# Version specifications that restrict all updates going forward. This excludes versions
|
151
151
|
# like ">= 1.0" or "!= 2.0.3".
|
152
152
|
def restrictive_version_specified_gem?(node)
|
153
|
-
return unless version_specified_gem?(node)
|
153
|
+
return false unless version_specified_gem?(node)
|
154
154
|
|
155
155
|
node.arguments[1..]
|
156
156
|
.any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) }
|
@@ -161,9 +161,9 @@ module RuboCop
|
|
161
161
|
end
|
162
162
|
|
163
163
|
def gem_options(node)
|
164
|
-
return [] unless node.
|
164
|
+
return [] unless node.last_argument&.type == :hash
|
165
165
|
|
166
|
-
node.
|
166
|
+
node.last_argument.keys.map(&:value)
|
167
167
|
end
|
168
168
|
end
|
169
169
|
end
|
@@ -105,13 +105,13 @@ module RuboCop
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def required_offense?(node)
|
108
|
-
return unless required_style?
|
108
|
+
return false unless required_style?
|
109
109
|
|
110
110
|
!includes_version_specification?(node) && !includes_commit_reference?(node)
|
111
111
|
end
|
112
112
|
|
113
113
|
def forbidden_offense?(node)
|
114
|
-
return unless forbidden_style?
|
114
|
+
return false unless forbidden_style?
|
115
115
|
|
116
116
|
includes_version_specification?(node) || includes_commit_reference?(node)
|
117
117
|
end
|
@@ -19,7 +19,15 @@ module RuboCop
|
|
19
19
|
#
|
20
20
|
# gem 'rspec'
|
21
21
|
#
|
22
|
-
#
|
22
|
+
# @example TreatCommentsAsGroupSeparators: true (default)
|
23
|
+
# # good
|
24
|
+
# # For code quality
|
25
|
+
# gem 'rubocop'
|
26
|
+
# # For tests
|
27
|
+
# gem 'rspec'
|
28
|
+
#
|
29
|
+
# @example TreatCommentsAsGroupSeparators: false
|
30
|
+
# # bad
|
23
31
|
# # For code quality
|
24
32
|
# gem 'rubocop'
|
25
33
|
# # For tests
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
def inside_string_ranges(node)
|
55
55
|
return [] unless node.is_a?(Parser::AST::Node)
|
56
56
|
|
57
|
-
node.each_node(:str, :dstr, :xstr).
|
57
|
+
node.each_node(:str, :dstr, :xstr).filter_map { |n| inside_string_range(n) }
|
58
58
|
end
|
59
59
|
|
60
60
|
def inside_string_range(node)
|