rubocop 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +34 -4
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  6. data/lib/rubocop/config.rb +2 -2
  7. data/lib/rubocop/config_loader.rb +7 -14
  8. data/lib/rubocop/config_store.rb +12 -1
  9. data/lib/rubocop/cop/base.rb +1 -1
  10. data/lib/rubocop/cop/generator.rb +1 -3
  11. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  12. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  14. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  15. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  16. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  17. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  18. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  19. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  20. data/lib/rubocop/cop/lint/symbol_conversion.rb +102 -0
  21. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  22. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  23. data/lib/rubocop/cop/mixin/comments_help.rb +0 -1
  24. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  25. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  26. data/lib/rubocop/cop/severity.rb +3 -3
  27. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  28. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  29. data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
  30. data/lib/rubocop/cop/style/float_division.rb +3 -0
  31. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  32. data/lib/rubocop/cop/style/if_inside_else.rb +14 -7
  33. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +96 -0
  34. data/lib/rubocop/cop/style/nil_comparison.rb +1 -0
  35. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  36. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  37. data/lib/rubocop/cop/style/sole_nested_conditional.rb +26 -2
  38. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  39. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  40. data/lib/rubocop/magic_comment.rb +30 -1
  41. data/lib/rubocop/options.rb +1 -1
  42. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  43. data/lib/rubocop/runner.rb +1 -0
  44. data/lib/rubocop/version.rb +2 -2
  45. metadata +12 -3
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for redundant `if` with boolean literal branches.
7
+ # It checks only conditions to return boolean value (`true` or `false`) for safe detection.
8
+ # The conditions to be checked are comparison methods, predicate methods, and double negative.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # if foo == bar
13
+ # true
14
+ # else
15
+ # false
16
+ # end
17
+ #
18
+ # # bad
19
+ # foo == bar ? true : false
20
+ #
21
+ # # good
22
+ # foo == bar
23
+ #
24
+ class IfWithBooleanLiteralBranches < Base
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Remove redundant %<keyword>s with boolean literal branches.'
28
+
29
+ def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
30
+ (if #return_boolean_value? {(true) (false) | (false) (true)})
31
+ PATTERN
32
+ def_node_matcher :double_negative?, '(send (send _ :!) :!)'
33
+
34
+ def on_if(node)
35
+ return unless if_with_boolean_literal_branches?(node)
36
+
37
+ condition = node.condition
38
+ range, keyword = if node.ternary?
39
+ range = condition.source_range.end.join(node.source_range.end)
40
+
41
+ [range, 'ternary operator']
42
+ else
43
+ keyword = node.loc.keyword
44
+
45
+ [keyword, "`#{keyword.source}`"]
46
+ end
47
+
48
+ add_offense(range, message: format(MSG, keyword: keyword)) do |corrector|
49
+ replacement = replacement_condition(node, condition)
50
+
51
+ corrector.replace(node, replacement)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def return_boolean_value?(condition)
58
+ if condition.begin_type?
59
+ return_boolean_value?(condition.children.first)
60
+ elsif condition.or_type?
61
+ return_boolean_value?(condition.lhs) && return_boolean_value?(condition.rhs)
62
+ elsif condition.and_type?
63
+ return_boolean_value?(condition.rhs)
64
+ else
65
+ assume_boolean_value?(condition)
66
+ end
67
+ end
68
+
69
+ def assume_boolean_value?(condition)
70
+ return false unless condition.send_type?
71
+
72
+ condition.comparison_method? || condition.predicate_method? || double_negative?(condition)
73
+ end
74
+
75
+ def replacement_condition(node, condition)
76
+ bang = '!' if opposite_condition?(node)
77
+
78
+ if bang && require_parentheses?(condition)
79
+ "#{bang}(#{condition.source})"
80
+ else
81
+ "#{bang}#{condition.source}"
82
+ end
83
+ end
84
+
85
+ def opposite_condition?(node)
86
+ !node.unless? && node.if_branch.false_type? || node.unless? && node.if_branch.true_type?
87
+ end
88
+
89
+ def require_parentheses?(condition)
90
+ condition.and_type? || condition.or_type? ||
91
+ condition.send_type? && condition.comparison_method?
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -50,6 +50,7 @@ module RuboCop
50
50
  end
51
51
 
52
52
  corrector.replace(node, new_code)
53
+ corrector.wrap(node, '(', ')') if node.parent&.method?(:!)
53
54
  end
54
55
  end
55
56
  end
@@ -8,6 +8,9 @@ module RuboCop
8
8
  # With `IncludeSemanticChanges` set to `false` by default, this cop
9
9
  # does not report offenses for `!x.nil?` and does no changes that might
10
10
  # change behavior.
11
+ # Also `IncludeSemanticChanges` set to `false` with `EnforcedStyle: comparison` of
12
+ # `Style/NilComparison` cop, this cop does not report offenses for `x != nil` and
13
+ # does no changes to `!x.nil?` style.
11
14
  #
12
15
  # With `IncludeSemanticChanges` set to `true`, this cop reports offenses
13
16
  # for `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which
@@ -41,6 +44,9 @@ module RuboCop
41
44
  class NonNilCheck < Base
42
45
  extend AutoCorrector
43
46
 
47
+ MSG_FOR_REPLACEMENT = 'Prefer `%<prefer>s` over `%<current>s`.'
48
+ MSG_FOR_REDUNDANCY = 'Explicit non-nil checks are usually redundant.'
49
+
44
50
  RESTRICT_ON_SEND = %i[!= nil? !].freeze
45
51
 
46
52
  def_node_matcher :not_equal_to_nil?, '(send _ :!= nil)'
@@ -49,11 +55,12 @@ module RuboCop
49
55
  def_node_matcher :not_and_nil_check?, '(send (send _ :nil?) :!)'
50
56
 
51
57
  def on_send(node)
52
- return if ignored_node?(node)
53
- return unless (offense_node = find_offense_node(node))
58
+ return if ignored_node?(node) ||
59
+ !include_semantic_changes? && nil_comparison_style == 'comparison'
60
+ return unless register_offense?(node)
54
61
 
55
62
  message = message(node)
56
- add_offense(offense_node, message: message) do |corrector|
63
+ add_offense(node, message: message) do |corrector|
57
64
  autocorrect(corrector, node)
58
65
  end
59
66
  end
@@ -73,13 +80,9 @@ module RuboCop
73
80
 
74
81
  private
75
82
 
76
- def find_offense_node(node)
77
- if not_equal_to_nil?(node)
78
- node.loc.selector
79
- elsif include_semantic_changes? &&
80
- (not_and_nil_check?(node) || unless_and_nil_check?(node))
81
- node
82
- end
83
+ def register_offense?(node)
84
+ not_equal_to_nil?(node) ||
85
+ include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node))
83
86
  end
