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

[Fix #13395] False positive for Lint/UselessAssignment when assigning in branch and block #13409

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

pCosta99
Copy link
Contributor

@pCosta99 pCosta99 commented Nov 1, 2024

As demonstrated in the issue #13395, there is a false positive as such:

changed = false
^^^^^^^ Useless assignment to variable - `changed`.

if Random.rand > 1
  changed = true
end

[].each do
  changed = true
end

puts changed

In the presence of a conditional, the cop Lint/UselessAssignment can't be certain if the variable will be reassigned or not, so, very much like the case for blocks, the best approach is simply to ignore it.

There appears to be no benefit in actually looking into all branches and checking if all branches reassign since even then the outer assignment defines the variable.

This also applies to case statements.


Before submitting the PR make sure the following are checked:

  • The PR relates to only one subject with a clear title and description in grammatically correct, complete sentences.
  • Wrote good commit messages.
  • Commit message starts with [Fix #issue-number] (if the related issue exists).
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Ran bundle exec rake default. It executes all tests and runs RuboCop on its own code.
  • Added an entry (file) to the changelog folder named {change_type}_{change_description}.md if the new code introduces user-observable changes. See changelog entry format for details.


@assignments << assignment
end

def mark_last_as_reassigned!(assignment)
return if captured_by_block?
return if candidate_condition?(assignment.node.parent)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@koic Can I make parent an attribute in RuboCop::Cop::VariableForce::Assignment?
Seems like a worthy refactor, makes sense as an attribute and simplifies a bunch of accesses throughout the class

@bbatsov
Copy link
Collaborator

bbatsov commented Nov 4, 2024

There appears to be no benefit in actually looking into all branches and checking if all branches reassign since even then the outer assignment defines the variable.

I don't quite get this part, as by looking at them you can actually determine whether some assignment is void or not.

@pCosta99
Copy link
Contributor Author

pCosta99 commented Nov 4, 2024

There appears to be no benefit in actually looking into all branches and checking if all branches reassign since even then the outer assignment defines the variable.

I don't quite get this part, as by looking at them you can actually determine whether some assignment is void or not.

Can you create an example? What I was trying to highlight is situations like this:

changed = false

if Random.rand > 1
  changed = true
else 
  changed = false
end

[].each do
  changed = true
end

puts changed

Even considering that any branch will assign to changed the assignment above is not useless since it creates the variable.
Out of the top of my head no examples come to mind that it matters to check all branches.

@bbatsov
Copy link
Collaborator

bbatsov commented Nov 4, 2024

Even considering that any branch will assign to changed the assignment above is not useless since it creates the variable.

So, your point applies only if there's a usage outside the branches, right? (in your case the puts)

@pCosta99
Copy link
Contributor Author

pCosta99 commented Nov 4, 2024

Even considering that any branch will assign to changed the assignment above is not useless since it creates the variable.

So, your point applies only if there's a usage outside the branches, right? (in your case the puts)

I'd say so. And testing with, for instance:

def some_method
  changed = false
  ^^^^^^^ Useless assignment to variable - `changed`.

  if Random.rand > 1
    changed = true
    ^^^^^^^ Useless assignment to variable - `changed`.
  else
    changed = false
    ^^^^^^^ Useless assignment to variable - `changed`.
  end
end

works as expected. However, one important detail, in the following scenario:

def some_method
  changed = false

  if Random.rand > 1
    changed = true
  end

  [].each do
    changed = true
  end
end

the variable is not unused since it is captured by a block. This is respectful of the comments under RuboCop::Cop::VariableForce::Variable::used? that quote the following:

    # This is a convenient way to check whether the variable is used
   # in its entire variable lifetime.
   # For more precise usage check, refer Assignment#used?.
   #
   # Once the variable is captured by a block, we have no idea
   # when, where, and how many times the block would be invoked.
   # This means we cannot track the usage of the variable.
  # So we consider it's used to suppress false positive offenses.

@bbatsov

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.

False positive for Lint/UselessAssignment when assigning in branch and block
3 participants