pylint-dev / astroid

A common base representation of python source code for pylint and other projects
https://pylint.readthedocs.io/projects/astroid/en/latest/
GNU Lesser General Public License v2.1
532 stars 276 forks source link

nonlocal in locals #2617

Closed yueyinqiu closed 2 weeks ago

yueyinqiu commented 1 month ago

Type of Changes

Type
:bug: Bug fix

Description

Closes #2616

I did this by adding a _nonlocal_names property in TreeRebuilder to store those nonlocal names, like what _global_names does. However it stores FunctionDefs where the variables are created, instead of Nonlocal nodes. (The saved Global nodes in _global_names is not used for as well, but I didn't touch it, in case we may need that one day.)

The items of _nonlocal_names are added in visit_nonlocal, which go through the tree and find the nearest FunctionDef whose locals contains that name.

And it is used in _save_assignment. If node.name is in self._nonlocal_names[-1], then it will be put into self._nonlocal_names[-1][node.name] (the found FunctionDef) rather than into node.parent.

I have also added a unit test test_locals_with_global_and_nonlocal in test_builder.py, but I'm not really sure if I put it in the correct place.

There might be some other problems since it's my first PR for this project. Really need someone to check it before merging.

yueyinqiu commented 1 month ago

Hmmm... Why pylint consider scope as Nonlocal since it's inside if isinstance(scope, nodes.FunctionDef)... Should I add # type: ignore here to suppress the warning?

jacobtylerwalls commented 2 weeks ago

Thanks for engaging in discussion. Let us know if the nodes_of_class() solution doesn't work well for you.