rubocop 0.67.2 → 0.68.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +86 -233
  4. data/exe/rubocop +0 -12
  5. data/lib/rubocop.rb +13 -30
  6. data/lib/rubocop/ast/builder.rb +4 -0
  7. data/lib/rubocop/ast/node/alias_node.rb +24 -0
  8. data/lib/rubocop/ast/node/class_node.rb +31 -0
  9. data/lib/rubocop/ast/node/module_node.rb +24 -0
  10. data/lib/rubocop/ast/node/range_node.rb +7 -0
  11. data/lib/rubocop/ast/node/resbody_node.rb +12 -0
  12. data/lib/rubocop/ast/node/self_class_node.rb +24 -0
  13. data/lib/rubocop/cli.rb +40 -4
  14. data/lib/rubocop/config.rb +9 -7
  15. data/lib/rubocop/config_loader.rb +48 -7
  16. data/lib/rubocop/config_loader_resolver.rb +5 -4
  17. data/lib/rubocop/cop/commissioner.rb +24 -0
  18. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +18 -6
  19. data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +12 -14
  20. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +9 -20
  21. data/lib/rubocop/cop/layout/align_arguments.rb +93 -0
  22. data/lib/rubocop/cop/layout/align_parameters.rb +57 -33
  23. data/lib/rubocop/cop/layout/class_structure.rb +5 -5
  24. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -8
  25. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +3 -6
  26. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +1 -2
  27. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -0
  28. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +292 -0
  29. data/lib/rubocop/cop/layout/{first_parameter_indentation.rb → indent_first_argument.rb} +11 -12
  30. data/lib/rubocop/cop/layout/{indent_array.rb → indent_first_array_element.rb} +2 -2
  31. data/lib/rubocop/cop/layout/{indent_hash.rb → indent_first_hash_element.rb} +2 -2
  32. data/lib/rubocop/cop/layout/indent_first_parameter.rb +96 -0
  33. data/lib/rubocop/cop/layout/indentation_width.rb +4 -16
  34. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -4
  35. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -16
  36. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -2
  37. data/lib/rubocop/cop/lint/duplicate_methods.rb +6 -8
  38. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +4 -8
  39. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +157 -0
  40. data/lib/rubocop/cop/lint/inherit_exception.rb +3 -4
  41. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  42. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -5
  43. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +25 -5
  44. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -6
  45. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -2
  46. data/lib/rubocop/cop/message_annotator.rb +1 -0
  47. data/lib/rubocop/cop/metrics/line_length.rb +139 -28
  48. data/lib/rubocop/cop/metrics/perceived_complexity.rb +3 -4
  49. data/lib/rubocop/cop/mixin/check_line_breakable.rb +190 -0
  50. data/lib/rubocop/cop/mixin/{array_hash_indentation.rb → multiline_element_indentation.rb} +3 -2
  51. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -7
  52. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +33 -4
  53. data/lib/rubocop/cop/rails/active_record_override.rb +23 -8
  54. data/lib/rubocop/cop/rails/delegate.rb +5 -8
  55. data/lib/rubocop/cop/rails/environment_comparison.rb +5 -3
  56. data/lib/rubocop/cop/rails/find_each.rb +1 -1
  57. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
  58. data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
  59. data/lib/rubocop/cop/rails/skips_model_validations.rb +6 -7
  60. data/lib/rubocop/cop/rails/time_zone.rb +3 -10
  61. data/lib/rubocop/cop/rails/validation.rb +3 -0
  62. data/lib/rubocop/cop/registry.rb +3 -3
  63. data/lib/rubocop/cop/style/alias.rb +13 -7
  64. data/lib/rubocop/cop/style/block_delimiters.rb +20 -0
  65. data/lib/rubocop/cop/style/class_and_module_children.rb +19 -21
  66. data/lib/rubocop/cop/style/class_methods.rb +16 -24
  67. data/lib/rubocop/cop/style/conditional_assignment.rb +20 -49
  68. data/lib/rubocop/cop/style/documentation.rb +3 -7
  69. data/lib/rubocop/cop/style/format_string.rb +18 -21
  70. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  71. data/lib/rubocop/cop/style/inverse_methods.rb +4 -0
  72. data/lib/rubocop/cop/style/lambda.rb +12 -8
  73. data/lib/rubocop/cop/style/mixin_grouping.rb +8 -10
  74. data/lib/rubocop/cop/style/module_function.rb +2 -3
  75. data/lib/rubocop/cop/style/next.rb +10 -14
  76. data/lib/rubocop/cop/style/one_line_conditional.rb +5 -3
  77. data/lib/rubocop/cop/style/optional_arguments.rb +1 -4
  78. data/lib/rubocop/cop/style/random_with_offset.rb +44 -47
  79. data/lib/rubocop/cop/style/redundant_return.rb +6 -14
  80. data/lib/rubocop/cop/style/redundant_sort_by.rb +1 -1
  81. data/lib/rubocop/cop/style/safe_navigation.rb +3 -0
  82. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -3
  83. data/lib/rubocop/cop/style/symbol_proc.rb +20 -40
  84. data/lib/rubocop/cop/style/unless_else.rb +1 -2
  85. data/lib/rubocop/cop/style/yoda_condition.rb +8 -7
  86. data/lib/rubocop/cop/util.rb +2 -4
  87. data/lib/rubocop/file_finder.rb +5 -10
  88. data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -0
  89. data/lib/rubocop/node_pattern.rb +304 -170
  90. data/lib/rubocop/options.rb +4 -1
  91. data/lib/rubocop/rspec/shared_contexts.rb +3 -0
  92. data/lib/rubocop/version.rb +1 -1
  93. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  94. metadata +26 -50
  95. data/lib/rubocop/cop/performance/caller.rb +0 -69
  96. data/lib/rubocop/cop/performance/case_when_splat.rb +0 -177
  97. data/lib/rubocop/cop/performance/casecmp.rb +0 -108
  98. data/lib/rubocop/cop/performance/chain_array_allocation.rb +0 -78
  99. data/lib/rubocop/cop/performance/compare_with_block.rb +0 -122
  100. data/lib/rubocop/cop/performance/count.rb +0 -102
  101. data/lib/rubocop/cop/performance/detect.rb +0 -110
  102. data/lib/rubocop/cop/performance/double_start_end_with.rb +0 -94
  103. data/lib/rubocop/cop/performance/end_with.rb +0 -56
  104. data/lib/rubocop/cop/performance/fixed_size.rb +0 -97
  105. data/lib/rubocop/cop/performance/flat_map.rb +0 -78
  106. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +0 -99
  107. data/lib/rubocop/cop/performance/open_struct.rb +0 -46
  108. data/lib/rubocop/cop/performance/range_include.rb +0 -50
  109. data/lib/rubocop/cop/performance/redundant_block_call.rb +0 -93
  110. data/lib/rubocop/cop/performance/redundant_match.rb +0 -56
  111. data/lib/rubocop/cop/performance/redundant_merge.rb +0 -183
  112. data/lib/rubocop/cop/performance/regexp_match.rb +0 -265
  113. data/lib/rubocop/cop/performance/reverse_each.rb +0 -42
  114. data/lib/rubocop/cop/performance/size.rb +0 -77
  115. data/lib/rubocop/cop/performance/start_with.rb +0 -59
  116. data/lib/rubocop/cop/performance/string_replacement.rb +0 -173
  117. data/lib/rubocop/cop/performance/times_map.rb +0 -71
  118. data/lib/rubocop/cop/performance/unfreeze_string.rb +0 -50
  119. data/lib/rubocop/cop/performance/uri_default_parser.rb +0 -47
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop is used to identify usages of `reverse.each` and
7
- # change them to use `reverse_each` instead.
8
- #
9
- # @example
10
- # # bad
11
- # [].reverse.each
12
- #
13
- # # good
14
- # [].reverse_each
15
- class ReverseEach < Cop
16
- include RangeHelp
17
-
18
- MSG = 'Use `reverse_each` instead of `reverse.each`.'.freeze
19
- UNDERSCORE = '_'.freeze
20
-
21
- def_node_matcher :reverse_each?, <<-MATCHER
22
- (send $(send _ :reverse) :each)
23
- MATCHER
24
-
25
- def on_send(node)
26
- reverse_each?(node) do |receiver|
27
- location_of_reverse = receiver.loc.selector.begin_pos
28
- end_location = node.loc.selector.end_pos
29
-
30
- range = range_between(location_of_reverse, end_location)
31
-
32
- add_offense(node, location: range)
33
- end
34
- end
35
-
36
- def autocorrect(node)
37
- ->(corrector) { corrector.replace(node.loc.dot, UNDERSCORE) }
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop is used to identify usages of `count` on an
7
- # `Array` and `Hash` and change them to `size`.
8
- #
9
- # @example
10
- # # bad
11
- # [1, 2, 3].count
12
- #
13
- # # bad
14
- # {a: 1, b: 2, c: 3}.count
15
- #
16
- # # good
17
- # [1, 2, 3].size
18
- #
19
- # # good
20
- # {a: 1, b: 2, c: 3}.size
21
- #
22
- # # good
23
- # [1, 2, 3].count { |e| e > 2 }
24
- # TODO: Add advanced detection of variables that could
25
- # have been assigned to an array or a hash.
26
- class Size < Cop
27
- MSG = 'Use `size` instead of `count`.'.freeze
28
-
29
- def on_send(node)
30
- return unless eligible_node?(node)
31
-
32
- add_offense(node, location: :selector)
33
- end
34
-
35
- def autocorrect(node)
36
- ->(corrector) { corrector.replace(node.loc.selector, 'size') }
37
- end
38
-
39
- private
40
-
41
- def eligible_node?(node)
42
- return false unless node.method?(:count) && !node.arguments?
43
-
44
- eligible_receiver?(node.receiver) && !allowed_parent?(node.parent)
45
- end
46
-
47
- def eligible_receiver?(node)
48
- return false unless node
49
-
50
- array?(node) || hash?(node)
51
- end
52
-
53
- def allowed_parent?(node)
54
- node && node.block_type?
55
- end
56
-
57
- def array?(node)
58
- return true if node.array_type?
59
- return false unless node.send_type?
60
-
61
- _, constant = *node.receiver
62
-
63
- constant == :Array || node.method_name == :to_a
64
- end
65
-
66
- def hash?(node)
67
- return true if node.hash_type?
68
- return false unless node.send_type?
69
-
70
- _, constant = *node.receiver
71
-
72
- constant == :Hash || node.method_name == :to_h
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop identifies unnecessary use of a regex where
7
- # `String#start_with?` would suffice.
8
- #
9
- # @example
10
- # # bad
11
- # 'abc'.match?(/\Aab/)
12
- # 'abc' =~ /\Aab/
13
- # 'abc'.match(/\Aab/)
14
- #
15
- # # good
16
- # 'abc'.start_with?('ab')
17
- class StartWith < Cop
18
- MSG = 'Use `String#start_with?` instead of a regex match anchored to ' \
19
- 'the beginning of the string.'.freeze
20
- SINGLE_QUOTE = "'".freeze
21
-
22
- def_node_matcher :redundant_regex?, <<-PATTERN
23
- {(send $!nil? {:match :=~ :match?} (regexp (str $#literal_at_start?) (regopt)))
24
- (send (regexp (str $#literal_at_start?) (regopt)) {:match :=~} $_)}
25
- PATTERN
26
-
27
- def literal_at_start?(regex_str)
28
- # is this regexp 'literal' in the sense of only matching literal
29
- # chars, rather than using metachars like `.` and `*` and so on?
30
- # also, is it anchored at the start of the string?
31
- # (tricky: \s, \d, and so on are metacharacters, but other characters
32
- # escaped with a slash are just literals. LITERAL_REGEX takes all
33
- # that into account.)
34
- regex_str =~ /\A\\A(?:#{LITERAL_REGEX})+\z/
35
- end
36
-
37
- def on_send(node)
38
- return unless redundant_regex?(node)
39
-
40
- add_offense(node)
41
- end
42
-
43
- def autocorrect(node)
44
- redundant_regex?(node) do |receiver, regex_str|
45
- receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
46
- regex_str = regex_str[2..-1] # drop \A anchor
47
- regex_str = interpret_string_escapes(regex_str)
48
-
49
- lambda do |corrector|
50
- new_source = receiver.source + '.start_with?(' +
51
- to_string_literal(regex_str) + ')'
52
- corrector.replace(node.source_range, new_source)
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,173 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop identifies places where `gsub` can be replaced by
7
- # `tr` or `delete`.
8
- #
9
- # @example
10
- # # bad
11
- # 'abc'.gsub('b', 'd')
12
- # 'abc'.gsub('a', '')
13
- # 'abc'.gsub(/a/, 'd')
14
- # 'abc'.gsub!('a', 'd')
15
- #
16
- # # good
17
- # 'abc'.gsub(/.*/, 'a')
18
- # 'abc'.gsub(/a+/, 'd')
19
- # 'abc'.tr('b', 'd')
20
- # 'a b c'.delete(' ')
21
- class StringReplacement < Cop
22
- include RangeHelp
23
-
24
- MSG = 'Use `%<prefer>s` instead of `%<current>s`.'.freeze
25
- DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze
26
- DELETE = 'delete'.freeze
27
- TR = 'tr'.freeze
28
- BANG = '!'.freeze
29
- SINGLE_QUOTE = "'".freeze
30
-
31
- def_node_matcher :string_replacement?, <<-PATTERN
32
- (send _ {:gsub :gsub!}
33
- ${regexp str (send (const nil? :Regexp) {:new :compile} _)}
34
- $str)
35
- PATTERN
36
-
37
- def on_send(node)
38
- string_replacement?(node) do |first_param, second_param|
39
- return if accept_second_param?(second_param)
40
- return if accept_first_param?(first_param)
41
-
42
- offense(node, first_param, second_param)
43
- end
44
- end
45
-
46
- def autocorrect(node)
47
- _string, _method, first_param, second_param = *node
48
- first_source, = first_source(first_param)
49
- second_source, = *second_param
50
-
51
- unless first_param.str_type?
52
- first_source = interpret_string_escapes(first_source)
53
- end
54
-
55
- replacement_method =
56
- replacement_method(node, first_source, second_source)
57
-
58
- replace_method(node, first_source, second_source, first_param,
59
- replacement_method)
60
- end
61
-
62
- def replace_method(node, first, second, first_param, replacement)
63
- lambda do |corrector|
64
- corrector.replace(node.loc.selector, replacement)
65
- unless first_param.str_type?
66
- corrector.replace(first_param.source_range,
67
- to_string_literal(first))
68
- end
69
-
70
- if second.empty? && first.length == 1
71
- remove_second_param(corrector, node, first_param)
72
- end
73
- end
74
- end
75
-
76
- private
77
-
78
- def accept_second_param?(second_param)
79
- second_source, = *second_param
80
- second_source.length > 1
81
- end
82
-
83
- def accept_first_param?(first_param)
84
- first_source, options = first_source(first_param)
85
- return true if first_source.nil?
86
-
87
- unless first_param.str_type?
88
- return true if options
89
- return true unless first_source =~ DETERMINISTIC_REGEX
90
-
91
- # This must be done after checking DETERMINISTIC_REGEX
92
- # Otherwise things like \s will trip us up
93
- first_source = interpret_string_escapes(first_source)
94
- end
95
-
96
- first_source.length != 1
97
- end
98
-
99
- def offense(node, first_param, second_param)
100
- first_source, = first_source(first_param)
101
- unless first_param.str_type?
102
- first_source = interpret_string_escapes(first_source)
103
- end
104
- second_source, = *second_param
105
- message = message(node, first_source, second_source)
106
-
107
- add_offense(node, location: range(node), message: message)
108
- end
109
-
110
- def first_source(first_param)
111
- case first_param.type
112
- when :regexp
113
- source_from_regex_literal(first_param)
114
- when :send
115
- source_from_regex_constructor(first_param)
116
- when :str
117
- first_param.children.first
118
- end
119
- end
120
-
121
- def source_from_regex_literal(node)
122
- regex, options = *node
123
- source, = *regex
124
- options, = *options
125
- [source, options]
126
- end
127
-
128
- def source_from_regex_constructor(node)
129
- _const, _init, regex = *node
130
- case regex.type
131
- when :regexp
132
- source_from_regex_literal(regex)
133
- when :str
134
- source, = *regex
135
- source
136
- end
137
- end
138
-
139
- def range(node)
140
- range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
141
- end
142
-
143
- def replacement_method(node, first_source, second_source)
144
- replacement = if second_source.empty? && first_source.length == 1
145
- DELETE
146
- else
147
- TR
148
- end
149
-
150
- "#{replacement}#{BANG if node.bang_method?}"
151
- end
152
-
153
- def message(node, first_source, second_source)
154
- replacement_method =
155
- replacement_method(node, first_source, second_source)
156
-
157
- format(MSG, prefer: replacement_method, current: node.method_name)
158
- end
159
-
160
- def method_suffix(node)
161
- node.loc.end ? node.loc.end.source : ''
162
- end
163
-
164
- def remove_second_param(corrector, node, first_param)
165
- end_range = range_between(first_param.source_range.end_pos,
166
- node.source_range.end_pos)
167
-
168
- corrector.replace(end_range, method_suffix(node))
169
- end
170
- end
171
- end
172
- end
173
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop checks for .times.map calls.
7
- # In most cases such calls can be replaced
8
- # with an explicit array creation.
9
- #
10
- # @example
11
- # # bad
12
- # 9.times.map do |i|
13
- # i.to_s
14
- # end
15
- #
16
- # # good
17
- # Array.new(9) do |i|
18
- # i.to_s
19
- # end
20
- class TimesMap < Cop
21
- MESSAGE = 'Use `Array.new(%<count>s)` with a block ' \
22
- 'instead of `.times.%<map_or_collect>s`'.freeze
23
- MESSAGE_ONLY_IF = 'only if `%<count>s` is always 0 or more'.freeze
24
-
25
- def on_send(node)
26
- check(node)
27
- end
28
-
29
- def on_block(node)
30
- check(node)
31
- end
32
-
33
- def autocorrect(node)
34
- map_or_collect, count = times_map_call(node)
35
-
36
- replacement =
37
- "Array.new(#{count.source}" \
38
- "#{map_or_collect.arguments.map { |arg| ", #{arg.source}" }.join})"
39
-
40
- lambda do |corrector|
41
- corrector.replace(map_or_collect.loc.expression, replacement)
42
- end
43
- end
44
-
45
- private
46
-
47
- def check(node)
48
- times_map_call(node) do |map_or_collect, count|
49
- add_offense(node, message: message(map_or_collect, count))
50
- end
51
- end
52
-
53
- def message(map_or_collect, count)
54
- template = if count.literal?
55
- MESSAGE + '.'
56
- else
57
- "#{MESSAGE} #{MESSAGE_ONLY_IF}."
58
- end
59
- format(template,
60
- count: count.source,
61
- map_or_collect: map_or_collect.method_name)
62
- end
63
-
64
- def_node_matcher :times_map_call, <<-PATTERN
65
- {(block $(send (send $!nil? :times) {:map :collect}) ...)
66
- $(send (send $!nil? :times) {:map :collect} (block_pass ...))}
67
- PATTERN
68
- end
69
- end
70
- end
71
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # In Ruby 2.3 or later, use unary plus operator to unfreeze a string
7
- # literal instead of `String#dup` and `String.new`.
8
- # Unary plus operator is faster than `String#dup`.
9
- #
10
- # Note: `String.new` (without operator) is not exactly the same as `+''`.
11
- # These differ in encoding. `String.new.encoding` is always `ASCII-8BIT`.
12
- # However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`).
13
- # So, if you expect `ASCII-8BIT` encoding, disable this cop.
14
- #
15
- # @example
16
- # # bad
17
- # ''.dup
18
- # "something".dup
19
- # String.new
20
- # String.new('')
21
- # String.new('something')
22
- #
23
- # # good
24
- # +'something'
25
- # +''
26
- class UnfreezeString < Cop
27
- extend TargetRubyVersion
28
-
29
- minimum_target_ruby_version 2.3
30
-
31
- MSG = 'Use unary plus to get an unfrozen string literal.'.freeze
32
-
33
- def_node_matcher :dup_string?, <<-PATTERN
34
- (send {str dstr} :dup)
35
- PATTERN
36
-
37
- def_node_matcher :string_new?, <<-PATTERN
38
- {
39
- (send (const nil? :String) :new {str dstr})
40
- (send (const nil? :String) :new)
41
- }
42
- PATTERN
43
-
44
- def on_send(node)
45
- add_offense(node) if dup_string?(node) || string_new?(node)
46
- end
47
- end
48
- end
49
- end
50
- end