rubocop 1.36.0 → 1.39.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 +31 -3
- data/lib/rubocop/arguments_env.rb +17 -0
- data/lib/rubocop/arguments_file.rb +17 -0
- data/lib/rubocop/cli/command/execute_runner.rb +7 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
- data/lib/rubocop/comment_config.rb +36 -1
- data/lib/rubocop/cop/commissioner.rb +3 -1
- data/lib/rubocop/cop/generator.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +30 -3
- data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +28 -9
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +20 -8
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +38 -10
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
- data/lib/rubocop/cop/mixin/range_help.rb +23 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +10 -8
- data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/registry.rb +10 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +5 -7
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/character_literal.rb +1 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +8 -6
- data/lib/rubocop/cop/style/collection_compact.rb +12 -3
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +62 -21
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
- data/lib/rubocop/cop/style/hash_except.rb +4 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/module_function.rb +28 -6
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +3 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +53 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- data/lib/rubocop/cop/style/redundant_each.rb +116 -0
- data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
- data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/cop/team.rb +3 -4
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +2 -1
- data/lib/rubocop/ext/processed_source.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
- data/lib/rubocop/options.rb +19 -15
- data/lib/rubocop/rspec/cop_helper.rb +21 -1
- data/lib/rubocop/rspec/shared_contexts.rb +14 -1
- data/lib/rubocop/runner.rb +15 -11
- data/lib/rubocop/server/cache.rb +5 -1
- data/lib/rubocop/server/cli.rb +9 -2
- data/lib/rubocop/server/client_command/exec.rb +5 -0
- data/lib/rubocop/server/core.rb +18 -1
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/version.rb +8 -3
- data/lib/rubocop.rb +4 -0
- metadata +13 -5
@@ -46,10 +46,13 @@ module RuboCop
|
|
46
46
|
# # bad
|
47
47
|
# foo = { }
|
48
48
|
# bar = { }
|
49
|
+
# baz = {
|
50
|
+
# }
|
49
51
|
#
|
50
52
|
# # good
|
51
53
|
# foo = {}
|
52
54
|
# bar = {}
|
55
|
+
# baz = {}
|
53
56
|
#
|
54
57
|
# @example EnforcedStyleForEmptyBraces: space
|
55
58
|
# # The `space` EnforcedStyleForEmptyBraces style enforces that
|
@@ -60,8 +63,9 @@ module RuboCop
|
|
60
63
|
#
|
61
64
|
# # good
|
62
65
|
# foo = { }
|
63
|
-
# foo = {
|
64
|
-
# foo = {
|
66
|
+
# foo = { }
|
67
|
+
# foo = {
|
68
|
+
# }
|
65
69
|
#
|
66
70
|
class SpaceInsideHashLiteralBraces < Base
|
67
71
|
include SurroundingSpace
|
@@ -77,6 +81,7 @@ module RuboCop
|
|
77
81
|
|
78
82
|
check(tokens[0], tokens[1])
|
79
83
|
check(tokens[-2], tokens[-1]) if tokens.size > 2
|
84
|
+
check_whitespace_only_hash(node) if enforce_no_space_style_for_empty_braces?
|
80
85
|
end
|
81
86
|
|
82
87
|
private
|
@@ -103,7 +108,7 @@ module RuboCop
|
|
103
108
|
if is_same_braces && style == :compact
|
104
109
|
false
|
105
110
|
elsif is_empty_braces
|
106
|
-
|
111
|
+
!enforce_no_space_style_for_empty_braces?
|
107
112
|
else
|
108
113
|
style != :no_space
|
109
114
|
end
|
@@ -175,6 +180,28 @@ module RuboCop
|
|
175
180
|
|
176
181
|
range_between(begin_pos, range.end_pos - 1)
|
177
182
|
end
|
183
|
+
|
184
|
+
def check_whitespace_only_hash(node)
|
185
|
+
range = range_inside_hash(node)
|
186
|
+
return unless range.source.match?(/\A\s+\z/m)
|
187
|
+
|
188
|
+
add_offense(
|
189
|
+
range,
|
190
|
+
message: format(MSG, problem: 'empty hash literal braces detected')
|
191
|
+
) do |corrector|
|
192
|
+
corrector.remove(range)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def range_inside_hash(node)
|
197
|
+
return node.source_range if node.location.begin.nil?
|
198
|
+
|
199
|
+
range_between(node.location.begin.end_pos, node.location.end.begin_pos)
|
200
|
+
end
|
201
|
+
|
202
|
+
def enforce_no_space_style_for_empty_braces?
|
203
|
+
cop_config['EnforcedStyleForEmptyBraces'] == 'no_space'
|
204
|
+
end
|
178
205
|
end
|
179
206
|
end
|
180
207
|
end
|
@@ -8,14 +8,31 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
#
|
11
|
+
# # bad
|
12
|
+
# %i( foo bar baz )
|
13
|
+
#
|
11
14
|
# # good
|
12
15
|
# %i(foo bar baz)
|
13
16
|
#
|
14
17
|
# # bad
|
15
18
|
# %w( foo bar baz )
|
16
19
|
#
|
20
|
+
# # good
|
21
|
+
# %w(foo bar baz)
|
22
|
+
#
|
17
23
|
# # bad
|
18
24
|
# %x( ls -l )
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# %x(ls -l)
|
28
|
+
#
|
29
|
+
# # bad
|
30
|
+
# %w( )
|
31
|
+
# %w(
|
32
|
+
# )
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# %w()
|
19
36
|
class SpaceInsidePercentLiteralDelimiters < Base
|
20
37
|
include MatchRange
|
21
38
|
include PercentLiteral
|
@@ -34,11 +51,21 @@ module RuboCop
|
|
34
51
|
end
|
35
52
|
|
36
53
|
def on_percent_literal(node)
|
54
|
+
add_offenses_for_blank_spaces(node)
|
37
55
|
add_offenses_for_unnecessary_spaces(node)
|
38
56
|
end
|
39
57
|
|
40
58
|
private
|
41
59
|
|
60
|
+
def add_offenses_for_blank_spaces(node)
|
61
|
+
range = body_range(node)
|
62
|
+
return if range.source.empty? || !range.source.strip.empty?
|
63
|
+
|
64
|
+
add_offense(range) do |corrector|
|
65
|
+
corrector.remove(range)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
42
69
|
def add_offenses_for_unnecessary_spaces(node)
|
43
70
|
return unless node.single_line?
|
44
71
|
|
@@ -54,6 +81,13 @@ module RuboCop
|
|
54
81
|
each_match_range(contents_range(node), regex, &blk)
|
55
82
|
end
|
56
83
|
end
|
84
|
+
|
85
|
+
def body_range(node)
|
86
|
+
node.location.expression.with(
|
87
|
+
begin_pos: node.location.begin.end_pos,
|
88
|
+
end_pos: node.location.end.begin_pos
|
89
|
+
)
|
90
|
+
end
|
57
91
|
end
|
58
92
|
end
|
59
93
|
end
|
@@ -38,6 +38,8 @@ module RuboCop
|
|
38
38
|
# # bad
|
39
39
|
# foo[ ]
|
40
40
|
# foo[ ]
|
41
|
+
# foo[
|
42
|
+
# ]
|
41
43
|
#
|
42
44
|
# # good
|
43
45
|
# foo[]
|
@@ -49,6 +51,8 @@ module RuboCop
|
|
49
51
|
# # bad
|
50
52
|
# foo[]
|
51
53
|
# foo[ ]
|
54
|
+
# foo[
|
55
|
+
# ]
|
52
56
|
#
|
53
57
|
# # good
|
54
58
|
# foo[ ]
|
@@ -64,8 +68,6 @@ module RuboCop
|
|
64
68
|
RESTRICT_ON_SEND = %i[[] []=].freeze
|
65
69
|
|
66
70
|
def on_send(node)
|
67
|
-
return if node.multiline?
|
68
|
-
|
69
71
|
tokens = processed_source.tokens_within(node)
|
70
72
|
left_token = left_ref_bracket(node, tokens)
|
71
73
|
return unless left_token
|
@@ -76,6 +78,8 @@ module RuboCop
|
|
76
78
|
return empty_offenses(node, left_token, right_token, EMPTY_MSG)
|
77
79
|
end
|
78
80
|
|
81
|
+
return if node.multiline?
|
82
|
+
|
79
83
|
if style == :no_space
|
80
84
|
no_space_offenses(node, left_token, right_token, MSG)
|
81
85
|
else
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for duplicated magic comments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
#
|
12
|
+
# # encoding: ascii
|
13
|
+
# # encoding: ascii
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
#
|
17
|
+
# # encoding: ascii
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
#
|
21
|
+
# # frozen_string_literal: true
|
22
|
+
# # frozen_string_literal: true
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
#
|
26
|
+
# # frozen_string_literal: true
|
27
|
+
#
|
28
|
+
class DuplicateMagicComment < Base
|
29
|
+
include FrozenStringLiteral
|
30
|
+
include RangeHelp
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Duplicate magic comment detected.'
|
34
|
+
|
35
|
+
def on_new_investigation
|
36
|
+
return if processed_source.buffer.source.empty?
|
37
|
+
|
38
|
+
magic_comment_lines.each_value do |comment_lines|
|
39
|
+
next if comment_lines.count <= 1
|
40
|
+
|
41
|
+
comment_lines[1..].each do |comment_line|
|
42
|
+
range = processed_source.buffer.line_range(comment_line + 1)
|
43
|
+
|
44
|
+
register_offense(range)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def magic_comment_lines
|
52
|
+
comment_lines = { encoding_magic_comments: [], frozen_string_literal_magic_comments: [] }
|
53
|
+
|
54
|
+
leading_magic_comments.each.with_index do |magic_comment, index|
|
55
|
+
if magic_comment.encoding_specified?
|
56
|
+
comment_lines[:encoding_magic_comments] << index
|
57
|
+
elsif magic_comment.frozen_string_literal_specified?
|
58
|
+
comment_lines[:frozen_string_literal_magic_comments] << index
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
comment_lines
|
63
|
+
end
|
64
|
+
|
65
|
+
def register_offense(range)
|
66
|
+
add_offense(range) do |corrector|
|
67
|
+
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -51,8 +51,8 @@ module RuboCop
|
|
51
51
|
# alias bar foo
|
52
52
|
class DuplicateMethods < Base
|
53
53
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
54
|
-
|
55
54
|
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr].freeze
|
55
|
+
DEF_TYPES = %i[def defs].freeze
|
56
56
|
|
57
57
|
def initialize(config = nil, options = nil)
|
58
58
|
super
|
@@ -127,13 +127,13 @@ module RuboCop
|
|
127
127
|
found_method(node, "#{enclosing}.#{name}")
|
128
128
|
end
|
129
129
|
|
130
|
-
def message_for_dup(node, method_name)
|
131
|
-
format(MSG, method: method_name, defined: source_location(@definitions[
|
130
|
+
def message_for_dup(node, method_name, key)
|
131
|
+
format(MSG, method: method_name, defined: source_location(@definitions[key]),
|
132
132
|
current: source_location(node))
|
133
133
|
end
|
134
134
|
|
135
135
|
def found_instance_method(node, name)
|
136
|
-
return unless (scope = node.parent_module_name)
|
136
|
+
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
137
137
|
|
138
138
|
# Humanize the scope
|
139
139
|
scope = scope.sub(
|
@@ -145,19 +145,38 @@ module RuboCop
|
|
145
145
|
found_method(node, "#{scope}#{name}")
|
146
146
|
end
|
147
147
|
|
148
|
+
def found_sclass_method(node, name)
|
149
|
+
singleton_ancestor = node.each_ancestor.find(&:sclass_type?)
|
150
|
+
return unless singleton_ancestor
|
151
|
+
|
152
|
+
singleton_receiver_node = singleton_ancestor.children[0]
|
153
|
+
return unless singleton_receiver_node.send_type?
|
154
|
+
|
155
|
+
found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
|
156
|
+
end
|
157
|
+
|
148
158
|
def found_method(node, method_name)
|
149
|
-
|
150
|
-
|
151
|
-
|
159
|
+
key = method_key(node, method_name)
|
160
|
+
|
161
|
+
if @definitions.key?(key)
|
162
|
+
loc = if DEF_TYPES.include?(node.type)
|
152
163
|
node.loc.keyword.join(node.loc.name)
|
153
164
|
else
|
154
165
|
node.loc.expression
|
155
166
|
end
|
156
|
-
message = message_for_dup(node, method_name)
|
167
|
+
message = message_for_dup(node, method_name, key)
|
157
168
|
|
158
169
|
add_offense(loc, message: message)
|
159
170
|
else
|
160
|
-
@definitions[
|
171
|
+
@definitions[key] = node
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def method_key(node, method_name)
|
176
|
+
if (ancestor_def = node.each_ancestor(*DEF_TYPES).first)
|
177
|
+
"#{ancestor_def.method_name}.#{method_name}"
|
178
|
+
else
|
179
|
+
method_name
|
161
180
|
end
|
162
181
|
end
|
163
182
|
|
@@ -32,26 +32,40 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
35
36
|
def each_repeated_character_class_element_loc(node)
|
36
37
|
node.parsed_tree&.each_expression do |expr|
|
37
|
-
next if expr
|
38
|
+
next if skip_expression?(expr)
|
38
39
|
|
39
40
|
seen = Set.new
|
41
|
+
enum = expr.expressions.to_enum
|
42
|
+
expression_count = expr.expressions.count
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
expression_count.times do |current_number|
|
45
|
+
current_child = enum.next
|
46
|
+
next if within_interpolation?(node, current_child)
|
43
47
|
|
44
|
-
|
48
|
+
current_child_source = current_child.to_s
|
49
|
+
next_child = enum.peek if current_number + 1 < expression_count
|
45
50
|
|
46
|
-
|
51
|
+
if seen.include?(current_child_source)
|
52
|
+
next if start_with_escaped_zero_number?(current_child_source, next_child.to_s)
|
47
53
|
|
48
|
-
|
54
|
+
yield current_child.expression
|
55
|
+
end
|
56
|
+
|
57
|
+
seen << current_child_source
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
61
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
52
62
|
|
53
63
|
private
|
54
64
|
|
65
|
+
def skip_expression?(expr)
|
66
|
+
expr.type != :set || expr.token == :intersection
|
67
|
+
end
|
68
|
+
|
55
69
|
# Since we blank interpolations with a space for every char of the interpolation, we would
|
56
70
|
# mark every space (except the first) as duplicate if we do not skip regexp_parser nodes
|
57
71
|
# that are within an interpolation.
|
@@ -61,6 +75,11 @@ module RuboCop
|
|
61
75
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
62
76
|
end
|
63
77
|
|
78
|
+
def start_with_escaped_zero_number?(current_child, next_child)
|
79
|
+
# Represents escaped code from `"\00"` (`"\u0000"`) to `"\07"` (`"\a"`).
|
80
|
+
current_child == '\\0' && next_child.match?(/[0-7]/)
|
81
|
+
end
|
82
|
+
|
64
83
|
def interpolation_locs(node)
|
65
84
|
@interpolation_locs ||= {}
|
66
85
|
|
@@ -85,7 +85,9 @@ module RuboCop
|
|
85
85
|
private
|
86
86
|
|
87
87
|
def body_or_allowed_comment_lines?(node)
|
88
|
-
|
88
|
+
return true if node.body
|
89
|
+
|
90
|
+
cop_config['AllowComments'] && processed_source.contains_comment?(node.source_range)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
end
|
@@ -92,13 +92,17 @@ module RuboCop
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def remove_empty_branch(corrector, node)
|
95
|
-
|
95
|
+
if empty_if_branch?(node) && else_branch?(node)
|
96
|
+
corrector.remove(branch_range(node))
|
97
|
+
else
|
98
|
+
corrector.remove(deletion_range(branch_range(node)))
|
99
|
+
end
|
96
100
|
end
|
97
101
|
|
98
102
|
def correct_other_branches(corrector, node)
|
99
103
|
return unless require_other_branches_correction?(node)
|
100
104
|
|
101
|
-
if node.else_branch
|
105
|
+
if node.else_branch&.if_type?
|
102
106
|
# Replace an orphaned `elsif` with `if`
|
103
107
|
corrector.replace(node.else_branch.loc.keyword, 'if')
|
104
108
|
else
|
@@ -108,10 +112,10 @@ module RuboCop
|
|
108
112
|
end
|
109
113
|
|
110
114
|
def require_other_branches_correction?(node)
|
111
|
-
return false unless node.if_type? && node.
|
115
|
+
return false unless node.if_type? && node.else?
|
112
116
|
return false if !empty_if_branch?(node) && node.elsif?
|
113
117
|
|
114
|
-
!
|
118
|
+
!empty_elsif_branch?(node)
|
115
119
|
end
|
116
120
|
|
117
121
|
def empty_if_branch?(node)
|
@@ -122,14 +126,22 @@ module RuboCop
|
|
122
126
|
if_branch.if_type? && !if_branch.body
|
123
127
|
end
|
124
128
|
|
125
|
-
def
|
126
|
-
|
129
|
+
def empty_elsif_branch?(node)
|
130
|
+
return false unless (else_branch = node.else_branch)
|
131
|
+
|
132
|
+
else_branch.if_type? && !else_branch.body
|
133
|
+
end
|
134
|
+
|
135
|
+
def else_branch?(node)
|
136
|
+
node.else_branch && !node.else_branch.if_type?
|
127
137
|
end
|
128
138
|
|
129
139
|
# rubocop:disable Metrics/AbcSize
|
130
140
|
def branch_range(node)
|
131
|
-
if node
|
132
|
-
node.source_range.with(end_pos: node.loc.else.begin_pos
|
141
|
+
if empty_if_branch?(node) && else_branch?(node)
|
142
|
+
node.source_range.with(end_pos: node.loc.else.begin_pos)
|
143
|
+
elsif node.loc.else
|
144
|
+
node.source_range.with(end_pos: node.condition.loc.expression.end_pos)
|
133
145
|
elsif all_branches_body_missing?(node)
|
134
146
|
if_node = node.ancestors.detect(&:if?)
|
135
147
|
node.source_range.with(end_pos: if_node.loc.end.end_pos)
|
@@ -50,9 +50,7 @@ module RuboCop
|
|
50
50
|
|
51
51
|
def on_new_investigation
|
52
52
|
each_missing_enable do |cop, line_range|
|
53
|
-
|
54
|
-
# the case when max_range is Float::INFINITY
|
55
|
-
next if line_range.max - line_range.min < max_range + 2
|
53
|
+
next if acceptable_range?(cop, line_range)
|
56
54
|
|
57
55
|
range = source_range(processed_source.buffer, line_range.min, (0..0))
|
58
56
|
comment = processed_source.comment_at_line(line_range.begin)
|
@@ -69,6 +67,23 @@ module RuboCop
|
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
70
|
+
def acceptable_range?(cop, line_range)
|
71
|
+
# This has to remain a strict inequality to handle
|
72
|
+
# the case when max_range is Float::INFINITY
|
73
|
+
return true if line_range.max - line_range.min < max_range + 2
|
74
|
+
# This cop is disabled in the config, it is not expected to be re-enabled
|
75
|
+
return true if line_range.min == CommentConfig::CONFIG_DISABLED_LINE_RANGE_MIN
|
76
|
+
|
77
|
+
cop_class = RuboCop::Cop::Registry.global.find_by_cop_name cop
|
78
|
+
if cop_class &&
|
79
|
+
!processed_source.registry.enabled?(cop_class, config) &&
|
80
|
+
line_range.max == Float::INFINITY
|
81
|
+
return true
|
82
|
+
end
|
83
|
+
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
72
87
|
def max_range
|
73
88
|
@max_range ||= cop_config['MaximumRangeSize']
|
74
89
|
end
|
@@ -30,6 +30,9 @@ module RuboCop
|
|
30
30
|
#
|
31
31
|
# # good
|
32
32
|
#
|
33
|
+
# # `class_eval`, `instance_eval`, `module_eval`, `class_exec`, `instance_exec`, and
|
34
|
+
# # `module_exec` blocks are allowed by default.
|
35
|
+
#
|
33
36
|
# def foo
|
34
37
|
# self.class.class_eval do
|
35
38
|
# def bar
|
@@ -54,7 +57,47 @@ module RuboCop
|
|
54
57
|
# end
|
55
58
|
# end
|
56
59
|
# end
|
60
|
+
#
|
61
|
+
# @example AllowedMethods: [] (default)
|
62
|
+
# # bad
|
63
|
+
# def do_something
|
64
|
+
# has_many :articles do
|
65
|
+
# def find_or_create_by_name(name)
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @example AllowedMethods: ['has_many']
|
71
|
+
# # bad
|
72
|
+
# def do_something
|
73
|
+
# has_many :articles do
|
74
|
+
# def find_or_create_by_name(name)
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# @example AllowedPatterns: [] (default)
|
80
|
+
# # bad
|
81
|
+
# def foo(obj)
|
82
|
+
# obj.do_baz do
|
83
|
+
# def bar
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# @example AllowedPatterns: ['baz']
|
89
|
+
# # good
|
90
|
+
# def foo(obj)
|
91
|
+
# obj.do_baz do
|
92
|
+
# def bar
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
#
|
57
97
|
class NestedMethodDefinition < Base
|
98
|
+
include AllowedMethods
|
99
|
+
include AllowedPattern
|
100
|
+
|
58
101
|
MSG = 'Method definitions must not be nested. Use `lambda` instead.'
|
59
102
|
|
60
103
|
def on_def(node)
|
@@ -77,7 +120,13 @@ module RuboCop
|
|
77
120
|
|
78
121
|
def scoping_method_call?(child)
|
79
122
|
child.sclass_type? || eval_call?(child) || exec_call?(child) ||
|
80
|
-
class_or_module_or_struct_new_call?(child)
|
123
|
+
class_or_module_or_struct_new_call?(child) || allowed_method_name?(child)
|
124
|
+
end
|
125
|
+
|
126
|
+
def allowed_method_name?(node)
|
127
|
+
name = node.method_name
|
128
|
+
|
129
|
+
allowed_method?(name) || matches_allowed_pattern?(name)
|
81
130
|
end
|
82
131
|
|
83
132
|
# @!method eval_call?(node)
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# Checks the proper ordering of magic comments and whether
|
8
8
|
# a magic comment is not placed before a shebang.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because file encoding may change.
|
12
|
+
#
|
10
13
|
# @example
|
11
14
|
# # bad
|
12
15
|
#
|
@@ -61,7 +64,7 @@ module RuboCop
|
|
61
64
|
def magic_comment_lines
|
62
65
|
lines = [nil, nil]
|
63
66
|
|
64
|
-
|
67
|
+
leading_magic_comments.each.with_index do |comment, index|
|
65
68
|
if comment.encoding_specified?
|
66
69
|
lines[0] = index
|
67
70
|
elsif comment.frozen_string_literal_specified?
|
@@ -73,10 +76,6 @@ module RuboCop
|
|
73
76
|
|
74
77
|
lines
|
75
78
|
end
|
76
|
-
|
77
|
-
def magic_comments
|
78
|
-
leading_comment_lines.map { |line| MagicComment.parse(line) }
|
79
|
-
end
|
80
79
|
end
|
81
80
|
end
|
82
81
|
end
|
@@ -113,6 +113,7 @@ module RuboCop
|
|
113
113
|
def each_line_range(cop, line_ranges)
|
114
114
|
line_ranges.each_with_index do |line_range, line_range_index|
|
115
115
|
next if ignore_offense?(line_range)
|
116
|
+
next if expected_final_disable?(cop, line_range)
|
116
117
|
|
117
118
|
comment = processed_source.comment_at_line(line_range.begin)
|
118
119
|
redundant = if all_disabled?(comment)
|
@@ -179,11 +180,21 @@ module RuboCop
|
|
179
180
|
end
|
180
181
|
|
181
182
|
def ignore_offense?(line_range)
|
183
|
+
return true if line_range.min == CommentConfig::CONFIG_DISABLED_LINE_RANGE_MIN
|
184
|
+
|
182
185
|
disabled_ranges.any? do |range|
|
183
186
|
range.cover?(line_range.min) && range.cover?(line_range.max)
|
184
187
|
end
|
185
188
|
end
|
186
189
|
|
190
|
+
def expected_final_disable?(cop, line_range)
|
191
|
+
# A cop which is disabled in the config is being re-disabled until end of file
|
192
|
+
cop_class = RuboCop::Cop::Registry.global.find_by_cop_name cop
|
193
|
+
cop_class &&
|
194
|
+
!processed_source.registry.enabled?(cop_class, config) &&
|
195
|
+
line_range.max == Float::INFINITY
|
196
|
+
end
|
197
|
+
|
187
198
|
def department_disabled?(cop, comment)
|
188
199
|
directive = DirectiveComment.new(comment)
|
189
200
|
directive.in_directive_department?(cop) && !directive.overridden_by_department?(cop)
|
@@ -209,7 +220,12 @@ module RuboCop
|
|
209
220
|
|
210
221
|
add_offense(location, message: message(cop_names)) do |corrector|
|
211
222
|
range = comment_range_with_surrounding_space(location, comment.loc.expression)
|
212
|
-
|
223
|
+
|
224
|
+
if leave_free_comment?(comment, range)
|
225
|
+
corrector.replace(range, ' # ')
|
226
|
+
else
|
227
|
+
corrector.remove(range)
|
228
|
+
end
|
213
229
|
end
|
214
230
|
end
|
215
231
|
|
@@ -227,6 +243,12 @@ module RuboCop
|
|
227
243
|
end
|
228
244
|
end
|
229
245
|
|
246
|
+
def leave_free_comment?(comment, range)
|
247
|
+
free_comment = comment.text.gsub(range.source.strip, '')
|
248
|
+
|
249
|
+
!free_comment.empty? && !free_comment.start_with?('#')
|
250
|
+
end
|
251
|
+
|
230
252
|
def cop_range(comment, cop)
|
231
253
|
cop = remove_department_marker(cop)
|
232
254
|
matching_range(comment.loc.expression, cop) ||
|