rubocop 1.75.0 → 1.76.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 +19 -13
- data/config/default.yml +80 -24
- 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/gemspec/duplicated_assignment.rb +50 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- 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/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 +6 -2
- 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/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 +6 -32
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +5 -1
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -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 +27 -0
- 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_type_conversion.rb +7 -4
- data/lib/rubocop/cop/lint/return_in_void_context.rb +7 -2
- 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_assignment.rb +2 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +87 -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/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/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 +0 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- 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/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 +216 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
- 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/class_and_module_children.rb +19 -3
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- 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 +16 -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/frozen_string_literal_comment.rb +3 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- 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 +22 -4
- 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 +5 -2
- 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/raise_args.rb +8 -8
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -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_line_continuation.rb +0 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +31 -3
- 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 +28 -10
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- 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/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_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/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +8 -0
- data/lib/rubocop/rspec/cop_helper.rb +2 -2
- 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 +6 -1
- metadata +12 -7
|
@@ -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)
|
|
@@ -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,
|
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
|
8
8
|
# given by `ruby -cw` prior to Ruby 2.6:
|
|
9
9
|
# "shadowing outer local variable - foo".
|
|
10
10
|
#
|
|
11
|
+
# The cop is now disabled by default to match the upstream Ruby behavior.
|
|
12
|
+
# It's useful, however, if you'd like to avoid shadowing variables from outer
|
|
13
|
+
# scopes, which some people consider an anti-pattern that makes it harder
|
|
14
|
+
# to keep track of what's going on in a program.
|
|
15
|
+
#
|
|
11
16
|
# NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
|
|
12
17
|
# because `Ractor` should not access outer variables.
|
|
13
18
|
# eg. following style is encouraged:
|
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
|
116
116
|
private
|
|
117
117
|
|
|
118
118
|
def comment_between_rescue_and_end?(node)
|
|
119
|
-
ancestor = node.each_ancestor(:kwbegin, :
|
|
119
|
+
ancestor = node.each_ancestor(:kwbegin, :any_def, :any_block).first
|
|
120
120
|
return false unless ancestor
|
|
121
121
|
|
|
122
122
|
end_line = ancestor.loc.end&.line || ancestor.loc.last_line
|
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
|
40
40
|
# top-level return node's ancestors should not be of block, def, or
|
|
41
41
|
# defs type.
|
|
42
42
|
def top_level_return?(return_node)
|
|
43
|
-
return_node.each_ancestor(:block, :
|
|
43
|
+
return_node.each_ancestor(:block, :any_def).none?
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for usage of method `fetch` or `Array.new` with default value argument
|
|
7
|
+
# and block. In such cases, block will always be used as default value.
|
|
8
|
+
#
|
|
9
|
+
# This cop emulates Ruby warning "block supersedes default value argument" which
|
|
10
|
+
# applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
|
|
11
|
+
# `Thread#fetch`.
|
|
12
|
+
#
|
|
13
|
+
# @safety
|
|
14
|
+
# This cop is unsafe because the receiver could have nonstandard implementation
|
|
15
|
+
# of `fetch`, or be a class other than the one listed above.
|
|
16
|
+
#
|
|
17
|
+
# It is also unsafe because default value argument could have side effects:
|
|
18
|
+
#
|
|
19
|
+
# [source,ruby]
|
|
20
|
+
# ----
|
|
21
|
+
# def x(a) = puts "side effect"
|
|
22
|
+
# Array.new(5, x(1)) { 2 }
|
|
23
|
+
# ----
|
|
24
|
+
#
|
|
25
|
+
# so removing it would change behavior.
|
|
26
|
+
#
|
|
27
|
+
# @example
|
|
28
|
+
# # bad
|
|
29
|
+
# x.fetch(key, default_value) { block_value }
|
|
30
|
+
# Array.new(size, default_value) { block_value }
|
|
31
|
+
#
|
|
32
|
+
# # good
|
|
33
|
+
# x.fetch(key) { block_value }
|
|
34
|
+
# Array.new(size) { block_value }
|
|
35
|
+
#
|
|
36
|
+
# # also good - in case default value argument is desired instead
|
|
37
|
+
# x.fetch(key, default_value)
|
|
38
|
+
# Array.new(size, default_value)
|
|
39
|
+
#
|
|
40
|
+
# # good - keyword arguments aren't registered as offenses
|
|
41
|
+
# x.fetch(key, keyword: :arg) { block_value }
|
|
42
|
+
#
|
|
43
|
+
# @example AllowedReceivers: ['Rails.cache']
|
|
44
|
+
# # good
|
|
45
|
+
# Rails.cache.fetch(name, options) { block }
|
|
46
|
+
#
|
|
47
|
+
class UselessDefaultValueArgument < Base
|
|
48
|
+
include AllowedReceivers
|
|
49
|
+
extend AutoCorrector
|
|
50
|
+
|
|
51
|
+
MSG = 'Block supersedes default value argument.'
|
|
52
|
+
|
|
53
|
+
RESTRICT_ON_SEND = %i[fetch new].freeze
|
|
54
|
+
|
|
55
|
+
# @!method default_value_argument_and_block(node)
|
|
56
|
+
def_node_matcher :default_value_argument_and_block, <<~PATTERN
|
|
57
|
+
(any_block
|
|
58
|
+
{
|
|
59
|
+
(call _receiver :fetch $_key $_default_value)
|
|
60
|
+
(send (const _ :Array) :new $_size $_default_value)
|
|
61
|
+
}
|
|
62
|
+
_args
|
|
63
|
+
_block_body)
|
|
64
|
+
PATTERN
|
|
65
|
+
|
|
66
|
+
def on_send(node)
|
|
67
|
+
unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
return if allowed_receiver?(node.receiver)
|
|
71
|
+
return if hash_without_braces?(default_value_node)
|
|
72
|
+
|
|
73
|
+
add_offense(default_value_node) do |corrector|
|
|
74
|
+
corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
alias on_csend on_send
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def hash_without_braces?(node)
|
|
82
|
+
node.hash_type? && !node.braces?
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for useless OR (`||` and `or`) expressions.
|
|
7
|
+
#
|
|
8
|
+
# Some methods always return a truthy value, even when called
|
|
9
|
+
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
|
10
|
+
# appended after these methods will never evaluate.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
#
|
|
14
|
+
# # bad
|
|
15
|
+
# x.to_a || fallback
|
|
16
|
+
# x.to_c || fallback
|
|
17
|
+
# x.to_d || fallback
|
|
18
|
+
# x.to_i || fallback
|
|
19
|
+
# x.to_f || fallback
|
|
20
|
+
# x.to_h || fallback
|
|
21
|
+
# x.to_r || fallback
|
|
22
|
+
# x.to_s || fallback
|
|
23
|
+
# x.to_sym || fallback
|
|
24
|
+
# x.intern || fallback
|
|
25
|
+
# x.inspect || fallback
|
|
26
|
+
# x.hash || fallback
|
|
27
|
+
# x.object_id || fallback
|
|
28
|
+
# x.__id__ || fallback
|
|
29
|
+
#
|
|
30
|
+
# x.to_s or fallback
|
|
31
|
+
#
|
|
32
|
+
# # good - if fallback is same as return value of method called on nil
|
|
33
|
+
# x.to_a # nil.to_a returns []
|
|
34
|
+
# x.to_c # nil.to_c returns (0+0i)
|
|
35
|
+
# x.to_d # nil.to_d returns 0.0
|
|
36
|
+
# x.to_i # nil.to_i returns 0
|
|
37
|
+
# x.to_f # nil.to_f returns 0.0
|
|
38
|
+
# x.to_h # nil.to_h returns {}
|
|
39
|
+
# x.to_r # nil.to_r returns (0/1)
|
|
40
|
+
# x.to_s # nil.to_s returns ''
|
|
41
|
+
# x.to_sym # nil.to_sym raises an error
|
|
42
|
+
# x.intern # nil.intern raises an error
|
|
43
|
+
# x.inspect # nil.inspect returns "nil"
|
|
44
|
+
# x.hash # nil.hash returns an Integer
|
|
45
|
+
# x.object_id # nil.object_id returns an Integer
|
|
46
|
+
# x.__id__ # nil.object_id returns an Integer
|
|
47
|
+
#
|
|
48
|
+
# # good - if the intention is not to call the method on nil
|
|
49
|
+
# x&.to_a || fallback
|
|
50
|
+
# x&.to_c || fallback
|
|
51
|
+
# x&.to_d || fallback
|
|
52
|
+
# x&.to_i || fallback
|
|
53
|
+
# x&.to_f || fallback
|
|
54
|
+
# x&.to_h || fallback
|
|
55
|
+
# x&.to_r || fallback
|
|
56
|
+
# x&.to_s || fallback
|
|
57
|
+
# x&.to_sym || fallback
|
|
58
|
+
# x&.intern || fallback
|
|
59
|
+
# x&.inspect || fallback
|
|
60
|
+
# x&.hash || fallback
|
|
61
|
+
# x&.object_id || fallback
|
|
62
|
+
# x&.__id__ || fallback
|
|
63
|
+
#
|
|
64
|
+
# x&.to_s or fallback
|
|
65
|
+
#
|
|
66
|
+
class UselessOr < Base
|
|
67
|
+
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
|
68
|
+
|
|
69
|
+
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
|
70
|
+
:to_s, :to_sym, :intern, :inspect, :hash, :object_id,
|
|
71
|
+
:__id__].freeze
|
|
72
|
+
|
|
73
|
+
# @!method truthy_return_value_method?(node)
|
|
74
|
+
def_node_matcher :truthy_return_value_method?, <<~PATTERN
|
|
75
|
+
(send _ %TRUTHY_RETURN_VALUE_METHODS)
|
|
76
|
+
PATTERN
|
|
77
|
+
|
|
78
|
+
def on_or(node)
|
|
79
|
+
if truthy_return_value_method?(node.lhs)
|
|
80
|
+
report_offense(node, node.lhs)
|
|
81
|
+
elsif truthy_return_value_method?(node.rhs)
|
|
82
|
+
parent = node.parent
|
|
83
|
+
parent = parent.parent if parent&.begin_type?
|
|
84
|
+
|
|
85
|
+
report_offense(parent, node.rhs) if parent&.or_type?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def report_offense(or_node, truthy_node)
|
|
92
|
+
add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
|
|
93
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -128,8 +128,8 @@ module RuboCop
|
|
|
128
128
|
|
|
129
129
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
130
130
|
def check_void_op(node, &block)
|
|
131
|
-
node = node.children.first while node
|
|
132
|
-
return unless node
|
|
131
|
+
node = node.children.first while node&.begin_type?
|
|
132
|
+
return unless node&.call_type? && OPERATORS.include?(node.method_name)
|
|
133
133
|
if !UNARY_OPERATORS.include?(node.method_name) && node.loc.dot && node.arguments.none?
|
|
134
134
|
return
|
|
135
135
|
end
|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
|
32
32
|
# @param [String] cop_name for specific cop name
|
|
33
33
|
# @param [Hash] cop_config configs for specific cop, from config#for_cop
|
|
34
34
|
# @option cop_config [String] :StyleGuide Extension of base styleguide URL
|
|
35
|
-
# @option cop_config [String] :
|
|
35
|
+
# @option cop_config [String] :References Full reference URLs
|
|
36
36
|
# @option cop_config [String] :Details
|
|
37
37
|
#
|
|
38
38
|
# @param [Hash, nil] options optional
|
|
@@ -100,8 +100,12 @@ module RuboCop
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def reference_urls
|
|
103
|
-
urls =
|
|
104
|
-
|
|
103
|
+
urls = cop_config
|
|
104
|
+
.values_at('References', 'Reference') # Support legacy Reference key
|
|
105
|
+
.flat_map { Array(_1) }
|
|
106
|
+
.reject(&:empty?)
|
|
107
|
+
|
|
108
|
+
urls unless urls.empty?
|
|
105
109
|
end
|
|
106
110
|
|
|
107
111
|
def extra_details?
|
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
|
39
39
|
class AbcSize < Base
|
|
40
40
|
include MethodComplexity
|
|
41
41
|
|
|
42
|
-
MSG = 'Assignment Branch Condition size for
|
|
42
|
+
MSG = 'Assignment Branch Condition size for `%<method>s` is too high. ' \
|
|
43
43
|
'[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
|
|
44
44
|
|
|
45
45
|
private
|
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
|
48
48
|
|
|
49
49
|
args = process_args(node.arguments)
|
|
50
50
|
return extract_breakable_node_from_elements(node, args, max)
|
|
51
|
-
elsif node.
|
|
51
|
+
elsif node.any_def_type?
|
|
52
52
|
return extract_breakable_node_from_elements(node, node.arguments, max)
|
|
53
53
|
elsif node.type?(:array, :hash)
|
|
54
54
|
return extract_breakable_node_from_elements(node, node.children, max)
|
|
@@ -220,7 +220,7 @@ module RuboCop
|
|
|
220
220
|
|
|
221
221
|
# @api private
|
|
222
222
|
def already_on_multiple_lines?(node)
|
|
223
|
-
return node.first_line != node.last_argument.last_line if node.
|
|
223
|
+
return node.first_line != node.last_argument.last_line if node.any_def_type?
|
|
224
224
|
|
|
225
225
|
!node.single_line?
|
|
226
226
|
end
|
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def safe_to_split?(node)
|
|
43
|
-
node.each_descendant(:if, :case, :kwbegin, :
|
|
43
|
+
node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
|
|
44
44
|
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
|
45
45
|
node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
|
|
46
46
|
end
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
|
19
19
|
|
|
20
20
|
# @!method non_public_modifier?(node)
|
|
21
21
|
def_node_matcher :non_public_modifier?, <<~PATTERN
|
|
22
|
-
(send nil? {:private :protected :private_class_method} (
|
|
22
|
+
(send nil? {:private :protected :private_class_method} (any_def ...))
|
|
23
23
|
PATTERN
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
|
21
21
|
|
|
22
22
|
# @!method empty_line_required?(node)
|
|
23
23
|
def_node_matcher :empty_line_required?,
|
|
24
|
-
'{
|
|
24
|
+
'{any_def class module (send nil? {:private :protected :public})}'
|
|
25
25
|
|
|
26
26
|
def check(node, body, adjusted_first_line: nil)
|
|
27
27
|
return if valid_body_style?(body)
|
|
@@ -6,7 +6,6 @@ module RuboCop
|
|
|
6
6
|
module FrozenStringLiteral
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
|
-
FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
|
|
10
9
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
|
11
10
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
|
12
11
|
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
true
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def deltas_for_first_pair(first_pair
|
|
13
|
+
def deltas_for_first_pair(first_pair)
|
|
14
14
|
{
|
|
15
15
|
separator: separator_delta(first_pair),
|
|
16
16
|
value: value_delta(first_pair)
|
|
@@ -81,13 +81,7 @@ module RuboCop
|
|
|
81
81
|
class TableAlignment
|
|
82
82
|
include ValueAlignment
|
|
83
83
|
|
|
84
|
-
def
|
|
85
|
-
self.max_key_width = 0
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def deltas_for_first_pair(first_pair, node)
|
|
89
|
-
self.max_key_width = node.keys.map { |key| key.source.length }.max
|
|
90
|
-
|
|
84
|
+
def deltas_for_first_pair(first_pair)
|
|
91
85
|
separator_delta = separator_delta(first_pair, first_pair, 0)
|
|
92
86
|
{
|
|
93
87
|
separator: separator_delta,
|
|
@@ -97,30 +91,37 @@ module RuboCop
|
|
|
97
91
|
|
|
98
92
|
private
|
|
99
93
|
|
|
100
|
-
attr_accessor :max_key_width
|
|
101
|
-
|
|
102
94
|
def key_delta(first_pair, current_pair)
|
|
103
95
|
first_pair.key_delta(current_pair)
|
|
104
96
|
end
|
|
105
97
|
|
|
106
98
|
def hash_rocket_delta(first_pair, current_pair)
|
|
107
|
-
first_pair.loc.column + max_key_width + 1 -
|
|
99
|
+
first_pair.loc.column + max_key_width(first_pair.parent) + 1 -
|
|
100
|
+
current_pair.loc.operator.column
|
|
108
101
|
end
|
|
109
102
|
|
|
110
103
|
def value_delta(first_pair, current_pair)
|
|
111
104
|
correct_value_column = first_pair.key.loc.column +
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
max_key_width(first_pair.parent) +
|
|
106
|
+
max_delimiter_width(first_pair.parent)
|
|
114
107
|
|
|
115
108
|
current_pair.value_omission? ? 0 : correct_value_column - current_pair.value.loc.column
|
|
116
109
|
end
|
|
110
|
+
|
|
111
|
+
def max_key_width(hash_node)
|
|
112
|
+
hash_node.keys.map { |key| key.source.length }.max
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def max_delimiter_width(hash_node)
|
|
116
|
+
hash_node.pairs.map { |pair| pair.delimiter(true).length }.max
|
|
117
|
+
end
|
|
117
118
|
end
|
|
118
119
|
|
|
119
120
|
# Handles calculation of deltas when the enforced style is 'separator'.
|
|
120
121
|
class SeparatorAlignment
|
|
121
122
|
include ValueAlignment
|
|
122
123
|
|
|
123
|
-
def deltas_for_first_pair(
|
|
124
|
+
def deltas_for_first_pair(_first_pair)
|
|
124
125
|
{}
|
|
125
126
|
end
|
|
126
127
|
|
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
|
24
24
|
gem_canonical_name(string_a) < gem_canonical_name(string_b)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def consecutive_lines(previous, current)
|
|
27
|
+
def consecutive_lines?(previous, current)
|
|
28
28
|
first_line = get_source_range(current, treat_comments_as_separators).first_line
|
|
29
29
|
previous.source_range.last_line == first_line - 1
|
|
30
30
|
end
|
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
|
107
107
|
# of the argument is not considered multiline, even if the argument
|
|
108
108
|
# itself might span multiple lines.
|
|
109
109
|
def allowed_multiline_argument?(node)
|
|
110
|
-
elements(node).one? && !Util.begins_its_line?(node
|
|
110
|
+
elements(node).one? && !Util.begins_its_line?(node_end_location(node))
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def elements(node)
|
|
@@ -127,18 +127,22 @@ module RuboCop
|
|
|
127
127
|
|
|
128
128
|
def no_elements_on_same_line?(node)
|
|
129
129
|
items = elements(node).map(&:source_range)
|
|
130
|
-
items << node
|
|
130
|
+
items << node_end_location(node)
|
|
131
131
|
items.each_cons(2).none? { |a, b| on_same_line?(a, b) }
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
def node_end_location(node)
|
|
135
|
+
node.loc.end || node.source_range.end.adjust(begin_pos: -1)
|
|
136
|
+
end
|
|
137
|
+
|
|
134
138
|
def on_same_line?(range1, range2)
|
|
135
139
|
range1.last_line == range2.line
|
|
136
140
|
end
|
|
137
141
|
|
|
138
142
|
def last_item_precedes_newline?(node)
|
|
139
|
-
after_last_item =
|
|
140
|
-
|
|
141
|
-
after_last_item.source
|
|
143
|
+
after_last_item = node.children.last.source_range.end.join(node.loc.end.begin)
|
|
144
|
+
|
|
145
|
+
after_last_item.source.start_with?(/,?\s*(#.*)?\n/)
|
|
142
146
|
end
|
|
143
147
|
|
|
144
148
|
def avoid_comma(kind, comma_begin_pos, extra_info)
|