rubocop 1.36.0 → 1.40.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 +78 -12
- data/exe/rubocop +1 -1
- 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 +41 -1
- data/lib/rubocop/config.rb +5 -4
- data/lib/rubocop/config_loader.rb +5 -5
- data/lib/rubocop/config_loader_resolver.rb +1 -1
- data/lib/rubocop/cop/base.rb +2 -9
- data/lib/rubocop/cop/commissioner.rb +3 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
- 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/lambda_or_proc.rb +46 -0
- data/lib/rubocop/cop/internal_affairs.rb +3 -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 +2 -2
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -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_block.rb +1 -5
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +21 -9
- data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
- 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/parentheses_as_grouped_expression.rb +5 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +36 -4
- 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 +18 -8
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
- data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -3
- 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/lint/void.rb +6 -6
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +9 -4
- data/lib/rubocop/cop/metrics/class_length.rb +9 -4
- data/lib/rubocop/cop/metrics/method_length.rb +9 -4
- data/lib/rubocop/cop/metrics/module_length.rb +9 -4
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -2
- 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 +30 -8
- 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/statement_modifier.rb +15 -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 +32 -14
- 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/array_intersect.rb +111 -0
- 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 +90 -22
- 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/if_with_semicolon.rb +2 -1
- 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/nil_lambda.rb +1 -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_argument.rb +3 -0
- 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_constant_base.rb +72 -0
- 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_return.rb +7 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
- data/lib/rubocop/cop/style/require_order.rb +88 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/string_literals.rb +1 -5
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +3 -5
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/cop/team.rb +4 -5
- data/lib/rubocop/cop/util.rb +2 -2
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +20 -29
- 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 +25 -8
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
- data/lib/rubocop/formatter.rb +3 -1
- data/lib/rubocop/optimized_patterns.rb +38 -0
- data/lib/rubocop/options.rb +28 -16
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +24 -1
- data/lib/rubocop/rspec/shared_contexts.rb +14 -1
- data/lib/rubocop/rspec/support.rb +2 -2
- 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 +19 -2
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +8 -3
- data/lib/rubocop.rb +18 -6
- metadata +18 -5
@@ -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
|
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
|
66
66
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
67
67
|
return if node.body
|
68
|
-
return if allow_empty_lambdas? && lambda_or_proc?
|
68
|
+
return if allow_empty_lambdas? && node.lambda_or_proc?
|
69
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
70
70
|
|
71
71
|
add_offense(node)
|
@@ -88,10 +88,6 @@ module RuboCop
|
|
88
88
|
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
|
89
89
|
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
|
90
90
|
end
|
91
|
-
|
92
|
-
def lambda_or_proc?(node)
|
93
|
-
node.lambda? || node.proc?
|
94
|
-
end
|
95
91
|
end
|
96
92
|
end
|
97
93
|
end
|
@@ -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
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
69
69
|
|
70
70
|
def on_if(node)
|
71
|
-
return if node.body
|
71
|
+
return if node.body || same_line?(node.loc.begin, node.loc.end)
|
72
72
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
73
73
|
|
74
74
|
add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
|
@@ -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)
|
@@ -6,9 +6,10 @@ module RuboCop
|
|
6
6
|
# Checks for interpolation in a single quoted string.
|
7
7
|
#
|
8
8
|
# @safety
|
9
|
-
# This cop is
|
10
|
-
# it is
|
11
|
-
#
|
9
|
+
# This cop's autocorrection is unsafe because although it always replaces single quotes as
|
10
|
+
# if it were miswritten double quotes, it is not always the case. For example,
|
11
|
+
# `'#{foo} bar'` would be replaced by `"#{foo} bar"`, so the replaced code would evaluate
|
12
|
+
# the expression `foo`.
|
12
13
|
#
|
13
14
|
# @example
|
14
15
|
#
|
@@ -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
|
@@ -40,11 +40,16 @@ module RuboCop
|
|
40
40
|
unless node.arguments.one? && first_argument_starts_with_left_parenthesis?(node)
|
41
41
|
return true
|
42
42
|
end
|
43
|
+
return true if first_argument_block_type?(node.first_argument)
|
43
44
|
|
44
45
|
node.operator_method? || node.setter_method? || chained_calls?(node) ||
|
45
46
|
valid_first_argument?(node.first_argument)
|
46
47
|
end
|
47
48
|
|
49
|
+
def first_argument_block_type?(first_arg)
|
50
|
+
first_arg.block_type? || first_arg.numblock_type?
|
51
|
+
end
|
52
|
+
|
48
53
|
def valid_first_argument?(first_arg)
|
49
54
|
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg)
|
50
55
|
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)
|
@@ -130,18 +131,28 @@ module RuboCop
|
|
130
131
|
def each_already_disabled(cop, line_ranges)
|
131
132
|
line_ranges.each_cons(2) do |previous_range, range|
|
132
133
|
next if ignore_offense?(range)
|
133
|
-
next unless followed_ranges?(previous_range, range)
|
134
|
-
|
135
134
|
# If a cop is disabled in a range that begins on the same line as
|
136
135
|
# the end of the previous range, it means that the cop was
|
137
136
|
# already disabled by an earlier comment. So it's redundant
|
138
137
|
# whether there are offenses or not.
|
138
|
+
next unless followed_ranges?(previous_range, range)
|
139
|
+
|
139
140
|
comment = processed_source.comment_at_line(range.begin)
|
140
141
|
|
142
|
+
next unless comment
|
141
143
|
# Comments disabling all cops don't count since it's reasonable
|
142
144
|
# to disable a few select cops first and then all cops further
|
143
145
|
# down in the code.
|
144
|
-
|
146
|
+
next if all_disabled?(comment)
|
147
|
+
|
148
|
+
redundant =
|
149
|
+
if department_disabled?(cop, comment)
|
150
|
+
find_redundant_department(cop, range)
|
151
|
+
else
|
152
|
+
cop
|
153
|
+
end
|
154
|
+
|
155
|
+
yield comment, redundant
|
145
156
|
end
|
146
157
|
end
|
147
158
|
|
@@ -179,11 +190,21 @@ module RuboCop
|
|
179
190
|
end
|
180
191
|
|
181
192
|
def ignore_offense?(line_range)
|
193
|
+
return true if line_range.min == CommentConfig::CONFIG_DISABLED_LINE_RANGE_MIN
|
194
|
+
|
182
195
|
disabled_ranges.any? do |range|
|
183
196
|
range.cover?(line_range.min) && range.cover?(line_range.max)
|
184
197
|
end
|
185
198
|
end
|
186
199
|
|
200
|
+
def expected_final_disable?(cop, line_range)
|
201
|
+
# A cop which is disabled in the config is being re-disabled until end of file
|
202
|
+
cop_class = RuboCop::Cop::Registry.global.find_by_cop_name cop
|
203
|
+
cop_class &&
|
204
|
+
!processed_source.registry.enabled?(cop_class, config) &&
|
205
|
+
line_range.max == Float::INFINITY
|
206
|
+
end
|
207
|
+
|
187
208
|
def department_disabled?(cop, comment)
|
188
209
|
directive = DirectiveComment.new(comment)
|
189
210
|
directive.in_directive_department?(cop) && !directive.overridden_by_department?(cop)
|
@@ -209,7 +230,12 @@ module RuboCop
|
|
209
230
|
|
210
231
|
add_offense(location, message: message(cop_names)) do |corrector|
|
211
232
|
range = comment_range_with_surrounding_space(location, comment.loc.expression)
|
212
|
-
|
233
|
+
|
234
|
+
if leave_free_comment?(comment, range)
|
235
|
+
corrector.replace(range, ' # ')
|
236
|
+
else
|
237
|
+
corrector.remove(range)
|
238
|
+
end
|
213
239
|
end
|
214
240
|
end
|
215
241
|
|
@@ -227,6 +253,12 @@ module RuboCop
|
|
227
253
|
end
|
228
254
|
end
|
229
255
|
|
256
|
+
def leave_free_comment?(comment, range)
|
257
|
+
free_comment = comment.text.gsub(range.source.strip, '')
|
258
|
+
|
259
|
+
!free_comment.empty? && !free_comment.start_with?('#')
|
260
|
+
end
|
261
|
+
|
230
262
|
def cop_range(comment, cop)
|
231
263
|
cop = remove_department_marker(cop)
|
232
264
|
matching_range(comment.loc.expression, cop) ||
|
@@ -41,6 +41,7 @@ module RuboCop
|
|
41
41
|
return unless (receiver = node.receiver)
|
42
42
|
return unless receiver.receiver&.const_type? && receiver.receiver.short_name == :Dir
|
43
43
|
return unless GLOB_METHODS.include?(receiver.method_name)
|
44
|
+
return if multiple_argument?(receiver)
|
44
45
|
|
45
46
|
selector = node.loc.selector
|
46
47
|
|
@@ -49,6 +50,12 @@ module RuboCop
|
|
49
50
|
corrector.remove(node.loc.dot)
|
50
51
|
end
|
51
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def multiple_argument?(glob_method)
|
57
|
+
glob_method.arguments.count >= 2 || glob_method.first_argument&.splat_type?
|
58
|
+
end
|
52
59
|
end
|
53
60
|
end
|
54
61
|
end
|
@@ -6,13 +6,23 @@ module RuboCop
|
|
6
6
|
# Checks for unnecessary `require` statement.
|
7
7
|
#
|
8
8
|
# The following features are unnecessary `require` statement because
|
9
|
-
# they are already loaded.
|
9
|
+
# they are already loaded. e.g. Ruby 2.2:
|
10
10
|
#
|
11
11
|
# ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }'
|
12
12
|
# ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-darwin13]
|
13
13
|
# ["enumerator.so", "rational.so", "complex.so", "thread.rb"]
|
14
14
|
#
|
15
|
-
#
|
15
|
+
# Below are the features that each `TargetRubyVersion` targets.
|
16
|
+
#
|
17
|
+
# * 2.0+ ... `enumerator`
|
18
|
+
# * 2.1+ ... `thread`
|
19
|
+
# * 2.2+ ... Add `rational` and `complex` above
|
20
|
+
# * 2.5+ ... Add `pp` above
|
21
|
+
# * 2.7+ ... Add `ruby2_keywords` above
|
22
|
+
# * 3.1+ ... Add `fiber` above
|
23
|
+
# * 3.2+ ... `set`
|
24
|
+
#
|
25
|
+
# This cop target those features.
|
16
26
|
#
|
17
27
|
# @example
|
18
28
|
# # bad
|
@@ -24,28 +34,46 @@ module RuboCop
|
|
24
34
|
class RedundantRequireStatement < Base
|
25
35
|
include RangeHelp
|
26
36
|
extend AutoCorrector
|
27
|
-
extend TargetRubyVersion
|
28
|
-
|
29
|
-
minimum_target_ruby_version 2.2
|
30
37
|
|
31
38
|
MSG = 'Remove unnecessary `require` statement.'
|
32
39
|
RESTRICT_ON_SEND = %i[require].freeze
|
40
|
+
RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
|
33
41
|
|
34
|
-
# @!method
|
35
|
-
def_node_matcher :
|
42
|
+
# @!method redundant_require_statement?(node)
|
43
|
+
def_node_matcher :redundant_require_statement?, <<~PATTERN
|
36
44
|
(send nil? :require
|
37
|
-
(str
|
45
|
+
(str #redundant_feature?))
|
38
46
|
PATTERN
|
39
47
|
|
40
48
|
def on_send(node)
|
41
|
-
return unless
|
49
|
+
return unless redundant_require_statement?(node)
|
42
50
|
|
43
51
|
add_offense(node) do |corrector|
|
44
|
-
|
52
|
+
if node.parent.respond_to?(:modifier_form?) && node.parent.modifier_form?
|
53
|
+
corrector.insert_after(node.parent, "\nend")
|
54
|
+
|
55
|
+
range = range_with_surrounding_space(node.loc.expression, side: :right)
|
56
|
+
else
|
57
|
+
range = range_by_whole_lines(node.source_range, include_final_newline: true)
|
58
|
+
end
|
45
59
|
|
46
60
|
corrector.remove(range)
|
47
61
|
end
|
48
62
|
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
67
|
+
def redundant_feature?(feature_name)
|
68
|
+
feature_name == 'enumerator' ||
|
69
|
+
(target_ruby_version >= 2.1 && feature_name == 'thread') ||
|
70
|
+
(target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
|
71
|
+
(target_ruby_version >= 2.5 && feature_name == 'pp') ||
|
72
|
+
(target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
|
73
|
+
(target_ruby_version >= 3.1 && feature_name == 'fiber') ||
|
74
|
+
(target_ruby_version >= 3.2 && feature_name == 'set')
|
75
|
+
end
|
76
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
49
77
|
end
|
50
78
|
end
|
51
79
|
end
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def check_ternary(ternary, node)
|
49
|
-
return
|
49
|
+
return if node.method?(:[]) || !ternary.condition.operator_keyword?
|
50
50
|
|
51
51
|
range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
|
52
52
|
|