rubocop 1.7.0 → 1.10.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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -3
  4. data/config/default.yml +137 -31
  5. data/config/obsoletion.yml +4 -0
  6. data/lib/rubocop.rb +14 -1
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +5 -2
  10. data/lib/rubocop/config_loader.rb +7 -14
  11. data/lib/rubocop/config_store.rb +12 -1
  12. data/lib/rubocop/cop/base.rb +2 -1
  13. data/lib/rubocop/cop/exclude_limit.rb +26 -0
  14. data/lib/rubocop/cop/gemspec/date_assignment.rb +56 -0
  15. data/lib/rubocop/cop/generator.rb +1 -3
  16. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  17. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  18. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  19. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  21. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  22. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +38 -18
  23. data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
  24. data/lib/rubocop/cop/layout/line_length.rb +2 -1
  25. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +26 -0
  26. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  27. data/lib/rubocop/cop/layout/space_before_brackets.rb +19 -16
  28. data/lib/rubocop/cop/lint/debugger.rb +58 -14
  29. data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
  30. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +13 -4
  31. data/lib/rubocop/cop/lint/duplicate_require.rb +2 -2
  32. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  33. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  34. data/lib/rubocop/cop/lint/multiple_comparison.rb +4 -4
  35. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  36. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  37. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  38. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  39. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  40. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  41. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +5 -3
  42. data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
  43. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  44. data/lib/rubocop/cop/message_annotator.rb +4 -1
  45. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  46. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  47. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  49. data/lib/rubocop/cop/mixin/code_length.rb +3 -1
  50. data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
  51. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  52. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  53. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
  54. data/lib/rubocop/cop/mixin/preferred_delimiters.rb +2 -2
  55. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  56. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  57. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  58. data/lib/rubocop/cop/naming/variable_number.rb +2 -9
  59. data/lib/rubocop/cop/registry.rb +1 -1
  60. data/lib/rubocop/cop/severity.rb +3 -3
  61. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  62. data/lib/rubocop/cop/style/constant_visibility.rb +27 -0
  63. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  64. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  65. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  66. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  67. data/lib/rubocop/cop/style/eval_with_location.rb +138 -49
  68. data/lib/rubocop/cop/style/explicit_block_argument.rb +11 -1
  69. data/lib/rubocop/cop/style/exponential_notation.rb +6 -7
  70. data/lib/rubocop/cop/style/float_division.rb +3 -0
  71. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  72. data/lib/rubocop/cop/style/hash_conversion.rb +81 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
  75. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
  76. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -0
  77. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  78. data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
  79. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  80. data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
  81. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  82. data/lib/rubocop/cop/style/raise_args.rb +3 -2
  83. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  84. data/lib/rubocop/cop/style/single_line_methods.rb +32 -2
  85. data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
  86. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  87. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  88. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  89. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  90. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  91. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  92. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
  93. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  94. data/lib/rubocop/magic_comment.rb +30 -1
  95. data/lib/rubocop/options.rb +1 -1
  96. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  97. data/lib/rubocop/runner.rb +1 -0
  98. data/lib/rubocop/target_ruby.rb +47 -11
  99. data/lib/rubocop/version.rb +2 -2
  100. metadata +24 -7
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # This cop enforces the use of explicit block argument to avoid writing
7
7
  # block literal that just passes its arguments to another block.
8
8
  #
9
+ # NOTE: This cop only registers an offense if the block args match the
10
+ # yield args exactly.
11
+ #
9
12
  # @example
10
13
  # # bad
11
14
  # def with_tmp_dir
@@ -75,7 +78,14 @@ module RuboCop
75
78
  private
76
79
 
77
80
  def yielding_arguments?(block_args, yield_args)
81
+ yield_args = yield_args.dup.fill(
82
+ nil,
83
+ yield_args.length, block_args.length - yield_args.length
84
+ )
85
+
78
86
  yield_args.zip(block_args).all? do |yield_arg, block_arg|
87
+ next false unless yield_arg && block_arg
88
+
79
89
  block_arg && yield_arg.children.first == block_arg.children.first
80
90
  end
81
91
  end
@@ -87,7 +97,7 @@ module RuboCop
87
97
  replacement = ' &block'
88
98
  replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
89
99
  corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
90
- elsif node.call_type?
100
+ elsif node.call_type? || node.zsuper_type?
91
101
  corrector.insert_after(node, '(&block)')
92
102
  else
