rubocop 1.84.2 → 1.86.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/config/default.yml +91 -15
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cache_config.rb +1 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +1 -1
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +1 -1
- data/lib/rubocop/cli.rb +6 -3
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +1 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.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 +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +6 -3
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +5 -3
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +28 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
- data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +22 -7
- data/lib/rubocop/cop/lint/void.rb +32 -12
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/registry.rb +20 -13
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +4 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +5 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +3 -1
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +25 -33
- data/lib/rubocop/cop/style/case_equality.rb +4 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +10 -2
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
- data/lib/rubocop/cop/style/copyright.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_class_definition.rb +43 -20
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +8 -3
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string_token.rb +29 -2
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +9 -6
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
- data/lib/rubocop/cop/style/hash_lookup_method.rb +7 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -5
- data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
- data/lib/rubocop/cop/style/module_member_existence_check.rb +1 -11
- data/lib/rubocop/cop/style/multiline_if_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +4 -0
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/reduce_to_hash.rb +184 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +25 -22
- data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
- data/lib/rubocop/cop/style/semicolon.rb +2 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +4 -3
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +2 -2
- data/lib/rubocop/directive_comment.rb +2 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +1 -0
- data/lib/rubocop/lsp/routes.rb +10 -3
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +10 -1
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/result_cache.rb +22 -10
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +11 -2
- data/lib/rubocop/runner.rb +8 -3
- data/lib/rubocop/server/cache.rb +5 -7
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +18 -12
- data/lib/rubocop/version.rb +2 -2
- data/lib/rubocop.rb +14 -0
- metadata +22 -5
|
@@ -60,6 +60,11 @@ module RuboCop
|
|
|
60
60
|
END_OF_HEREDOC_LINE = 1
|
|
61
61
|
SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
|
|
62
62
|
|
|
63
|
+
# @!method guard_clause_branch?(node)
|
|
64
|
+
def_node_matcher :guard_clause_branch?, <<~PATTERN
|
|
65
|
+
{(send nil? {:raise :fail} ...) return break next}
|
|
66
|
+
PATTERN
|
|
67
|
+
|
|
63
68
|
def on_if(node)
|
|
64
69
|
return if correct_style?(node)
|
|
65
70
|
return if multiple_statements_on_line?(node)
|
|
@@ -97,14 +102,16 @@ module RuboCop
|
|
|
97
102
|
end
|
|
98
103
|
|
|
99
104
|
def correct_style?(node)
|
|
100
|
-
!
|
|
105
|
+
!node.if_branch&.guard_clause? ||
|
|
101
106
|
next_line_rescue_or_ensure?(node) ||
|
|
102
107
|
next_sibling_parent_empty_or_else?(node) ||
|
|
103
108
|
next_sibling_empty_or_guard_clause?(node)
|
|
104
109
|
end
|
|
105
110
|
|
|
106
111
|
def contains_guard_clause?(node)
|
|
107
|
-
node.if_branch
|
|
112
|
+
return false unless (branch = node.if_branch)
|
|
113
|
+
|
|
114
|
+
branch.guard_clause? || guard_clause_branch?(branch)
|
|
108
115
|
end
|
|
109
116
|
|
|
110
117
|
def next_line_empty_or_allowed_directive_comment?(line)
|
|
@@ -185,7 +185,7 @@ module RuboCop
|
|
|
185
185
|
end
|
|
186
186
|
|
|
187
187
|
def empty_line_between_macros
|
|
188
|
-
cop_config.fetch('DefLikeMacros', []).map(&:to_sym)
|
|
188
|
+
@empty_line_between_macros ||= cop_config.fetch('DefLikeMacros', []).map(&:to_sym).freeze
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
def macro_candidate?(node)
|
|
@@ -7,15 +7,25 @@ module RuboCop
|
|
|
7
7
|
# the configuration.
|
|
8
8
|
#
|
|
9
9
|
# @example EnforcedStyle: no_empty_lines (default)
|
|
10
|
-
# #
|
|
10
|
+
# # bad
|
|
11
|
+
# foo do |bar|
|
|
12
|
+
#
|
|
13
|
+
# # ...
|
|
14
|
+
#
|
|
15
|
+
# end
|
|
11
16
|
#
|
|
17
|
+
# # good
|
|
12
18
|
# foo do |bar|
|
|
13
19
|
# # ...
|
|
14
20
|
# end
|
|
15
21
|
#
|
|
16
22
|
# @example EnforcedStyle: empty_lines
|
|
17
|
-
# #
|
|
23
|
+
# # bad
|
|
24
|
+
# foo do |bar|
|
|
25
|
+
# # ...
|
|
26
|
+
# end
|
|
18
27
|
#
|
|
28
|
+
# # good
|
|
19
29
|
# foo do |bar|
|
|
20
30
|
#
|
|
21
31
|
# # ...
|
|
@@ -7,8 +7,16 @@ module RuboCop
|
|
|
7
7
|
# the configuration.
|
|
8
8
|
#
|
|
9
9
|
# @example EnforcedStyle: no_empty_lines (default)
|
|
10
|
-
# #
|
|
10
|
+
# # bad
|
|
11
|
+
# class Foo
|
|
12
|
+
#
|
|
13
|
+
# def bar
|
|
14
|
+
# # ...
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# end
|
|
11
18
|
#
|
|
19
|
+
# # good
|
|
12
20
|
# class Foo
|
|
13
21
|
# def bar
|
|
14
22
|
# # ...
|
|
@@ -16,8 +24,14 @@ module RuboCop
|
|
|
16
24
|
# end
|
|
17
25
|
#
|
|
18
26
|
# @example EnforcedStyle: empty_lines
|
|
19
|
-
# #
|
|
27
|
+
# # bad
|
|
28
|
+
# class Foo
|
|
29
|
+
# def bar
|
|
30
|
+
# # ...
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
20
33
|
#
|
|
34
|
+
# # good
|
|
21
35
|
# class Foo
|
|
22
36
|
#
|
|
23
37
|
# def bar
|
|
@@ -7,8 +7,16 @@ module RuboCop
|
|
|
7
7
|
# the configuration.
|
|
8
8
|
#
|
|
9
9
|
# @example EnforcedStyle: no_empty_lines (default)
|
|
10
|
-
# #
|
|
10
|
+
# # bad
|
|
11
|
+
# module Foo
|
|
12
|
+
#
|
|
13
|
+
# def bar
|
|
14
|
+
# # ...
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# end
|
|
11
18
|
#
|
|
19
|
+
# # good
|
|
12
20
|
# module Foo
|
|
13
21
|
# def bar
|
|
14
22
|
# # ...
|
|
@@ -16,8 +24,14 @@ module RuboCop
|
|
|
16
24
|
# end
|
|
17
25
|
#
|
|
18
26
|
# @example EnforcedStyle: empty_lines
|
|
19
|
-
# #
|
|
27
|
+
# # bad
|
|
28
|
+
# module Foo
|
|
29
|
+
# def bar
|
|
30
|
+
# # ...
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
20
33
|
#
|
|
34
|
+
# # good
|
|
21
35
|
# module Foo
|
|
22
36
|
#
|
|
23
37
|
# def bar
|
|
@@ -123,20 +123,23 @@ module RuboCop
|
|
|
123
123
|
AlignmentCorrector.align_end(corrector, processed_source, node, alignment_node(node))
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
126
127
|
def check_assignment(node, rhs)
|
|
127
128
|
# If there are method calls chained to the right hand side of the
|
|
128
129
|
# assignment, we let rhs be the receiver of those method calls before
|
|
129
130
|
# we check if it's an if/unless/while/until.
|
|
130
131
|
return unless (rhs = first_part_of_call_chain(rhs))
|
|
131
132
|
|
|
132
|
-
# If `rhs` is a `begin` node
|
|
133
|
-
|
|
133
|
+
# If `rhs` is a `begin` node or a logical operator,
|
|
134
|
+
# unwrap to find the leading conditional.
|
|
135
|
+
rhs = rhs.child_nodes.first while rhs&.type?(:begin, :or, :and)
|
|
134
136
|
|
|
135
|
-
return unless rhs
|
|
137
|
+
return unless rhs&.conditional?
|
|
136
138
|
return if rhs.if_type? && rhs.ternary?
|
|
137
139
|
|
|
138
140
|
check_asgn_alignment(node, rhs)
|
|
139
141
|
end
|
|
142
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
140
143
|
|
|
141
144
|
def check_asgn_alignment(outer_node, inner_node)
|
|
142
145
|
align_with = {
|
|
@@ -135,7 +135,13 @@ module RuboCop
|
|
|
135
135
|
private
|
|
136
136
|
|
|
137
137
|
def autocorrect(corrector, node)
|
|
138
|
-
|
|
138
|
+
line_range = if !node.is_a?(AST::Node) || node.value.first_line <= node.key.first_line
|
|
139
|
+
node
|
|
140
|
+
else
|
|
141
|
+
processed_source.buffer.line_range(node.loc.line)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
AlignmentCorrector.correct(corrector, processed_source, line_range, @column_delta)
|
|
139
145
|
end
|
|
140
146
|
|
|
141
147
|
def brace_alignment_style
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Layout
|
|
6
|
-
#
|
|
6
|
+
# Checks that the keys, separators, and values of a multi-line hash
|
|
7
7
|
# literal are aligned according to configuration. The configuration
|
|
8
8
|
# options are:
|
|
9
9
|
#
|
|
@@ -406,9 +406,11 @@ module RuboCop
|
|
|
406
406
|
end
|
|
407
407
|
|
|
408
408
|
def string_delimiter(node)
|
|
409
|
-
delimiter = node.loc
|
|
410
|
-
|
|
411
|
-
|
|
409
|
+
delimiter = if node.loc?(:begin)
|
|
410
|
+
node.loc.begin
|
|
411
|
+
elsif node.parent&.dstr_type? && node.parent.loc?(:begin)
|
|
412
|
+
node.parent.loc.begin
|
|
413
|
+
end&.source
|
|
412
414
|
|
|
413
415
|
delimiter if %w[' "].include?(delimiter)
|
|
414
416
|
end
|
|
@@ -69,14 +69,18 @@ module RuboCop
|
|
|
69
69
|
SAME_LINE_OFFENSE = 'Right hand side of multi-line assignment is not ' \
|
|
70
70
|
'on the same line as the assignment operator `=`.'
|
|
71
71
|
|
|
72
|
+
BLOCK_TYPES = %i[block numblock itblock].freeze
|
|
73
|
+
|
|
74
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
72
75
|
def check_assignment(node, rhs)
|
|
73
76
|
return if node.send_type? && node.loc.operator&.source != '='
|
|
74
77
|
return unless rhs
|
|
75
78
|
return unless supported_types.include?(rhs.type)
|
|
76
|
-
return if rhs.single_line?
|
|
79
|
+
return if rhs.single_line? && (!rhs.block_type? || same_line?(node, rhs.loc.begin))
|
|
77
80
|
|
|
78
81
|
check_by_enforced_style(node, rhs)
|
|
79
82
|
end
|
|
83
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
80
84
|
|
|
81
85
|
def check_by_enforced_style(node, rhs)
|
|
82
86
|
case style
|
|
@@ -109,7 +113,10 @@ module RuboCop
|
|
|
109
113
|
private
|
|
110
114
|
|
|
111
115
|
def supported_types
|
|
112
|
-
@supported_types ||= cop_config['SupportedTypes'].
|
|
116
|
+
@supported_types ||= cop_config['SupportedTypes'].flat_map do |type|
|
|
117
|
+
sym = type.to_sym
|
|
118
|
+
sym == :block ? BLOCK_TYPES : sym
|
|
119
|
+
end
|
|
113
120
|
end
|
|
114
121
|
end
|
|
115
122
|
end
|
|
@@ -128,12 +128,15 @@ module RuboCop
|
|
|
128
128
|
if hash_pair_indented?(node, pair_ancestor, given_style)
|
|
129
129
|
return check_hash_pair_indented_style(rhs, pair_ancestor)
|
|
130
130
|
end
|
|
131
|
-
|
|
132
|
-
return false if !pair_ancestor && not_for_this_cop?(node)
|
|
131
|
+
return false if skip_for_context?(node, pair_ancestor)
|
|
133
132
|
|
|
134
133
|
check_regular_indentation(node, lhs, rhs, given_style)
|
|
135
134
|
end
|
|
136
135
|
|
|
136
|
+
def skip_for_context?(node, pair_ancestor)
|
|
137
|
+
pair_ancestor ? inside_multiline_chain_arg?(node) : not_for_this_cop?(node)
|
|
138
|
+
end
|
|
139
|
+
|
|
137
140
|
def hash_pair_aligned?(pair_ancestor, given_style)
|
|
138
141
|
pair_ancestor && given_style == :aligned
|
|
139
142
|
end
|
|
@@ -152,7 +155,10 @@ module RuboCop
|
|
|
152
155
|
end
|
|
153
156
|
|
|
154
157
|
def check_hash_pair_indentation(node, lhs, rhs)
|
|
155
|
-
@base = find_hash_pair_alignment_base(node)
|
|
158
|
+
@base = find_hash_pair_alignment_base(node)
|
|
159
|
+
return false if !@base && inside_multiline_chain_arg?(node)
|
|
160
|
+
|
|
161
|
+
@base ||= lhs.source_range
|
|
156
162
|
return if aligned_with_first_line_dot?(node, rhs)
|
|
157
163
|
|
|
158
164
|
calculate_column_delta_offense(rhs, @base.column)
|
|
@@ -166,6 +172,25 @@ module RuboCop
|
|
|
166
172
|
first_call.loc.dot.join(first_call.loc.selector)
|
|
167
173
|
end
|
|
168
174
|
|
|
175
|
+
def inside_multiline_chain_arg?(node)
|
|
176
|
+
enclosing_call = find_enclosing_chain_call(node)
|
|
177
|
+
return false unless enclosing_call
|
|
178
|
+
|
|
179
|
+
!same_line?(enclosing_call.loc.selector, enclosing_call.receiver.source_range)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def find_enclosing_chain_call(node)
|
|
183
|
+
hash_ancestor = find_pair_ancestor(node).parent
|
|
184
|
+
enclosing_call = hash_ancestor.parent
|
|
185
|
+
return unless hash_arg_in_chain?(enclosing_call, hash_ancestor)
|
|
186
|
+
|
|
187
|
+
enclosing_call
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def hash_arg_in_chain?(call, hash_node)
|
|
191
|
+
call&.call_type? && call.receiver != hash_node && call.loc?(:dot)
|
|
192
|
+
end
|
|
193
|
+
|
|
169
194
|
def aligned_with_first_line_dot?(node, rhs)
|
|
170
195
|
return false unless rhs.source.start_with?('.', '&.')
|
|
171
196
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Layout
|
|
6
|
-
#
|
|
6
|
+
# Checks that the parameters on a multi-line method call or definition are aligned.
|
|
7
7
|
#
|
|
8
8
|
# To set the alignment of the first argument, use the
|
|
9
9
|
# `Layout/FirstParameterIndentation` cop.
|
|
@@ -114,7 +114,7 @@ module RuboCop
|
|
|
114
114
|
|
|
115
115
|
def other_cop_takes_precedence?(node)
|
|
116
116
|
single_line_block_chain_enabled? && any_descendant?(node, :any_block) do |block_node|
|
|
117
|
-
block_node.parent.send_type? && block_node.parent.loc.dot &&
|
|
117
|
+
block_node.parent.send_type? && block_node.parent.loc.dot && block_node.single_line?
|
|
118
118
|
end
|
|
119
119
|
end
|
|
120
120
|
|
|
@@ -29,7 +29,7 @@ module RuboCop
|
|
|
29
29
|
include RangeHelp
|
|
30
30
|
extend AutoCorrector
|
|
31
31
|
|
|
32
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
32
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
33
33
|
arguments = node.arguments
|
|
34
34
|
|
|
35
35
|
return unless node.arguments? && pipes?(arguments)
|
|
@@ -47,9 +47,11 @@ module RuboCop
|
|
|
47
47
|
check(node, [:operator].freeze) if node.keyword?
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def on_block(node)
|
|
50
|
+
def on_block(node)
|
|
51
51
|
check(node, %i[begin end].freeze)
|
|
52
52
|
end
|
|
53
|
+
alias on_numblock on_block
|
|
54
|
+
alias on_itblock on_block
|
|
53
55
|
|
|
54
56
|
def on_break(node)
|
|
55
57
|
check(node, [:keyword].freeze)
|
|
@@ -26,6 +26,7 @@ module RuboCop
|
|
|
26
26
|
|
|
27
27
|
MSG_REQUIRE_SPACE = 'Use a space between `->` and `(` in lambda literals.'
|
|
28
28
|
MSG_REQUIRE_NO_SPACE = 'Do not use spaces between `->` and `(` in lambda literals.'
|
|
29
|
+
RESTRICT_ON_SEND = %i[lambda].freeze
|
|
29
30
|
|
|
30
31
|
def on_send(node)
|
|
31
32
|
return unless arrow_lambda_with_args?(node)
|
|
@@ -6,8 +6,11 @@ module RuboCop
|
|
|
6
6
|
# Checks for constant reassignments.
|
|
7
7
|
#
|
|
8
8
|
# Emulates Ruby's runtime warning "already initialized constant X"
|
|
9
|
-
# when a constant is reassigned in the same file and namespace
|
|
10
|
-
#
|
|
9
|
+
# when a constant is reassigned in the same file and namespace.
|
|
10
|
+
#
|
|
11
|
+
# The cop tracks constants defined via `NAME = value` syntax as well as
|
|
12
|
+
# class/module keyword definitions. It detects reassignment when a constant
|
|
13
|
+
# is first defined one way and then redefined using the `NAME = value` syntax.
|
|
11
14
|
#
|
|
12
15
|
# The cop cannot catch all offenses, like, for example, when a constant
|
|
13
16
|
# is reassigned in another file, or when using metaprogramming (`Module#const_set`).
|
|
@@ -36,6 +39,14 @@ module RuboCop
|
|
|
36
39
|
# X = :bar
|
|
37
40
|
# end
|
|
38
41
|
#
|
|
42
|
+
# # bad
|
|
43
|
+
# class FooError < StandardError; end
|
|
44
|
+
# FooError = Class.new(RuntimeError)
|
|
45
|
+
#
|
|
46
|
+
# # bad
|
|
47
|
+
# module M; end
|
|
48
|
+
# M = 1
|
|
49
|
+
#
|
|
39
50
|
# # good - keep only one assignment
|
|
40
51
|
# X = :bar
|
|
41
52
|
#
|
|
@@ -69,16 +80,30 @@ module RuboCop
|
|
|
69
80
|
|
|
70
81
|
# @!method remove_constant(node)
|
|
71
82
|
def_node_matcher :remove_constant, <<~PATTERN
|
|
72
|
-
(send
|
|
83
|
+
(send {nil? self} :remove_const
|
|
73
84
|
({sym str} $_))
|
|
74
85
|
PATTERN
|
|
75
86
|
|
|
87
|
+
def on_class(node)
|
|
88
|
+
return unless unconditional_definition?(node)
|
|
89
|
+
|
|
90
|
+
constant_definitions[definition_name(node)] ||= :class
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def on_module(node)
|
|
94
|
+
return unless unconditional_definition?(node)
|
|
95
|
+
|
|
96
|
+
constant_definitions[definition_name(node)] ||= :module
|
|
97
|
+
end
|
|
98
|
+
|
|
76
99
|
def on_casgn(node)
|
|
77
100
|
return unless fixed_constant_path?(node)
|
|
78
101
|
return unless simple_assignment?(node)
|
|
79
|
-
return if constant_names.add?(fully_qualified_constant_name(node))
|
|
80
102
|
|
|
81
|
-
|
|
103
|
+
name = fully_qualified_constant_name(node)
|
|
104
|
+
return constant_definitions[name] = :casgn unless constant_definitions.key?(name)
|
|
105
|
+
|
|
106
|
+
add_offense(node, message: format(MSG, constant: constant_display_name(node)))
|
|
82
107
|
end
|
|
83
108
|
|
|
84
109
|
def on_send(node)
|
|
@@ -90,7 +115,7 @@ module RuboCop
|
|
|
90
115
|
|
|
91
116
|
return if namespaces.none?
|
|
92
117
|
|
|
93
|
-
|
|
118
|
+
constant_definitions.delete(fully_qualified_name_for(namespaces, constant))
|
|
94
119
|
end
|
|
95
120
|
|
|
96
121
|
private
|
|
@@ -104,7 +129,7 @@ module RuboCop
|
|
|
104
129
|
return true if ancestor.type?(:module, :class)
|
|
105
130
|
|
|
106
131
|
ancestor.begin_type? || ancestor.literal? || ancestor.casgn_type? ||
|
|
107
|
-
freeze_method?(ancestor)
|
|
132
|
+
ancestor.type?(:masgn, :mlhs) || freeze_method?(ancestor)
|
|
108
133
|
end
|
|
109
134
|
end
|
|
110
135
|
|
|
@@ -128,6 +153,10 @@ module RuboCop
|
|
|
128
153
|
['', *namespaces, constant].join('::')
|
|
129
154
|
end
|
|
130
155
|
|
|
156
|
+
def constant_display_name(node)
|
|
157
|
+
[*constant_namespaces(node), node.name].join('::')
|
|
158
|
+
end
|
|
159
|
+
|
|
131
160
|
def constant_namespaces(node)
|
|
132
161
|
node.each_path.select(&:const_type?).map(&:short_name)
|
|
133
162
|
end
|
|
@@ -139,8 +168,29 @@ module RuboCop
|
|
|
139
168
|
.reverse
|
|
140
169
|
end
|
|
141
170
|
|
|
142
|
-
def
|
|
143
|
-
|
|
171
|
+
def unconditional_definition?(node)
|
|
172
|
+
node.each_ancestor.all? do |ancestor|
|
|
173
|
+
ancestor.type?(:begin, :module, :class)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def definition_name(node)
|
|
178
|
+
identifier = node.identifier
|
|
179
|
+
|
|
180
|
+
if identifier.namespace&.cbase_type?
|
|
181
|
+
fully_qualified_name_for([], identifier.short_name)
|
|
182
|
+
else
|
|
183
|
+
namespaces = ancestor_namespaces(node) + identifier_namespaces(identifier)
|
|
184
|
+
fully_qualified_name_for(namespaces, identifier.short_name)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def identifier_namespaces(identifier)
|
|
189
|
+
identifier.each_path.select(&:const_type?).map(&:short_name)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def constant_definitions
|
|
193
|
+
@constant_definitions ||= {}
|
|
144
194
|
end
|
|
145
195
|
end
|
|
146
196
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks unexpected overrides of the `Data` built-in methods
|
|
7
|
+
# via `Data.define`.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# Bad = Data.define(:members, :clone, :to_s)
|
|
12
|
+
# b = Bad.new(members: [], clone: true, to_s: 'bad')
|
|
13
|
+
# b.members #=> [] (overriding `Data#members`)
|
|
14
|
+
# b.clone #=> true (overriding `Object#clone`)
|
|
15
|
+
# b.to_s #=> "bad" (overriding `Data#to_s`)
|
|
16
|
+
#
|
|
17
|
+
# # good
|
|
18
|
+
# Good = Data.define(:id, :name)
|
|
19
|
+
# g = Good.new(id: 1, name: "foo")
|
|
20
|
+
# g.members #=> [:id, :name]
|
|
21
|
+
# g.clone #=> #<data Good id=1, name="foo">
|
|
22
|
+
#
|
|
23
|
+
class DataDefineOverride < Base
|
|
24
|
+
MSG = '`%<member_name>s` member overrides `Data#%<method_name>s` and it may be unexpected.'
|
|
25
|
+
RESTRICT_ON_SEND = %i[define].freeze
|
|
26
|
+
|
|
27
|
+
# This is based on `Data.define.instance_methods.sort` in Ruby 4.0.0.
|
|
28
|
+
DATA_METHOD_NAMES = %i[
|
|
29
|
+
! != !~ <=> == === __id__ __send__ class clone deconstruct deconstruct_keys
|
|
30
|
+
define_singleton_method display dup enum_for eql? equal? extend freeze frozen? hash
|
|
31
|
+
inspect instance_eval instance_exec instance_of? instance_variable_defined?
|
|
32
|
+
instance_variable_get instance_variable_set instance_variables is_a? itself kind_of?
|
|
33
|
+
members method methods nil? object_id private_methods protected_methods
|
|
34
|
+
public_method public_methods public_send remove_instance_variable respond_to? send
|
|
35
|
+
singleton_class singleton_method singleton_methods tap then to_enum to_h to_s with
|
|
36
|
+
yield_self
|
|
37
|
+
].freeze
|
|
38
|
+
MEMBER_NAME_TYPES = %i[sym str].freeze
|
|
39
|
+
|
|
40
|
+
# @!method data_define(node)
|
|
41
|
+
def_node_matcher :data_define, <<~PATTERN
|
|
42
|
+
(send
|
|
43
|
+
(const {nil? cbase} :Data) :define ...)
|
|
44
|
+
PATTERN
|
|
45
|
+
|
|
46
|
+
def on_send(node)
|
|
47
|
+
return unless data_define(node)
|
|
48
|
+
|
|
49
|
+
node.arguments.each do |arg|
|
|
50
|
+
next unless MEMBER_NAME_TYPES.include?(arg.type)
|
|
51
|
+
|
|
52
|
+
member_name = arg.value
|
|
53
|
+
|
|
54
|
+
next unless DATA_METHOD_NAMES.include?(member_name.to_sym)
|
|
55
|
+
|
|
56
|
+
message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
|
|
57
|
+
add_offense(arg, message: message)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -197,6 +197,13 @@ module RuboCop
|
|
|
197
197
|
# @!method sym_name(node)
|
|
198
198
|
def_node_matcher :sym_name, '(sym $_name)'
|
|
199
199
|
|
|
200
|
+
# @!method class_or_module_new_block?(node)
|
|
201
|
+
def_node_matcher :class_or_module_new_block?, <<~PATTERN
|
|
202
|
+
(block
|
|
203
|
+
(send (const _ {:Class :Module}) :new ...)
|
|
204
|
+
...)
|
|
205
|
+
PATTERN
|
|
206
|
+
|
|
200
207
|
def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
201
208
|
name, original_name = alias_method?(node)
|
|
202
209
|
|
|
@@ -233,9 +240,12 @@ module RuboCop
|
|
|
233
240
|
|
|
234
241
|
def check_self_receiver(node, name)
|
|
235
242
|
enclosing = node.parent_module_name
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
243
|
+
if enclosing
|
|
244
|
+
found_method(node, "#{enclosing}.#{name}")
|
|
245
|
+
elsif (anon_block = anonymous_class_block(node))
|
|
246
|
+
scope = qualified_name(anon_block.parent_module_name, nil, 'Object')
|
|
247
|
+
found_method(node, "#{scope}.#{name}", scope_id: anon_block_scope_id(anon_block))
|
|
248
|
+
end
|
|
239
249
|
end
|
|
240
250
|
|
|
241
251
|
def inside_condition?(node)
|
|
@@ -274,16 +284,50 @@ module RuboCop
|
|
|
274
284
|
end
|
|
275
285
|
|
|
276
286
|
def found_instance_method(node, name)
|
|
277
|
-
|
|
287
|
+
if (scope = node.parent_module_name)
|
|
288
|
+
found_method(node, "#{humanize_scope(scope)}#{name}")
|
|
289
|
+
elsif (anon_block = anonymous_class_block(node))
|
|
290
|
+
base = qualified_name(anon_block.parent_module_name, nil, 'Object')
|
|
291
|
+
scope = node.each_ancestor(:sclass).any? ? "#<Class:#{base}>" : base
|
|
292
|
+
found_method(
|
|
293
|
+
node, "#{humanize_scope(scope)}#{name}", scope_id: anon_block_scope_id(anon_block)
|
|
294
|
+
)
|
|
295
|
+
else
|
|
296
|
+
found_sclass_method(node, name)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
278
299
|
|
|
279
|
-
|
|
300
|
+
def humanize_scope(scope)
|
|
280
301
|
scope = scope.sub(
|
|
281
302
|
/(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
|
|
282
303
|
'\k<name>.'
|
|
283
304
|
)
|
|
284
|
-
scope
|
|
305
|
+
scope.end_with?('.') ? scope : "#{scope}#"
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def anonymous_class_block(node)
|
|
309
|
+
first_block = node.each_ancestor(:block).first
|
|
310
|
+
return unless class_or_module_new_block?(first_block)
|
|
311
|
+
return if first_block.parent&.type?(:lvasgn)
|
|
312
|
+
return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? }
|
|
313
|
+
|
|
314
|
+
first_block
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def anon_block_scope_id(anon_block)
|
|
318
|
+
parent = anon_block.parent
|
|
319
|
+
return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def)
|
|
320
|
+
|
|
321
|
+
if (receiver = named_receiver(parent))
|
|
322
|
+
"#{receiver.source}.#{parent.method_name}"
|
|
323
|
+
elsif !parent.begin_type? || parent.parent&.any_block_type?
|
|
324
|
+
source_location(anon_block)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
285
327
|
|
|
286
|
-
|
|
328
|
+
def named_receiver(node)
|
|
329
|
+
receiver = node.receiver
|
|
330
|
+
receiver unless class_or_module_new_block?(receiver)
|
|
287
331
|
end
|
|
288
332
|
|
|
289
333
|
def found_sclass_method(node, name)
|
|
@@ -296,8 +340,10 @@ module RuboCop
|
|
|
296
340
|
found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
|
|
297
341
|
end
|
|
298
342
|
|
|
299
|
-
|
|
343
|
+
# rubocop:disable Metrics/AbcSize
|
|
344
|
+
def found_method(node, method_name, scope_id: nil)
|
|
300
345
|
key = method_key(node, method_name)
|
|
346
|
+
key = "#{key}@#{scope_id}" if scope_id
|
|
301
347
|
scope = node.each_ancestor(:rescue, :ensure).first&.type
|
|
302
348
|
|
|
303
349
|
if @definitions.key?(key)
|
|
@@ -314,6 +360,7 @@ module RuboCop
|
|
|
314
360
|
@definitions[key] = node
|
|
315
361
|
end
|
|
316
362
|
end
|
|
363
|
+
# rubocop:enable Metrics/AbcSize
|
|
317
364
|
|
|
318
365
|
def method_key(node, method_name)
|
|
319
366
|
if (ancestor_def = node.each_ancestor(:any_def).first)
|