mirror of
https://github.com/astral-sh/ruff
synced 2026-01-22 22:10:48 -05:00
250 lines
7.0 KiB
Rust
250 lines
7.0 KiB
Rust
use once_cell::sync::Lazy;
|
|
use rustc_hash::{FxHashMap, FxHashSet};
|
|
use rustpython_ast::Expr;
|
|
|
|
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
|
|
|
// See: https://pypi.org/project/typing-extensions/
|
|
static TYPING_EXTENSIONS: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
|
FxHashSet::from_iter([
|
|
"Annotated",
|
|
"Any",
|
|
"AsyncContextManager",
|
|
"AsyncGenerator",
|
|
"AsyncIterable",
|
|
"AsyncIterator",
|
|
"Awaitable",
|
|
"ChainMap",
|
|
"ClassVar",
|
|
"Concatenate",
|
|
"ContextManager",
|
|
"Coroutine",
|
|
"Counter",
|
|
"DefaultDict",
|
|
"Deque",
|
|
"Final",
|
|
"Literal",
|
|
"LiteralString",
|
|
"NamedTuple",
|
|
"Never",
|
|
"NewType",
|
|
"NotRequired",
|
|
"OrderedDict",
|
|
"ParamSpec",
|
|
"ParamSpecArgs",
|
|
"ParamSpecKwargs",
|
|
"Protocol",
|
|
"Required",
|
|
"Self",
|
|
"TYPE_CHECKING",
|
|
"Text",
|
|
"Type",
|
|
"TypeAlias",
|
|
"TypeGuard",
|
|
"TypeVar",
|
|
"TypeVarTuple",
|
|
"TypedDict",
|
|
"Unpack",
|
|
"assert_never",
|
|
"assert_type",
|
|
"clear_overloads",
|
|
"final",
|
|
"get_Type_hints",
|
|
"get_args",
|
|
"get_origin",
|
|
"get_overloads",
|
|
"is_typeddict",
|
|
"overload",
|
|
"reveal_type",
|
|
"runtime_checkable",
|
|
])
|
|
});
|
|
|
|
pub fn in_extensions(name: &str) -> bool {
|
|
TYPING_EXTENSIONS.contains(name)
|
|
}
|
|
|
|
// See: https://docs.python.org/3/library/typing.html
|
|
const SUBSCRIPTS: &[(&str, &str)] = &[
|
|
// builtins
|
|
("", "dict"),
|
|
("", "frozenset"),
|
|
("", "list"),
|
|
("", "set"),
|
|
("", "tuple"),
|
|
("", "type"),
|
|
// `collections`
|
|
("collections", "ChainMap"),
|
|
("collections", "Counter"),
|
|
("collections", "OrderedDict"),
|
|
("collections", "defaultdict"),
|
|
("collections", "deque"),
|
|
// `collections.abc`
|
|
("collections.abc", "AsyncGenerator"),
|
|
("collections.abc", "AsyncIterable"),
|
|
("collections.abc", "AsyncIterator"),
|
|
("collections.abc", "Awaitable"),
|
|
("collections.abc", "ByteString"),
|
|
("collections.abc", "Callable"),
|
|
("collections.abc", "Collection"),
|
|
("collections.abc", "Container"),
|
|
("collections.abc", "Coroutine"),
|
|
("collections.abc", "Generator"),
|
|
("collections.abc", "ItemsView"),
|
|
("collections.abc", "Iterable"),
|
|
("collections.abc", "Iterator"),
|
|
("collections.abc", "KeysView"),
|
|
("collections.abc", "Mapping"),
|
|
("collections.abc", "MappingView"),
|
|
("collections.abc", "MutableMapping"),
|
|
("collections.abc", "MutableSequence"),
|
|
("collections.abc", "MutableSet"),
|
|
("collections.abc", "Reversible"),
|
|
("collections.abc", "Sequence"),
|
|
("collections.abc", "Set"),
|
|
("collections.abc", "ValuesView"),
|
|
// `contextlib`
|
|
("contextlib", "AbstractAsyncContextManager"),
|
|
("contextlib", "AbstractContextManager"),
|
|
// `re`
|
|
("re", "Match"),
|
|
("re", "Pattern"),
|
|
// `typing`
|
|
("typing", "AbstractSet"),
|
|
("typing", "AsyncContextManager"),
|
|
("typing", "AsyncGenerator"),
|
|
("typing", "AsyncIterator"),
|
|
("typing", "Awaitable"),
|
|
("typing", "BinaryIO"),
|
|
("typing", "ByteString"),
|
|
("typing", "Callable"),
|
|
("typing", "ChainMap"),
|
|
("typing", "ClassVar"),
|
|
("typing", "Collection"),
|
|
("typing", "Concatenate"),
|
|
("typing", "Container"),
|
|
("typing", "ContextManager"),
|
|
("typing", "Coroutine"),
|
|
("typing", "Counter"),
|
|
("typing", "DefaultDict"),
|
|
("typing", "Deque"),
|
|
("typing", "Dict"),
|
|
("typing", "Final"),
|
|
("typing", "FrozenSet"),
|
|
("typing", "Generator"),
|
|
("typing", "Generic"),
|
|
("typing", "IO"),
|
|
("typing", "ItemsView"),
|
|
("typing", "Iterable"),
|
|
("typing", "Iterator"),
|
|
("typing", "KeysView"),
|
|
("typing", "List"),
|
|
("typing", "Mapping"),
|
|
("typing", "Match"),
|
|
("typing", "MutableMapping"),
|
|
("typing", "MutableSequence"),
|
|
("typing", "MutableSet"),
|
|
("typing", "Optional"),
|
|
("typing", "OrderedDict"),
|
|
("typing", "Pattern"),
|
|
("typing", "Reversible"),
|
|
("typing", "Sequence"),
|
|
("typing", "Set"),
|
|
("typing", "TextIO"),
|
|
("typing", "Tuple"),
|
|
("typing", "Type"),
|
|
("typing", "TypeGuard"),
|
|
("typing", "Union"),
|
|
("typing", "Unpack"),
|
|
("typing", "ValuesView"),
|
|
// `typing.io`
|
|
("typing.io", "BinaryIO"),
|
|
("typing.io", "IO"),
|
|
("typing.io", "TextIO"),
|
|
// `typing.re`
|
|
("typing.re", "Match"),
|
|
("typing.re", "Pattern"),
|
|
// `typing_extensions`
|
|
("typing_extensions", "AsyncContextManager"),
|
|
("typing_extensions", "AsyncGenerator"),
|
|
("typing_extensions", "AsyncIterable"),
|
|
("typing_extensions", "AsyncIterator"),
|
|
("typing_extensions", "Awaitable"),
|
|
("typing_extensions", "ChainMap"),
|
|
("typing_extensions", "ClassVar"),
|
|
("typing_extensions", "Concatenate"),
|
|
("typing_extensions", "ContextManager"),
|
|
("typing_extensions", "Coroutine"),
|
|
("typing_extensions", "Counter"),
|
|
("typing_extensions", "DefaultDict"),
|
|
("typing_extensions", "Deque"),
|
|
("typing_extensions", "Type"),
|
|
// `weakref`
|
|
("weakref", "WeakKeyDictionary"),
|
|
("weakref", "WeakSet"),
|
|
("weakref", "WeakValueDictionary"),
|
|
];
|
|
|
|
// See: https://docs.python.org/3/library/typing.html
|
|
const PEP_583_SUBSCRIPTS: &[(&str, &str)] = &[
|
|
// `typing`
|
|
("typing", "Annotated"),
|
|
// `typing_extensions`
|
|
("typing_extensions", "Annotated"),
|
|
];
|
|
|
|
// See: https://peps.python.org/pep-0585/
|
|
const PEP_585_BUILTINS_ELIGIBLE: &[(&str, &str)] = &[
|
|
("typing", "Dict"),
|
|
("typing", "FrozenSet"),
|
|
("typing", "List"),
|
|
("typing", "Set"),
|
|
("typing", "Tuple"),
|
|
("typing", "Type"),
|
|
("typing_extensions", "Type"),
|
|
];
|
|
|
|
pub enum SubscriptKind {
|
|
AnnotatedSubscript,
|
|
PEP593AnnotatedSubscript,
|
|
}
|
|
|
|
pub fn match_annotated_subscript(
|
|
expr: &Expr,
|
|
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
|
import_aliases: &FxHashMap<&str, &str>,
|
|
) -> Option<SubscriptKind> {
|
|
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
|
if !call_path.is_empty() {
|
|
for (module, member) in SUBSCRIPTS {
|
|
if match_call_path(&call_path, module, member, from_imports) {
|
|
return Some(SubscriptKind::AnnotatedSubscript);
|
|
}
|
|
}
|
|
for (module, member) in PEP_583_SUBSCRIPTS {
|
|
if match_call_path(&call_path, module, member, from_imports) {
|
|
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Returns `true` if `Expr` represents a reference to a typing object with a
|
|
/// PEP 585 built-in.
|
|
pub fn is_pep585_builtin(
|
|
expr: &Expr,
|
|
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
|
import_aliases: &FxHashMap<&str, &str>,
|
|
) -> bool {
|
|
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
|
if !call_path.is_empty() {
|
|
for (module, member) in PEP_585_BUILTINS_ELIGIBLE {
|
|
if match_call_path(&call_path, module, member, from_imports) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
false
|
|
}
|