rubocop 1.73.0 → 1.74.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 +1 -1
- data/config/default.yml +35 -4
- data/config/internal_affairs.yml +4 -0
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
- data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -16
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +9 -3
- data/lib/rubocop/cop/lint/return_in_void_context.rb +4 -11
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +2 -11
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +12 -0
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +29 -7
- data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
- data/lib/rubocop/cop/style/comparable_between.rb +75 -0
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -5
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
- data/lib/rubocop/cop/style/redundant_condition.rb +11 -0
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +0 -6
- data/lib/rubocop/cop/utils/format_string.rb +5 -2
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 440bee0e28f294bab2eba4c11e9c681342917c69ad4c00e36eceb88743767c29
|
|
4
|
+
data.tar.gz: 68e9e209a22e891a38b677f97344d2d10e9a8913dd999751472f301deed43b31
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70db27a5b7a0e00696672a5b4fcd4e3bf35aa40c85ef65ccb630914ab110a5e5b657927aa1b1c8637be76b7041a90e2ad3c4ed188110266c048d0c4d6a4be0b4
|
|
7
|
+
data.tar.gz: e5599d30a4f776d85d202acad2ac03c7e4568e64a1c4038cb87b8ee3372b2428882924a91ea49853c98cf0614280d002918363eef41fe0990dc8b1895d8e9776
|
data/README.md
CHANGED
|
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
|
52
52
|
in your `Gemfile`:
|
|
53
53
|
|
|
54
54
|
```rb
|
|
55
|
-
gem 'rubocop', '~> 1.
|
|
55
|
+
gem 'rubocop', '~> 1.74', require: false
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
|
@@ -1887,10 +1887,9 @@ Lint/EmptyConditionalBody:
|
|
|
1887
1887
|
Description: 'Checks for the presence of `if`, `elsif` and `unless` branches without a body.'
|
|
1888
1888
|
Enabled: true
|
|
1889
1889
|
AutoCorrect: contextual
|
|
1890
|
-
SafeAutoCorrect: false
|
|
1891
1890
|
AllowComments: true
|
|
1892
1891
|
VersionAdded: '0.89'
|
|
1893
|
-
VersionChanged: '1.
|
|
1892
|
+
VersionChanged: '1.73'
|
|
1894
1893
|
|
|
1895
1894
|
Lint/EmptyEnsure:
|
|
1896
1895
|
Description: 'Checks for empty ensure block.'
|
|
@@ -3105,6 +3104,8 @@ Naming/VariableNumber:
|
|
|
3105
3104
|
CheckMethodNames: true
|
|
3106
3105
|
CheckSymbols: true
|
|
3107
3106
|
AllowedIdentifiers:
|
|
3107
|
+
- TLS1_1 # OpenSSL::SSL::TLS1_1_VERSION
|
|
3108
|
+
- TLS1_2 # OpenSSL::SSL::TLS1_2_VERSION
|
|
3108
3109
|
- capture3 # Open3.capture3
|
|
3109
3110
|
- iso8601 # Time#iso8601
|
|
3110
3111
|
- rfc1123_date # CGI.rfc1123_date
|
|
@@ -3500,6 +3501,7 @@ Style/ClassAndModuleChildren:
|
|
|
3500
3501
|
SafeAutoCorrect: false
|
|
3501
3502
|
Enabled: true
|
|
3502
3503
|
VersionAdded: '0.19'
|
|
3504
|
+
VersionChanged: '1.74'
|
|
3503
3505
|
#
|
|
3504
3506
|
# Basically there are two different styles:
|
|
3505
3507
|
#
|
|
@@ -3515,7 +3517,21 @@ Style/ClassAndModuleChildren:
|
|
|
3515
3517
|
#
|
|
3516
3518
|
# The compact style is only forced, for classes or modules with one child.
|
|
3517
3519
|
EnforcedStyle: nested
|
|
3518
|
-
SupportedStyles:
|
|
3520
|
+
SupportedStyles: &supported_styles
|
|
3521
|
+
- nested
|
|
3522
|
+
- compact
|
|
3523
|
+
# Configure classes separately, if desired. If not set, or set to `nil`,
|
|
3524
|
+
# the `EnforcedStyle` value will be used.
|
|
3525
|
+
EnforcedStyleForClasses: ~
|
|
3526
|
+
SupportedStylesForClasses:
|
|
3527
|
+
- ~
|
|
3528
|
+
- nested
|
|
3529
|
+
- compact
|
|
3530
|
+
# Configure modules separately, if desired. If not set, or set to `nil`,
|
|
3531
|
+
# the `EnforcedStyle` value will be used.
|
|
3532
|
+
EnforcedStyleForModules: ~
|
|
3533
|
+
SupportedStylesForModules:
|
|
3534
|
+
- ~
|
|
3519
3535
|
- nested
|
|
3520
3536
|
- compact
|
|
3521
3537
|
|
|
@@ -3668,6 +3684,12 @@ Style/CommentedKeyword:
|
|
|
3668
3684
|
VersionAdded: '0.51'
|
|
3669
3685
|
VersionChanged: '1.19'
|
|
3670
3686
|
|
|
3687
|
+
Style/ComparableBetween:
|
|
3688
|
+
Description: 'Enforces the use of `Comparable#between?` instead of logical comparison.'
|
|
3689
|
+
Enabled: pending
|
|
3690
|
+
VersionAdded: '1.74'
|
|
3691
|
+
StyleGuide: '#ranges-or-between'
|
|
3692
|
+
|
|
3671
3693
|
Style/ComparableClamp:
|
|
3672
3694
|
Description: 'Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.'
|
|
3673
3695
|
Enabled: pending
|
|
@@ -4070,8 +4092,14 @@ Style/FormatStringToken:
|
|
|
4070
4092
|
# style token in a format string to be allowed when enforced style is not
|
|
4071
4093
|
# `unannotated`.
|
|
4072
4094
|
MaxUnannotatedPlaceholdersAllowed: 1
|
|
4095
|
+
# The mode the cop operates in. Two values are allowed:
|
|
4096
|
+
# * aggressive (default): all strings are considered
|
|
4097
|
+
# * conservative:
|
|
4098
|
+
# only register offenses for strings given to `printf`, `sprintf`,
|
|
4099
|
+
# format` and `%` methods. Other strings are not considered.
|
|
4100
|
+
Mode: aggressive
|
|
4073
4101
|
VersionAdded: '0.49'
|
|
4074
|
-
VersionChanged: '1.
|
|
4102
|
+
VersionChanged: '1.74'
|
|
4075
4103
|
AllowedMethods: []
|
|
4076
4104
|
AllowedPatterns: []
|
|
4077
4105
|
|
|
@@ -5108,6 +5136,9 @@ Style/RedundantCondition:
|
|
|
5108
5136
|
Description: 'Checks for unnecessary conditional expressions.'
|
|
5109
5137
|
Enabled: true
|
|
5110
5138
|
VersionAdded: '0.76'
|
|
5139
|
+
VersionChanged: '1.73'
|
|
5140
|
+
AllowedMethods:
|
|
5141
|
+
- nonzero?
|
|
5111
5142
|
|
|
5112
5143
|
Style/RedundantConditional:
|
|
5113
5144
|
Description: "Don't return true/false from a conditional."
|
data/config/internal_affairs.yml
CHANGED
|
@@ -63,7 +63,6 @@ module RuboCop
|
|
|
63
63
|
loaded_features = resolver.resolve_requires(path, hash)
|
|
64
64
|
add_loaded_features(loaded_features)
|
|
65
65
|
|
|
66
|
-
resolver.override_department_setting_for_cops({}, hash)
|
|
67
66
|
resolver.resolve_inheritance_from_gems(hash)
|
|
68
67
|
resolver.resolve_inheritance(path, hash, file, debug?)
|
|
69
68
|
hash.delete('inherit_from')
|
|
@@ -9,7 +9,8 @@ module RuboCop
|
|
|
9
9
|
# @api private
|
|
10
10
|
class ConfigLoaderResolver # rubocop:disable Metrics/ClassLength
|
|
11
11
|
def resolve_plugins(rubocop_config, plugins)
|
|
12
|
-
|
|
12
|
+
plugins = Array(plugins) - ConfigLoader.loaded_plugins.map { |plugin| plugin.about.name }
|
|
13
|
+
return if plugins.empty?
|
|
13
14
|
|
|
14
15
|
Plugin.integrate_plugins(rubocop_config, plugins)
|
|
15
16
|
end
|
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def violated?
|
|
18
|
-
return false if
|
|
18
|
+
return false if plugin_loaded?
|
|
19
19
|
|
|
20
20
|
affected_cops.any?
|
|
21
21
|
end
|
|
@@ -38,8 +38,9 @@ module RuboCop
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def
|
|
42
|
-
|
|
41
|
+
def plugin_loaded?
|
|
42
|
+
# Plugins loaded via `require` are included in `loaded_features`.
|
|
43
|
+
config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
|
|
43
44
|
end
|
|
44
45
|
end
|
|
45
46
|
end
|
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
|
50
50
|
# Default rules for obsoletions are in config/obsoletion.yml
|
|
51
51
|
# Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
|
|
52
52
|
def load_rules # rubocop:disable Metrics/AbcSize
|
|
53
|
-
rules = LOAD_RULES_CACHE[self.class.files] ||=
|
|
53
|
+
rules = LOAD_RULES_CACHE[self.class.files.hash] ||=
|
|
54
54
|
self.class.files.each_with_object({}) do |filename, hash|
|
|
55
55
|
hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
|
|
56
56
|
case first
|
|
@@ -50,10 +50,12 @@ module RuboCop
|
|
|
50
50
|
}.freeze
|
|
51
51
|
|
|
52
52
|
EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
|
|
53
|
-
/\A(auto[- ]?)?
|
|
53
|
+
/\A(auto[- ]?)?corrects?/ => 'does not correct',
|
|
54
|
+
/\band (auto[- ]?)?corrects/ => 'but does not correct'
|
|
54
55
|
}.freeze
|
|
55
56
|
|
|
56
57
|
EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
|
|
58
|
+
/\bbut (does not|doesn't) (auto[- ]?)?correct/ => 'and autocorrects',
|
|
57
59
|
/\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
|
|
58
60
|
}.freeze
|
|
59
61
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module InternalAffairs
|
|
6
|
+
# Checks that node types are checked against their group when all types of a
|
|
7
|
+
# group are checked.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# node.type?(:irange, :erange)
|
|
12
|
+
#
|
|
13
|
+
# # good
|
|
14
|
+
# node.range_type?
|
|
15
|
+
#
|
|
16
|
+
# # bad
|
|
17
|
+
# node.type?(:irange, :erange, :send, :csend)
|
|
18
|
+
#
|
|
19
|
+
# # good
|
|
20
|
+
# node.type?(:range, :call)
|
|
21
|
+
#
|
|
22
|
+
class NodeTypeGroup < Base
|
|
23
|
+
extend AutoCorrector
|
|
24
|
+
include RangeHelp
|
|
25
|
+
|
|
26
|
+
MSG = 'Use `:%<group>s` instead of individually listing group types.'
|
|
27
|
+
|
|
28
|
+
RESTRICT_ON_SEND = %i[type? each_ancestor each_child_node each_descendant each_node].freeze
|
|
29
|
+
|
|
30
|
+
def on_send(node)
|
|
31
|
+
return unless node.receiver
|
|
32
|
+
|
|
33
|
+
symbol_args = node.arguments.select(&:sym_type?)
|
|
34
|
+
return if symbol_args.none?
|
|
35
|
+
|
|
36
|
+
NodePatternGroups::NODE_GROUPS.each do |group_name, group_types|
|
|
37
|
+
next unless group_satisfied?(group_types, symbol_args)
|
|
38
|
+
|
|
39
|
+
offense_range = arguments_range(node)
|
|
40
|
+
add_offense(offense_range, message: format(MSG, group: group_name)) do |corrector|
|
|
41
|
+
autocorrect(corrector, node, symbol_args, group_name, group_types)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
alias on_csend on_send
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def arguments_range(node)
|
|
50
|
+
range_between(
|
|
51
|
+
node.first_argument.source_range.begin_pos,
|
|
52
|
+
node.last_argument.source_range.end_pos
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def group_satisfied?(group_types, symbol_args)
|
|
57
|
+
group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def autocorrect(corrector, node, symbol_args, group_name, group_types)
|
|
61
|
+
if node.method?(:type?) && node.arguments.count == group_types.count
|
|
62
|
+
autocorrect_to_explicit_predicate(corrector, node, group_name)
|
|
63
|
+
else
|
|
64
|
+
autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def autocorrect_to_explicit_predicate(corrector, node, group_name)
|
|
69
|
+
corrector.replace(node.selector, "#{group_name}_type?")
|
|
70
|
+
corrector.remove(arguments_range(node))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
|
|
74
|
+
first_replaced = false
|
|
75
|
+
symbol_args.each do |arg|
|
|
76
|
+
next unless group_types.include?(arg.value)
|
|
77
|
+
|
|
78
|
+
if first_replaced
|
|
79
|
+
range = range_with_surrounding_space(arg.source_range)
|
|
80
|
+
range = range_with_surrounding_comma(range, :left)
|
|
81
|
+
corrector.remove(range)
|
|
82
|
+
else
|
|
83
|
+
first_replaced = true
|
|
84
|
+
corrector.replace(arg, ":#{group_name}")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -17,6 +17,7 @@ require_relative 'internal_affairs/node_destructuring'
|
|
|
17
17
|
require_relative 'internal_affairs/node_first_or_last_argument'
|
|
18
18
|
require_relative 'internal_affairs/node_matcher_directive'
|
|
19
19
|
require_relative 'internal_affairs/node_pattern_groups'
|
|
20
|
+
require_relative 'internal_affairs/node_type_group'
|
|
20
21
|
require_relative 'internal_affairs/node_type_multiple_predicates'
|
|
21
22
|
require_relative 'internal_affairs/node_type_predicate'
|
|
22
23
|
require_relative 'internal_affairs/numblock_handler'
|
|
@@ -155,10 +155,10 @@ module RuboCop
|
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
def all_elements_aligned?(elements)
|
|
158
|
-
elements.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
if elements.first.hash_type?
|
|
159
|
+
elements.first.each_child_node.map { |child| child.loc.column }
|
|
160
|
+
else
|
|
161
|
+
elements.flat_map do |e|
|
|
162
162
|
e.loc.column
|
|
163
163
|
end
|
|
164
164
|
end.uniq.count == 1
|
|
@@ -7,11 +7,6 @@ module RuboCop
|
|
|
7
7
|
#
|
|
8
8
|
# NOTE: empty `else` branches are handled by `Style/EmptyElse`.
|
|
9
9
|
#
|
|
10
|
-
# @safety
|
|
11
|
-
# Autocorrection for this cop is not safe. The conditions for empty branches that
|
|
12
|
-
# the autocorrection removes may have side effects, or the logic in subsequent
|
|
13
|
-
# branches may change due to the removal of a previous condition.
|
|
14
|
-
#
|
|
15
10
|
# @example
|
|
16
11
|
# # bad
|
|
17
12
|
# if condition
|
|
@@ -41,6 +36,13 @@ module RuboCop
|
|
|
41
36
|
# if condition
|
|
42
37
|
# do_something
|
|
43
38
|
# elsif other_condition
|
|
39
|
+
# nil
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # good
|
|
43
|
+
# if condition
|
|
44
|
+
# do_something
|
|
45
|
+
# elsif other_condition
|
|
44
46
|
# do_something_else
|
|
45
47
|
# end
|
|
46
48
|
#
|
|
@@ -63,11 +65,9 @@ module RuboCop
|
|
|
63
65
|
class EmptyConditionalBody < Base
|
|
64
66
|
extend AutoCorrector
|
|
65
67
|
include CommentsHelp
|
|
66
|
-
include RangeHelp
|
|
67
68
|
|
|
68
69
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
|
69
70
|
|
|
70
|
-
# rubocop:disable Metrics/AbcSize
|
|
71
71
|
def on_if(node)
|
|
72
72
|
return if node.body || same_line?(node.loc.begin, node.loc.end)
|
|
73
73
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
|
@@ -75,12 +75,11 @@ module RuboCop
|
|
|
75
75
|
range = offense_range(node)
|
|
76
76
|
|
|
77
77
|
add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
|
|
78
|
-
next
|
|
78
|
+
next unless can_simplify_conditional?(node)
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
flip_orphaned_else(corrector, node)
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
|
-
# rubocop:enable Metrics/AbcSize
|
|
84
83
|
|
|
85
84
|
private
|
|
86
85
|
|
|
@@ -92,53 +91,23 @@ module RuboCop
|
|
|
92
91
|
end
|
|
93
92
|
end
|
|
94
93
|
|
|
95
|
-
def
|
|
96
|
-
|
|
97
|
-
remove_empty_branch(corrector, node)
|
|
98
|
-
correct_other_branches(corrector, node)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def remove_comments(corrector, node)
|
|
102
|
-
comments_in_range(node).each do |comment|
|
|
103
|
-
range = range_by_whole_lines(comment.source_range, include_final_newline: true)
|
|
104
|
-
corrector.remove(range)
|
|
105
|
-
end
|
|
94
|
+
def can_simplify_conditional?(node)
|
|
95
|
+
node.else_branch && node.loc.else.source == 'else'
|
|
106
96
|
end
|
|
107
97
|
|
|
108
|
-
# rubocop:disable Metrics/AbcSize
|
|
109
98
|
def remove_empty_branch(corrector, node)
|
|
110
99
|
range = if empty_if_branch?(node) && else_branch?(node)
|
|
111
100
|
branch_range(node)
|
|
112
|
-
elsif same_line?(node, else_kw_loc = node.loc.else)
|
|
113
|
-
node.source_range.begin.join(else_kw_loc.begin)
|
|
114
|
-
elsif node.parent&.loc.respond_to?(:end) &&
|
|
115
|
-
same_line?(node, end_loc = node.parent.loc.end)
|
|
116
|
-
node.source_range.begin.join(end_loc.begin)
|
|
117
101
|
else
|
|
118
102
|
deletion_range(branch_range(node))
|
|
119
103
|
end
|
|
120
104
|
|
|
121
105
|
corrector.remove(range)
|
|
122
106
|
end
|
|
123
|
-
# rubocop:enable Metrics/AbcSize
|
|
124
|
-
|
|
125
|
-
def correct_other_branches(corrector, node)
|
|
126
|
-
return unless require_other_branches_correction?(node)
|
|
127
|
-
|
|
128
|
-
if node.else_branch&.if_type? && !node.else_branch.modifier_form?
|
|
129
|
-
# Replace an orphaned `elsif` with `if`
|
|
130
|
-
corrector.replace(node.else_branch.loc.keyword, 'if')
|
|
131
|
-
else
|
|
132
|
-
# Flip orphaned `else`
|
|
133
|
-
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def require_other_branches_correction?(node)
|
|
138
|
-
return false unless node.if_type? && node.else?
|
|
139
|
-
return false if !empty_if_branch?(node) && node.elsif?
|
|
140
107
|
|
|
141
|
-
|
|
108
|
+
def flip_orphaned_else(corrector, node)
|
|
109
|
+
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
|
110
|
+
remove_empty_branch(corrector, node)
|
|
142
111
|
end
|
|
143
112
|
|
|
144
113
|
def empty_if_branch?(node)
|
|
@@ -149,36 +118,17 @@ module RuboCop
|
|
|
149
118
|
if_branch.if_type? && !if_branch.body
|
|
150
119
|
end
|
|
151
120
|
|
|
152
|
-
def empty_elsif_branch?(node)
|
|
153
|
-
return false unless (else_branch = node.else_branch)
|
|
154
|
-
|
|
155
|
-
else_branch.if_type? && !else_branch.body
|
|
156
|
-
end
|
|
157
|
-
|
|
158
121
|
def else_branch?(node)
|
|
159
122
|
node.else_branch && !node.else_branch.if_type?
|
|
160
123
|
end
|
|
161
124
|
|
|
162
|
-
# rubocop:disable Metrics/AbcSize
|
|
163
125
|
def branch_range(node)
|
|
164
126
|
if empty_if_branch?(node) && else_branch?(node)
|
|
165
127
|
node.source_range.with(end_pos: node.loc.else.begin_pos)
|
|
166
128
|
elsif node.loc.else
|
|
167
129
|
node.source_range.with(end_pos: node.condition.source_range.end_pos)
|
|
168
|
-
elsif all_branches_body_missing?(node)
|
|
169
|
-
if_node = node.ancestors.detect(&:if?)
|
|
170
|
-
node.source_range.join(if_node.loc.end.end)
|
|
171
|
-
else
|
|
172
|
-
node.source_range
|
|
173
130
|
end
|
|
174
131
|
end
|
|
175
|
-
# rubocop:enable Metrics/AbcSize
|
|
176
|
-
|
|
177
|
-
def all_branches_body_missing?(node)
|
|
178
|
-
return false unless node.parent&.if_type?
|
|
179
|
-
|
|
180
|
-
node.parent.branches.compact.empty?
|
|
181
|
-
end
|
|
182
132
|
|
|
183
133
|
def deletion_range(range)
|
|
184
134
|
# Collect a range between the start of the `if` node and the next relevant node,
|
|
@@ -156,12 +156,6 @@ module RuboCop
|
|
|
156
156
|
|
|
157
157
|
overridden_kwargs
|
|
158
158
|
end
|
|
159
|
-
|
|
160
|
-
def arguments_range(node)
|
|
161
|
-
arguments = node.arguments
|
|
162
|
-
|
|
163
|
-
range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
|
|
164
|
-
end
|
|
165
159
|
end
|
|
166
160
|
end
|
|
167
161
|
end
|
|
@@ -18,12 +18,15 @@ module RuboCop
|
|
|
18
18
|
# end
|
|
19
19
|
#
|
|
20
20
|
# # bad
|
|
21
|
-
#
|
|
21
|
+
# # We're only interested in the left hand side being a truthy literal,
|
|
22
|
+
# # because it affects the evaluation of the &&, whereas the right hand
|
|
23
|
+
# # side will be conditionally executed/called and can be a literal.
|
|
24
|
+
# if true && some_var
|
|
22
25
|
# do_something
|
|
23
26
|
# end
|
|
24
27
|
#
|
|
25
28
|
# # good
|
|
26
|
-
# if some_var
|
|
29
|
+
# if some_var
|
|
27
30
|
# do_something
|
|
28
31
|
# end
|
|
29
32
|
#
|
|
@@ -39,23 +42,17 @@ module RuboCop
|
|
|
39
42
|
MSG = 'Literal `%<literal>s` appeared as a condition.'
|
|
40
43
|
RESTRICT_ON_SEND = [:!].freeze
|
|
41
44
|
|
|
42
|
-
# rubocop:disable Metrics/AbcSize
|
|
43
45
|
def on_and(node)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
elsif node.rhs.truthy_literal?
|
|
53
|
-
add_offense(node.rhs) do |corrector|
|
|
54
|
-
corrector.replace(node, node.lhs.source)
|
|
55
|
-
end
|
|
46
|
+
return unless node.lhs.truthy_literal?
|
|
47
|
+
|
|
48
|
+
add_offense(node.lhs) do |corrector|
|
|
49
|
+
# Don't autocorrect `'foo' && return` because having `return` as
|
|
50
|
+
# the leftmost node can lead to a void value expression syntax error.
|
|
51
|
+
next if node.rhs.type?(:return, :break, :next)
|
|
52
|
+
|
|
53
|
+
corrector.replace(node, node.rhs.source)
|
|
56
54
|
end
|
|
57
55
|
end
|
|
58
|
-
# rubocop:enable Metrics/AbcSize
|
|
59
56
|
|
|
60
57
|
def on_if(node)
|
|
61
58
|
cond = condition(node)
|
|
@@ -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(:
|
|
49
|
+
return_node.each_ancestor(:any_block, :def, :defs) do |node|
|
|
50
50
|
break if scoped_node?(node)
|
|
51
51
|
|
|
52
52
|
# if a proc is passed to `Module#define_method` or
|
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
|
54
54
|
# non-local exit error
|
|
55
55
|
break if define_method?(node.send_node)
|
|
56
56
|
|
|
57
|
-
next
|
|
57
|
+
next if node.argument_list.empty?
|
|
58
58
|
|
|
59
59
|
if chained_send?(node.send_node)
|
|
60
60
|
add_offense(return_node.loc.keyword)
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Lint
|
|
6
|
-
# Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_r`, `to_c`,
|
|
6
|
+
# Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_d`, `to_r`, `to_c`,
|
|
7
7
|
# `to_a`, `to_h`, and `to_set`.
|
|
8
8
|
#
|
|
9
9
|
# When one of these methods is called on an object of the same type, that object
|
|
10
10
|
# is returned, making the call unnecessary. The cop detects conversion methods called
|
|
11
11
|
# on object literals, class constructors, class `[]` methods, and the `Kernel` methods
|
|
12
|
-
# `String()`, `Integer()`, `Float()`, `Rational()`, `Complex()
|
|
12
|
+
# `String()`, `Integer()`, `Float()`, BigDecimal(), `Rational()`, `Complex()`, and `Array()`.
|
|
13
13
|
#
|
|
14
14
|
# Specifically, these cases are detected for each conversion method:
|
|
15
15
|
#
|
|
@@ -98,6 +98,7 @@ module RuboCop
|
|
|
98
98
|
to_s: 'string_constructor?',
|
|
99
99
|
to_i: 'integer_constructor?',
|
|
100
100
|
to_f: 'float_constructor?',
|
|
101
|
+
to_d: 'bigdecimal_constructor?',
|
|
101
102
|
to_r: 'rational_constructor?',
|
|
102
103
|
to_c: 'complex_constructor?',
|
|
103
104
|
to_a: 'array_constructor?',
|
|
@@ -110,7 +111,7 @@ module RuboCop
|
|
|
110
111
|
TYPED_METHODS = { to_s: %i[inspect] }.freeze
|
|
111
112
|
|
|
112
113
|
CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
|
|
113
|
-
RESTRICT_ON_SEND = CONVERSION_METHODS
|
|
114
|
+
RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
|
|
114
115
|
|
|
115
116
|
private_constant :LITERAL_NODE_TYPES, :CONSTRUCTOR_MAPPING
|
|
116
117
|
|
|
@@ -137,6 +138,11 @@ module RuboCop
|
|
|
137
138
|
#type_constructor?(:Float)
|
|
138
139
|
PATTERN
|
|
139
140
|
|
|
141
|
+
# @!method bigdecimal_constructor?(node)
|
|
142
|
+
def_node_matcher :bigdecimal_constructor?, <<~PATTERN
|
|
143
|
+
#type_constructor?(:BigDecimal)
|
|
144
|
+
PATTERN
|
|
145
|
+
|
|
140
146
|
# @!method rational_constructor?(node)
|
|
141
147
|
def_node_matcher :rational_constructor?, <<~PATTERN
|
|
142
148
|
#type_constructor?(:Rational)
|
|
@@ -35,22 +35,15 @@ module RuboCop
|
|
|
35
35
|
def on_return(return_node)
|
|
36
36
|
return unless return_node.descendants.any?
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return
|
|
41
|
-
return unless context_node&.void_context?
|
|
38
|
+
def_node = return_node.each_ancestor(:def).first
|
|
39
|
+
return unless def_node&.void_context?
|
|
40
|
+
return if return_node.each_ancestor(:any_block).any?(&:lambda?)
|
|
42
41
|
|
|
43
42
|
add_offense(
|
|
44
43
|
return_node.loc.keyword,
|
|
45
|
-
message: format(message, method:
|
|
44
|
+
message: format(message, method: def_node.method_name)
|
|
46
45
|
)
|
|
47
46
|
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
|
-
def non_void_context(return_node)
|
|
52
|
-
return_node.each_ancestor(:block, :def, :defs).first
|
|
53
|
-
end
|
|
54
47
|
end
|
|
55
48
|
end
|
|
56
49
|
end
|
|
@@ -51,7 +51,18 @@ module RuboCop
|
|
|
51
51
|
|
|
52
52
|
# @!method hash_initialized_with_mutable_shared_object?(node)
|
|
53
53
|
def_node_matcher :hash_initialized_with_mutable_shared_object?, <<~PATTERN
|
|
54
|
-
|
|
54
|
+
{
|
|
55
|
+
(send (const {nil? cbase} :Hash) :new [
|
|
56
|
+
{array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
|
|
57
|
+
!#capacity_keyword_argument?
|
|
58
|
+
])
|
|
59
|
+
(send (const {nil? cbase} :Hash) :new hash #capacity_keyword_argument?)
|
|
60
|
+
}
|
|
61
|
+
PATTERN
|
|
62
|
+
|
|
63
|
+
# @!method capacity_keyword_argument?(node)
|
|
64
|
+
def_node_matcher :capacity_keyword_argument?, <<~PATTERN
|
|
65
|
+
(hash (pair (sym :capacity) _))
|
|
55
66
|
PATTERN
|
|
56
67
|
|
|
57
68
|
def on_send(node)
|
|
@@ -4,8 +4,8 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Lint
|
|
6
6
|
# Checks for useless constant scoping. Private constants must be defined using
|
|
7
|
-
# `private_constant
|
|
8
|
-
#
|
|
7
|
+
# `private_constant`. Even if `private` access modifier is used, it is public scope despite
|
|
8
|
+
# its appearance.
|
|
9
9
|
#
|
|
10
10
|
# It does not support autocorrection due to behavior change and multiple ways to fix it.
|
|
11
11
|
# Or a public constant may be intended.
|
|
@@ -26,14 +26,6 @@ module RuboCop
|
|
|
26
26
|
#
|
|
27
27
|
# # good
|
|
28
28
|
# class Foo
|
|
29
|
-
# class << self
|
|
30
|
-
# private
|
|
31
|
-
# PRIVATE_CONST = 42
|
|
32
|
-
# end
|
|
33
|
-
# end
|
|
34
|
-
#
|
|
35
|
-
# # good
|
|
36
|
-
# class Foo
|
|
37
29
|
# PUBLIC_CONST = 42 # If private scope is not intended.
|
|
38
30
|
# end
|
|
39
31
|
#
|
|
@@ -46,7 +38,6 @@ module RuboCop
|
|
|
46
38
|
PATTERN
|
|
47
39
|
|
|
48
40
|
def on_casgn(node)
|
|
49
|
-
return if node.each_ancestor(:sclass).any?
|
|
50
41
|
return unless after_private_modifier?(node.left_siblings)
|
|
51
42
|
return if private_constantize?(node.right_siblings, node.name)
|
|
52
43
|
|