84
87
 
85
88
  def autocorrect(corrector, node)
@@ -101,10 +104,11 @@ module RuboCop
101
104
  end
102
105
 
103
106
  def message(node)
104
- if node.method?(:!=)
105
- 'Prefer `!expression.nil?` over `expression != nil`.'
107
+ if node.method?(:!=) && !include_semantic_changes?
108
+ prefer = "!#{node.receiver.source}.nil?"
109
+ format(MSG_FOR_REPLACEMENT, prefer: prefer, current: node.source)
106
110
  else
107
- 'Explicit non-nil checks are usually redundant.'
111
+ MSG_FOR_REDUNDANCY
108
112
  end
109
113
  end
110
114
 
@@ -138,6 +142,12 @@ module RuboCop
138
142
  corrector.replace(node.parent.loc.keyword, 'if')
139
143
  corrector.replace(node, receiver.source)
140
144
  end
145
+
146
+ def nil_comparison_style
147
+ nil_comparison_conf = config.for_cop('Style/NilComparison')
148
+
149
+ nil_comparison_conf['Enabled'] && nil_comparison_conf['EnforcedStyle']
150
+ end
141
151
  end
142
152
  end
143
153
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # Endless methods added in Ruby 3.0 are also accepted by this cop.
10
10
  #
11
- # If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow` or
11
+ # If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow_single_line` or
12
12
  # `allow_always`, single-line methods will be auto-corrected to endless
