rubocop 1.40.0 → 1.42.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +44 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +34 -11
- data/lib/rubocop/config_loader.rb +9 -0
- data/lib/rubocop/config_loader_resolver.rb +5 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/badge.rb +9 -4
- data/lib/rubocop/cop/base.rb +83 -66
- data/lib/rubocop/cop/commissioner.rb +8 -3
- data/lib/rubocop/cop/cop.rb +29 -29
- data/lib/rubocop/cop/corrector.rb +23 -11
- data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +32 -11
- data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
- data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
- data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
- data/lib/rubocop/cop/layout/line_length.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
- data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +3 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
- data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -19
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
- data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/require_library.rb +2 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
- data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
- data/lib/rubocop/cop/registry.rb +28 -25
- data/lib/rubocop/cop/security/compound_hash.rb +2 -1
- data/lib/rubocop/cop/style/alias.rb +9 -1
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
- data/lib/rubocop/cop/style/documentation.rb +11 -5
- data/lib/rubocop/cop/style/guard_clause.rb +17 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +10 -7
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
- data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
- data/lib/rubocop/cop/style/map_to_set.rb +61 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +13 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
- data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
- data/lib/rubocop/cop/style/require_order.rb +63 -9
- data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
- data/lib/rubocop/cop/style/semicolon.rb +2 -1
- data/lib/rubocop/cop/style/signal_exception.rb +8 -6
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
- data/lib/rubocop/cop/style/word_array.rb +41 -0
- data/lib/rubocop/cop/style/yoda_expression.rb +74 -0
- data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
- data/lib/rubocop/cop/team.rb +29 -29
- data/lib/rubocop/cop/util.rb +31 -4
- data/lib/rubocop/cop/variable_force.rb +0 -3
- data/lib/rubocop/cops_documentation_generator.rb +33 -11
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/file_patterns.rb +43 -0
- data/lib/rubocop/formatter.rb +2 -0
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/path_util.rb +26 -15
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +10 -3
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +15 -10
- data/lib/rubocop/optimized_patterns.rb +0 -38
@@ -36,6 +36,33 @@ module RuboCop
|
|
36
36
|
# require 'b'
|
37
37
|
# require_relative 'c'
|
38
38
|
# require 'a'
|
39
|
+
#
|
40
|
+
# # bad
|
41
|
+
# require 'a'
|
42
|
+
# require 'c' if foo
|
43
|
+
# require 'b'
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# require 'a'
|
47
|
+
# require 'b'
|
48
|
+
# require 'c' if foo
|
49
|
+
#
|
50
|
+
# # bad
|
51
|
+
# require 'c'
|
52
|
+
# if foo
|
53
|
+
# require 'd'
|
54
|
+
# require 'b'
|
55
|
+
# end
|
56
|
+
# require 'a'
|
57
|
+
#
|
58
|
+
# # good
|
59
|
+
# require 'c'
|
60
|
+
# if foo
|
61
|
+
# require 'b'
|
62
|
+
# require 'd'
|
63
|
+
# end
|
64
|
+
# require 'a'
|
65
|
+
#
|
39
66
|
class RequireOrder < Base
|
40
67
|
extend AutoCorrector
|
41
68
|
|
@@ -43,17 +70,27 @@ module RuboCop
|
|
43
70
|
|
44
71
|
RESTRICT_ON_SEND = %i[require require_relative].freeze
|
45
72
|
|
73
|
+
MSG = 'Sort `%<name>s` in alphabetical order.'
|
74
|
+
|
75
|
+
# @!method if_inside_only_require(node)
|
76
|
+
def_node_matcher :if_inside_only_require, <<~PATTERN
|
77
|
+
{
|
78
|
+
(if _ _ $(send nil? {:require :require_relative} _))
|
79
|
+
(if _ $(send nil? {:require :require_relative} _) _)
|
80
|
+
}
|
81
|
+
PATTERN
|
82
|
+
|
46
83
|
def on_send(node)
|
84
|
+
return unless node.parent && node.arguments?
|
85
|
+
return if not_modifier_form?(node.parent)
|
86
|
+
|
47
87
|
previous_older_sibling = find_previous_older_sibling(node)
|
48
88
|
return unless previous_older_sibling
|
49
89
|
|
50
|
-
add_offense(
|
51
|
-
node,
|
52
|
-
message: "Sort `#{node.method_name}` in alphabetical order."
|
53
|
-
) do |corrector|
|
90
|
+
add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
|
54
91
|
swap(
|
55
92
|
range_with_comments_and_lines(previous_older_sibling),
|
56
|
-
range_with_comments_and_lines(node),
|
93
|
+
range_with_comments_and_lines(node.parent.if_type? ? node.parent : node),
|
57
94
|
corrector: corrector
|
58
95
|
)
|
59
96
|
end
|
@@ -61,16 +98,33 @@ module RuboCop
|
|
61
98
|
|
62
99
|
private
|
63
100
|
|
64
|
-
def
|
65
|
-
node.
|
66
|
-
|
67
|
-
|
101
|
+
def not_modifier_form?(node)
|
102
|
+
node.if_type? && !node.modifier_form?
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_previous_older_sibling(node) # rubocop:disable Metrics
|
106
|
+
search_node(node).left_siblings.reverse.find do |sibling|
|
107
|
+
next unless sibling.is_a?(AST::Node)
|
108
|
+
|
109
|
+
sibling = sibling_node(sibling)
|
110
|
+
break unless sibling&.send_type? && sibling&.method?(node.method_name)
|
111
|
+
break unless sibling.arguments? && !sibling.receiver
|
68
112
|
break unless in_same_section?(sibling, node)
|
69
113
|
|
70
114
|
node.first_argument.source < sibling.first_argument.source
|
71
115
|
end
|
72
116
|
end
|
73
117
|
|
118
|
+
def search_node(node)
|
119
|
+
node.parent.if_type? ? node.parent : node
|
120
|
+
end
|
121
|
+
|
122
|
+
def sibling_node(node)
|
123
|
+
return if not_modifier_form?(node)
|
124
|
+
|
125
|
+
node.if_type? ? if_inside_only_require(node) : node
|
126
|
+
end
|
127
|
+
|
74
128
|
def in_same_section?(node1, node2)
|
75
129
|
!node1.location.expression.with(
|
76
130
|
end_pos: node2.location.expression.end_pos
|
@@ -86,12 +86,12 @@ module RuboCop
|
|
86
86
|
|
87
87
|
def on_send(node)
|
88
88
|
return unless (block_node = node.block_node)
|
89
|
-
return if block_node.body
|
89
|
+
return if block_node.body&.begin_type?
|
90
90
|
return if receiver_allowed?(block_node.receiver)
|
91
91
|
return unless (regexp_method_send_node = extract_send_node(block_node))
|
92
92
|
return if match_predicate_without_receiver?(regexp_method_send_node)
|
93
93
|
|
94
|
-
opposite =
|
94
|
+
opposite = opposite?(regexp_method_send_node)
|
95
95
|
regexp = find_regexp(regexp_method_send_node, block_node)
|
96
96
|
|
97
97
|
register_offense(node, block_node, regexp, opposite)
|
@@ -128,6 +128,10 @@ module RuboCop
|
|
128
128
|
regexp_method_send_node
|
129
129
|
end
|
130
130
|
|
131
|
+
def opposite?(regexp_method_send_node)
|
132
|
+
regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
|
133
|
+
end
|
134
|
+
|
131
135
|
def find_regexp(node, block)
|
132
136
|
return node.child_nodes.first if node.match_with_lvasgn_type?
|
133
137
|
|
@@ -37,13 +37,14 @@ module RuboCop
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def on_new_investigation
|
40
|
-
return if processed_source.blank?
|
40
|
+
return if processed_source.blank? || !processed_source.raw_source.include?(';')
|
41
41
|
|
42
42
|
check_for_line_terminator_or_opener
|
43
43
|
end
|
44
44
|
|
45
45
|
def on_begin(node)
|
46
46
|
return if cop_config['AllowAsExpressionSeparator']
|
47
|
+
return unless node.source.include?(';')
|
47
48
|
|
48
49
|
exprs = node.children
|
49
50
|
|
@@ -119,11 +119,6 @@ module RuboCop
|
|
119
119
|
# @!method custom_fail_methods(node)
|
120
120
|
def_node_search :custom_fail_methods, '{(def :fail ...) (defs _ :fail ...)}'
|
121
121
|
|
122
|
-
def on_new_investigation
|
123
|
-
ast = processed_source.ast
|
124
|
-
@custom_fail_defined = ast && custom_fail_methods(ast).any?
|
125
|
-
end
|
126
|
-
|
127
122
|
def on_rescue(node)
|
128
123
|
return unless style == :semantic
|
129
124
|
|
@@ -141,7 +136,7 @@ module RuboCop
|
|
141
136
|
when :semantic
|
142
137
|
check_send(:raise, node) unless ignored_node?(node)
|
143
138
|
when :only_raise
|
144
|
-
return if
|
139
|
+
return if custom_fail_defined?
|
145
140
|
|
146
141
|
check_send(:fail, node)
|
147
142
|
when :only_fail
|
@@ -151,6 +146,13 @@ module RuboCop
|
|
151
146
|
|
152
147
|
private
|
153
148
|
|
149
|
+
def custom_fail_defined?
|
150
|
+
return @custom_fail_defined if defined?(@custom_fail_defined)
|
151
|
+
|
152
|
+
ast = processed_source.ast
|
153
|
+
@custom_fail_defined = ast && custom_fail_methods(ast).any?
|
154
|
+
end
|
155
|
+
|
154
156
|
def message(method_name)
|
155
157
|
case style
|
156
158
|
when :semantic
|
@@ -88,6 +88,10 @@ module RuboCop
|
|
88
88
|
include TrailingComma
|
89
89
|
extend AutoCorrector
|
90
90
|
|
91
|
+
def self.autocorrect_incompatible_with
|
92
|
+
[Layout::HeredocArgumentClosingParenthesis]
|
93
|
+
end
|
94
|
+
|
91
95
|
def on_send(node)
|
92
96
|
return unless node.arguments? && node.parenthesized?
|
93
97
|
|
@@ -96,10 +100,6 @@ module RuboCop
|
|
96
100
|
node.source_range.end_pos)
|
97
101
|
end
|
98
102
|
alias on_csend on_send
|
99
|
-
|
100
|
-
def self.autocorrect_incompatible_with
|
101
|
-
[Layout::HeredocArgumentClosingParenthesis]
|
102
|
-
end
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -27,6 +27,25 @@ module RuboCop
|
|
27
27
|
# # bad (contains spaces)
|
28
28
|
# %w[foo\ bar baz\ quux]
|
29
29
|
#
|
30
|
+
# # bad
|
31
|
+
# [
|
32
|
+
# ['one', 'One'],
|
33
|
+
# ['two', 'Two']
|
34
|
+
# ]
|
35
|
+
#
|
36
|
+
# # good
|
37
|
+
# [
|
38
|
+
# %w[one One],
|
39
|
+
# %w[two Two]
|
40
|
+
# ]
|
41
|
+
#
|
42
|
+
# # good (2d array containing spaces)
|
43
|
+
# [
|
44
|
+
# ['one', 'One'],
|
45
|
+
# ['two', 'Two'],
|
46
|
+
# ['forty two', 'Forty Two']
|
47
|
+
# ]
|
48
|
+
#
|
30
49
|
# @example EnforcedStyle: brackets
|
31
50
|
# # good
|
32
51
|
# ['foo', 'bar', 'baz']
|
@@ -36,6 +55,19 @@ module RuboCop
|
|
36
55
|
#
|
37
56
|
# # good (contains spaces)
|
38
57
|
# ['foo bar', 'baz quux']
|
58
|
+
#
|
59
|
+
# # good
|
60
|
+
# [
|
61
|
+
# ['one', 'One'],
|
62
|
+
# ['two', 'Two']
|
63
|
+
# ]
|
64
|
+
#
|
65
|
+
# # bad
|
66
|
+
# [
|
67
|
+
# %w[one One],
|
68
|
+
# %w[two Two]
|
69
|
+
# ]
|
70
|
+
#
|
39
71
|
class WordArray < Base
|
40
72
|
include ArrayMinSize
|
41
73
|
include ArraySyntax
|
@@ -53,6 +85,7 @@ module RuboCop
|
|
53
85
|
def on_array(node)
|
54
86
|
if bracketed_array_of?(:str, node)
|
55
87
|
return if complex_content?(node.values)
|
88
|
+
return if within_2d_array_of_complex_content?(node)
|
56
89
|
|
57
90
|
check_bracketed_array(node, 'w')
|
58
91
|
elsif node.percent_literal?(:string)
|
@@ -62,6 +95,14 @@ module RuboCop
|
|
62
95
|
|
63
96
|
private
|
64
97
|
|
98
|
+
def within_2d_array_of_complex_content?(node)
|
99
|
+
return false unless (parent = node.parent)
|
100
|
+
|
101
|
+
parent.array_type? &&
|
102
|
+
parent.values.all?(&:array_type?) &&
|
103
|
+
parent.values.any? { |subarray| complex_content?(subarray.values) }
|
104
|
+
end
|
105
|
+
|
65
106
|
def complex_content?(strings, complex_regex: word_regex)
|
66
107
|
strings.any? do |s|
|
67
108
|
next unless s.str_content
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Forbids Yoda expressions, i.e. binary operations (using `*`, `+`, `&`, `|`,
|
7
|
+
# and `^` operators) where the order of expression is reversed, eg. `1 + x`.
|
8
|
+
# This cop complements `Style/YodaCondition` cop, which has a similar purpose.
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because binary operators can be defined
|
12
|
+
# differently on different classes, and are not guaranteed to
|
13
|
+
# have the same result if reversed.
|
14
|
+
#
|
15
|
+
# @example SupportedOperators: ['*', '+', '&'']
|
16
|
+
# # bad
|
17
|
+
# 1 + x
|
18
|
+
# 10 * y
|
19
|
+
# 1 & z
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# 60 * 24
|
23
|
+
# x + 1
|
24
|
+
# y * 10
|
25
|
+
# z & 1
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# 1 | x
|
29
|
+
#
|
30
|
+
class YodaExpression < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Non-literal operand (`%<source>s`) should be first.'
|
34
|
+
|
35
|
+
RESTRICT_ON_SEND = %i[* + & | ^].freeze
|
36
|
+
|
37
|
+
def on_new_investigation
|
38
|
+
@offended_nodes = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
return unless supported_operators.include?(node.method_name.to_s)
|
43
|
+
|
44
|
+
lhs = node.receiver
|
45
|
+
rhs = node.first_argument
|
46
|
+
return if !lhs.numeric_type? || rhs.numeric_type?
|
47
|
+
|
48
|
+
return if offended_ancestor?(node)
|
49
|
+
|
50
|
+
message = format(MSG, source: rhs.source)
|
51
|
+
add_offense(node, message: message) do |corrector|
|
52
|
+
corrector.swap(lhs, rhs)
|
53
|
+
end
|
54
|
+
|
55
|
+
offended_nodes.add(node)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def supported_operators
|
61
|
+
Array(cop_config['SupportedOperators'])
|
62
|
+
end
|
63
|
+
|
64
|
+
def offended_ancestor?(node)
|
65
|
+
node.each_ancestor(:send).any? { |ancestor| @offended_nodes&.include?(ancestor) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def offended_nodes
|
69
|
+
@offended_nodes ||= Set.new.compare_by_identity
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -34,43 +34,55 @@ module RuboCop
|
|
34
34
|
class ZeroLengthPredicate < Base
|
35
35
|
extend AutoCorrector
|
36
36
|
|
37
|
-
ZERO_MSG = 'Use `empty?` instead of `%<
|
38
|
-
NONZERO_MSG = 'Use `!empty?` instead of `%<
|
37
|
+
ZERO_MSG = 'Use `empty?` instead of `%<current>s`.'
|
38
|
+
NONZERO_MSG = 'Use `!empty?` instead of `%<current>s`.'
|
39
39
|
|
40
40
|
RESTRICT_ON_SEND = %i[size length].freeze
|
41
41
|
|
42
42
|
def on_send(node)
|
43
43
|
check_zero_length_predicate(node)
|
44
|
-
|
44
|
+
check_zero_length_comparison(node)
|
45
|
+
check_nonzero_length_comparison(node)
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
49
|
|
49
50
|
def check_zero_length_predicate(node)
|
50
|
-
|
51
|
-
return unless zero_length_predicate
|
51
|
+
return unless (length_method = zero_length_predicate(node.parent))
|
52
52
|
|
53
|
-
|
53
|
+
offense = node.loc.selector.join(node.parent.source_range.end)
|
54
|
+
message = format(ZERO_MSG, current: "#{length_method}.zero?")
|
55
|
+
|
56
|
+
add_offense(offense, message: message) do |corrector|
|
57
|
+
corrector.replace(offense, 'empty?')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_zero_length_comparison(node)
|
62
|
+
zero_length_comparison = zero_length_comparison(node.parent)
|
63
|
+
return unless zero_length_comparison
|
64
|
+
|
65
|
+
lhs, opr, rhs = zero_length_comparison
|
54
66
|
|
55
67
|
return if non_polymorphic_collection?(node.parent)
|
56
68
|
|
57
69
|
add_offense(
|
58
|
-
node.parent, message: format(ZERO_MSG,
|
70
|
+
node.parent, message: format(ZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
|
59
71
|
) do |corrector|
|
60
72
|
corrector.replace(node.parent, replacement(node.parent))
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
64
|
-
def
|
65
|
-
|
66
|
-
return unless
|
76
|
+
def check_nonzero_length_comparison(node)
|
77
|
+
nonzero_length_comparison = nonzero_length_comparison(node.parent)
|
78
|
+
return unless nonzero_length_comparison
|
67
79
|
|
68
|
-
lhs, opr, rhs =
|
80
|
+
lhs, opr, rhs = nonzero_length_comparison
|
69
81
|
|
70
82
|
return if non_polymorphic_collection?(node.parent)
|
71
83
|
|
72
84
|
add_offense(
|
73
|
-
node.parent, message: format(NONZERO_MSG,
|
85
|
+
node.parent, message: format(NONZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
|
74
86
|
) do |corrector|
|
75
87
|
corrector.replace(node.parent, replacement(node.parent))
|
76
88
|
end
|
@@ -78,14 +90,19 @@ module RuboCop
|
|
78
90
|
|
79
91
|
# @!method zero_length_predicate(node)
|
80
92
|
def_node_matcher :zero_length_predicate, <<~PATTERN
|
93
|
+
(send (send (...) ${:length :size}) :zero?)
|
94
|
+
PATTERN
|
95
|
+
|
96
|
+
# @!method zero_length_comparison(node)
|
97
|
+
def_node_matcher :zero_length_comparison, <<~PATTERN
|
81
98
|
{(send (send (...) ${:length :size}) $:== (int $0))
|
82
99
|
(send (int $0) $:== (send (...) ${:length :size}))
|
83
100
|
(send (send (...) ${:length :size}) $:< (int $1))
|
84
101
|
(send (int $1) $:> (send (...) ${:length :size}))}
|
85
102
|
PATTERN
|
86
103
|
|
87
|
-
# @!method
|
88
|
-
def_node_matcher :
|
104
|
+
# @!method nonzero_length_comparison(node)
|
105
|
+
def_node_matcher :nonzero_length_comparison, <<~PATTERN
|
89
106
|
{(send (send (...) ${:length :size}) ${:> :!=} (int $0))
|
90
107
|
(send (int $0) ${:< :!=} (send (...) ${:length :size}))}
|
91
108
|
PATTERN
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -10,20 +10,6 @@ module RuboCop
|
|
10
10
|
# first the ones needed for autocorrection (if any), then the rest
|
11
11
|
# (unless autocorrections happened).
|
12
12
|
class Team
|
13
|
-
attr_reader :errors, :warnings, :updated_source_file, :cops
|
14
|
-
|
15
|
-
alias updated_source_file? updated_source_file
|
16
|
-
|
17
|
-
def initialize(cops, config = nil, options = {})
|
18
|
-
@cops = cops
|
19
|
-
@config = config
|
20
|
-
@options = options
|
21
|
-
reset
|
22
|
-
@ready = true
|
23
|
-
|
24
|
-
validate_config
|
25
|
-
end
|
26
|
-
|
27
13
|
# @return [Team]
|
28
14
|
def self.new(cop_or_classes, config, options = {})
|
29
15
|
# Support v0 api:
|
@@ -47,6 +33,35 @@ module RuboCop
|
|
47
33
|
end
|
48
34
|
end
|
49
35
|
|
36
|
+
# @return [Array<Force>] needed for the given cops
|
37
|
+
def self.forces_for(cops)
|
38
|
+
needed = Hash.new { |h, k| h[k] = [] }
|
39
|
+
cops.each do |cop|
|
40
|
+
forces = cop.class.joining_forces
|
41
|
+
if forces.is_a?(Array)
|
42
|
+
forces.each { |force| needed[force] << cop }
|
43
|
+
elsif forces
|
44
|
+
needed[forces] << cop
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :errors, :warnings, :updated_source_file, :cops
|
52
|
+
|
53
|
+
alias updated_source_file? updated_source_file
|
54
|
+
|
55
|
+
def initialize(cops, config = nil, options = {})
|
56
|
+
@cops = cops
|
57
|
+
@config = config
|
58
|
+
@options = options
|
59
|
+
reset
|
60
|
+
@ready = true
|
61
|
+
|
62
|
+
validate_config
|
63
|
+
end
|
64
|
+
|
50
65
|
def autocorrect?
|
51
66
|
@options[:autocorrect]
|
52
67
|
end
|
@@ -94,21 +109,6 @@ module RuboCop
|
|
94
109
|
@forces ||= self.class.forces_for(cops)
|
95
110
|
end
|
96
111
|
|
97
|
-
# @return [Array<Force>] needed for the given cops
|
98
|
-
def self.forces_for(cops)
|
99
|
-
needed = Hash.new { |h, k| h[k] = [] }
|
100
|
-
cops.each do |cop|
|
101
|
-
forces = cop.class.joining_forces
|
102
|
-
if forces.is_a?(Array)
|
103
|
-
forces.each { |force| needed[force] << cop }
|
104
|
-
elsif forces
|
105
|
-
needed[forces] << cop
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
|
110
|
-
end
|
111
|
-
|
112
112
|
def external_dependency_checksum
|
113
113
|
keys = cops.map(&:external_dependency_checksum).compact
|
114
114
|
Digest::SHA1.hexdigest(keys.join)
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -52,6 +52,21 @@ module RuboCop
|
|
52
52
|
end
|
53
53
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
54
54
|
|
55
|
+
def any_descendant?(node, *types)
|
56
|
+
if block_given?
|
57
|
+
node.each_descendant(*types) do |descendant|
|
58
|
+
return true if yield(descendant)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# Use a block version to avoid allocating enumerators.
|
62
|
+
node.each_descendant do # rubocop:disable Lint/UnreachableLoop
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
55
70
|
def args_begin(node)
|
56
71
|
loc = node.loc
|
57
72
|
selector = if node.super_type? || node.yield_type?
|
@@ -71,14 +86,19 @@ module RuboCop
|
|
71
86
|
def on_node(syms, sexp, excludes = [], &block)
|
72
87
|
return to_enum(:on_node, syms, sexp, excludes) unless block
|
73
88
|
|
74
|
-
yield sexp if
|
75
|
-
return if
|
89
|
+
yield sexp if include_or_equal?(syms, sexp.type)
|
90
|
+
return if include_or_equal?(excludes, sexp.type)
|
76
91
|
|
77
92
|
sexp.each_child_node { |elem| on_node(syms, elem, excludes, &block) }
|
78
93
|
end
|
79
94
|
|
95
|
+
LINE_BEGINS_REGEX_CACHE = Hash.new do |hash, index|
|
96
|
+
hash[index] = /^\s{#{index}}\S/
|
97
|
+
end
|
98
|
+
private_constant :LINE_BEGINS_REGEX_CACHE
|
99
|
+
|
80
100
|
def begins_its_line?(range)
|
81
|
-
range.source_line.
|
101
|
+
range.source_line.match?(LINE_BEGINS_REGEX_CACHE[range.column])
|
82
102
|
end
|
83
103
|
|
84
104
|
# Returns, for example, a bare `if` node if the given node is an `if`
|
@@ -152,8 +172,11 @@ module RuboCop
|
|
152
172
|
' ' * (node.loc.column + offset)
|
153
173
|
end
|
154
174
|
|
175
|
+
@to_supported_styles_cache = {}
|
176
|
+
|
155
177
|
def to_supported_styles(enforced_style)
|
156
|
-
enforced_style
|
178
|
+
@to_supported_styles_cache[enforced_style] ||=
|
179
|
+
enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
|
157
180
|
end
|
158
181
|
|
159
182
|
private
|
@@ -162,6 +185,10 @@ module RuboCop
|
|
162
185
|
src = src.dup if RUBY_ENGINE == 'jruby'
|
163
186
|
src.force_encoding(Encoding.default_external).valid_encoding?
|
164
187
|
end
|
188
|
+
|
189
|
+
def include_or_equal?(source, target)
|
190
|
+
source == target || (source.is_a?(Array) && source.include?(target))
|
191
|
+
end
|
165
192
|
end
|
166
193
|
end
|
167
194
|
end
|
@@ -108,7 +108,6 @@ module RuboCop
|
|
108
108
|
:skip_children
|
109
109
|
end
|
110
110
|
|
111
|
-
# rubocop:disable Layout/ClassStructure
|
112
111
|
NODE_HANDLER_METHOD_NAMES = [
|
113
112
|
[VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment],
|
114
113
|
[REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures],
|
@@ -123,8 +122,6 @@ module RuboCop
|
|
123
122
|
*SCOPE_TYPES.product([:process_scope])
|
124
123
|
].to_h.freeze
|
125
124
|
private_constant :NODE_HANDLER_METHOD_NAMES
|
126
|
-
# rubocop:enable Layout/ClassStructure
|
127
|
-
|
128
125
|
def node_handler_method_name(node)
|
129
126
|
NODE_HANDLER_METHOD_NAMES[node.type]
|
130
127
|
end
|