rubocop 0.90.0 → 0.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +35 -0
- data/lib/rubocop.rb +10 -1
- data/lib/rubocop/cli/command/execute_runner.rb +8 -0
- data/lib/rubocop/config_loader.rb +3 -3
- data/lib/rubocop/config_store.rb +3 -3
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +5 -1
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -0
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -0
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +77 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +6 -5
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -10
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +17 -4
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -3
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -6
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +2 -0
- data/lib/rubocop/cop/lint/big_decimal_new.rb +1 -2
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +54 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -3
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -3
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -4
- data/lib/rubocop/cop/lint/duplicate_require.rb +7 -2
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -0
- data/lib/rubocop/cop/lint/empty_file.rb +1 -4
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -0
- data/lib/rubocop/cop/lint/float_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
- data/lib/rubocop/cop/lint/identity_comparison.rb +49 -0
- data/lib/rubocop/cop/lint/inherit_exception.rb +2 -2
- data/lib/rubocop/cop/lint/multiple_comparison.rb +3 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -0
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -2
- data/lib/rubocop/cop/lint/raise_exception.rb +1 -0
- data/lib/rubocop/cop/lint/rand_one.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -0
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +3 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +1 -0
- data/lib/rubocop/cop/lint/to_json.rb +16 -5
- data/lib/rubocop/cop/lint/unreachable_loop.rb +2 -1
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +3 -1
- data/lib/rubocop/cop/lint/uri_regexp.rb +2 -1
- data/lib/rubocop/cop/lint/useless_method_definition.rb +20 -27
- data/lib/rubocop/cop/lint/useless_times.rb +97 -0
- data/lib/rubocop/cop/mixin/comments_help.rb +3 -9
- data/lib/rubocop/cop/mixin/configurable_naming.rb +2 -2
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +9 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -1
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/security/eval.rb +1 -0
- data/lib/rubocop/cop/security/json_load.rb +1 -0
- data/lib/rubocop/cop/security/marshal_load.rb +1 -0
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/security/yaml_load.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -11
- data/lib/rubocop/cop/style/alias.rb +2 -0
- data/lib/rubocop/cop/style/array_join.rb +1 -0
- data/lib/rubocop/cop/style/attr.rb +1 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -0
- data/lib/rubocop/cop/style/case_equality.rb +3 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -0
- data/lib/rubocop/cop/style/class_check.rb +6 -9
- data/lib/rubocop/cop/style/class_methods_definitions.rb +42 -16
- data/lib/rubocop/cop/style/class_vars.rb +1 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +49 -60
- data/lib/rubocop/cop/style/dir.rb +1 -0
- data/lib/rubocop/cop/style/double_negation.rb +1 -0
- data/lib/rubocop/cop/style/empty_literal.rb +3 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -3
- data/lib/rubocop/cop/style/even_odd.rb +1 -0
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +2 -0
- data/lib/rubocop/cop/style/format_string.rb +1 -4
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +12 -2
- data/lib/rubocop/cop/style/hash_transform_keys.rb +5 -11
- data/lib/rubocop/cop/style/hash_transform_values.rb +5 -11
- data/lib/rubocop/cop/style/implicit_runtime_error.rb +1 -0
- data/lib/rubocop/cop/style/lambda_call.rb +3 -1
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -0
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +14 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -0
- data/lib/rubocop/cop/style/not.rb +1 -0
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -3
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +2 -0
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/random_with_offset.rb +1 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -3
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +2 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -3
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -7
- data/lib/rubocop/cop/style/safe_navigation.rb +5 -0
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/send.rb +2 -3
- data/lib/rubocop/cop/style/signal_exception.rb +2 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +1 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +2 -1
- data/lib/rubocop/cop/style/stderr_puts.rb +1 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +16 -2
- data/lib/rubocop/cop/style/strip.rb +1 -0
- data/lib/rubocop/cop/style/unpack_first.rb +1 -0
- data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -5
- data/lib/rubocop/core_ext/string.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +4 -4
- data/lib/rubocop/options.rb +19 -1
- data/lib/rubocop/result_cache.rb +30 -13
- data/lib/rubocop/runner.rb +29 -14
- data/lib/rubocop/version.rb +1 -1
- metadata +8 -4
@@ -49,6 +49,10 @@ module RuboCop
|
|
49
49
|
# foo && foo < bar
|
50
50
|
# foo < bar if foo
|
51
51
|
#
|
52
|
+
# # When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
|
53
|
+
# # do the opposite of what the author intends.
|
54
|
+
# foo && foo.empty?
|
55
|
+
#
|
52
56
|
# # This could start returning `nil` as well as the return of the method
|
53
57
|
# foo.nil? || foo.bar
|
54
58
|
# !foo || foo.bar
|
@@ -104,6 +108,7 @@ module RuboCop
|
|
104
108
|
# chain greater than 2
|
105
109
|
return if chain_size(method_chain, method) > 1
|
106
110
|
return if unsafe_method_used?(method_chain, method)
|
111
|
+
return if method_chain.method?(:empty?)
|
107
112
|
|
108
113
|
add_offense(node) do |corrector|
|
109
114
|
autocorrect(corrector, node)
|
@@ -31,9 +31,10 @@ module RuboCop
|
|
31
31
|
extend AutoCorrector
|
32
32
|
|
33
33
|
MSG = 'Use `%<correct>s` instead of `%<incorrect>s`.'
|
34
|
+
RESTRICT_ON_SEND = %i[first last [] at slice].freeze
|
34
35
|
|
35
36
|
def_node_matcher :sample_candidate?, <<~PATTERN
|
36
|
-
(send $(send _ :shuffle $...) ${
|
37
|
+
(send $(send _ :shuffle $...) ${:#{RESTRICT_ON_SEND.join(' :')}} $...)
|
37
38
|
PATTERN
|
38
39
|
|
39
40
|
def on_send(node)
|
@@ -16,11 +16,10 @@ module RuboCop
|
|
16
16
|
class Send < Base
|
17
17
|
MSG = 'Prefer `Object#__send__` or `Object#public_send` to ' \
|
18
18
|
'`send`.'
|
19
|
-
|
20
|
-
def_node_matcher :sending?, '({send csend} _ :send ...)'
|
19
|
+
RESTRICT_ON_SEND = %i[send].freeze
|
21
20
|
|
22
21
|
def on_send(node)
|
23
|
-
return unless
|
22
|
+
return unless node.arguments?
|
24
23
|
|
25
24
|
add_offense(node.loc.selector)
|
26
25
|
end
|
@@ -112,6 +112,8 @@ module RuboCop
|
|
112
112
|
RAISE_MSG = 'Use `raise` instead of `fail` to ' \
|
113
113
|
'rethrow exceptions.'
|
114
114
|
|
115
|
+
RESTRICT_ON_SEND = %i[raise fail].freeze
|
116
|
+
|
115
117
|
def_node_matcher :kernel_call?, '(send (const {nil? cbase} :Kernel) %1 ...)'
|
116
118
|
def_node_search :custom_fail_methods,
|
117
119
|
'{(def :fail ...) (defs _ :fail ...)}'
|
@@ -19,11 +19,12 @@ module RuboCop
|
|
19
19
|
minimum_target_ruby_version 2.6
|
20
20
|
|
21
21
|
MSG = 'Prefer ary[n..] over ary[n..-1].'
|
22
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
22
23
|
|
23
24
|
def_node_matcher :range_till_minus_one?, '(irange !nil? (int -1))'
|
24
25
|
|
25
26
|
def on_send(node)
|
26
|
-
return unless node.
|
27
|
+
return unless node.arguments.count == 1
|
27
28
|
return unless range_till_minus_one?(node.arguments.first)
|
28
29
|
|
29
30
|
add_offense(node.first_argument) do |corrector|
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# This cop checks for places where string concatenation
|
7
7
|
# can be replaced with string interpolation.
|
8
8
|
#
|
9
|
+
# The cop can autocorrect simple cases but will skip autocorrecting
|
10
|
+
# more complex cases where the resulting code would be harder to read.
|
11
|
+
# In those cases, it might be useful to extract statements to local
|
12
|
+
# variables or methods which you can then interpolate in a string.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
11
16
|
# email_with_name = user.name + ' <' + user.email + '>'
|
@@ -19,6 +24,7 @@ module RuboCop
|
|
19
24
|
extend AutoCorrector
|
20
25
|
|
21
26
|
MSG = 'Prefer string interpolation to string concatenation.'
|
27
|
+
RESTRICT_ON_SEND = %i[+].freeze
|
22
28
|
|
23
29
|
def_node_matcher :string_concatenation?, <<~PATTERN
|
24
30
|
{
|
@@ -28,7 +34,6 @@ module RuboCop
|
|
28
34
|
PATTERN
|
29
35
|
|
30
36
|
def on_send(node)
|
31
|
-
return unless node.method?(:+)
|
32
37
|
return unless string_concatenation?(node)
|
33
38
|
|
34
39
|
topmost_plus_node = find_topmost_plus_node(node)
|
@@ -37,7 +42,9 @@ module RuboCop
|
|
37
42
|
collect_parts(topmost_plus_node, parts)
|
38
43
|
|
39
44
|
add_offense(topmost_plus_node) do |corrector|
|
40
|
-
|
45
|
+
if parts.none? { |part| uncorrectable?(part) }
|
46
|
+
corrector.replace(topmost_plus_node, replacement(parts))
|
47
|
+
end
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
@@ -66,6 +73,13 @@ module RuboCop
|
|
66
73
|
node.send_type? && node.method?(:+)
|
67
74
|
end
|
68
75
|
|
76
|
+
def uncorrectable?(part)
|
77
|
+
part.multiline? ||
|
78
|
+
part.dstr_type? ||
|
79
|
+
(part.str_type? && part.heredoc?) ||
|
80
|
+
part.each_descendant(:block).any?
|
81
|
+
end
|
82
|
+
|
69
83
|
def replacement(parts)
|
70
84
|
interpolated_parts =
|
71
85
|
parts.map do |part|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
NONZERO_MSG = 'Use `!empty?` instead of ' \
|
33
33
|
'`%<lhs>s %<opr>s %<rhs>s`.'
|
34
34
|
|
35
|
-
|
35
|
+
RESTRICT_ON_SEND = %i[size length].freeze
|
36
36
|
|
37
37
|
def on_send(node)
|
38
38
|
check_zero_length_predicate(node)
|
@@ -42,8 +42,6 @@ module RuboCop
|
|
42
42
|
private
|
43
43
|
|
44
44
|
def check_zero_length_predicate(node)
|
45
|
-
return unless LENGTH_METHODS.include?(node.method_name)
|
46
|
-
|
47
45
|
zero_length_predicate = zero_length_predicate(node.parent)
|
48
46
|
return unless zero_length_predicate
|
49
47
|
|
@@ -59,8 +57,6 @@ module RuboCop
|
|
59
57
|
end
|
60
58
|
|
61
59
|
def check_nonzero_length_predicate(node)
|
62
|
-
return unless LENGTH_METHODS.include?(node.method_name)
|
63
|
-
|
64
60
|
nonzero_length_predicate = nonzero_length_predicate(node.parent)
|
65
61
|
return unless nonzero_length_predicate
|
66
62
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# Extensions to the core String class
|
4
4
|
class String
|
5
|
-
unless method_defined?
|
5
|
+
unless method_defined?(:blank?) && ' '.blank?
|
6
6
|
# Checks whether a string is blank. A string is considered blank if it
|
7
7
|
# is either empty or contains only whitespace characters.
|
8
8
|
#
|
@@ -21,10 +21,10 @@ module RuboCop
|
|
21
21
|
|
22
22
|
str = content
|
23
23
|
Ext::RegexpNode.parsed_cache[str] ||= begin
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
Regexp::Parser.parse(str)
|
25
|
+
rescue StandardError
|
26
|
+
nil
|
27
|
+
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def each_capture(named: ANY)
|
data/lib/rubocop/options.rb
CHANGED
@@ -69,6 +69,7 @@ module RuboCop
|
|
69
69
|
|
70
70
|
add_severity_option(opts)
|
71
71
|
add_flags_with_optional_args(opts)
|
72
|
+
add_cache_options(opts)
|
72
73
|
add_boolean_flags(opts)
|
73
74
|
add_aliases(opts)
|
74
75
|
|
@@ -164,10 +165,16 @@ module RuboCop
|
|
164
165
|
end
|
165
166
|
end
|
166
167
|
|
168
|
+
def add_cache_options(opts)
|
169
|
+
option(opts, '-C', '--cache FLAG')
|
170
|
+
option(opts, '--cache-root DIR') do
|
171
|
+
@validator.validate_cache_enabled_for_cache_root
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
167
175
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
168
176
|
def add_boolean_flags(opts)
|
169
177
|
option(opts, '-F', '--fail-fast')
|
170
|
-
option(opts, '-C', '--cache FLAG')
|
171
178
|
option(opts, '-d', '--debug')
|
172
179
|
option(opts, '-D', '--[no-]display-cop-names')
|
173
180
|
option(opts, '-E', '--extra-details')
|
@@ -392,6 +399,13 @@ module RuboCop
|
|
392
399
|
# of option order.
|
393
400
|
raise OptionParser::MissingArgument
|
394
401
|
end
|
402
|
+
|
403
|
+
def validate_cache_enabled_for_cache_root
|
404
|
+
return unless @options[:cache] == 'false'
|
405
|
+
|
406
|
+
raise OptionArgumentError, '--cache-root can not be used with ' \
|
407
|
+
'--cache false'
|
408
|
+
end
|
395
409
|
end
|
396
410
|
|
397
411
|
# This module contains help texts for command line options.
|
@@ -464,6 +478,10 @@ module RuboCop
|
|
464
478
|
cache: ["Use result caching (FLAG=true) or don't",
|
465
479
|
'(FLAG=false), default determined by',
|
466
480
|
'configuration parameter AllCops: UseCache.'],
|
481
|
+
cache_root: ['Set the cache root directory.',
|
482
|
+
'Takes precedence over the configuration',
|
483
|
+
'parameter AllCops: CacheRootDirectory and',
|
484
|
+
'the $RUBOCOP_CACHE_ROOT environment variable.'],
|
467
485
|
debug: 'Display debug info.',
|
468
486
|
display_cop_names: ['Display cop names in offense messages.',
|
469
487
|
'Default is true.'],
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'digest/sha1'
|
4
4
|
require 'find'
|
5
5
|
require 'etc'
|
6
|
+
require 'zlib'
|
6
7
|
|
7
8
|
module RuboCop
|
8
9
|
# Provides functionality for caching rubocop runs.
|
@@ -30,6 +31,11 @@ module RuboCop
|
|
30
31
|
end
|
31
32
|
|
32
33
|
class << self
|
34
|
+
# @api private
|
35
|
+
attr_accessor :rubocop_required_features
|
36
|
+
|
37
|
+
ResultCache.rubocop_required_features = []
|
38
|
+
|
33
39
|
private
|
34
40
|
|
35
41
|
def requires_file_removal?(file_count, config_store)
|
@@ -61,7 +67,8 @@ module RuboCop
|
|
61
67
|
end
|
62
68
|
|
63
69
|
def self.cache_root(config_store)
|
64
|
-
root =
|
70
|
+
root = ENV['RUBOCOP_CACHE_ROOT']
|
71
|
+
root ||= config_store.for_pwd.for_all_cops['CacheRootDirectory']
|
65
72
|
root ||= if ENV.key?('XDG_CACHE_HOME')
|
66
73
|
# Include user ID in the path to make sure the user has write
|
67
74
|
# access.
|
@@ -76,7 +83,10 @@ module RuboCop
|
|
76
83
|
config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
|
77
84
|
end
|
78
85
|
|
86
|
+
attr :path
|
87
|
+
|
79
88
|
def initialize(file, team, options, config_store, cache_root = nil)
|
89
|
+
cache_root ||= options[:cache_root]
|
80
90
|
cache_root ||= ResultCache.cache_root(config_store)
|
81
91
|
@allow_symlinks_in_cache_location =
|
82
92
|
ResultCache.allow_symlinks_in_cache_location?(config_store)
|
@@ -159,27 +169,34 @@ module RuboCop
|
|
159
169
|
end
|
160
170
|
|
161
171
|
# The checksum of the rubocop program running the inspection.
|
162
|
-
# rubocop:disable Metrics/AbcSize
|
163
172
|
def rubocop_checksum
|
164
173
|
ResultCache.source_checksum ||=
|
165
174
|
begin
|
166
|
-
lib_root = File.join(File.dirname(__FILE__), '..')
|
167
|
-
exe_root = File.join(lib_root, '..', 'exe')
|
168
|
-
|
169
|
-
# These are all the files we have `require`d plus everything in the
|
170
|
-
# exe directory. A change to any of them could affect the cop output
|
171
|
-
# so we include them in the cache hash.
|
172
|
-
source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
|
173
|
-
|
174
175
|
digest = Digest::SHA1.new
|
175
|
-
|
176
|
+
rubocop_extra_features
|
176
177
|
.select { |path| File.file?(path) }
|
177
178
|
.sort!
|
178
|
-
.each
|
179
|
+
.each do |path|
|
180
|
+
content = File.open(path, 'rb', &:read)
|
181
|
+
digest << Zlib.crc32(content).to_s # mtime not reliable
|
182
|
+
end
|
183
|
+
digest << RuboCop::Version::STRING << RuboCop::AST::Version::STRING
|
179
184
|
digest.hexdigest
|
180
185
|
end
|
181
186
|
end
|
182
|
-
|
187
|
+
|
188
|
+
def rubocop_extra_features
|
189
|
+
lib_root = File.join(File.dirname(__FILE__), '..')
|
190
|
+
exe_root = File.join(lib_root, '..', 'exe')
|
191
|
+
|
192
|
+
# These are all the files we have `require`d plus everything in the
|
193
|
+
# exe directory. A change to any of them could affect the cop output
|
194
|
+
# so we include them in the cache hash.
|
195
|
+
source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
|
196
|
+
source_files -= ResultCache.rubocop_required_features # Rely on gem versions
|
197
|
+
|
198
|
+
source_files
|
199
|
+
end
|
183
200
|
|
184
201
|
# Return a hash of the options given at invocation, minus the ones that have
|
185
202
|
# no effect on which offenses and disabled line ranges are found, and thus
|
data/lib/rubocop/runner.rb
CHANGED
@@ -11,9 +11,12 @@ module RuboCop
|
|
11
11
|
class InfiniteCorrectionLoop < RuntimeError
|
12
12
|
attr_reader :offenses
|
13
13
|
|
14
|
-
def initialize(path,
|
15
|
-
|
16
|
-
|
14
|
+
def initialize(path, offenses_by_iteration, loop_start: -1)
|
15
|
+
@offenses = offenses_by_iteration.flatten.uniq
|
16
|
+
root_cause = offenses_by_iteration[loop_start..-1]
|
17
|
+
.map { |x| x.map(&:cop_name).uniq.join(', ') }
|
18
|
+
.join(' -> ')
|
19
|
+
super "Infinite loop detected in #{path} and caused by #{root_cause}"
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
@@ -81,7 +84,10 @@ module RuboCop
|
|
81
84
|
# OPTIMIZE: Calling `ResultCache.cleanup` takes time. This optimization
|
82
85
|
# mainly targets editors that integrates RuboCop. When RuboCop is run
|
83
86
|
# by an editor, it should be inspecting only one file.
|
84
|
-
|
87
|
+
if files.size > 1 && cached_run?
|
88
|
+
ResultCache.cleanup(@config_store, @options[:debug], @options[:cache_root])
|
89
|
+
end
|
90
|
+
|
85
91
|
formatter_set.finished(inspected_files.freeze)
|
86
92
|
formatter_set.close_output_files
|
87
93
|
end
|
@@ -233,18 +239,21 @@ module RuboCop
|
|
233
239
|
|
234
240
|
def do_inspection_loop(file)
|
235
241
|
processed_source = get_processed_source(file)
|
236
|
-
offenses
|
242
|
+
# This variable is 2d array used to track corrected offenses after each
|
243
|
+
# inspection iteration. This is used to output meaningful infinite loop
|
244
|
+
# error message.
|
245
|
+
offenses_by_iteration = []
|
237
246
|
|
238
247
|
# When running with --auto-correct, we need to inspect the file (which
|
239
248
|
# includes writing a corrected version of it) until no more corrections
|
240
249
|
# are made. This is because automatic corrections can introduce new
|
241
250
|
# offenses. In the normal case the loop is only executed once.
|
242
|
-
iterate_until_no_changes(processed_source,
|
251
|
+
iterate_until_no_changes(processed_source, offenses_by_iteration) do
|
243
252
|
# The offenses that couldn't be corrected will be found again so we
|
244
253
|
# only keep the corrected ones in order to avoid duplicate reporting.
|
245
|
-
|
254
|
+
!offenses_by_iteration.empty? && offenses_by_iteration.last.select!(&:corrected?)
|
246
255
|
new_offenses, updated_source_file = inspect_file(processed_source)
|
247
|
-
|
256
|
+
offenses_by_iteration.push(new_offenses)
|
248
257
|
|
249
258
|
# We have to reprocess the source to pickup the changes. Since the
|
250
259
|
# change could (theoretically) introduce parsing errors, we break the
|
@@ -254,10 +263,12 @@ module RuboCop
|
|
254
263
|
processed_source = get_processed_source(file)
|
255
264
|
end
|
256
265
|
|
266
|
+
# Return summary of corrected offenses after all iterations
|
267
|
+
offenses = offenses_by_iteration.flatten.uniq
|
257
268
|
[processed_source, offenses]
|
258
269
|
end
|
259
270
|
|
260
|
-
def iterate_until_no_changes(source,
|
271
|
+
def iterate_until_no_changes(source, offenses_by_iteration)
|
261
272
|
# Keep track of the state of the source. If a cop modifies the source
|
262
273
|
# and another cop undoes it producing identical source we have an
|
263
274
|
# infinite loop.
|
@@ -269,10 +280,10 @@ module RuboCop
|
|
269
280
|
iterations = 0
|
270
281
|
|
271
282
|
loop do
|
272
|
-
check_for_infinite_loop(source,
|
283
|
+
check_for_infinite_loop(source, offenses_by_iteration)
|
273
284
|
|
274
285
|
if (iterations += 1) > MAX_ITERATIONS
|
275
|
-
raise InfiniteCorrectionLoop.new(source.path,
|
286
|
+
raise InfiniteCorrectionLoop.new(source.path, offenses_by_iteration)
|
276
287
|
end
|
277
288
|
|
278
289
|
source = yield
|
@@ -282,11 +293,15 @@ module RuboCop
|
|
282
293
|
|
283
294
|
# Check whether a run created source identical to a previous run, which
|
284
295
|
# means that we definitely have an infinite loop.
|
285
|
-
def check_for_infinite_loop(processed_source,
|
296
|
+
def check_for_infinite_loop(processed_source, offenses_by_iteration)
|
286
297
|
checksum = processed_source.checksum
|
287
298
|
|
288
|
-
if @processed_sources.
|
289
|
-
raise InfiniteCorrectionLoop.new(
|
299
|
+
if (loop_start_index = @processed_sources.index(checksum))
|
300
|
+
raise InfiniteCorrectionLoop.new(
|
301
|
+
processed_source.path,
|
302
|
+
offenses_by_iteration,
|
303
|
+
loop_start: loop_start_index
|
304
|
+
)
|
290
305
|
end
|
291
306
|
|
292
307
|
@processed_sources << checksum
|
data/lib/rubocop/version.rb
CHANGED