mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-22 11:25:26 +00:00

This PR productionizes @MichaReiser's suggestion in https://github.com/charliermarsh/ruff/issues/1820#issuecomment-1440204423, by creating a separate crate for the `ast` module (`rust_python_ast`). This will enable us to further split up the `ruff` crate, as we'll be able to create (e.g.) separate sub-linter crates that have access to these common AST utilities. This was mostly a straightforward copy (with adjustments to module imports), as the few dependencies that _did_ require modifications were handled in #3366, #3367, and #3368.
73 lines
2.1 KiB
Rust
73 lines
2.1 KiB
Rust
use ruff_python_stdlib::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS};
|
|
use rustpython_parser::ast::{Expr, ExprKind};
|
|
|
|
use crate::types::CallPath;
|
|
|
|
pub enum Callable {
|
|
ForwardRef,
|
|
Cast,
|
|
NewType,
|
|
TypeVar,
|
|
NamedTuple,
|
|
TypedDict,
|
|
MypyExtension,
|
|
}
|
|
|
|
pub enum SubscriptKind {
|
|
AnnotatedSubscript,
|
|
PEP593AnnotatedSubscript,
|
|
}
|
|
|
|
pub fn match_annotated_subscript<'a, F>(
|
|
expr: &'a Expr,
|
|
resolve_call_path: F,
|
|
typing_modules: impl Iterator<Item = &'a str>,
|
|
) -> Option<SubscriptKind>
|
|
where
|
|
F: FnOnce(&'a Expr) -> Option<CallPath<'a>>,
|
|
{
|
|
if !matches!(
|
|
expr.node,
|
|
ExprKind::Name { .. } | ExprKind::Attribute { .. }
|
|
) {
|
|
return None;
|
|
}
|
|
|
|
resolve_call_path(expr).and_then(|call_path| {
|
|
if SUBSCRIPTS.contains(&call_path.as_slice()) {
|
|
return Some(SubscriptKind::AnnotatedSubscript);
|
|
}
|
|
if PEP_593_SUBSCRIPTS.contains(&call_path.as_slice()) {
|
|
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
|
}
|
|
|
|
for module in typing_modules {
|
|
let module_call_path = module.split('.').collect::<Vec<_>>();
|
|
if call_path.starts_with(&module_call_path) {
|
|
for subscript in SUBSCRIPTS.iter() {
|
|
if call_path.last() == subscript.last() {
|
|
return Some(SubscriptKind::AnnotatedSubscript);
|
|
}
|
|
}
|
|
for subscript in PEP_593_SUBSCRIPTS.iter() {
|
|
if call_path.last() == subscript.last() {
|
|
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<'a, F>(expr: &'a Expr, resolve_call_path: F) -> bool
|
|
where
|
|
F: FnOnce(&'a Expr) -> Option<CallPath<'a>>,
|
|
{
|
|
resolve_call_path(expr).map_or(false, |call_path| {
|
|
PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice())
|
|
})
|
|
}
|