Skip to content

Commit 19ee909

Browse files
koicbbatsov
authored andcommittedDec 12, 2024
[Fix #13556] Fix false positives for Style/FileNull
Fixes #13556. This PR fixes false positives for `Style/FileNull` when using `'nul'` string. This PR ensures only files that use the string `'/dev/null'` are targeted for detection. This is because the string `'nul'` is not limited to the null device. This behavior results in false negatives when the `'/dev/null'` string is not used, but it is a trade-off to avoid false positives.
1 parent fd13dab commit 19ee909

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#13556](https://github.com/rubocop/rubocop/issues/13556): Fix false positives for `Style/FileNull` when using `'nul'` string. ([@koic][])

‎lib/rubocop/cop/style/file_null.rb

+20-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ module Style
88
# Only looks for full string matches, substrings within a longer string are not
99
# considered.
1010
#
11+
# However, only files that use the string `'/dev/null'` are targeted for detection.
12+
# This is because the string `'NUL'` is not limited to the null device.
13+
# This behavior results in false negatives when the `'/dev/null'` string is not used,
14+
# but it is a trade-off to avoid false positives. `NULL:`
15+
# Unlike `'NUL'`, `'NUL:'` is regarded as something like `C:` and is always detected.
16+
#
1117
# NOTE: Uses inside arrays and hashes are ignored.
1218
#
1319
# @safety
@@ -42,11 +48,21 @@ class FileNull < Base
4248
REGEXP = %r{\A(/dev/null|NUL:?)\z}i.freeze
4349
MSG = 'Use `File::NULL` instead of `%<source>s`.'
4450

51+
def on_new_investigation
52+
return unless (ast = processed_source.ast)
53+
54+
@contain_dev_null_string_in_file = ast.each_descendant(:str).any? do |str|
55+
content = str.str_content
56+
57+
valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull
58+
end
59+
end
60+
4561
def on_str(node)
4662
value = node.value
47-
48-
return if invalid_string?(value)
63+
return unless valid_string?(value)
4964
return if acceptable?(node)
65+
return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull
5066
return unless REGEXP.match?(value)
5167

5268
add_offense(node, message: format(MSG, source: value)) do |corrector|
@@ -56,8 +72,8 @@ def on_str(node)
5672

5773
private
5874

59-
def invalid_string?(value)
60-
value.empty? || !value.valid_encoding?
75+
def valid_string?(value)
76+
!value.empty? && value.valid_encoding?
6177
end
6278

6379
def acceptable?(node)

‎spec/rubocop/cop/style/file_null_spec.rb

+24-2
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,40 @@
2424
RUBY
2525
end
2626

27-
it 'registers an offense and corrects when the entire string is `NUL`' do
27+
it "registers an offense and corrects when the entire string is `NUL` or '/dev/null'" do
2828
expect_offense(<<~RUBY)
29+
CONST = '/dev/null'
30+
^^^^^^^^^^^ Use `File::NULL` instead of `/dev/null`.
2931
path = 'NUL'
3032
^^^^^ Use `File::NULL` instead of `NUL`.
3133
RUBY
3234

3335
expect_correction(<<~RUBY)
36+
CONST = File::NULL
3437
path = File::NULL
3538
RUBY
3639
end
3740

38-
it 'registers an offense and corrects when the entire string is `NUL:`' do
41+
it "does not register an offense when the entire string is `NUL` without '/dev/null'" do
42+
expect_no_offenses(<<~RUBY)
43+
path = 'NUL'
44+
RUBY
45+
end
46+
47+
it "registers an offense and corrects when the entire string is `NUL:` or '/dev/null'" do
48+
expect_offense(<<~RUBY)
49+
path = cond ? '/dev/null' : 'NUL:'
50+
^^^^^^^^^^^ Use `File::NULL` instead of `/dev/null`.
51+
^^^^^^ Use `File::NULL` instead of `NUL:`.
52+
RUBY
53+
54+
# Different cops will detect duplication of the branch bodies.
55+
expect_correction(<<~RUBY)
56+
path = cond ? File::NULL : File::NULL
57+
RUBY
58+
end
59+
60+
it "registers an offense when the entire string is `NUL:` without '/dev/null'" do
3961
expect_offense(<<~RUBY)
4062
path = 'NUL:'
4163
^^^^^^ Use `File::NULL` instead of `NUL:`.

0 commit comments

Comments
 (0)