diff --git a/crates/ruff/src/importer/mod.rs b/crates/ruff/src/importer/mod.rs index 6649e467c1..9f994edcf4 100644 --- a/crates/ruff/src/importer/mod.rs +++ b/crates/ruff/src/importer/mod.rs @@ -150,10 +150,7 @@ impl<'a> Importer<'a> { // Case 1: `from functools import lru_cache` is in scope, and we're trying to reference // `functools.cache`; thus, we add `cache` to the import, and return `"cache"` as the // bound name. - if semantic_model - .find_binding(member) - .map_or(true, |binding| binding.kind.is_builtin()) - { + if semantic_model.is_unbound(member) { let import_edit = self.add_member(stmt, member)?; Ok((import_edit, member.to_string())) } else { @@ -162,10 +159,7 @@ impl<'a> Importer<'a> { } else { // Case 2: No `functools` import is in scope; thus, we add `import functools`, and // return `"functools.cache"` as the bound name. - if semantic_model - .find_binding(module) - .map_or(true, |binding| binding.kind.is_builtin()) - { + if semantic_model.is_unbound(module) { let import_edit = self.add_import(&AnyImport::Import(Import::module(module)), at); Ok((import_edit, format!("{module}.{member}"))) } else { diff --git a/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs index b51c115271..c8e3809123 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs @@ -29,17 +29,15 @@ pub(crate) fn open_alias(checker: &mut Checker, expr: &Expr, func: &Expr) { .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["io", "open"]) { - let fixable = checker - .semantic_model() - .find_binding("open") - .map_or(true, |binding| binding.kind.is_builtin()); let mut diagnostic = Diagnostic::new(OpenAlias, expr.range()); - if fixable && checker.patch(diagnostic.kind.rule()) { - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( - "open".to_string(), - func.range(), - ))); + if checker.patch(diagnostic.kind.rule()) { + if checker.semantic_model().is_unbound("open") { + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( + "open".to_string(), + func.range(), + ))); + } } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index a43e718ed7..cedd65cf76 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -123,6 +123,12 @@ impl<'a> SemanticModel<'a> { .map_or(false, |binding| binding.kind.is_builtin()) } + /// Return `true` if `member` is unbound. + pub fn is_unbound(&self, member: &str) -> bool { + self.find_binding(member) + .map_or(true, |binding| binding.kind.is_builtin()) + } + /// Resolve a reference to the given symbol. pub fn resolve_reference(&mut self, symbol: &str, range: TextRange) -> ResolvedReference { // PEP 563 indicates that if a forward reference can be resolved in the module scope, we