diff --git a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs index aaac685e2980f..53a5df9c5023f 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs @@ -109,7 +109,7 @@ pub(crate) fn definitions(checker: &mut Checker) { }; let definitions = std::mem::take(&mut checker.semantic.definitions); - let mut overloaded_name: Option = None; + let mut overloaded_name: Option<&str> = None; for ContextualizedDefinition { definition, visibility, @@ -127,7 +127,7 @@ pub(crate) fn definitions(checker: &mut Checker) { if !overloaded_name.is_some_and(|overloaded_name| { flake8_annotations::helpers::is_overload_impl( definition, - &overloaded_name, + overloaded_name, &checker.semantic, ) }) { diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 7b0a9bf2d627d..a046261725621 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -877,7 +877,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) { checker.diagnostics.push(Diagnostic::new( pyflakes::rules::UndefinedLocalWithNestedImportStarUsage { - name: helpers::format_import_from(level, module), + name: helpers::format_import_from(level, module).to_string(), }, stmt.range(), )); @@ -886,7 +886,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::UndefinedLocalWithImportStar) { checker.diagnostics.push(Diagnostic::new( pyflakes::rules::UndefinedLocalWithImportStar { - name: helpers::format_import_from(level, module), + name: helpers::format_import_from(level, module).to_string(), }, stmt.range(), )); diff --git a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs index 873b1859820c5..fd5b66cd4e288 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs @@ -17,10 +17,13 @@ use crate::importer::{ImportRequest, Importer}; use crate::settings::types::PythonVersion; /// Return the name of the function, if it's overloaded. -pub(crate) fn overloaded_name(definition: &Definition, semantic: &SemanticModel) -> Option { +pub(crate) fn overloaded_name<'a>( + definition: &'a Definition, + semantic: &SemanticModel, +) -> Option<&'a str> { let function = definition.as_function_def()?; if visibility::is_overload(&function.decorator_list, semantic) { - Some(function.name.to_string()) + Some(function.name.as_str()) } else { None } diff --git a/crates/ruff_linter/src/rules/isort/types.rs b/crates/ruff_linter/src/rules/isort/types.rs index 8da3ee2b15d6c..9fc4cc7ff86bc 100644 --- a/crates/ruff_linter/src/rules/isort/types.rs +++ b/crates/ruff_linter/src/rules/isort/types.rs @@ -29,29 +29,38 @@ pub(crate) struct CommentSet<'a> { pub(crate) inline: Vec>, } -pub(crate) trait Importable { - fn module_name(&self) -> String; - fn module_base(&self) -> String; -} - -impl Importable for AliasData<'_> { - fn module_name(&self) -> String { - self.name.to_string() +pub(crate) trait Importable<'a> { + fn module_name(&self) -> Cow<'a, str>; + + fn module_base(&self) -> Cow<'a, str> { + match self.module_name() { + Cow::Borrowed(module_name) => Cow::Borrowed( + module_name + .split('.') + .next() + .expect("module to include at least one segment"), + ), + Cow::Owned(module_name) => Cow::Owned( + module_name + .split('.') + .next() + .expect("module to include at least one segment") + .to_owned(), + ), + } } +} - fn module_base(&self) -> String { - self.module_name().split('.').next().unwrap().to_string() +impl<'a> Importable<'a> for AliasData<'a> { + fn module_name(&self) -> Cow<'a, str> { + Cow::Borrowed(self.name) } } -impl Importable for ImportFromData<'_> { - fn module_name(&self) -> String { +impl<'a> Importable<'a> for ImportFromData<'a> { + fn module_name(&self) -> Cow<'a, str> { format_import_from(self.level, self.module) } - - fn module_base(&self) -> String { - self.module_name().split('.').next().unwrap().to_string() - } } #[derive(Debug, Default)] diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 3beaf4a270136..7213355ff6af8 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -715,17 +715,21 @@ where /// assert_eq!(format_import_from(1, None), ".".to_string()); /// assert_eq!(format_import_from(1, Some("foo")), ".foo".to_string()); /// ``` -pub fn format_import_from(level: u32, module: Option<&str>) -> String { - let mut module_name = String::with_capacity(16); - if level > 0 { - for _ in 0..level { - module_name.push('.'); +pub fn format_import_from(level: u32, module: Option<&str>) -> Cow { + match (level, module) { + (0, Some(module)) => Cow::Borrowed(module), + (level, module) => { + let mut module_name = + String::with_capacity((level as usize) + module.map_or(0, str::len)); + for _ in 0..level { + module_name.push('.'); + } + if let Some(module) = module { + module_name.push_str(module); + } + Cow::Owned(module_name) } } - if let Some(module) = module { - module_name.push_str(module); - } - module_name } /// Format the member reference name for a relative import. @@ -740,9 +744,8 @@ pub fn format_import_from(level: u32, module: Option<&str>) -> String { /// assert_eq!(format_import_from_member(1, Some("foo"), "bar"), ".foo.bar".to_string()); /// ``` pub fn format_import_from_member(level: u32, module: Option<&str>, member: &str) -> String { - let mut qualified_name = String::with_capacity( - (level as usize) + module.as_ref().map_or(0, |module| module.len()) + 1 + member.len(), - ); + let mut qualified_name = + String::with_capacity((level as usize) + module.map_or(0, str::len) + 1 + member.len()); if level > 0 { for _ in 0..level { qualified_name.push('.');