mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-17 00:50:16 +00:00
Add autofix for Set
-to-AbstractSet
rewrite using reference tracking (#5074)
## Summary This PR enables autofix behavior for the `flake8-pyi` rule that asks you to alias `Set` to `AbstractSet` when importing `collections.abc.Set`. It's not the most important rule, but it's a good isolated test-case for local symbol renaming. The renaming algorithm is outlined in-detail in the `renamer.rs` module. But to demonstrate the behavior, here's the diff when running this fix over a complex file that exercises a few edge cases: ```diff --- a/foo.pyi +++ b/foo.pyi @@ -1,16 +1,16 @@ if True: - from collections.abc import Set + from collections.abc import Set as AbstractSet else: - Set = 1 + AbstractSet = 1 -x: Set = set() +x: AbstractSet = set() -x: Set +x: AbstractSet -del Set +del AbstractSet def f(): - print(Set) + print(AbstractSet) def Set(): pass ``` Making this work required resolving a bunch of edge cases in the semantic model that were causing us to "lose track" of references. For example, the above wasn't possible with our previous approach to handling deletions (#5071). Similarly, the `x: Set` "delayed annotation" tracking was enabled via #5070. And many of these edits would've failed if we hadn't changed `BindingKind` to always match the identifier range (#5090). So it's really the culmination of a bunch of changes over the course of the week. The main outstanding TODO is that this doesn't support `global` or `nonlocal` usages. I'm going to take a look at that tonight, but I'm comfortable merging this as-is. Closes #1106. Closes #5091.
This commit is contained in:
parent
307f7a735c
commit
b9754bd5c5
9 changed files with 414 additions and 100 deletions
|
@ -44,6 +44,18 @@ impl<'a> Binding<'a> {
|
|||
self.flags.contains(BindingFlags::EXPLICIT_EXPORT)
|
||||
}
|
||||
|
||||
/// Return `true` if this [`Binding`] represents an external symbol
|
||||
/// (e.g., `FastAPI` in `from fastapi import FastAPI`).
|
||||
pub const fn is_external(&self) -> bool {
|
||||
self.flags.contains(BindingFlags::EXTERNAL)
|
||||
}
|
||||
|
||||
/// Return `true` if this [`Binding`] represents an aliased symbol
|
||||
/// (e.g., `app` in `from fastapi import FastAPI as app`).
|
||||
pub const fn is_alias(&self) -> bool {
|
||||
self.flags.contains(BindingFlags::ALIAS)
|
||||
}
|
||||
|
||||
/// Return `true` if this [`Binding`] represents an unbound variable
|
||||
/// (e.g., `x` in `x = 1; del x`).
|
||||
pub const fn is_unbound(&self) -> bool {
|
||||
|
@ -161,9 +173,25 @@ bitflags! {
|
|||
///
|
||||
/// For example, the binding could be `FastAPI` in:
|
||||
/// ```python
|
||||
/// import FastAPI as FastAPI
|
||||
/// from fastapi import FastAPI as FastAPI
|
||||
/// ```
|
||||
const EXPLICIT_EXPORT = 1 << 0;
|
||||
|
||||
/// The binding represents an external symbol, like an import or a builtin.
|
||||
///
|
||||
/// For example, the binding could be `FastAPI` in:
|
||||
/// ```python
|
||||
/// from fastapi import FastAPI
|
||||
/// ```
|
||||
const EXTERNAL = 1 << 1;
|
||||
|
||||
/// The binding is an aliased symbol.
|
||||
///
|
||||
/// For example, the binding could be `app` in:
|
||||
/// ```python
|
||||
/// from fastapi import FastAPI as app
|
||||
/// ```
|
||||
const ALIAS = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue