Compare commits
1 Commits
david/defa
...
ag/switch-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf762fe2ca |
@@ -43,6 +43,7 @@ use ruff_python_ast::helpers::{
|
|||||||
collect_import_from_member, extract_handled_exceptions, is_docstring_stmt, to_module_path,
|
collect_import_from_member, extract_handled_exceptions, is_docstring_stmt, to_module_path,
|
||||||
};
|
};
|
||||||
use ruff_python_ast::identifier::Identifier;
|
use ruff_python_ast::identifier::Identifier;
|
||||||
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::str::trailing_quote;
|
use ruff_python_ast::str::trailing_quote;
|
||||||
use ruff_python_ast::visitor::{walk_except_handler, walk_f_string_element, walk_pattern, Visitor};
|
use ruff_python_ast::visitor::{walk_except_handler, walk_f_string_element, walk_pattern, Visitor};
|
||||||
use ruff_python_ast::{helpers, str, visitor, PySourceType};
|
use ruff_python_ast::{helpers, str, visitor, PySourceType};
|
||||||
@@ -418,7 +419,7 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
self.semantic.add_module(module);
|
self.semantic.add_module(module);
|
||||||
|
|
||||||
if alias.asname.is_none() && alias.name.contains('.') {
|
if alias.asname.is_none() && alias.name.contains('.') {
|
||||||
let qualified_name: Box<[&str]> = alias.name.split('.').collect();
|
let qualified_name = QualifiedName::imported(&alias.name);
|
||||||
self.add_binding(
|
self.add_binding(
|
||||||
module,
|
module,
|
||||||
alias.identifier(),
|
alias.identifier(),
|
||||||
@@ -439,7 +440,7 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let name = alias.asname.as_ref().unwrap_or(&alias.name);
|
let name = alias.asname.as_ref().unwrap_or(&alias.name);
|
||||||
let qualified_name: Box<[&str]> = alias.name.split('.').collect();
|
let qualified_name = QualifiedName::imported(&alias.name);
|
||||||
self.add_binding(
|
self.add_binding(
|
||||||
name,
|
name,
|
||||||
alias.identifier(),
|
alias.identifier(),
|
||||||
@@ -503,8 +504,7 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
// Attempt to resolve any relative imports; but if we don't know the current
|
// Attempt to resolve any relative imports; but if we don't know the current
|
||||||
// module path, or the relative import extends beyond the package root,
|
// module path, or the relative import extends beyond the package root,
|
||||||
// fallback to a literal representation (e.g., `[".", "foo"]`).
|
// fallback to a literal representation (e.g., `[".", "foo"]`).
|
||||||
let qualified_name = collect_import_from_member(level, module, &alias.name)
|
let qualified_name = collect_import_from_member(level, module, &alias.name);
|
||||||
.into_boxed_slice();
|
|
||||||
self.add_binding(
|
self.add_binding(
|
||||||
name,
|
name,
|
||||||
alias.identifier(),
|
alias.identifier(),
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ impl Renamer {
|
|||||||
}
|
}
|
||||||
BindingKind::SubmoduleImport(import) => {
|
BindingKind::SubmoduleImport(import) => {
|
||||||
// Ex) Rename `import pandas.core` to `import pandas as pd`.
|
// Ex) Rename `import pandas.core` to `import pandas as pd`.
|
||||||
let module_name = import.qualified_name.first().unwrap();
|
let module_name = import.qualified_name.segments().first().unwrap();
|
||||||
Some(Edit::range_replacement(
|
Some(Edit::range_replacement(
|
||||||
format!("{module_name} as {target}"),
|
format!("{module_name} as {target}"),
|
||||||
binding.range(),
|
binding.range(),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
use ruff_index::{newtype_index, IndexSlice, IndexVec};
|
use ruff_index::{newtype_index, IndexSlice, IndexVec};
|
||||||
use ruff_python_ast::name::format_qualified_name_segments;
|
use ruff_python_ast::name::{format_qualified_name_segments, QualifiedName};
|
||||||
use ruff_python_ast::Stmt;
|
use ruff_python_ast::Stmt;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
@@ -362,7 +362,7 @@ pub struct Import<'a> {
|
|||||||
/// The full name of the module being imported.
|
/// The full name of the module being imported.
|
||||||
/// Ex) Given `import foo`, `qualified_name` would be "foo".
|
/// Ex) Given `import foo`, `qualified_name` would be "foo".
|
||||||
/// Ex) Given `import foo as bar`, `qualified_name` would be "foo".
|
/// Ex) Given `import foo as bar`, `qualified_name` would be "foo".
|
||||||
pub qualified_name: Box<[&'a str]>,
|
pub qualified_name: QualifiedName<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A binding for a member imported from a module, keyed on the name to which the member is bound.
|
/// A binding for a member imported from a module, keyed on the name to which the member is bound.
|
||||||
@@ -373,7 +373,7 @@ pub struct FromImport<'a> {
|
|||||||
/// The full name of the member being imported.
|
/// The full name of the member being imported.
|
||||||
/// Ex) Given `from foo import bar`, `qualified_name` would be "foo.bar".
|
/// Ex) Given `from foo import bar`, `qualified_name` would be "foo.bar".
|
||||||
/// Ex) Given `from foo import bar as baz`, `qualified_name` would be "foo.bar".
|
/// Ex) Given `from foo import bar as baz`, `qualified_name` would be "foo.bar".
|
||||||
pub qualified_name: Box<[&'a str]>,
|
pub qualified_name: QualifiedName<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A binding for a submodule imported from a module, keyed on the name of the parent module.
|
/// A binding for a submodule imported from a module, keyed on the name of the parent module.
|
||||||
@@ -382,7 +382,7 @@ pub struct FromImport<'a> {
|
|||||||
pub struct SubmoduleImport<'a> {
|
pub struct SubmoduleImport<'a> {
|
||||||
/// The full name of the submodule being imported.
|
/// The full name of the submodule being imported.
|
||||||
/// Ex) Given `import foo.bar`, `qualified_name` would be "foo.bar".
|
/// Ex) Given `import foo.bar`, `qualified_name` would be "foo.bar".
|
||||||
pub qualified_name: Box<[&'a str]>,
|
pub qualified_name: QualifiedName<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, is_macro::Is)]
|
#[derive(Debug, Clone, is_macro::Is)]
|
||||||
@@ -569,12 +569,12 @@ pub trait Imported<'a> {
|
|||||||
impl<'a> Imported<'a> for Import<'a> {
|
impl<'a> Imported<'a> for Import<'a> {
|
||||||
/// For example, given `import foo`, returns `["foo"]`.
|
/// For example, given `import foo`, returns `["foo"]`.
|
||||||
fn call_path(&self) -> &[&'a str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
self.qualified_name.as_ref()
|
self.qualified_name.segments()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo`, returns `["foo"]`.
|
/// For example, given `import foo`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&'a str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.qualified_name[..1]
|
&self.qualified_name.segments()[..1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo`, returns `"foo"`.
|
/// For example, given `import foo`, returns `"foo"`.
|
||||||
@@ -586,12 +586,12 @@ impl<'a> Imported<'a> for Import<'a> {
|
|||||||
impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
||||||
/// For example, given `import foo.bar`, returns `["foo", "bar"]`.
|
/// For example, given `import foo.bar`, returns `["foo", "bar"]`.
|
||||||
fn call_path(&self) -> &[&'a str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
self.qualified_name.as_ref()
|
self.qualified_name.segments()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo.bar`, returns `["foo"]`.
|
/// For example, given `import foo.bar`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&'a str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.qualified_name[..1]
|
&self.qualified_name.segments()[..1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo.bar`, returns `"foo.bar"`.
|
/// For example, given `import foo.bar`, returns `"foo.bar"`.
|
||||||
@@ -603,17 +603,17 @@ impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
|||||||
impl<'a> Imported<'a> for FromImport<'a> {
|
impl<'a> Imported<'a> for FromImport<'a> {
|
||||||
/// For example, given `from foo import bar`, returns `["foo", "bar"]`.
|
/// For example, given `from foo import bar`, returns `["foo", "bar"]`.
|
||||||
fn call_path(&self) -> &[&'a str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
&self.qualified_name
|
self.qualified_name.segments()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `from foo import bar`, returns `["foo"]`.
|
/// For example, given `from foo import bar`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&'a str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.qualified_name[..self.qualified_name.len() - 1]
|
&self.qualified_name.segments()[..self.qualified_name.segments().len() - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `from foo import bar`, returns `"bar"`.
|
/// For example, given `from foo import bar`, returns `"bar"`.
|
||||||
fn member_name(&self) -> Cow<'a, str> {
|
fn member_name(&self) -> Cow<'a, str> {
|
||||||
Cow::Borrowed(self.qualified_name[self.qualified_name.len() - 1])
|
Cow::Borrowed(self.qualified_name.segments()[self.qualified_name.segments().len() - 1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ use crate::reference::{
|
|||||||
use crate::scope::{Scope, ScopeId, ScopeKind, Scopes};
|
use crate::scope::{Scope, ScopeId, ScopeKind, Scopes};
|
||||||
use crate::Imported;
|
use crate::Imported;
|
||||||
|
|
||||||
|
// pub trait Captures<U> {}
|
||||||
|
// impl<T: ?Sized, U> Captures<U> for T {}
|
||||||
|
|
||||||
/// A semantic model for a Python module, to enable querying the module's semantic information.
|
/// A semantic model for a Python module, to enable querying the module's semantic information.
|
||||||
pub struct SemanticModel<'a> {
|
pub struct SemanticModel<'a> {
|
||||||
typing_modules: &'a [String],
|
typing_modules: &'a [String],
|
||||||
@@ -692,8 +695,12 @@ impl<'a> SemanticModel<'a> {
|
|||||||
BindingKind::Import(Import { qualified_name }) => {
|
BindingKind::Import(Import { qualified_name }) => {
|
||||||
let unqualified_name = UnqualifiedName::from_expr(value)?;
|
let unqualified_name = UnqualifiedName::from_expr(value)?;
|
||||||
let (_, tail) = unqualified_name.segments().split_first()?;
|
let (_, tail) = unqualified_name.segments().split_first()?;
|
||||||
let resolved: QualifiedName =
|
let resolved: QualifiedName = qualified_name
|
||||||
qualified_name.iter().chain(tail.iter()).copied().collect();
|
.segments()
|
||||||
|
.iter()
|
||||||
|
.chain(tail.iter())
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
Some(resolved)
|
Some(resolved)
|
||||||
}
|
}
|
||||||
BindingKind::SubmoduleImport(SubmoduleImport { qualified_name }) => {
|
BindingKind::SubmoduleImport(SubmoduleImport { qualified_name }) => {
|
||||||
@@ -702,6 +709,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
|
|
||||||
Some(
|
Some(
|
||||||
qualified_name
|
qualified_name
|
||||||
|
.segments()
|
||||||
.iter()
|
.iter()
|
||||||
.take(1)
|
.take(1)
|
||||||
.chain(tail.iter())
|
.chain(tail.iter())
|
||||||
@@ -714,12 +722,18 @@ impl<'a> SemanticModel<'a> {
|
|||||||
let (_, tail) = value_name.segments().split_first()?;
|
let (_, tail) = value_name.segments().split_first()?;
|
||||||
|
|
||||||
let resolved: QualifiedName = if qualified_name
|
let resolved: QualifiedName = if qualified_name
|
||||||
|
.segments()
|
||||||
.first()
|
.first()
|
||||||
.map_or(false, |segment| *segment == ".")
|
.map_or(false, |segment| *segment == ".")
|
||||||
{
|
{
|
||||||
from_relative_import(self.module_path?, qualified_name, tail)?
|
from_relative_import(self.module_path?, qualified_name.segments(), tail)?
|
||||||
} else {
|
} else {
|
||||||
qualified_name.iter().chain(tail.iter()).copied().collect()
|
qualified_name
|
||||||
|
.segments()
|
||||||
|
.iter()
|
||||||
|
.chain(tail.iter())
|
||||||
|
.copied()
|
||||||
|
.collect()
|
||||||
};
|
};
|
||||||
Some(resolved)
|
Some(resolved)
|
||||||
}
|
}
|
||||||
@@ -780,7 +794,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
// `import sys` -> `sys.exit`
|
// `import sys` -> `sys.exit`
|
||||||
// `import sys as sys2` -> `sys2.exit`
|
// `import sys as sys2` -> `sys2.exit`
|
||||||
BindingKind::Import(Import { qualified_name }) => {
|
BindingKind::Import(Import { qualified_name }) => {
|
||||||
if qualified_name.as_ref() == module_path.as_slice() {
|
if qualified_name.segments() == module_path.as_slice() {
|
||||||
if let Some(source) = binding.source {
|
if let Some(source) = binding.source {
|
||||||
// Verify that `sys` isn't bound in an inner scope.
|
// Verify that `sys` isn't bound in an inner scope.
|
||||||
if self
|
if self
|
||||||
@@ -803,7 +817,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
// `from os.path import join as join2` -> `join2`
|
// `from os.path import join as join2` -> `join2`
|
||||||
BindingKind::FromImport(FromImport { qualified_name }) => {
|
BindingKind::FromImport(FromImport { qualified_name }) => {
|
||||||
if let Some((target_member, target_module)) =
|
if let Some((target_member, target_module)) =
|
||||||
qualified_name.split_last()
|
qualified_name.segments().split_last()
|
||||||
{
|
{
|
||||||
if target_module == module_path.as_slice()
|
if target_module == module_path.as_slice()
|
||||||
&& target_member == &member
|
&& target_member == &member
|
||||||
@@ -831,7 +845,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
// Ex) Given `module="os.path"` and `object="join"`:
|
// Ex) Given `module="os.path"` and `object="join"`:
|
||||||
// `import os.path ` -> `os.path.join`
|
// `import os.path ` -> `os.path.join`
|
||||||
BindingKind::SubmoduleImport(SubmoduleImport { qualified_name }) => {
|
BindingKind::SubmoduleImport(SubmoduleImport { qualified_name }) => {
|
||||||
if qualified_name.starts_with(&module_path) {
|
if qualified_name.segments().starts_with(&module_path) {
|
||||||
if let Some(source) = binding.source {
|
if let Some(source) = binding.source {
|
||||||
// Verify that `os` isn't bound in an inner scope.
|
// Verify that `os` isn't bound in an inner scope.
|
||||||
if self
|
if self
|
||||||
@@ -959,6 +973,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
/// Returns an [`Iterator`] over the current statement hierarchy represented as [`NodeId`],
|
/// Returns an [`Iterator`] over the current statement hierarchy represented as [`NodeId`],
|
||||||
/// from the current [`NodeId`] through to any parents.
|
/// from the current [`NodeId`] through to any parents.
|
||||||
pub fn current_statement_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
|
pub fn current_statement_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
|
||||||
|
// ) -> impl Iterator<Item = NodeId> + Captures<(&'a (), &'_ ())> {
|
||||||
self.node_id
|
self.node_id
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|id| self.nodes.ancestor_ids(*id))
|
.flat_map(|id| self.nodes.ancestor_ids(*id))
|
||||||
@@ -1555,6 +1570,7 @@ impl<'a> SemanticModel<'a> {
|
|||||||
scope_id: ScopeId,
|
scope_id: ScopeId,
|
||||||
binding_id: BindingId,
|
binding_id: BindingId,
|
||||||
) -> impl Iterator<Item = ShadowedBinding> + '_ {
|
) -> impl Iterator<Item = ShadowedBinding> + '_ {
|
||||||
|
// ) -> impl Iterator<Item = ShadowedBinding> + Captures<(&'a (), &'_ ())> {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
let mut binding_id = binding_id;
|
let mut binding_id = binding_id;
|
||||||
std::iter::from_fn(move || {
|
std::iter::from_fn(move || {
|
||||||
|
|||||||
Reference in New Issue
Block a user