rubocop 1.75.1 → 1.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +20 -14
- data/config/default.yml +103 -25
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/config_validator.rb +6 -6
- data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +2 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/class_structure.rb +35 -0
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -5
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -4
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -38
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +12 -3
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- 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/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +86 -5
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +31 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +31 -25
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +7 -4
- data/lib/rubocop/cop/lint/return_in_void_context.rb +7 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -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/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/void.rb +2 -2
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +9 -5
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +281 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
- data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -5
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -3
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
- data/lib/rubocop/cop/style/comparable_between.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +18 -4
- data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +4 -0
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- 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/hash_conversion.rb +12 -3
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +0 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -0
- 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 +3 -3
- data/lib/rubocop/cop/style/if_unless_modifier.rb +33 -6
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +3 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -3
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +13 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +6 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +0 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +41 -3
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +42 -14
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -3
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
- data/lib/rubocop/cop/style/super_arguments.rb +1 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +7 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +6 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +4 -4
- data/lib/rubocop/magic_comment.rb +8 -0
- data/lib/rubocop/rspec/cop_helper.rb +2 -2
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/rspec/shared_contexts.rb +1 -2
- data/lib/rubocop/server/cache.rb +13 -10
- data/lib/rubocop/target_finder.rb +6 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +8 -1
- data/lib/ruby_lsp/rubocop/addon.rb +2 -2
- metadata +14 -7
@@ -6,6 +6,8 @@ module RuboCop
|
|
6
6
|
# Checks that brackets used for array literals have or don't have
|
7
7
|
# surrounding space depending on configuration.
|
8
8
|
#
|
9
|
+
# Array pattern matching is handled in the same way.
|
10
|
+
#
|
9
11
|
# @example EnforcedStyle: no_space (default)
|
10
12
|
# # The `no_space` style enforces that array literals have
|
11
13
|
# # no surrounding space.
|
@@ -82,9 +84,11 @@ module RuboCop
|
|
82
84
|
EMPTY_MSG = '%<command>s space inside empty array brackets.'
|
83
85
|
|
84
86
|
def on_array(node)
|
85
|
-
return
|
87
|
+
return if node.array_type? && !node.square_brackets?
|
86
88
|
|
89
|
+
node = find_node_with_brackets(node)
|
87
90
|
tokens, left, right = array_brackets(node)
|
91
|
+
return unless left && right
|
88
92
|
|
89
93
|
if empty_brackets?(left, right, tokens: tokens)
|
90
94
|
return empty_offenses(node, left, right, EMPTY_MSG)
|
@@ -95,9 +99,14 @@ module RuboCop
|
|
95
99
|
|
96
100
|
issue_offenses(node, left, right, start_ok, end_ok)
|
97
101
|
end
|
102
|
+
alias on_array_pattern on_array
|
98
103
|
|
99
104
|
private
|
100
105
|
|
106
|
+
def find_node_with_brackets(node)
|
107
|
+
node.ancestors.find(&:const_pattern_type?) || node
|
108
|
+
end
|
109
|
+
|
101
110
|
def autocorrect(corrector, node)
|
102
111
|
tokens, left, right = array_brackets(node)
|
103
112
|
|
@@ -115,7 +124,7 @@ module RuboCop
|
|
115
124
|
def array_brackets(node)
|
116
125
|
tokens = processed_source.tokens_within(node)
|
117
126
|
|
118
|
-
left = tokens.find(&:
|
127
|
+
left = tokens.find(&:left_bracket?)
|
119
128
|
right = tokens.reverse_each.find(&:right_bracket?)
|
120
129
|
|
121
130
|
[tokens, left, right]
|
@@ -188,7 +197,7 @@ module RuboCop
|
|
188
197
|
if side == :right
|
189
198
|
processed_source.tokens_within(node)[i].right_bracket?
|
190
199
|
else
|
191
|
-
processed_source.tokens_within(node)[i].
|
200
|
+
processed_source.tokens_within(node)[i].left_bracket?
|
192
201
|
end
|
193
202
|
end
|
194
203
|
|
@@ -6,6 +6,8 @@ module RuboCop
|
|
6
6
|
# Checks that braces used for hash literals have or don't have
|
7
7
|
# surrounding space depending on configuration.
|
8
8
|
#
|
9
|
+
# Hash pattern matching is handled in the same way.
|
10
|
+
#
|
9
11
|
# @example EnforcedStyle: space (default)
|
10
12
|
# # The `space` style enforces that hash literals have
|
11
13
|
# # surrounding space.
|
@@ -87,6 +89,7 @@ module RuboCop
|
|
87
89
|
check(tokens[-2], tokens[-1]) if tokens.size > 2
|
88
90
|
check_whitespace_only_hash(node) if enforce_no_space_style_for_empty_braces?
|
89
91
|
end
|
92
|
+
alias on_hash_pattern on_hash
|
90
93
|
|
91
94
|
private
|
92
95
|
|
@@ -27,7 +27,9 @@ module RuboCop
|
|
27
27
|
# @example
|
28
28
|
# # bad
|
29
29
|
# x || 1..2
|
30
|
+
# x - 1..2
|
30
31
|
# (x || 1..2)
|
32
|
+
# x || 1..y || 2
|
31
33
|
# 1..2.to_a
|
32
34
|
#
|
33
35
|
# # good, unambiguous
|
@@ -41,6 +43,7 @@ module RuboCop
|
|
41
43
|
#
|
42
44
|
# # good, ambiguity removed
|
43
45
|
# x || (1..2)
|
46
|
+
# (x - 1)..2
|
44
47
|
# (x || 1)..2
|
45
48
|
# (x || 1)..(y || 2)
|
46
49
|
# (1..2).to_a
|
@@ -96,6 +99,8 @@ module RuboCop
|
|
96
99
|
# to avoid the ambiguity of `1..2.to_a`.
|
97
100
|
return false if node.receiver&.basic_literal?
|
98
101
|
|
102
|
+
return false if node.operator_method? && !node.method?(:[])
|
103
|
+
|
99
104
|
require_parentheses_for_method_chain? || node.receiver.nil?
|
100
105
|
end
|
101
106
|
|
@@ -51,10 +51,9 @@ module RuboCop
|
|
51
51
|
'in a regexp.'
|
52
52
|
|
53
53
|
def on_interpolation(begin_node)
|
54
|
-
final_node = begin_node.children.last
|
55
|
-
|
56
|
-
return unless begin_node.parent.regexp_type?
|
54
|
+
return unless (final_node = begin_node.children.last)
|
57
55
|
return unless final_node.array_type?
|
56
|
+
return unless begin_node.parent.regexp_type?
|
58
57
|
|
59
58
|
if array_of_literal_values?(final_node)
|
60
59
|
register_array_of_literal_values(begin_node, final_node)
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
def autocorrect(corrector, node)
|
49
49
|
boolean_literal = node.source.delete(':')
|
50
50
|
parent = node.parent
|
51
|
-
if parent&.pair_type? && node.equal?(parent.children[0])
|
51
|
+
if parent&.pair_type? && parent.colon? && node.equal?(parent.children[0])
|
52
52
|
corrector.remove(parent.loc.operator)
|
53
53
|
boolean_literal = "#{node.source} =>"
|
54
54
|
end
|
@@ -6,9 +6,8 @@ module RuboCop
|
|
6
6
|
# Checks for circular argument references in optional keyword
|
7
7
|
# arguments and optional ordinal arguments.
|
8
8
|
#
|
9
|
-
# This
|
10
|
-
#
|
11
|
-
# NOTE: This syntax is no longer valid on Ruby 2.7 or higher.
|
9
|
+
# NOTE: This syntax was made invalid on Ruby 2.7 - Ruby 3.3 but is allowed
|
10
|
+
# again since Ruby 3.4.
|
12
11
|
#
|
13
12
|
# @example
|
14
13
|
#
|
@@ -41,8 +40,6 @@ module RuboCop
|
|
41
40
|
|
42
41
|
MSG = 'Circular argument reference - `%<arg_name>s`.'
|
43
42
|
|
44
|
-
maximum_target_ruby_version 2.6
|
45
|
-
|
46
43
|
def on_kwoptarg(node)
|
47
44
|
check_for_circular_argument_references(*node)
|
48
45
|
end
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
if NO_ARG_ALGORITHM.include?(algorithm_parts.first.upcase) && no_arguments
|
135
135
|
"'#{algorithm_parts.first}'"
|
136
136
|
else
|
137
|
-
mode = 'cbc'
|
137
|
+
mode = 'cbc' if size_and_mode.empty?
|
138
138
|
|
139
139
|
"'#{(algorithm_parts + size_and_mode + [mode]).compact.take(3).join('-')}'"
|
140
140
|
end
|
@@ -39,10 +39,52 @@ module RuboCop
|
|
39
39
|
# end
|
40
40
|
#
|
41
41
|
# alias bar foo
|
42
|
+
#
|
43
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# def foo
|
47
|
+
# 1
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# delegate :foo, to: :bar
|
51
|
+
#
|
52
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
53
|
+
#
|
54
|
+
# # bad
|
55
|
+
# def foo
|
56
|
+
# 1
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# delegate :foo, to: :bar
|
60
|
+
#
|
61
|
+
# # good
|
62
|
+
# def foo
|
63
|
+
# 1
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# delegate :baz, to: :bar
|
67
|
+
#
|
68
|
+
# # good - delegate with splat arguments is ignored
|
69
|
+
# def foo
|
70
|
+
# 1
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# delegate :foo, **options
|
74
|
+
#
|
75
|
+
# # good - delegate inside a condition is ignored
|
76
|
+
# def foo
|
77
|
+
# 1
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# if cond
|
81
|
+
# delegate :foo, to: :bar
|
82
|
+
# end
|
83
|
+
#
|
42
84
|
class DuplicateMethods < Base
|
43
85
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
44
|
-
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
45
|
-
|
86
|
+
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
87
|
+
delegate].freeze
|
46
88
|
|
47
89
|
def initialize(config = nil, options = nil)
|
48
90
|
super
|
@@ -86,15 +128,28 @@ module RuboCop
|
|
86
128
|
(send nil? :alias_method (sym $_name) _)
|
87
129
|
PATTERN
|
88
130
|
|
131
|
+
# @!method delegate_method?(node)
|
132
|
+
def_node_matcher :delegate_method?, <<~PATTERN
|
133
|
+
(send nil? :delegate
|
134
|
+
({sym str} $_)+
|
135
|
+
(hash <(pair (sym :to) {sym str}) ...>)
|
136
|
+
)
|
137
|
+
PATTERN
|
138
|
+
|
89
139
|
# @!method sym_name(node)
|
90
140
|
def_node_matcher :sym_name, '(sym $_name)'
|
91
|
-
|
141
|
+
|
142
|
+
def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
92
143
|
if (name = alias_method?(node))
|
93
144
|
return if node.ancestors.any?(&:if_type?)
|
94
145
|
|
95
146
|
found_instance_method(node, name)
|
96
147
|
elsif (attr = node.attribute_accessor?)
|
97
148
|
on_attr(node, *attr)
|
149
|
+
elsif active_support_extensions_enabled? && (names = delegate_method?(node))
|
150
|
+
return if node.ancestors.any?(&:if_type?)
|
151
|
+
|
152
|
+
on_delegate(node, names)
|
98
153
|
end
|
99
154
|
end
|
100
155
|
|
@@ -119,6 +174,32 @@ module RuboCop
|
|
119
174
|
current: source_location(node))
|
120
175
|
end
|
121
176
|
|
177
|
+
def on_delegate(node, method_names)
|
178
|
+
name_prefix = delegate_prefix(node)
|
179
|
+
|
180
|
+
method_names.each do |name|
|
181
|
+
name = "#{name_prefix}_#{name}" if name_prefix
|
182
|
+
|
183
|
+
found_instance_method(node, name)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def delegate_prefix(node)
|
188
|
+
kwargs_node = node.last_argument
|
189
|
+
|
190
|
+
return unless (prefix = hash_value(kwargs_node, :prefix))
|
191
|
+
|
192
|
+
if prefix.true_type?
|
193
|
+
hash_value(kwargs_node, :to).value
|
194
|
+
elsif prefix.type?(:sym, :str)
|
195
|
+
prefix.value
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def hash_value(node, key)
|
200
|
+
node.pairs.find { |pair| pair.key.value == key }&.value
|
201
|
+
end
|
202
|
+
|
122
203
|
def found_instance_method(node, name)
|
123
204
|
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
124
205
|
|
@@ -162,7 +243,7 @@ module RuboCop
|
|
162
243
|
end
|
163
244
|
|
164
245
|
def method_key(node, method_name)
|
165
|
-
if (ancestor_def = node.each_ancestor(
|
246
|
+
if (ancestor_def = node.each_ancestor(:any_def).first)
|
166
247
|
"#{ancestor_def.method_name}.#{method_name}"
|
167
248
|
else
|
168
249
|
method_name
|
@@ -170,7 +251,7 @@ module RuboCop
|
|
170
251
|
end
|
171
252
|
|
172
253
|
def location(node)
|
173
|
-
if
|
254
|
+
if node.any_def_type?
|
174
255
|
node.loc.keyword.join(node.loc.name)
|
175
256
|
else
|
176
257
|
node.source_range
|
@@ -19,7 +19,9 @@ module RuboCop
|
|
19
19
|
MSG = 'Empty interpolation detected.'
|
20
20
|
|
21
21
|
def on_interpolation(begin_node)
|
22
|
-
|
22
|
+
node_children = begin_node.children.dup
|
23
|
+
node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
|
24
|
+
return unless node_children.empty?
|
23
25
|
|
24
26
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
25
27
|
end
|
@@ -15,6 +15,14 @@ module RuboCop
|
|
15
15
|
# x == 0.1
|
16
16
|
# x != 0.1
|
17
17
|
#
|
18
|
+
# # bad
|
19
|
+
# case value
|
20
|
+
# when 1.0
|
21
|
+
# foo
|
22
|
+
# when 2.0
|
23
|
+
# bar
|
24
|
+
# end
|
25
|
+
#
|
18
26
|
# # good - using BigDecimal
|
19
27
|
# x.to_d == 0.1.to_d
|
20
28
|
#
|
@@ -32,12 +40,21 @@ module RuboCop
|
|
32
40
|
# # good - comparing against nil
|
33
41
|
# Float(x, exception: false) == nil
|
34
42
|
#
|
43
|
+
# # good - using epsilon comparison in case expression
|
44
|
+
# case
|
45
|
+
# when (value - 1.0).abs < Float::EPSILON
|
46
|
+
# foo
|
47
|
+
# when (value - 2.0).abs < Float::EPSILON
|
48
|
+
# bar
|
49
|
+
# end
|
50
|
+
#
|
35
51
|
# # Or some other epsilon based type of comparison:
|
36
52
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
37
53
|
#
|
38
54
|
class FloatComparison < Base
|
39
55
|
MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
|
40
56
|
MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
|
57
|
+
MSG_CASE = 'Avoid float literal comparisons in case statements as they are unreliable.'
|
41
58
|
|
42
59
|
EQUALITY_METHODS = %i[== != eql? equal?].freeze
|
43
60
|
FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
|
@@ -58,6 +75,16 @@ module RuboCop
|
|
58
75
|
end
|
59
76
|
alias on_csend on_send
|
60
77
|
|
78
|
+
def on_case(node)
|
79
|
+
node.when_branches.each do |when_branch|
|
80
|
+
when_branch.each_condition do |condition|
|
81
|
+
next if !float?(condition) || literal_safe?(condition)
|
82
|
+
|
83
|
+
add_offense(condition, message: MSG_CASE)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
61
88
|
private
|
62
89
|
|
63
90
|
def float?(node)
|
@@ -67,7 +94,7 @@ module RuboCop
|
|
67
94
|
when :float
|
68
95
|
true
|
69
96
|
when :send
|
70
|
-
|
97
|
+
float_send?(node)
|
71
98
|
when :begin
|
72
99
|
float?(node.children.first)
|
73
100
|
else
|
@@ -81,18 +108,18 @@ module RuboCop
|
|
81
108
|
(node.numeric_type? && node.value.zero?) || node.nil_type?
|
82
109
|
end
|
83
110
|
|
84
|
-
def
|
111
|
+
def float_send?(node)
|
85
112
|
if node.arithmetic_operation?
|
86
113
|
float?(node.receiver) || float?(node.first_argument)
|
87
114
|
elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
|
88
115
|
true
|
89
116
|
elsif node.receiver&.float_type?
|
90
117
|
FLOAT_INSTANCE_METHODS.include?(node.method_name) ||
|
91
|
-
|
118
|
+
numeric_returning_method?(node)
|
92
119
|
end
|
93
120
|
end
|
94
121
|
|
95
|
-
def
|
122
|
+
def numeric_returning_method?(node)
|
96
123
|
return false unless node.receiver
|
97
124
|
|
98
125
|
case node.method_name
|
@@ -11,39 +11,43 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# foo.object_id == bar.object_id
|
14
|
+
# foo.object_id != baz.object_id
|
14
15
|
#
|
15
16
|
# # good
|
16
17
|
# foo.equal?(bar)
|
18
|
+
# !foo.equal?(baz)
|
17
19
|
#
|
18
20
|
class IdentityComparison < Base
|
19
21
|
extend AutoCorrector
|
20
22
|
|
21
|
-
MSG = 'Use
|
22
|
-
RESTRICT_ON_SEND = %i[==].freeze
|
23
|
+
MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
|
24
|
+
RESTRICT_ON_SEND = %i[== !=].freeze
|
25
|
+
|
26
|
+
# @!method object_id_comparison(node)
|
27
|
+
def_node_matcher :object_id_comparison, <<~PATTERN
|
28
|
+
(send
|
29
|
+
(send
|
30
|
+
_lhs_receiver :object_id) ${:== :!=}
|
31
|
+
(send
|
32
|
+
_rhs_receiver :object_id))
|
33
|
+
PATTERN
|
23
34
|
|
24
35
|
def on_send(node)
|
25
|
-
return unless
|
36
|
+
return unless (comparison_method = object_id_comparison(node))
|
26
37
|
|
27
|
-
|
38
|
+
bang = comparison_method == :== ? '' : '!'
|
39
|
+
add_offense(node,
|
40
|
+
message: format(MSG, comparison_method: comparison_method,
|
41
|
+
bang: bang)) do |corrector|
|
28
42
|
receiver = node.receiver.receiver
|
29
43
|
argument = node.first_argument.receiver
|
30
44
|
return unless receiver && argument
|
31
45
|
|
32
|
-
replacement = "#{receiver.source}.equal?(#{argument.source})"
|
46
|
+
replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
|
33
47
|
|
34
48
|
corrector.replace(node, replacement)
|
35
49
|
end
|
36
50
|
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def compare_between_object_id_by_double_equal?(node)
|
41
|
-
object_id_method?(node.receiver) && object_id_method?(node.first_argument)
|
42
|
-
end
|
43
|
-
|
44
|
-
def object_id_method?(node)
|
45
|
-
node.send_type? && node.method?(:object_id)
|
46
|
-
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
@@ -57,13 +57,9 @@ module RuboCop
|
|
57
57
|
def on_if(node)
|
58
58
|
cond = condition(node)
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
correct_if_node(node, cond, true) if cond.truthy_literal?
|
65
|
-
correct_if_node(node, cond, false) if cond.falsey_literal?
|
66
|
-
end
|
60
|
+
return unless cond.falsey_literal? || cond.truthy_literal?
|
61
|
+
|
62
|
+
correct_if_node(node, cond)
|
67
63
|
end
|
68
64
|
|
69
65
|
def on_while(node)
|
@@ -232,27 +228,37 @@ module RuboCop
|
|
232
228
|
)
|
233
229
|
end
|
234
230
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
add_offense(cond) do |corrector|
|
239
|
-
corrector.replace(node, node.if_branch.source)
|
240
|
-
end
|
241
|
-
elsif node.elsif_conditional?
|
242
|
-
add_offense(cond) do |corrector|
|
243
|
-
corrector.replace(node, "#{node.else_branch.source.sub('elsif', 'if')}\nend")
|
244
|
-
end
|
245
|
-
elsif node.else? || node.ternary?
|
246
|
-
add_offense(cond) do |corrector|
|
247
|
-
corrector.replace(node, node.else_branch.source)
|
248
|
-
end
|
231
|
+
def condition_evaluation?(node, cond)
|
232
|
+
if node.unless?
|
233
|
+
cond.falsey_literal?
|
249
234
|
else
|
250
|
-
|
251
|
-
|
252
|
-
|
235
|
+
cond.truthy_literal?
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
240
|
+
def correct_if_node(node, cond)
|
241
|
+
result = condition_evaluation?(node, cond)
|
242
|
+
|
243
|
+
new_node = if node.elsif? && result
|
244
|
+
"else\n #{range_with_comments(node.if_branch).source}"
|
245
|
+
elsif node.elsif? && !result
|
246
|
+
"else\n #{node.else_branch.source}"
|
247
|
+
elsif node.if_branch && result
|
248
|
+
node.if_branch.source
|
249
|
+
elsif node.elsif_conditional?
|
250
|
+
"#{node.else_branch.source.sub('elsif', 'if')}\nend"
|
251
|
+
elsif node.else? || node.ternary?
|
252
|
+
node.else_branch.source
|
253
|
+
else
|
254
|
+
'' # Equivalent to removing the node
|
255
|
+
end
|
256
|
+
|
257
|
+
add_offense(cond) do |corrector|
|
258
|
+
corrector.replace(node, new_node)
|
253
259
|
end
|
254
260
|
end
|
255
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
261
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
256
262
|
end
|
257
263
|
end
|
258
264
|
end
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
each_missing_enable do |cop, line_range|
|
53
53
|
next if acceptable_range?(cop, line_range)
|
54
54
|
|
55
|
-
range = source_range(processed_source.buffer, line_range.min,
|
55
|
+
range = source_range(processed_source.buffer, line_range.min, 0..0)
|
56
56
|
comment = processed_source.comment_at_line(line_range.begin)
|
57
57
|
|
58
58
|
add_offense(range, message: message(cop, comment))
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
99
99
|
return if node.defs_type? && allowed_subject_type?(subject)
|
100
100
|
|
101
|
-
def_ancestor = node.each_ancestor(:
|
101
|
+
def_ancestor = node.each_ancestor(:any_def).first
|
102
102
|
return unless def_ancestor
|
103
103
|
|
104
104
|
within_scoping_def =
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
def on_return(return_node)
|
47
47
|
return if return_value?(return_node)
|
48
48
|
|
49
|
-
return_node.each_ancestor(:any_block, :
|
49
|
+
return_node.each_ancestor(:any_block, :any_def) do |node|
|
50
50
|
break if scoped_node?(node)
|
51
51
|
|
52
52
|
# if a proc is passed to `Module#define_method` or
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
private
|
67
67
|
|
68
68
|
def scoped_node?(node)
|
69
|
-
node.
|
69
|
+
node.any_def_type? || node.lambda?
|
70
70
|
end
|
71
71
|
|
72
72
|
def return_value?(return_node)
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def redundant_group?(expr)
|
76
|
-
expr.is?(:passive, :group) && expr.
|
76
|
+
expr.is?(:passive, :group) && expr.one? { |child| child.type != :free_space }
|
77
77
|
end
|
78
78
|
|
79
79
|
def redundantly_quantifiable?(node)
|
@@ -27,7 +27,8 @@ module RuboCop
|
|
27
27
|
# In all cases, chaining one same `to_*` conversion methods listed above is redundant.
|
28
28
|
#
|
29
29
|
# The cop can also register an offense for chaining conversion methods on methods that are
|
30
|
-
# expected to return a specific type regardless of receiver (eg. `foo.inspect.to_s`
|
30
|
+
# expected to return a specific type regardless of receiver (eg. `foo.inspect.to_s` and
|
31
|
+
# `foo.to_json.to_s`).
|
31
32
|
#
|
32
33
|
# @example
|
33
34
|
# # bad
|
@@ -69,10 +70,12 @@ module RuboCop
|
|
69
70
|
# foo.to_s
|
70
71
|
#
|
71
72
|
# # bad - chaining a conversion to a method that is expected to return the same type
|
72
|
-
# inspect.to_s
|
73
|
+
# foo.inspect.to_s
|
74
|
+
# foo.to_json.to_s
|
73
75
|
#
|
74
76
|
# # good
|
75
|
-
# inspect
|
77
|
+
# foo.inspect
|
78
|
+
# foo.to_json
|
76
79
|
#
|
77
80
|
class RedundantTypeConversion < Base
|
78
81
|
extend AutoCorrector
|
@@ -108,7 +111,7 @@ module RuboCop
|
|
108
111
|
|
109
112
|
# Methods that already are expected to return a given type, which makes a further
|
110
113
|
# conversion redundant.
|
111
|
-
TYPED_METHODS = { to_s: %i[inspect] }.freeze
|
114
|
+
TYPED_METHODS = { to_s: %i[inspect to_json] }.freeze
|
112
115
|
|
113
116
|
CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
|
114
117
|
RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
|
@@ -32,12 +32,17 @@ module RuboCop
|
|
32
32
|
class ReturnInVoidContext < Base
|
33
33
|
MSG = 'Do not return a value in `%<method>s`.'
|
34
34
|
|
35
|
+
# Returning out of these methods only exits the block itself.
|
36
|
+
SCOPE_CHANGING_METHODS = %i[lambda define_method define_singleton_method].freeze
|
37
|
+
|
35
38
|
def on_return(return_node)
|
36
39
|
return unless return_node.descendants.any?
|
37
40
|
|
38
|
-
def_node = return_node.each_ancestor(:
|
41
|
+
def_node = return_node.each_ancestor(:any_def).first
|
39
42
|
return unless def_node&.void_context?
|
40
|
-
return if return_node.each_ancestor(:any_block).any?
|
43
|
+
return if return_node.each_ancestor(:any_block).any? do |block_node|
|
44
|
+
SCOPE_CHANGING_METHODS.include?(block_node.method_name)
|
45
|
+
end
|
41
46
|
|
42
47
|
add_offense(
|
43
48
|
return_node.loc.keyword,
|
@@ -97,7 +97,7 @@ module RuboCop
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def require_parentheses?(send_node)
|
100
|
-
return true if
|
100
|
+
return true if operator_inside_collection_literal?(send_node)
|
101
101
|
return false unless send_node.comparison_method?
|
102
102
|
return false unless (node = send_node.parent)
|
103
103
|
|
@@ -105,10 +105,10 @@ module RuboCop
|
|
105
105
|
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
106
106
|
end
|
107
107
|
|
108
|
-
def
|
109
|
-
# If an operator call (without a dot) is inside a hash, it needs
|
108
|
+
def operator_inside_collection_literal?(send_node)
|
109
|
+
# If an operator call (without a dot) is inside an array or a hash, it needs
|
110
110
|
# to be parenthesized when converted to safe navigation.
|
111
|
-
send_node.parent&.
|
111
|
+
send_node.parent&.type?(:array, :pair) && !send_node.loc.dot
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|