rubocop 1.66.1 → 1.68.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +55 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cached_data.rb +12 -4
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +16 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -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/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
- data/lib/rubocop/cop/layout/leading_comment_space.rb +56 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +7 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +9 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +107 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -1
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +4 -5
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +31 -3
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -14
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +15 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -3
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +59 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/multiple_comparison.rb +28 -39
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +23 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -11
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +104 -50
- data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +5 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cops_documentation_generator.rb +81 -40
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +17 -6
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +13 -13
- data/lib/rubocop/version.rb +28 -7
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +10 -0
- metadata +13 -4
@@ -3,88 +3,154 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Check to make sure that if safe navigation is used
|
7
|
-
#
|
8
|
-
# method calls on
|
6
|
+
# Check to make sure that if safe navigation is used in an `&&` or `||` condition,
|
7
|
+
# consistent and appropriate safe navigation, without excess or deficiency,
|
8
|
+
# is used for all method calls on the same object.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
|
-
# foo&.bar && foo
|
12
|
+
# foo&.bar && foo&.baz
|
13
13
|
#
|
14
|
-
# #
|
15
|
-
# foo
|
14
|
+
# # good
|
15
|
+
# foo&.bar && foo.baz
|
16
16
|
#
|
17
17
|
# # bad
|
18
|
-
# foo
|
18
|
+
# foo.bar && foo&.baz
|
19
19
|
#
|
20
20
|
# # good
|
21
21
|
# foo.bar && foo.baz
|
22
22
|
#
|
23
|
+
# # bad
|
24
|
+
# foo&.bar || foo.baz
|
25
|
+
#
|
23
26
|
# # good
|
24
27
|
# foo&.bar || foo&.baz
|
25
28
|
#
|
29
|
+
# # bad
|
30
|
+
# foo.bar || foo&.baz
|
31
|
+
#
|
26
32
|
# # good
|
33
|
+
# foo.bar || foo.baz
|
34
|
+
#
|
35
|
+
# # bad
|
27
36
|
# foo&.bar && (foobar.baz || foo&.baz)
|
28
37
|
#
|
38
|
+
# # good
|
39
|
+
# foo&.bar && (foobar.baz || foo.baz)
|
40
|
+
#
|
29
41
|
class SafeNavigationConsistency < Base
|
30
|
-
include IgnoredNode
|
31
42
|
include NilMethods
|
32
43
|
extend AutoCorrector
|
33
44
|
|
34
|
-
|
45
|
+
USE_DOT_MSG = 'Use `.` instead of unnecessary `&.`.'
|
46
|
+
USE_SAFE_NAVIGATION_MSG = 'Use `&.` for consistency with safe navigation.'
|
47
|
+
|
48
|
+
def on_and(node)
|
49
|
+
all_operands = collect_operands(node, [])
|
50
|
+
operand_groups = all_operands.group_by { |operand| receiver_name_as_key(operand, +'') }
|
51
|
+
|
52
|
+
operand_groups.each_value do |grouped_operands|
|
53
|
+
next unless (dot_op, begin_of_rest_operands = find_consistent_parts(grouped_operands))
|
35
54
|
|
36
|
-
|
37
|
-
|
55
|
+
rest_operands = grouped_operands[begin_of_rest_operands..]
|
56
|
+
rest_operands.each do |operand|
|
57
|
+
next if already_appropriate_call?(operand, dot_op)
|
38
58
|
|
39
|
-
|
59
|
+
register_offense(operand, dot_op)
|
60
|
+
end
|
61
|
+
end
|
40
62
|
end
|
63
|
+
alias on_or on_and
|
64
|
+
|
65
|
+
private
|
41
66
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
safe_nav_receiver = node.receiver
|
67
|
+
def collect_operands(node, operand_nodes)
|
68
|
+
operand_nodes(node.lhs, operand_nodes)
|
69
|
+
operand_nodes(node.rhs, operand_nodes)
|
46
70
|
|
47
|
-
|
48
|
-
|
71
|
+
operand_nodes
|
72
|
+
end
|
49
73
|
|
50
|
-
|
51
|
-
|
74
|
+
def receiver_name_as_key(method, fully_receivers)
|
75
|
+
if method.parent.call_type?
|
76
|
+
receiver(method.parent, fully_receivers)
|
77
|
+
else
|
78
|
+
fully_receivers << method.receiver&.source.to_s
|
79
|
+
end
|
80
|
+
end
|
52
81
|
|
53
|
-
|
82
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
83
|
+
def find_consistent_parts(grouped_operands)
|
84
|
+
csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
|
54
85
|
|
55
|
-
|
86
|
+
if csend_in_and
|
87
|
+
['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
|
88
|
+
elsif send_in_or && csend_in_or
|
89
|
+
send_in_or < csend_in_or ? ['.', send_in_or + 1] : ['&.', csend_in_or + 1]
|
90
|
+
elsif send_in_and && csend_in_or && send_in_and < csend_in_or
|
91
|
+
['.', csend_in_or]
|
56
92
|
end
|
57
93
|
end
|
94
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
58
95
|
|
59
|
-
|
96
|
+
def already_appropriate_call?(operand, dot_op)
|
97
|
+
return true if operand.safe_navigation? && dot_op == '&.'
|
60
98
|
|
61
|
-
|
62
|
-
|
99
|
+
(operand.dot? || operand.operator_method?) && dot_op == '.'
|
100
|
+
end
|
101
|
+
|
102
|
+
def register_offense(operand, dot_operator)
|
103
|
+
offense_range = operand.operator_method? ? operand : operand.loc.dot
|
104
|
+
message = dot_operator == '.' ? USE_DOT_MSG : USE_SAFE_NAVIGATION_MSG
|
105
|
+
|
106
|
+
add_offense(offense_range, message: message) do |corrector|
|
107
|
+
next if operand.operator_method?
|
63
108
|
|
64
|
-
|
109
|
+
corrector.replace(operand.loc.dot, dot_operator)
|
110
|
+
end
|
65
111
|
end
|
66
112
|
|
67
|
-
def
|
68
|
-
|
113
|
+
def operand_nodes(operand, operand_nodes)
|
114
|
+
if operand.operator_keyword?
|
115
|
+
collect_operands(operand, operand_nodes)
|
116
|
+
elsif operand.call_type?
|
117
|
+
operand_nodes << operand
|
118
|
+
end
|
69
119
|
end
|
70
120
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
121
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
122
|
+
def most_left_indices(grouped_operands)
|
123
|
+
indices = { csend_in_and: nil, csend_in_or: nil, send_in_and: nil, send_in_or: nil }
|
124
|
+
|
125
|
+
grouped_operands.each_with_index do |operand, index|
|
126
|
+
indices[:csend_in_and] ||= index if operand_in_and?(operand) && operand.csend_type?
|
127
|
+
indices[:csend_in_or] ||= index if operand_in_or?(operand) && operand.csend_type?
|
128
|
+
indices[:send_in_and] ||= index if operand_in_and?(operand) && !nilable?(operand)
|
129
|
+
indices[:send_in_or] ||= index if operand_in_or?(operand) && !nilable?(operand)
|
77
130
|
end
|
78
131
|
|
79
|
-
|
132
|
+
indices.values
|
80
133
|
end
|
134
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
81
135
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
136
|
+
def operand_in_and?(node)
|
137
|
+
return true if node.parent.and_type?
|
138
|
+
|
139
|
+
parent = node.parent.parent while node.parent.begin_type?
|
140
|
+
|
141
|
+
parent&.and_type?
|
142
|
+
end
|
143
|
+
|
144
|
+
def operand_in_or?(node)
|
145
|
+
return true if node.parent.or_type?
|
146
|
+
|
147
|
+
parent = node.parent.parent while node.parent.begin_type?
|
148
|
+
|
149
|
+
parent&.or_type?
|
150
|
+
end
|
151
|
+
|
152
|
+
def nilable?(node)
|
153
|
+
node.csend_type? || nil_methods.include?(node.method_name)
|
88
154
|
end
|
89
155
|
end
|
90
156
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for Regexpes (both literals and via `Regexp.new` / `Regexp.compile`)
|
7
|
+
# that contain unescaped `]` characters.
|
8
|
+
#
|
9
|
+
# It emulates the following Ruby warning:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# $ ruby -e '/abc]123/'
|
14
|
+
# -e:1: warning: regular expression has ']' without escape: /abc]123/
|
15
|
+
# ----
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# /abc]123/
|
20
|
+
# %r{abc]123}
|
21
|
+
# Regexp.new('abc]123')
|
22
|
+
# Regexp.compile('abc]123')
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# /abc\]123/
|
26
|
+
# %r{abc\]123}
|
27
|
+
# Regexp.new('abc\]123')
|
28
|
+
# Regexp.compile('abc\]123')
|
29
|
+
#
|
30
|
+
class UnescapedBracketInRegexp < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Regular expression has `]` without escape.'
|
34
|
+
RESTRICT_ON_SEND = %i[new compile].freeze
|
35
|
+
|
36
|
+
# @!method regexp_constructor(node)
|
37
|
+
def_node_search :regexp_constructor, <<~PATTERN
|
38
|
+
(send
|
39
|
+
(const {nil? cbase} :Regexp) {:new :compile}
|
40
|
+
$str
|
41
|
+
...
|
42
|
+
)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def on_regexp(node)
|
46
|
+
RuboCop::Util.silence_warnings do
|
47
|
+
node.parsed_tree&.each_expression do |expr|
|
48
|
+
detect_offenses(node, expr)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_send(node)
|
54
|
+
# Ignore nodes that contain interpolation
|
55
|
+
return if node.each_descendant(:dstr).any?
|
56
|
+
|
57
|
+
regexp_constructor(node) do |text|
|
58
|
+
Regexp::Parser.parse(text.value)&.each_expression do |expr|
|
59
|
+
detect_offenses(text, expr)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def detect_offenses(node, expr)
|
67
|
+
return unless expr.type?(:literal)
|
68
|
+
|
69
|
+
expr.text.scan(/(?<!\\)\]/) do
|
70
|
+
pos = Regexp.last_match.begin(0)
|
71
|
+
next if pos.zero? # if the unescaped bracket is the first character, Ruby does not warn
|
72
|
+
|
73
|
+
location = range_at_index(node, expr.ts, pos)
|
74
|
+
|
75
|
+
add_offense(location) do |corrector|
|
76
|
+
corrector.replace(location, '\]')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def range_at_index(node, index, offset)
|
82
|
+
adjustment = index + offset
|
83
|
+
node.loc.begin.end.adjust(begin_pos: adjustment, end_pos: adjustment + 1)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -3,29 +3,47 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Identifies places where `URI.regexp` is obsolete and should
|
7
|
-
#
|
6
|
+
# Identifies places where `URI.regexp` is obsolete and should not be used.
|
7
|
+
#
|
8
|
+
# For Ruby 3.3 or lower, use `URI::DEFAULT_PARSER.make_regexp`.
|
9
|
+
# For Ruby 3.4 or higher, use `URI::RFC2396_PARSER.make_regexp`.
|
10
|
+
#
|
11
|
+
# NOTE: If you need to support both Ruby 3.3 and lower as well as Ruby 3.4 and higher,
|
12
|
+
# consider manually changing the code as follows:
|
13
|
+
#
|
14
|
+
# [source,ruby]
|
15
|
+
# ----
|
16
|
+
# defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
|
17
|
+
# ----
|
8
18
|
#
|
9
19
|
# @example
|
10
20
|
# # bad
|
11
21
|
# URI.regexp('http://example.com')
|
12
22
|
#
|
13
|
-
# # good
|
23
|
+
# # good - Ruby 3.3 or lower
|
14
24
|
# URI::DEFAULT_PARSER.make_regexp('http://example.com')
|
15
25
|
#
|
26
|
+
# # good - Ruby 3.4 or higher
|
27
|
+
# URI::RFC2396_PARSER.make_regexp('http://example.com')
|
28
|
+
#
|
16
29
|
class UriRegexp < Base
|
17
30
|
extend AutoCorrector
|
18
31
|
|
19
32
|
MSG = '`%<current>s` is obsolete and should not be used. Instead, use `%<preferred>s`.'
|
20
|
-
URI_CONSTANTS = ['URI', '::URI'].freeze
|
21
33
|
RESTRICT_ON_SEND = %i[regexp].freeze
|
22
34
|
|
35
|
+
# @!method uri_constant?(node)
|
36
|
+
def_node_matcher :uri_constant?, <<~PATTERN
|
37
|
+
(const {cbase nil?} :URI)
|
38
|
+
PATTERN
|
39
|
+
|
23
40
|
def on_send(node)
|
24
|
-
return unless node.receiver
|
25
|
-
return unless URI_CONSTANTS.include?(node.receiver.source)
|
41
|
+
return unless uri_constant?(node.receiver)
|
26
42
|
|
43
|
+
parser = target_ruby_version >= 3.4 ? 'RFC2396_PARSER' : 'DEFAULT_PARSER'
|
27
44
|
argument = node.first_argument ? "(#{node.first_argument.source})" : ''
|
28
|
-
|
45
|
+
|
46
|
+
preferred_method = "#{node.receiver.source}::#{parser}.make_regexp#{argument}"
|
29
47
|
message = format(MSG, current: node.source, preferred: preferred_method)
|
30
48
|
|
31
49
|
add_offense(node.loc.selector, message: message) do |corrector|
|
@@ -14,11 +14,14 @@ module RuboCop
|
|
14
14
|
# and ||/or is shorthand for a sequence of ifs, so they also add one.
|
15
15
|
# Loops can be said to have an exit condition, so they add one.
|
16
16
|
# Blocks that are calls to builtin iteration methods
|
17
|
-
# (e.g. `ary.map{...}) also add one, others are ignored.
|
17
|
+
# (e.g. `ary.map{...}`) also add one, others are ignored.
|
18
|
+
#
|
19
|
+
# @example
|
18
20
|
#
|
19
21
|
# def each_child_node(*types) # count begins: 1
|
20
22
|
# unless block_given? # unless: +1
|
21
23
|
# return to_enum(__method__, *types)
|
24
|
+
# end
|
22
25
|
#
|
23
26
|
# children.each do |child| # each{}: +1
|
24
27
|
# next unless child.is_a?(Node) # unless: +1
|
@@ -44,6 +44,8 @@ module RuboCop
|
|
44
44
|
module CheckLineBreakable
|
45
45
|
def extract_breakable_node(node, max)
|
46
46
|
if node.send_type?
|
47
|
+
return if chained_to_heredoc?(node)
|
48
|
+
|
47
49
|
args = process_args(node.arguments)
|
48
50
|
return extract_breakable_node_from_elements(node, args, max)
|
49
51
|
elsif node.def_type?
|
@@ -222,6 +224,14 @@ module RuboCop
|
|
222
224
|
|
223
225
|
!node.single_line?
|
224
226
|
end
|
227
|
+
|
228
|
+
def chained_to_heredoc?(node)
|
229
|
+
while (node = node.receiver)
|
230
|
+
return true if (node.str_type? || node.dstr_type? || node.xstr_type?) && node.heredoc?
|
231
|
+
end
|
232
|
+
|
233
|
+
false
|
234
|
+
end
|
225
235
|
end
|
226
236
|
end
|
227
237
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for rewriting endless methods to normal method definitions
|
6
|
+
module EndlessMethodRewriter
|
7
|
+
def correct_to_multiline(corrector, node)
|
8
|
+
replacement = <<~RUBY.strip
|
9
|
+
def #{node.method_name}#{arguments(node)}
|
10
|
+
#{node.body.source}
|
11
|
+
end
|
12
|
+
RUBY
|
13
|
+
|
14
|
+
corrector.replace(node, replacement)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def arguments(node, missing = '')
|
20
|
+
node.arguments.any? ? node.arguments.source : missing
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -29,7 +29,9 @@ module RuboCop
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def uninterpolated_string?(node)
|
32
|
-
node.str_type? || (
|
32
|
+
node.str_type? || (
|
33
|
+
node.dstr_type? && node.each_descendant(:begin, :ivar, :cvar, :gvar).none?
|
34
|
+
)
|
33
35
|
end
|
34
36
|
|
35
37
|
def uninterpolated_heredoc?(node)
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
15
15
|
parent = node.parent
|
16
16
|
|
17
17
|
parent&.send_type? && parent.arguments.include?(node) &&
|
18
|
-
!parent.parenthesized? && parent
|
18
|
+
!parent.parenthesized? && parent.block_literal?
|
19
19
|
end
|
20
20
|
|
21
21
|
# Override to determine values that are invalid in a percent array
|
@@ -5,7 +5,6 @@ module RuboCop
|
|
5
5
|
# Common functionality for modifier cops.
|
6
6
|
module StatementModifier
|
7
7
|
include LineLengthHelp
|
8
|
-
include RangeHelp
|
9
8
|
|
10
9
|
private
|
11
10
|
|
@@ -65,7 +64,9 @@ module RuboCop
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def method_source(if_body)
|
68
|
-
|
67
|
+
end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
|
68
|
+
|
69
|
+
if_body.source_range.begin.join(end_range).source
|
69
70
|
end
|
70
71
|
|
71
72
|
def first_line_comment(node)
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
MSG = 'Use %<style>s block forwarding.'
|
49
49
|
|
50
50
|
def self.autocorrect_incompatible_with
|
51
|
-
[Lint::AmbiguousOperator, Style::ArgumentsForwarding]
|
51
|
+
[Lint::AmbiguousOperator, Style::ArgumentsForwarding, Style::ExplicitBlockArgument]
|
52
52
|
end
|
53
53
|
|
54
54
|
def on_def(node)
|
@@ -116,9 +116,9 @@ module RuboCop
|
|
116
116
|
add_offense(range, message: create_message(word)) do |corrector|
|
117
117
|
suggestions = find_flagged_term(word)['Suggestions']
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
119
|
+
if (preferred_term = preferred_sole_term(suggestions))
|
120
|
+
corrector.replace(range, preferred_term)
|
121
|
+
end
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
@@ -157,6 +157,15 @@ module RuboCop
|
|
157
157
|
set_regexes(flagged_term_strings, allowed_strings)
|
158
158
|
end
|
159
159
|
|
160
|
+
def preferred_sole_term(suggestions)
|
161
|
+
case suggestions
|
162
|
+
when Array
|
163
|
+
suggestions.one? && preferred_sole_term(suggestions.first)
|
164
|
+
when String
|
165
|
+
suggestions
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
160
169
|
def extract_regexp(term, term_definition)
|
161
170
|
return term_definition['Regex'] if term_definition['Regex']
|
162
171
|
return /(?:\b|(?<=[\W_]))#{term}(?:\b|(?=[\W_]))/ if term_definition['WholeWord']
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -43,11 +43,10 @@ module RuboCop
|
|
43
43
|
# @!attribute [r] cop_name
|
44
44
|
#
|
45
45
|
# @return [String]
|
46
|
-
#
|
47
|
-
# i.e. type of the violation.
|
46
|
+
# the cop name as a String for which this offense is for.
|
48
47
|
#
|
49
48
|
# @example
|
50
|
-
# 'LineLength'
|
49
|
+
# 'Layout/LineLength'
|
51
50
|
attr_reader :cop_name
|
52
51
|
|
53
52
|
# @api private
|
@@ -97,8 +96,8 @@ module RuboCop
|
|
97
96
|
# @!attribute [r] correctable?
|
98
97
|
#
|
99
98
|
# @return [Boolean]
|
100
|
-
# whether this offense can be automatically corrected via
|
101
|
-
#
|
99
|
+
# whether this offense can be automatically corrected via autocorrect.
|
100
|
+
# This includes todo comments, for example when requested with `--disable-uncorrectable`.
|
102
101
|
def correctable?
|
103
102
|
@status != :unsupported
|
104
103
|
end
|
@@ -68,6 +68,8 @@ module RuboCop
|
|
68
68
|
# class Foo
|
69
69
|
#
|
70
70
|
# private :bar, :baz
|
71
|
+
# private *%i[qux quux]
|
72
|
+
# private *METHOD_NAMES
|
71
73
|
#
|
72
74
|
# end
|
73
75
|
#
|
@@ -76,6 +78,8 @@ module RuboCop
|
|
76
78
|
# class Foo
|
77
79
|
#
|
78
80
|
# private :bar, :baz
|
81
|
+
# private *%i[qux quux]
|
82
|
+
# private *METHOD_NAMES
|
79
83
|
#
|
80
84
|
# end
|
81
85
|
#
|
@@ -128,7 +132,9 @@ module RuboCop
|
|
128
132
|
|
129
133
|
# @!method access_modifier_with_symbol?(node)
|
130
134
|
def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
|
131
|
-
(send nil? {:private :protected :public :module_function}
|
135
|
+
(send nil? {:private :protected :public :module_function}
|
136
|
+
{(sym _) (splat {#percent_symbol_array? const})}
|
137
|
+
)
|
132
138
|
PATTERN
|
133
139
|
|
134
140
|
# @!method access_modifier_with_attr?(node)
|
@@ -170,6 +176,10 @@ module RuboCop
|
|
170
176
|
end
|
171
177
|
end
|
172
178
|
|
179
|
+
def percent_symbol_array?(node)
|
180
|
+
node.array_type? && node.percent_literal?(:symbol)
|
181
|
+
end
|
182
|
+
|
173
183
|
def allow_modifiers_on_symbols?(node)
|
174
184
|
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
175
185
|
end
|
@@ -218,7 +228,7 @@ module RuboCop
|
|
218
228
|
|
219
229
|
def find_corresponding_def_node(node)
|
220
230
|
if access_modifier_with_symbol?(node)
|
221
|
-
method_name = node.first_argument.value
|
231
|
+
method_name = node.first_argument.respond_to?(:value) && node.first_argument.value
|
222
232
|
node.parent.each_child_node(:def).find do |child|
|
223
233
|
child.method?(method_name)
|
224
234
|
end
|
@@ -10,6 +10,9 @@ module RuboCop
|
|
10
10
|
# NOTE: If there is a method call before the accessor method it is always allowed
|
11
11
|
# as it might be intended like Sorbet.
|
12
12
|
#
|
13
|
+
# NOTE: If there is a RBS::Inline annotation comment just after the accessor method
|
14
|
+
# it is always allowed.
|
15
|
+
#
|
13
16
|
# @example EnforcedStyle: grouped (default)
|
14
17
|
# # bad
|
15
18
|
# class Foo
|
@@ -92,7 +95,7 @@ module RuboCop
|
|
92
95
|
comment_line?(processed_source[node.first_line - 2])
|
93
96
|
end
|
94
97
|
|
95
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
98
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
96
99
|
def groupable_accessor?(node)
|
97
100
|
return true unless (previous_expression = node.left_siblings.last)
|
98
101
|
|
@@ -105,11 +108,16 @@ module RuboCop
|
|
105
108
|
|
106
109
|
return true unless previous_expression.send_type?
|
107
110
|
|
111
|
+
# Accessors with RBS::Inline annotations shouldn't be groupable.
|
112
|
+
return false if processed_source.comments.any? do |c|
|
113
|
+
same_line?(c, previous_expression) && c.text.start_with?('#:')
|
114
|
+
end
|
115
|
+
|
108
116
|
previous_expression.attribute_accessor? ||
|
109
117
|
previous_expression.access_modifier? ||
|
110
118
|
node.first_line - previous_expression.last_line > 1 # there is a space between nodes
|
111
119
|
end
|
112
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
120
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
113
121
|
|
114
122
|
def class_send_elements(class_node)
|
115
123
|
class_def = class_node.body
|