93
103
  corrector.insert_after(node.loc.name, '(&block)')
@@ -5,13 +5,12 @@ module RuboCop
5
5
  module Style
6
6
  # This cop enforces consistency when using exponential notation
7
7
  # for numbers in the code (eg 1.2e4). Different styles are supported:
8
- # * `scientific` which enforces a mantissa between 1 (inclusive)
9
- # and 10 (exclusive).
10
- # * `engineering` which enforces the exponent to be a multiple of 3
11
- # and the mantissa to be between 0.1 (inclusive)
12
- # and 10 (exclusive).
13
- # * `integral` which enforces the mantissa to always be a whole number
14
- # without trailing zeroes.
8
+ #
9
+ # * `scientific` which enforces a mantissa between 1 (inclusive) and 10 (exclusive).
10
+ # * `engineering` which enforces the exponent to be a multiple of 3 and the mantissa
11
+ # to be between 0.1 (inclusive) and 10 (exclusive).
12
+ # * `integral` which enforces the mantissa to always be a whole number without
13
+ # trailing zeroes.
15
14
  #
16
15
  # @example EnforcedStyle: scientific (default)
17
16
  # # Enforces a mantissa between 1 (inclusive) and 10 (exclusive).
@@ -7,6 +7,9 @@ module RuboCop
7
7
  # It is recommended to either always use `fdiv` or coerce one side only.
8
8
  # This cop also provides other options for code consistency.
9
9
  #
10
+ # This cop is marked as unsafe, because if operand variable is a string object
11
+ # then `.to_f` will be removed and an error will occur.
12
+ #
10
13
  # @example EnforcedStyle: single_coerce (default)
11
14
  # # bad
12
15
  # a.to_f / b.to_f
@@ -11,6 +11,8 @@ module RuboCop
11
11
  # The reason is that _unannotated_ format is very similar
12
12
  # to encoded URLs or Date/Time formatting strings.
13
13
  #
14
+ # This cop can be customized ignored methods with `IgnoredMethods`.
15
+ #
14
16
  # @example EnforcedStyle: annotated (default)
15
17
  #
16
18
  # # bad
@@ -58,12 +60,18 @@ module RuboCop
58
60
  #
59
61
  # # good
60
62
  # format('%06d', 10)
63
+ #
64
+ # @example IgnoredMethods: [redirect]
65
+ #
66
+ # # good
67
+ # redirect('foo/%{bar_id}')
68
+ #
61
69
  class FormatStringToken < Base
62
70
  include ConfigurableEnforcedStyle
71
+ include IgnoredMethods
63
72
 
64
73
  def on_str(node)
65
- return unless node.value.include?('%')
66
- return if node.each_ancestor(:xstr, :regexp).any?
74
+ return if format_string_token?(node) || use_ignored_method?(node)
67
75
 
68
76
  detections = collect_detections(node)
69
77
  return if detections.empty?
@@ -88,6 +96,14 @@ module RuboCop
88
96
  }
89
97
  PATTERN
90
98
 
99
+ def format_string_token?(node)
100
+ !node.value.include?('%') || node.each_ancestor(:xstr, :regexp).any?
101
+ end
102
+
103
+ def use_ignored_method?(node)
104
+ (parent = node.parent) && parent.send_type? && ignored_method?(parent.method_name)
105
+ end
106
+
91
107
  def unannotated_format?(node, detected_style)
92
108
  detected_style == :unannotated && !format_string_in_typical_context?(node)