13
13
  # methods if there is only one statement in the body.
14
14
  #
@@ -80,8 +80,11 @@ module RuboCop
80
80
  end
81
81
 
82
82
  def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
83
+ outer_condition = node.condition
84
+ correct_outer_condition(corrector, outer_condition)
85
+
83
86
  condition = if_branch.condition
84
- corrector.insert_after(node.condition, replacement_condition(and_operator, condition))
87
+ corrector.insert_after(outer_condition, replacement_condition(and_operator, condition))
85
88
 
86
89
  range = range_between(if_branch.loc.keyword.begin_pos, condition.source_range.end_pos)
87
90
  corrector.remove(range_with_surrounding_space(range: range, newlines: false))
@@ -106,8 +109,29 @@ module RuboCop
106
109
  corrector.insert_before(node.loc.keyword, comment_text) unless comments.empty?
107
110
  end
108
111
 
112
+ def correct_outer_condition(corrector, condition)
113
+ return unless requrie_parentheses?(condition)
114
+
115
+ range = range_between(
116
+ condition.loc.selector.end_pos, condition.first_argument.source_range.begin_pos
117
+ )
118
+
119
+ corrector.replace(range, '(')
120
+ corrector.insert_after(condition.last_argument.source_range, ')')
121
+ end
122
+
123
+ def requrie_parentheses?(condition)
124
+ condition.send_type? && !condition.arguments.empty? && !condition.parenthesized?
125
+ end
126
+
127
+ def arguments_range(node)
128
+ range_between(
129
+ node.first_argument.source_range.begin_pos, node.last_argument.source_range.end_pos
130
+ )
131
+ end
132
+
109
133
  def wrap_condition?(node)
110
- node.or_type? ||
134
+ node.and_type? || node.or_type? ||
111
135
  (node.send_type? && node.arguments.any? && !node.parenthesized?)
112
136
  end
113
137
 
@@ -120,7 +120,7 @@ module RuboCop
120
120
  if condition.begin_type?
121
121
  condition.to_a.any? { |x| complex_condition?(x) }
122
122
  else
123
- non_complex_expression?(condition) ? false : true
123
+ !non_complex_expression?(condition)
124
124
  end
125
125
  end
126
126
 
@@ -23,6 +23,7 @@ module RuboCop
23
23
 
24
24
  def minimum_severity_to_fail
25
25
  @minimum_severity_to_fail ||= begin
26
+ # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
26
27
  name = options.fetch(:fail_level, :refactor)
27
28
  RuboCop::Cop::Severity.new(name)
28
29
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  end
28
28
 
29
29
  def any?
30
- frozen_string_literal_specified? || encoding_specified?
30
+ frozen_string_literal_specified? || encoding_specified? || shareable_constant_value_specified?
31
31
  end
32
32
 
33
33
  # Does the magic comment enable the frozen string literal feature.
@@ -46,6 +46,10 @@ module RuboCop
46
46
  [true, false].include?(frozen_string_literal)
47
47
  end
48
48
 
49
+ def valid_shareable_constant_value?
50
+ %w[none literal experimental_everything experimental_copy].include?(shareable_constant_values)
51
+ end
52
+
49
53
  # Was a magic comment for the frozen string literal found?
50
54
  #
51
55
  # @return [Boolean]
@@ -53,6 +57,13 @@ module RuboCop
53
57
  specified?(frozen_string_literal)
54
58
  end
55
59
 
