Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Lint/SelfAssignment to check attribute assignment and key assignment #12415

Merged
merged 1 commit into from
Nov 28, 2023

Conversation

fatkodima
Copy link
Contributor

This is an implementation of #12410 for Lint/SelfAssignment.

# bad
foo.bar = foo.bar
foo["bar"] = foo["bar"]

Comment on lines 30 to 41
case node.method_name
when :[]=
handle_key_assignment(node) if node.arguments.size == 2
when /=\z/
handle_attribute_assignment(node) if node.arguments.size == 1
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tweak to the below?

Suggested change
case node.method_name
when :[]=
handle_key_assignment(node) if node.arguments.size == 2
when /=\z/
handle_attribute_assignment(node) if node.arguments.size == 1
end
if node.method?(:[]=)
handle_key_assignment(node) if node.arguments.size == 2
elsif node.assignment_method?
handle_attribute_assignment(node) if node.arguments.size == 1
end

value_node = node.arguments[1]

if value_node.send_type? && value_node.method?(:[]) &&
node.receiver == value_node.receiver &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test case for the receiver condition?

first_argument = node.first_argument

if first_argument.send_type? &&
node.receiver == first_argument.receiver &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@fatkodima
Copy link
Contributor Author

Updated.

foo.bar = foo.baz
foo.bar
bar.foo = baz.foo
foo.bar = foo.bar + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you split the it blocks for each testing content?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done for both.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foo.bar = foo.bar + 1 is the same as L155. Is it left out intentionally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy paste errors 🤦 Updated

foo["bar"] = foo["baz"]
bar["foo"] = baz["foo"]
foo["bar"]
foo["bar"] = foo["bar"] + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

it 'does not register an offense when using []= assignment with different receivers' do
expect_no_offenses(<<~RUBY)
bar["foo"] = baz["foo"]
foo["bar"] = foo["bar"] + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foo["bar"] = foo["bar"] + 1 is the same as L181. Is it left out intentionally?


if value_node.send_type? && value_node.method?(:[]) &&
node.receiver == value_node.receiver &&
node.first_argument == value_node.first_argument

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this pick up cases where the hash index is non-deterministic, which (while extremely rare) would also render this cop unsafe? i.e.

hash = {}
hash[rand] = hash[rand]
###
{ 0.03256159230386502=>nil } 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this would pick up such cases. That is indeed extremely rare and I am not sure if it is worth marking this cop as unsafe because of this.

Copy link
Member

@koic koic Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. To ensure safety and certainty, it would be better to register an offense only when the key is some kind of literal or variable. Method calls carry the risk of side effects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with this suggestion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be beneficial to include in the documentation the reason for not registering offenses when the key is a method call.


if value_node.send_type? && value_node.method?(:[]) &&
node.receiver == value_node.receiver &&
!node.first_argument.call_type? &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for safe navigation method calls?

foo["bar"] = foo["bar"]
^^^^^^^^^^^^^^^^^^^^^^^ Self-assignment detected.
RUBY
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add test cases for other literal types and variables are used as keys?

@fatkodima
Copy link
Contributor Author

Updated.

foo[Foo] = foo[Foo]
^^^^^^^^^^^^^^^^^^^ Self-assignment detected.
foo[:bar] = foo[:bar]
^^^^^^^^^^^^^^^^^^^^^ Self-assignment detected.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please separate the tests for each type of literal?

foo[1] = foo[2]
foo[1.2] = foo[2.2]
foo[Foo] = foo[Bar]
foo[:bar] = foo[:baz]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

foo[@@var] = foo[@@var]
^^^^^^^^^^^^^^^^^^^^^^^ Self-assignment detected.
foo[$var] = foo[$var]
^^^^^^^^^^^^^^^^^^^^^ Self-assignment detected.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please separate the tests for each type of variable?

foo[var1] = foo[var2]
foo[@var1] = foo[@var2]
foo[@@var1] = foo[@@var2]
foo[$var1] = foo[$var2]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@fatkodima
Copy link
Contributor Author

Separated tests.

@koic koic merged commit 5182116 into rubocop:master Nov 28, 2023
28 checks passed
@koic
Copy link
Member

koic commented Nov 28, 2023

Thanks!

@fatkodima fatkodima deleted the enhance-lint-self_assignment branch November 28, 2023 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants