Skip to content

Commit cbc1dd5

Browse files
authored
Merge pull request #430 from Earlopain/fix-425
[Fix #425] Fix a false positive for`Performance/StringIdentifierArgument
2 parents 6e7c4cf + 749d072 commit cbc1dd5

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#425](https://github.com/rubocop/rubocop-performance/issues/425): Fix a false positive for `Performance/StringIdentifierArgument` when using string interpolation with methods that don't support symbols with `::` inside them. ([@earlopain][])

lib/rubocop/cop/performance/string_identifier_argument.rb

+19-7
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@ module Performance
1616
# send('do_something')
1717
# attr_accessor 'do_something'
1818
# instance_variable_get('@ivar')
19-
# const_get("string_#{interpolation}")
19+
# respond_to?("string_#{interpolation}")
2020
#
2121
# # good
2222
# send(:do_something)
2323
# attr_accessor :do_something
2424
# instance_variable_get(:@ivar)
25-
# const_get(:"string_#{interpolation}")
25+
# respond_to?(:"string_#{interpolation}")
26+
#
27+
# # good - these methods don't support namespaced symbols
28+
# const_get("#{module_path}::Base")
29+
# const_source_location("#{module_path}::Base")
30+
# const_defined?("#{module_path}::Base")
31+
#
2632
#
2733
class StringIdentifierArgument < Base
2834
extend AutoCorrector
@@ -34,6 +40,8 @@ class StringIdentifierArgument < Base
3440
protected public public_constant module_function
3541
].freeze
3642

43+
INTERPOLATION_IGNORE_METHODS = %i[const_get const_source_location const_defined?].freeze
44+
3745
TWO_ARGUMENTS_METHOD = :alias_method
3846
MULTIPLE_ARGUMENTS_METHODS = %i[
3947
attr_accessor attr_reader attr_writer private private_constant
@@ -44,14 +52,14 @@ class StringIdentifierArgument < Base
4452
# And `attr` may not be used because `Style/Attr` registers an offense.
4553
# https://github.com/rubocop/rubocop-performance/issues/278
4654
RESTRICT_ON_SEND = (%i[
47-
class_variable_defined? const_defined? const_get const_set const_source_location
55+
class_variable_defined? const_set
4856
define_method instance_method method_defined? private_class_method? private_method_defined?
4957
protected_method_defined? public_class_method public_instance_method public_method_defined?
5058
remove_class_variable remove_method undef_method class_variable_get class_variable_set
5159
deprecate_constant remove_const ruby2_keywords define_singleton_method instance_variable_defined?
5260
instance_variable_get instance_variable_set method public_method public_send remove_instance_variable
5361
respond_to? send singleton_method __send__
54-
] + COMMAND_METHODS).freeze
62+
] + COMMAND_METHODS + INTERPOLATION_IGNORE_METHODS).freeze
5563

5664
def on_send(node)
5765
return if COMMAND_METHODS.include?(node.method_name) && node.receiver
@@ -75,9 +83,13 @@ def string_arguments(node)
7583
[node.first_argument]
7684
end
7785

78-
arguments.compact.filter do |argument|
79-
argument.str_type? || argument.dstr_type?
80-
end
86+
arguments.compact.filter { |argument| string_argument_compatible?(argument, node) }
87+
end
88+
89+
def string_argument_compatible?(argument, node)
90+
return true if argument.str_type?
91+
92+
argument.dstr_type? && INTERPOLATION_IGNORE_METHODS.none? { |method| node.method?(method) }
8193
end
8294

8395
def register_offense(argument, argument_value)

spec/rubocop/cop/performance/string_identifier_argument_spec.rb

+20-9
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,26 @@
4444
RUBY
4545
end
4646

47-
it 'registers an offense when using interpolated string argument' do
48-
expect_offense(<<~RUBY, method: method)
49-
#{method}("do_something_\#{var}")
50-
_{method} ^^^^^^^^^^^^^^^^^^^^^ Use `:"do_something_\#{var}"` instead of `"do_something_\#{var}"`.
51-
RUBY
52-
53-
expect_correction(<<~RUBY)
54-
#{method}(:"do_something_\#{var}")
55-
RUBY
47+
if RuboCop::Cop::Performance::StringIdentifierArgument::INTERPOLATION_IGNORE_METHODS.include?(method)
48+
it 'does not register an offense when using string interpolation for `#{method}` method' do
49+
# NOTE: These methods don't support `::` when passing a symbol. const_get('A::B') is valid
50+
# but const_get(:'A::B') isn't. Since interpolated arguments may contain any content these
51+
# cases are not detected as an offense to prevent false positives.
52+
expect_no_offenses(<<~RUBY)
53+
#{method}("\#{module_name}class_name")
54+
RUBY
55+
end
56+
else
57+
it 'registers an offense when using interpolated string argument' do
58+
expect_offense(<<~RUBY, method: method)
59+
#{method}("do_something_\#{var}")
60+
_{method} ^^^^^^^^^^^^^^^^^^^^^ Use `:"do_something_\#{var}"` instead of `"do_something_\#{var}"`.
61+
RUBY
62+
63+
expect_correction(<<~RUBY)
64+
#{method}(:"do_something_\#{var}")
65+
RUBY
66+
end
5667
end
5768
end
5869
end

0 commit comments

Comments
 (0)