60
+ # Was a shareable_constant_value specified?
61
+ #
62
+ # @return [Boolean]
63
+ def shareable_constant_value_specified?
64
+ specified?(shareable_constant_value)
65
+ end
66
+
56
67
  # Expose the `frozen_string_literal` value coerced to a boolean if possible.
57
68
  #
58
69
  # @return [Boolean] if value is `true` or `false`
@@ -69,6 +80,13 @@ module RuboCop
69
80
  end
70
81
  end
71
82
 
83
+ # Expose the `shareable_constant_value` value coerced to a boolean if possible.
84
+ #
85
+ # @return [String] for shareable_constant_value config
86
+ def shareable_constant_value
87
+ extract_shareable_constant_value
88
+ end
89
+
72
90
  def encoding_specified?
73
91
  specified?(encoding)
74
92
  end
@@ -146,6 +164,10 @@ module RuboCop
146
164
  def extract_frozen_string_literal
147
165
  match('frozen[_-]string[_-]literal')
148
166
  end
167
+
168
+ def extract_shareable_constant_value
169
+ match('shareable[_-]constant[_-]values')
170
+ end
149
171
  end
150
172
 
151
173
  # Wrapper for Vim style magic comments.
@@ -176,6 +198,9 @@ module RuboCop
176
198
 
177
199
  # Vim comments cannot specify frozen string literal behavior.
178
200
  def frozen_string_literal; end
201
+
202
+ # Vim comments cannot specify shareable constant values behavior.
203
+ def shareable_constant_value; end
179
204
  end
180
205
 
181
206
  # Wrapper for regular magic comments not bound to an editor.
@@ -209,6 +234,10 @@ module RuboCop
209
234
  def extract_frozen_string_literal
