Skip to content

Commit 8c368f6

Browse files
committed
[Fix #492] Fix false positives for Performance/StringIdentifierArgument
This PR fixes false positives for `Performance/StringIdentifierArgument` when using interpolated string argument. Converting a string with interpolation into a symbol degrades performance. Fixes #492.
1 parent d842831 commit 8c368f6

File tree

3 files changed

+18
-32
lines changed

3 files changed

+18
-32
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#492](https://github.com/rubocop/rubocop-performance/issues/492): Fix false positives for `Performance/StringIdentifierArgument` when using interpolated string argument. ([@koic][])

lib/rubocop/cop/performance/string_identifier_argument.rb

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@ module Performance
1616
# send('do_something')
1717
# attr_accessor 'do_something'
1818
# instance_variable_get('@ivar')
19-
# respond_to?("string_#{interpolation}")
2019
#
2120
# # good
2221
# send(:do_something)
2322
# attr_accessor :do_something
2423
# instance_variable_get(:@ivar)
25-
# respond_to?(:"string_#{interpolation}")
2624
#
2725
# # good - these methods don't support namespaced symbols
2826
# const_get("#{module_path}::Base")
2927
# const_source_location("#{module_path}::Base")
3028
# const_defined?("#{module_path}::Base")
3129
#
30+
# # good - using a symbol when string interpolation is involved causes a performance regression.
31+
# respond_to?("string_#{interpolation}")
3232
#
3333
class StringIdentifierArgument < Base
3434
extend AutoCorrector
@@ -40,8 +40,6 @@ class StringIdentifierArgument < Base
4040
protected public public_constant module_function
4141
].freeze
4242

43-
INTERPOLATION_IGNORE_METHODS = %i[const_get const_source_location const_defined?].freeze
44-
4543
TWO_ARGUMENTS_METHOD = :alias_method
4644
MULTIPLE_ARGUMENTS_METHODS = %i[
4745
attr_accessor attr_reader attr_writer private private_constant
@@ -59,7 +57,7 @@ class StringIdentifierArgument < Base
5957
deprecate_constant remove_const ruby2_keywords define_singleton_method instance_variable_defined?
6058
instance_variable_get instance_variable_set method public_method public_send remove_instance_variable
6159
respond_to? send singleton_method __send__
62-
] + COMMAND_METHODS + INTERPOLATION_IGNORE_METHODS).freeze
60+
] + COMMAND_METHODS).freeze
6361

6462
def on_send(node)
6563
return if COMMAND_METHODS.include?(node.method_name) && node.receiver
@@ -83,13 +81,7 @@ def string_arguments(node)
8381
[node.first_argument]
8482
end
8583

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) }
84+
arguments.compact.filter(&:str_type?)
9385
end
9486

9587
def register_offense(argument, argument_value)

spec/rubocop/cop/performance/string_identifier_argument_spec.rb

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,19 @@
4444
RUBY
4545
end
4646

47-
if described_class::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
47+
it 'does not register an offense when using string interpolation for `#{method}` method' do
48+
# NOTE: These methods don't support `::` when passing a symbol. const_get('A::B') is valid
49+
# but const_get(:'A::B') isn't. Since interpolated arguments may contain any content these
50+
# cases are not detected as an offense to prevent false positives.
51+
expect_no_offenses(<<~RUBY)
52+
#{method}("\#{module_name}class_name")
53+
RUBY
54+
end
55+
56+
it 'does not register an offense when using interpolated string argument' do
57+
expect_no_offenses(<<~RUBY)
58+
#{method}("do_something_\#{var}")
59+
RUBY
6760
end
6861
end
6962
end

0 commit comments

Comments
 (0)