93
109
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks the usage of pre-2.1 `Hash[args]` method of converting enumerables and
7
+ # sequences of values to hashes.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Hash[ary]
12
+ #
13
+ # # good
14
+ # ary.to_h
15
+ #
16
+ # # bad
17
+ # Hash[key1, value1, key2, value2]
18
+ #
19
+ # # good
20
+ # {key1 => value1, key2 => value2}
21
+ class HashConversion < Base
22
+ extend AutoCorrector
23
+
24
+ MSG_TO_H = 'Prefer ary.to_h to Hash[ary].'
25
+ MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...].'
26
+ MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...].'
27
+ MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array].'
28
+ RESTRICT_ON_SEND = %i[[]].freeze
29
+
30
+ def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
31
+
32
+ def on_send(node)
33
+ return unless hash_from_array?(node)
34
+
35
+ # There are several cases:
36
+ # If there is one argument:
37
+ # Hash[ary] => ary.to_h
38
+ # Hash[*ary] => don't suggest corrections
39
+ # If there is 0 or 2+ arguments:
40
+ # Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
41
+ # ...but don't suggest correction if there is odd number of them (it is a bug)
42
+ node.arguments.count == 1 ? single_argument(node) : multi_argument(node)
43
+ end
44
+
45
+ private
46
+
47
+ def single_argument(node)
48
+ first_argument = node.first_argument
49
+ if first_argument.hash_type?
50
+ add_offense(node, message: MSG_LITERAL_HASH_ARG) do |corrector|
51
+ corrector.replace(node, "{#{first_argument.source}}")
52
+ end
53
+ elsif first_argument.splat_type?
54
+ add_offense(node, message: MSG_SPLAT)
55
+ else
56
+ add_offense(node, message: MSG_TO_H) do |corrector|
57
+ corrector.replace(node, "#{first_argument.source}.to_h")
58
+ end
59
+ end
60
+ end
61
+
62
+ def multi_argument(node)
63
+ if node.arguments.count.odd?
64
+ add_offense(node, message: MSG_LITERAL_MULTI_ARG)
65
+ else
66
+ add_offense(node, message: MSG_LITERAL_MULTI_ARG) do |corrector|
67
+ corrector.replace(node, args_to_hash(node.arguments))
68
+ end
69
+ end
70
+ end
71
+
72
+ def args_to_hash(args)
73
+ content = args.each_slice(2)
74
+ .map { |arg1, arg2| "#{arg1.source} => #{arg2.source}" }
75
+ .join(', ')
76
+ "{#{content}}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -68,7 +68,8 @@ module RuboCop
68
68
  length = cop_config['MinBranchesCount'] || 3
69
69
  return length if length.is_a?(Integer) && length.positive?
70
70
 
71
- raise 'MinBranchesCount needs to be a positive integer!'
71
+ warn Rainbow('`MinBranchesCount` needs to be a positive integer!').red
72
+ exit!
72
73
  end
73
74
  end
74
75
  end
@@ -82,15 +82,14 @@ module RuboCop
82
82
  def autocorrect(corrector, node)
83
83
  if node.modifier_form?
84
84
  correct_to_elsif_from_modifier_form(corrector, node)
85
- end_range = node.parent.loc.end
86
85
  else
87
86
  correct_to_elsif_from_if_inside_else_form(corrector, node, node.condition)
88
- end_range = node.loc.end
89
87
  end
90
- corrector.remove(range_by_whole_lines(end_range, include_final_newline: true))
91
- corrector.remove(
92
- range_by_whole_lines(node.if_branch.source_range, include_final_newline: true)
93
- )
88
+ corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
89
+ return unless (if_branch = node.if_branch)
90
+
91
+ range = range_by_whole_lines(if_branch.source_range, include_final_newline: true)
92
+ corrector.remove(range)
94
93
  end
95
94
 
96
95
  def correct_to_elsif_from_modifier_form(corrector, node)
@@ -103,13 +102,26 @@ module RuboCop
103
102
 
104
103
  def correct_to_elsif_from_if_inside_else_form(corrector, node, condition)
105
104
  corrector.replace(node.parent.loc.else, "elsif #{condition.source}")
106
- if_condition_range = range_between(
107
- node.loc.keyword.begin_pos, condition.source_range.end_pos
108
- )
109
- corrector.replace(if_condition_range, node.if_branch.source)
105
+ if_condition_range = if_condition_range(node, condition)
106
+ if (if_branch = node.if_branch)
107
+ corrector.replace(if_condition_range, if_branch.source)
108
+ else
109
+ corrector.remove(range_by_whole_lines(if_condition_range, include_final_newline: true))
110
+ end
110
111
  corrector.remove(condition)
111
112
  end
112
113
 
114
+ def find_end_range(node)
115
+ end_range = node.loc.end
116
+ return end_range if end_range
117
+
118
+ find_end_range(node.parent)
119
+ end
120
+
121
+ def if_condition_range(node, condition)
122
+ range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
123
+ end
124
+
113
125
  def allow_if_modifier_in_else_branch?(else_branch)
114
126
  allow_if_modifier? && else_branch&.modifier_form?
115
127
  end