210
235
  extract(/\A\s*#\s*frozen[_-]string[_-]literal:\s*(#{TOKEN})\s*\z/io)
211
236
  end
237
+
238
+ def extract_shareable_constant_value
239
+ extract(/\A\s*#\s*shareable[_-]constant[_-]value:\s*(#{TOKEN})\s*\z/io)
240
+ end
212
241
  end
213
242
  end
214
243
  end
@@ -470,7 +470,7 @@ module RuboCop
470
470
  'This option applies to the previously',
471
471
  'specified --format, or the default format',
472
472
  'if no format is specified.'],
473
- fail_level: ['Minimum severity (A/R/C/W/E/F) for exit',
473
+ fail_level: ['Minimum severity (A/I/R/C/W/E/F) for exit',
474
474
  'with error code.'],
475
475
  display_time: 'Display elapsed time in seconds.',
476
476
  display_only_failed: ['Only output offense messages. Omit passing',
@@ -111,9 +111,12 @@ module RuboCop
111
111
  source
112
112
  end
113
113
 
114
- def expect_offense(source, file = nil, severity: nil, **replacements)
114
+ def expect_offense(source, file = nil, severity: nil, chomp: false, **replacements)
115
115
  expected_annotations = parse_annotations(source, **replacements)
116
- @processed_source = parse_processed_source(expected_annotations.plain_source, file)
116
+ source = expected_annotations.plain_source
117
+ source = source.chomp if chomp
118
+
119
+ @processed_source = parse_processed_source(source, file)
117
120
  @offenses = _investigate(cop, @processed_source)
118
121
  actual_annotations =
119
122
  expected_annotations.with_offense_annotations(@offenses)
@@ -390,6 +390,7 @@ module RuboCop
390
390
 
391
391
  def minimum_severity_to_fail
392
392
  @minimum_severity_to_fail ||= begin
393
+ # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
393
394
  name = @options[:fail_level] || :refactor
394
395
  RuboCop::Cop::Severity.new(name)
395
396
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.8.1'
6
+ STRING = '1.9.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -37,7 +37,7 @@ module RuboCop
37
37
  features = Util.silence_warnings do
38
38
  # Suppress any config issues when loading the config (ie. deprecations,
39
39
  # pending cops, etc.).
40
- env.config_store.for_pwd.loaded_features.sort
40
+ env.config_store.unvalidated.for_pwd.loaded_features.sort
41
41
  end
42
42
 
43
43
  features.map do |loaded_feature|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-01-11 00:00:00.000000000 Z
13
+ date: 2021-01-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -252,10 +252,14 @@ files:
252
252
  - lib/rubocop/cop/generator/require_file_injector.rb
253
253
  - lib/rubocop/cop/ignored_node.rb
254
254
  - lib/rubocop/cop/internal_affairs.rb
255
+ - lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb
256
+ - lib/rubocop/cop/internal_affairs/example_description.rb
255
257
  - lib/rubocop/cop/internal_affairs/method_name_equal.rb
256
258
  - lib/rubocop/cop/internal_affairs/node_destructuring.rb
257
259
  - lib/rubocop/cop/internal_affairs/node_type_predicate.rb
258
260
  - lib/rubocop/cop/internal_affairs/offense_location_keyword.rb
261
+ - lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb
262
+ - lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb
259
263
  - lib/rubocop/cop/internal_affairs/redundant_location_argument.rb
260
264
  - lib/rubocop/cop/internal_affairs/redundant_message_argument.rb
261
265
  - lib/rubocop/cop/internal_affairs/style_detected_api_use.rb
@@ -417,6 +421,8 @@ files:
417
421
  - lib/rubocop/cop/lint/non_deterministic_require_order.rb
418
422
  - lib/rubocop/cop/lint/non_local_exit_from_iterator.rb
419
423
  - lib/rubocop/cop/lint/number_conversion.rb
424
+ - lib/rubocop/cop/lint/numbered_parameter_assignment.rb
425
+ - lib/rubocop/cop/lint/or_assignment_to_constant.rb
420
426
  - lib/rubocop/cop/lint/ordered_magic_comments.rb
421
427
  - lib/rubocop/cop/lint/out_of_range_regexp_ref.rb
422
428
  - lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb
@@ -449,11 +455,13 @@ files:
449
455
  - lib/rubocop/cop/lint/shadowing_outer_local_variable.rb
450
456
  - lib/rubocop/cop/lint/struct_new_override.rb
451
457
  - lib/rubocop/cop/lint/suppressed_exception.rb
458
+ - lib/rubocop/cop/lint/symbol_conversion.rb
452
459
  - lib/rubocop/cop/lint/syntax.rb
453
460
  - lib/rubocop/cop/lint/to_enum_arguments.rb
454
461
  - lib/rubocop/cop/lint/to_json.rb
455
462
  - lib/rubocop/cop/lint/top_level_return_with_argument.rb
456
463
  - lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb
464
+ - lib/rubocop/cop/lint/triple_quotes.rb
457
465
  - lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb
458
466
  - lib/rubocop/cop/lint/unexpected_block_arity.rb
459
467
  - lib/rubocop/cop/lint/unified_integer.rb
@@ -656,6 +664,7 @@ files:
656
664
  - lib/rubocop/cop/style/if_inside_else.rb
657
665
  - lib/rubocop/cop/style/if_unless_modifier.rb
658
666
  - lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb
667
+ - lib/rubocop/cop/style/if_with_boolean_literal_branches.rb
659
668
  - lib/rubocop/cop/style/if_with_semicolon.rb
660
669
  - lib/rubocop/cop/style/implicit_runtime_error.rb
661
670
  - lib/rubocop/cop/style/infinite_loop.rb
@@ -856,7 +865,7 @@ metadata:
856
865
  homepage_uri: https://rubocop.org/
857
866
  changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
858
867
  source_code_uri: https://github.com/rubocop-hq/rubocop/
859
- documentation_uri: https://docs.rubocop.org/rubocop/1.8/
868
+ documentation_uri: https://docs.rubocop.org/rubocop/1.9/
860
869
  bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
861
870
  post_install_message:
862
871
  rdoc_options: []