Use `qualified_name` terminology in more structs for consistency (#4873)

This commit is contained in:
Charlie Marsh 2023-06-05 15:06:48 -04:00 committed by GitHub
parent 33434fcb9c
commit 8938b2d555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 116 additions and 105 deletions

View File

@ -57,11 +57,11 @@ pub(crate) fn remove_imports<'a>(
// entire statement. // entire statement.
let mut found_star = false; let mut found_star = false;
for import in imports { for import in imports {
let full_name = match import_body.module.as_ref() { let qualified_name = match import_body.module.as_ref() {
Some(module_name) => format!("{}.*", compose_module_path(module_name)), Some(module_name) => format!("{}.*", compose_module_path(module_name)),
None => "*".to_string(), None => "*".to_string(),
}; };
if import == full_name { if import == qualified_name {
found_star = true; found_star = true;
} else { } else {
bail!("Expected \"*\" for unused import (got: \"{}\")", import); bail!("Expected \"*\" for unused import (got: \"{}\")", import);
@ -83,26 +83,26 @@ pub(crate) fn remove_imports<'a>(
for import in imports { for import in imports {
let alias_index = aliases.iter().position(|alias| { let alias_index = aliases.iter().position(|alias| {
let full_name = match import_module { let qualified_name = match import_module {
Some((relative, module)) => { Some((relative, module)) => {
let module = module.map(compose_module_path); let module = module.map(compose_module_path);
let member = compose_module_path(&alias.name); let member = compose_module_path(&alias.name);
let mut full_name = String::with_capacity( let mut qualified_name = String::with_capacity(
relative.len() + module.as_ref().map_or(0, String::len) + member.len() + 1, relative.len() + module.as_ref().map_or(0, String::len) + member.len() + 1,
); );
for _ in 0..relative.len() { for _ in 0..relative.len() {
full_name.push('.'); qualified_name.push('.');
} }
if let Some(module) = module { if let Some(module) = module {
full_name.push_str(&module); qualified_name.push_str(&module);
full_name.push('.'); qualified_name.push('.');
} }
full_name.push_str(&member); qualified_name.push_str(&member);
full_name qualified_name
} }
None => compose_module_path(&alias.name), None => compose_module_path(&alias.name),
}; };
full_name == import qualified_name == import
}); });
if let Some(index) = alias_index { if let Some(index) = alias_index {
@ -170,26 +170,26 @@ pub(crate) fn retain_imports(
aliases.retain(|alias| { aliases.retain(|alias| {
imports.iter().any(|import| { imports.iter().any(|import| {
let full_name = match import_module { let qualified_name = match import_module {
Some((relative, module)) => { Some((relative, module)) => {
let module = module.map(compose_module_path); let module = module.map(compose_module_path);
let member = compose_module_path(&alias.name); let member = compose_module_path(&alias.name);
let mut full_name = String::with_capacity( let mut qualified_name = String::with_capacity(
relative.len() + module.as_ref().map_or(0, String::len) + member.len() + 1, relative.len() + module.as_ref().map_or(0, String::len) + member.len() + 1,
); );
for _ in 0..relative.len() { for _ in 0..relative.len() {
full_name.push('.'); qualified_name.push('.');
} }
if let Some(module) = module { if let Some(module) = module {
full_name.push_str(&module); qualified_name.push_str(&module);
full_name.push('.'); qualified_name.push('.');
} }
full_name.push_str(&member); qualified_name.push_str(&member);
full_name qualified_name
} }
None => compose_module_path(&alias.name), None => compose_module_path(&alias.name),
}; };
full_name == *import qualified_name == *import
}) })
}); });

View File

@ -848,23 +848,25 @@ where
} }
} }
} else if alias.name.contains('.') && alias.asname.is_none() { } else if alias.name.contains('.') && alias.asname.is_none() {
// Given `import foo.bar`, `name` would be "foo", and `full_name` would be // Given `import foo.bar`, `name` would be "foo", and `qualified_name` would be
// "foo.bar". // "foo.bar".
let name = alias.name.split('.').next().unwrap(); let name = alias.name.split('.').next().unwrap();
let full_name = &alias.name; let qualified_name = &alias.name;
self.add_binding( self.add_binding(
name, name,
alias.range(), alias.range(),
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name }), BindingKind::SubmoduleImportation(SubmoduleImportation {
qualified_name,
}),
BindingFlags::empty(), BindingFlags::empty(),
); );
} else { } else {
let name = alias.asname.as_ref().unwrap_or(&alias.name); let name = alias.asname.as_ref().unwrap_or(&alias.name);
let full_name = &alias.name; let qualified_name = &alias.name;
self.add_binding( self.add_binding(
name, name,
alias.range(), alias.range(),
BindingKind::Importation(Importation { full_name }), BindingKind::Importation(Importation { qualified_name }),
if alias if alias
.asname .asname
.as_ref() .as_ref()
@ -1150,16 +1152,16 @@ where
} }
} }
// Given `from foo import bar`, `name` would be "bar" and `full_name` would // Given `from foo import bar`, `name` would be "bar" and `qualified_name` would
// be "foo.bar". Given `from foo import bar as baz`, `name` would be "baz" // be "foo.bar". Given `from foo import bar as baz`, `name` would be "baz"
// and `full_name` would be "foo.bar". // and `qualified_name` would be "foo.bar".
let name = alias.asname.as_ref().unwrap_or(&alias.name); let name = alias.asname.as_ref().unwrap_or(&alias.name);
let full_name = let qualified_name =
helpers::format_import_from_member(level, module, &alias.name); helpers::format_import_from_member(level, module, &alias.name);
self.add_binding( self.add_binding(
name, name,
alias.range(), alias.range(),
BindingKind::FromImportation(FromImportation { full_name }), BindingKind::FromImportation(FromImportation { qualified_name }),
if alias if alias
.asname .asname
.as_ref() .as_ref()
@ -1195,12 +1197,12 @@ where
} }
if self.enabled(Rule::UnconventionalImportAlias) { if self.enabled(Rule::UnconventionalImportAlias) {
let full_name = let qualified_name =
helpers::format_import_from_member(level, module, &alias.name); helpers::format_import_from_member(level, module, &alias.name);
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_import_conventions::rules::conventional_import_alias( flake8_import_conventions::rules::conventional_import_alias(
stmt, stmt,
&full_name, &qualified_name,
alias.asname.as_deref(), alias.asname.as_deref(),
&self.settings.flake8_import_conventions.aliases, &self.settings.flake8_import_conventions.aliases,
) )
@ -1211,12 +1213,12 @@ where
if self.enabled(Rule::BannedImportAlias) { if self.enabled(Rule::BannedImportAlias) {
if let Some(asname) = &alias.asname { if let Some(asname) = &alias.asname {
let full_name = let qualified_name =
helpers::format_import_from_member(level, module, &alias.name); helpers::format_import_from_member(level, module, &alias.name);
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_import_conventions::rules::banned_import_alias( flake8_import_conventions::rules::banned_import_alias(
stmt, stmt,
&full_name, &qualified_name,
asname, asname,
&self.settings.flake8_import_conventions.banned_aliases, &self.settings.flake8_import_conventions.banned_aliases,
) )

View File

@ -88,7 +88,7 @@ impl<'a> Importer<'a> {
) -> Result<RuntimeImportEdit> { ) -> Result<RuntimeImportEdit> {
// Generate the modified import statement. // Generate the modified import statement.
let content = autofix::codemods::retain_imports( let content = autofix::codemods::retain_imports(
&[import.full_name], &[import.qualified_name],
import.stmt, import.stmt,
self.locator, self.locator,
self.stylist, self.stylist,
@ -120,7 +120,7 @@ impl<'a> Importer<'a> {
) -> Result<TypingImportEdit> { ) -> Result<TypingImportEdit> {
// Generate the modified import statement. // Generate the modified import statement.
let content = autofix::codemods::retain_imports( let content = autofix::codemods::retain_imports(
&[import.full_name], &[import.qualified_name],
import.stmt, import.stmt,
self.locator, self.locator,
self.stylist, self.stylist,
@ -447,7 +447,7 @@ pub(crate) struct StmtImport<'a> {
/// The import statement. /// The import statement.
pub(crate) stmt: &'a Stmt, pub(crate) stmt: &'a Stmt,
/// The "full name" of the imported module or member. /// The "full name" of the imported module or member.
pub(crate) full_name: &'a str, pub(crate) qualified_name: &'a str,
} }
/// The result of an [`Importer::get_or_import_symbol`] call. /// The result of an [`Importer::get_or_import_symbol`] call.

View File

@ -39,7 +39,7 @@ use crate::registry::AsRule;
/// - [PEP 535](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) /// - [PEP 535](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
#[violation] #[violation]
pub struct RuntimeImportInTypeCheckingBlock { pub struct RuntimeImportInTypeCheckingBlock {
full_name: String, qualified_name: String,
} }
impl Violation for RuntimeImportInTypeCheckingBlock { impl Violation for RuntimeImportInTypeCheckingBlock {
@ -47,9 +47,9 @@ impl Violation for RuntimeImportInTypeCheckingBlock {
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
let RuntimeImportInTypeCheckingBlock { full_name } = self; let RuntimeImportInTypeCheckingBlock { qualified_name } = self;
format!( format!(
"Move import `{full_name}` out of type-checking block. Import is used for more than type hinting." "Move import `{qualified_name}` out of type-checking block. Import is used for more than type hinting."
) )
} }
@ -84,7 +84,7 @@ pub(crate) fn runtime_import_in_type_checking_block(
{ {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
RuntimeImportInTypeCheckingBlock { RuntimeImportInTypeCheckingBlock {
full_name: qualified_name.to_string(), qualified_name: qualified_name.to_string(),
}, },
binding.range, binding.range,
); );
@ -110,7 +110,7 @@ pub(crate) fn runtime_import_in_type_checking_block(
let add_import_edit = checker.importer.runtime_import_edit( let add_import_edit = checker.importer.runtime_import_edit(
&StmtImport { &StmtImport {
stmt, stmt,
full_name: qualified_name, qualified_name,
}, },
reference.range().start(), reference.range().start(),
)?; )?;

View File

@ -45,7 +45,7 @@ use crate::rules::isort::{categorize, ImportSection, ImportType};
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
#[violation] #[violation]
pub struct TypingOnlyFirstPartyImport { pub struct TypingOnlyFirstPartyImport {
full_name: String, qualified_name: String,
} }
impl Violation for TypingOnlyFirstPartyImport { impl Violation for TypingOnlyFirstPartyImport {
@ -55,7 +55,7 @@ impl Violation for TypingOnlyFirstPartyImport {
fn message(&self) -> String { fn message(&self) -> String {
format!( format!(
"Move application import `{}` into a type-checking block", "Move application import `{}` into a type-checking block",
self.full_name self.qualified_name
) )
} }
@ -101,7 +101,7 @@ impl Violation for TypingOnlyFirstPartyImport {
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
#[violation] #[violation]
pub struct TypingOnlyThirdPartyImport { pub struct TypingOnlyThirdPartyImport {
full_name: String, qualified_name: String,
} }
impl Violation for TypingOnlyThirdPartyImport { impl Violation for TypingOnlyThirdPartyImport {
@ -111,7 +111,7 @@ impl Violation for TypingOnlyThirdPartyImport {
fn message(&self) -> String { fn message(&self) -> String {
format!( format!(
"Move third-party import `{}` into a type-checking block", "Move third-party import `{}` into a type-checking block",
self.full_name self.qualified_name
) )
} }
@ -157,7 +157,7 @@ impl Violation for TypingOnlyThirdPartyImport {
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
#[violation] #[violation]
pub struct TypingOnlyStandardLibraryImport { pub struct TypingOnlyStandardLibraryImport {
full_name: String, qualified_name: String,
} }
impl Violation for TypingOnlyStandardLibraryImport { impl Violation for TypingOnlyStandardLibraryImport {
@ -167,7 +167,7 @@ impl Violation for TypingOnlyStandardLibraryImport {
fn message(&self) -> String { fn message(&self) -> String {
format!( format!(
"Move standard library import `{}` into a type-checking block", "Move standard library import `{}` into a type-checking block",
self.full_name self.qualified_name
) )
} }
@ -274,7 +274,7 @@ pub(crate) fn typing_only_runtime_import(
ImportSection::Known(ImportType::LocalFolder | ImportType::FirstParty) => { ImportSection::Known(ImportType::LocalFolder | ImportType::FirstParty) => {
Diagnostic::new( Diagnostic::new(
TypingOnlyFirstPartyImport { TypingOnlyFirstPartyImport {
full_name: qualified_name.to_string(), qualified_name: qualified_name.to_string(),
}, },
binding.range, binding.range,
) )
@ -282,14 +282,14 @@ pub(crate) fn typing_only_runtime_import(
ImportSection::Known(ImportType::ThirdParty) | ImportSection::UserDefined(_) => { ImportSection::Known(ImportType::ThirdParty) | ImportSection::UserDefined(_) => {
Diagnostic::new( Diagnostic::new(
TypingOnlyThirdPartyImport { TypingOnlyThirdPartyImport {
full_name: qualified_name.to_string(), qualified_name: qualified_name.to_string(),
}, },
binding.range, binding.range,
) )
} }
ImportSection::Known(ImportType::StandardLibrary) => Diagnostic::new( ImportSection::Known(ImportType::StandardLibrary) => Diagnostic::new(
TypingOnlyStandardLibraryImport { TypingOnlyStandardLibraryImport {
full_name: qualified_name.to_string(), qualified_name: qualified_name.to_string(),
}, },
binding.range, binding.range,
), ),
@ -319,7 +319,7 @@ pub(crate) fn typing_only_runtime_import(
let add_import_edit = checker.importer.typing_import_edit( let add_import_edit = checker.importer.typing_import_edit(
&StmtImport { &StmtImport {
stmt, stmt,
full_name: qualified_name, qualified_name,
}, },
reference.range().start(), reference.range().start(),
checker.semantic_model(), checker.semantic_model(),

View File

@ -40,11 +40,9 @@ pub(crate) fn test_expression(expr: &Expr, model: &SemanticModel) -> Resolution
| BindingKind::LoopVar | BindingKind::LoopVar
| BindingKind::Global | BindingKind::Global
| BindingKind::Nonlocal => Resolution::RelevantLocal, | BindingKind::Nonlocal => Resolution::RelevantLocal,
BindingKind::Importation(Importation { full_name: module }) BindingKind::Importation(Importation {
if module == "pandas" => qualified_name: module,
{ }) if module == "pandas" => Resolution::PandasModule,
Resolution::PandasModule
}
_ => Resolution::IrrelevantBinding, _ => Resolution::IrrelevantBinding,
} }
}) })

View File

@ -71,7 +71,7 @@ pub(crate) fn inplace_argument(
matches!( matches!(
binding.kind, binding.kind,
BindingKind::Importation(Importation { BindingKind::Importation(Importation {
full_name: "pandas" qualified_name: "pandas"
}) })
) )
}); });

View File

@ -165,7 +165,9 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
let fix = if !in_init && !in_except_handler && checker.patch(Rule::UnusedImport) { let fix = if !in_init && !in_except_handler && checker.patch(Rule::UnusedImport) {
autofix::edits::remove_unused_imports( autofix::edits::remove_unused_imports(
unused_imports.iter().map(|(full_name, _)| *full_name), unused_imports
.iter()
.map(|(qualified_name, _)| *qualified_name),
stmt, stmt,
parent, parent,
checker.locator, checker.locator,
@ -177,10 +179,10 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
None None
}; };
for (full_name, range) in unused_imports { for (qualified_name, range) in unused_imports {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
UnusedImport { UnusedImport {
name: full_name.to_string(), name: qualified_name.to_string(),
context: if in_except_handler { context: if in_except_handler {
Some(UnusedImportContext::ExceptHandler) Some(UnusedImportContext::ExceptHandler)
} else if in_init { } else if in_init {
@ -217,10 +219,10 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
let multiple = unused_imports.len() > 1; let multiple = unused_imports.len() > 1;
let in_except_handler = let in_except_handler =
exceptions.intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR); exceptions.intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR);
for (full_name, range) in unused_imports { for (qualified_name, range) in unused_imports {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
UnusedImport { UnusedImport {
name: full_name.to_string(), name: qualified_name.to_string(),
context: if in_except_handler { context: if in_except_handler {
Some(UnusedImportContext::ExceptHandler) Some(UnusedImportContext::ExceptHandler)
} else if in_init { } else if in_init {

View File

@ -493,14 +493,14 @@ impl<'a> ImportReplacer<'a> {
fn format_import_from(names: &[&Alias], module: &str) -> String { fn format_import_from(names: &[&Alias], module: &str) -> String {
// Construct the whitespace strings. // Construct the whitespace strings.
// Generate the formatted names. // Generate the formatted names.
let full_names: String = names let qualified_names: String = names
.iter() .iter()
.map(|name| match &name.asname { .map(|name| match &name.asname {
Some(asname) => format!("{} as {}", name.name, asname), Some(asname) => format!("{} as {}", name.name, asname),
None => format!("{}", name.name), None => format!("{}", name.name),
}) })
.join(", "); .join(", ");
format!("from {module} import {full_names}") format!("from {module} import {qualified_names}")
} }
} }

View File

@ -800,7 +800,7 @@ pub fn format_import_from(level: Option<u32>, module: Option<&str>) -> String {
/// assert_eq!(format_import_from_member(Some(1), Some("foo"), "bar"), ".foo.bar".to_string()); /// assert_eq!(format_import_from_member(Some(1), Some("foo"), "bar"), ".foo.bar".to_string());
/// ``` /// ```
pub fn format_import_from_member(level: Option<u32>, module: Option<&str>, member: &str) -> String { pub fn format_import_from_member(level: Option<u32>, module: Option<&str>, member: &str) -> String {
let mut full_name = String::with_capacity( let mut qualified_name = String::with_capacity(
(level.unwrap_or(0) as usize) (level.unwrap_or(0) as usize)
+ module.as_ref().map_or(0, |module| module.len()) + module.as_ref().map_or(0, |module| module.len())
+ 1 + 1
@ -808,15 +808,15 @@ pub fn format_import_from_member(level: Option<u32>, module: Option<&str>, membe
); );
if let Some(level) = level { if let Some(level) = level {
for _ in 0..level { for _ in 0..level {
full_name.push('.'); qualified_name.push('.');
} }
} }
if let Some(module) = module { if let Some(module) = module {
full_name.push_str(module); qualified_name.push_str(module);
full_name.push('.'); qualified_name.push('.');
} }
full_name.push_str(member); qualified_name.push_str(member);
full_name qualified_name
} }
/// Create a module path from a (package, path) pair. /// Create a module path from a (package, path) pair.

View File

@ -48,36 +48,36 @@ impl<'a> Binding<'a> {
/// Return `true` if this binding redefines the given binding. /// Return `true` if this binding redefines the given binding.
pub fn redefines(&self, existing: &'a Binding) -> bool { pub fn redefines(&self, existing: &'a Binding) -> bool {
match &self.kind { match &self.kind {
BindingKind::Importation(Importation { full_name }) => { BindingKind::Importation(Importation { qualified_name }) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name: existing, qualified_name: existing,
}) = &existing.kind }) = &existing.kind
{ {
return full_name == existing; return qualified_name == existing;
} }
} }
BindingKind::FromImportation(FromImportation { full_name }) => { BindingKind::FromImportation(FromImportation { qualified_name }) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name: existing, qualified_name: existing,
}) = &existing.kind }) = &existing.kind
{ {
return full_name == existing; return qualified_name == existing;
} }
} }
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name }) => { BindingKind::SubmoduleImportation(SubmoduleImportation { qualified_name }) => {
match &existing.kind { match &existing.kind {
BindingKind::Importation(Importation { BindingKind::Importation(Importation {
full_name: existing, qualified_name: existing,
}) })
| BindingKind::SubmoduleImportation(SubmoduleImportation { | BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name: existing, qualified_name: existing,
}) => { }) => {
return full_name == existing; return qualified_name == existing;
} }
BindingKind::FromImportation(FromImportation { BindingKind::FromImportation(FromImportation {
full_name: existing, qualified_name: existing,
}) => { }) => {
return full_name == existing; return qualified_name == existing;
} }
_ => {} _ => {}
} }
@ -104,10 +104,12 @@ impl<'a> Binding<'a> {
/// Returns the fully-qualified symbol name, if this symbol was imported from another module. /// Returns the fully-qualified symbol name, if this symbol was imported from another module.
pub fn qualified_name(&self) -> Option<&str> { pub fn qualified_name(&self) -> Option<&str> {
match &self.kind { match &self.kind {
BindingKind::Importation(Importation { full_name }) => Some(full_name), BindingKind::Importation(Importation { qualified_name }) => Some(qualified_name),
BindingKind::FromImportation(FromImportation { full_name }) => Some(full_name), BindingKind::FromImportation(FromImportation { qualified_name }) => {
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name }) => { Some(qualified_name)
Some(full_name) }
BindingKind::SubmoduleImportation(SubmoduleImportation { qualified_name }) => {
Some(qualified_name)
} }
_ => None, _ => None,
} }
@ -117,14 +119,14 @@ impl<'a> Binding<'a> {
/// symbol was imported from another module. /// symbol was imported from another module.
pub fn module_name(&self) -> Option<&str> { pub fn module_name(&self) -> Option<&str> {
match &self.kind { match &self.kind {
BindingKind::Importation(Importation { full_name }) BindingKind::Importation(Importation { qualified_name })
| BindingKind::SubmoduleImportation(SubmoduleImportation { full_name }) => { | BindingKind::SubmoduleImportation(SubmoduleImportation { qualified_name }) => {
Some(full_name.split('.').next().unwrap_or(full_name)) Some(qualified_name.split('.').next().unwrap_or(qualified_name))
} }
BindingKind::FromImportation(FromImportation { full_name }) => Some( BindingKind::FromImportation(FromImportation { qualified_name }) => Some(
full_name qualified_name
.rsplit_once('.') .rsplit_once('.')
.map_or(full_name, |(module, _)| module), .map_or(qualified_name, |(module, _)| module),
), ),
_ => None, _ => None,
} }
@ -241,9 +243,9 @@ pub struct Export<'a> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Importation<'a> { pub struct Importation<'a> {
/// The full name of the module being imported. /// The full name of the module being imported.
/// Ex) Given `import foo`, `full_name` would be "foo". /// Ex) Given `import foo`, `qualified_name` would be "foo".
/// Ex) Given `import foo as bar`, `full_name` would be "foo". /// Ex) Given `import foo as bar`, `qualified_name` would be "foo".
pub full_name: &'a str, pub qualified_name: &'a str,
} }
/// 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.
@ -252,9 +254,9 @@ pub struct Importation<'a> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FromImportation { pub struct FromImportation {
/// The full name of the member being imported. /// The full name of the member being imported.
/// Ex) Given `from foo import bar`, `full_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`, `full_name` would be "foo.bar". /// Ex) Given `from foo import bar as baz`, `qualified_name` would be "foo.bar".
pub full_name: String, pub qualified_name: String,
} }
/// 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.
@ -262,8 +264,8 @@ pub struct FromImportation {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SubmoduleImportation<'a> { pub struct SubmoduleImportation<'a> {
/// The full name of the submodule being imported. /// The full name of the submodule being imported.
/// Ex) Given `import foo.bar`, `full_name` would be "foo.bar". /// Ex) Given `import foo.bar`, `qualified_name` would be "foo.bar".
pub full_name: &'a str, pub qualified_name: &'a str,
} }
#[derive(Clone, Debug, is_macro::Is)] #[derive(Clone, Debug, is_macro::Is)]

View File

@ -327,7 +327,9 @@ impl<'a> SemanticModel<'a> {
let head = call_path.first()?; let head = call_path.first()?;
let binding = self.find_binding(head)?; let binding = self.find_binding(head)?;
match &binding.kind { match &binding.kind {
BindingKind::Importation(Importation { full_name: name }) => { BindingKind::Importation(Importation {
qualified_name: name,
}) => {
if name.starts_with('.') { if name.starts_with('.') {
let mut source_path = from_relative_import(self.module_path?, name); let mut source_path = from_relative_import(self.module_path?, name);
if source_path.is_empty() { if source_path.is_empty() {
@ -342,13 +344,17 @@ impl<'a> SemanticModel<'a> {
Some(source_path) Some(source_path)
} }
} }
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name: name }) => { BindingKind::SubmoduleImportation(SubmoduleImportation {
qualified_name: name,
}) => {
let name = name.split('.').next().unwrap_or(name); let name = name.split('.').next().unwrap_or(name);
let mut source_path: CallPath = from_unqualified_name(name); let mut source_path: CallPath = from_unqualified_name(name);
source_path.extend(call_path.into_iter().skip(1)); source_path.extend(call_path.into_iter().skip(1));
Some(source_path) Some(source_path)
} }
BindingKind::FromImportation(FromImportation { full_name: name }) => { BindingKind::FromImportation(FromImportation {
qualified_name: name,
}) => {
if name.starts_with('.') { if name.starts_with('.') {
let mut source_path = from_relative_import(self.module_path?, name); let mut source_path = from_relative_import(self.module_path?, name);
if source_path.is_empty() { if source_path.is_empty() {
@ -397,8 +403,8 @@ impl<'a> SemanticModel<'a> {
// Ex) Given `module="sys"` and `object="exit"`: // Ex) Given `module="sys"` and `object="exit"`:
// `import sys` -> `sys.exit` // `import sys` -> `sys.exit`
// `import sys as sys2` -> `sys2.exit` // `import sys as sys2` -> `sys2.exit`
BindingKind::Importation(Importation { full_name }) => { BindingKind::Importation(Importation { qualified_name }) => {
if full_name == &module { if qualified_name == &module {
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
@ -418,8 +424,9 @@ impl<'a> SemanticModel<'a> {
// Ex) Given `module="os.path"` and `object="join"`: // Ex) Given `module="os.path"` and `object="join"`:
// `from os.path import join` -> `join` // `from os.path import join` -> `join`
// `from os.path import join as join2` -> `join2` // `from os.path import join as join2` -> `join2`
BindingKind::FromImportation(FromImportation { full_name }) => { BindingKind::FromImportation(FromImportation { qualified_name }) => {
if let Some((target_module, target_member)) = full_name.split_once('.') { if let Some((target_module, target_member)) = qualified_name.split_once('.')
{
if target_module == module && target_member == member { if target_module == module && target_member == member {
if let Some(source) = binding.source { if let Some(source) = binding.source {
// Verify that `join` isn't bound in an inner scope. // Verify that `join` isn't bound in an inner scope.