@@ -0,0 +1,120 @@
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
+ # However, auto-correction is unsafe because there is no guarantee that all predicate methods
10
+ # will return boolean value. Those methods can be allowed with `AllowedMethods` config.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # if foo == bar
15
+ # true
16
+ # else
17
+ # false
18
+ # end
19
+ #
20
+ # # bad
21
+ # foo == bar ? true : false
22
+ #
23
+ # # good
24
+ # foo == bar
25
+ #
26
+ # @example AllowedMethods: ['nonzero?']
27
+ # # good
28
+ # num.nonzero? ? true : false
29
+ #
30
+ class IfWithBooleanLiteralBranches < Base
31
+ include AllowedMethods
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Remove redundant %<keyword>s with boolean literal branches.'
35
+ MSG_FOR_ELSIF = 'Use `else` instead of redundant `elsif` with boolean literal branches.'
36
+
37
+ def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
38
+ (if #return_boolean_value? {(true) (false) | (false) (true)})
39
+ PATTERN
40
+ def_node_matcher :double_negative?, '(send (send _ :!) :!)'
41
+
42
+ def on_if(node)
43
+ return unless if_with_boolean_literal_branches?(node)
44
+
45
+ condition = node.condition
46
+ range, keyword = offense_range_with_keyword(node, condition)
47
+
48
+ add_offense(range, message: message(node, keyword)) do |corrector|
49
+ replacement = replacement_condition(node, condition)
50
+
51
+ if node.elsif?
52
+ corrector.insert_before(node, "else\n")
53
+ corrector.replace(node, "#{indent(node.if_branch)}#{replacement}")
54
+ else
55
+ corrector.replace(node, replacement)
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def offense_range_with_keyword(node, condition)
63
+ if node.ternary?
64
+ range = condition.source_range.end.join(node.source_range.end)
65
+
66
+ [range, 'ternary operator']
67
+ else
68
+ keyword = node.loc.keyword
69
+
70
+ [keyword, "`#{keyword.source}`"]
71
+ end
72
+ end
73
+
74
+ def message(node, keyword)
75
+ message_template = node.elsif? ? MSG_FOR_ELSIF : MSG
76
+
77
+ format(message_template, keyword: keyword)
78
+ end
79
+
80
+ def return_boolean_value?(condition)
81
+ if condition.begin_type?
82
+ return_boolean_value?(condition.children.first)
83
+ elsif condition.or_type?
84
+ return_boolean_value?(condition.lhs) && return_boolean_value?(condition.rhs)
85
+ elsif condition.and_type?
86
+ return_boolean_value?(condition.rhs)
87
+ else
88
+ assume_boolean_value?(condition)
89
+ end
90
+ end
91
+
92
+ def assume_boolean_value?(condition)
93
+ return false unless condition.send_type?
94
+ return false if allowed_method?(condition.method_name)
95
+
96
+ condition.comparison_method? || condition.predicate_method? || double_negative?(condition)
97
+ end
98
+
99
+ def replacement_condition(node, condition)
100
+ bang = '!' if opposite_condition?(node)
101
+
102
+ if bang && require_parentheses?(condition)
103
+ "#{bang}(#{condition.source})"
104
+ else
105
+ "#{bang}#{condition.source}"
106
+ end
107
+ end
108
+
109
+ def opposite_condition?(node)
110
+ !node.unless? && node.if_branch.false_type? || node.unless? && node.if_branch.true_type?
111
+ end
112
+
113
+ def require_parentheses?(condition)
114
+ condition.and_type? || condition.or_type? ||
115
+ condition.send_type? && condition.comparison_method?
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -157,6 +157,10 @@ module RuboCop
157
157
  include OmitParentheses
158
158
  extend AutoCorrector
159
159
 
160
+ def self.autocorrect_incompatible_with
161
+ [Style::NestedParenthesizedCalls]
162
+ end
163
+
160
164
  def on_send(node)
161
165
  send(style, node) # call require_parentheses or omit_parentheses
162
166
  end
@@ -19,6 +19,10 @@ module RuboCop
19
19
 
20
20
  MSG = 'Add parentheses to nested method call `%<source>s`.'
21
21
 
22
+ def self.autocorrect_incompatible_with
23
+ [Style::MethodCallWithArgsParentheses]
24
+ end
25
+
22
26
  def on_send(node)
23
27
  return unless node.parenthesized?
24
28
 
@@ -50,6 +50,9 @@ module RuboCop
50
50
  end
51
51
 
52
52
  corrector.replace(node, new_code)
53
+
54
+ parent = node.parent
55
+ corrector.wrap(node, '(', ')') if parent.respond_to?(:method?) && parent.method?(:!)
53
56
  end
54
57
  end
55
58
  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