[ty] Move some pub functions in ty_python_core to be pub(crate) functions in ty_python_semantic (#24604)

This commit is contained in:
Alex Waygood authored and GitHub committed 2026-04-13 13:20:02 +01:00
1 parent 122a6c2a00
commit 28b5ce0307
7 files changed
+81 -69

No files matched your search

-7
View File
@@ -132,13 +132,6 @@ impl<'db> Definition<'db> {
}
}
/// Get the module-level docstring for the given file.
pub fn module_docstring(db: &dyn Db, file: File) -> Option<String> {
let module = parsed_module(db, file).load(db);
docstring_from_body(module.suite())
.map(|docstring_expr| docstring_expr.value.to_str().to_owned())
}
/// Extract a docstring from a function, module, or class body.
fn docstring_from_body(body: &[ast::Stmt]) -> Option<&ast::ExprStringLiteral> {
let stmt = body.first()?;
+9 -55
View File
@@ -80,16 +80,6 @@ pub fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<PlaceTable>
Arc::clone(&index.place_tables[scope.file_scope_id(db)])
}
/// Returns the set of modules that are imported anywhere in `file`.
///
/// This set only considers `import` statements, not `from...import` statements.
/// See [`ModuleLiteralType::available_submodule_attributes`] for discussion
/// of why this analysis is intentionally limited.
#[salsa::tracked(returns(deref), heap_size=ruff_memory_usage::heap_size)]
pub fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSet<ModuleName>> {
semantic_index(db, file).imported_modules.clone()
}
/// Returns the use-def map for a specific `scope`.
///
/// Using [`use_def_map`] over [`semantic_index`] has the advantage that
@@ -192,51 +182,6 @@ pub fn get_loop_header<'db>(_db: &'db dyn Db, _loop_token: LoopToken<'db>) -> Lo
panic!("should always be set by specify()");
}
/// Returns all attribute assignments (and their method scope IDs) with a symbol name matching
/// the one given for a specific class body scope.
///
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
/// introduces a direct dependency on that file's AST.
pub fn attribute_assignments<'db, 's>(
db: &'db dyn Db,
class_body_scope: ScopeId<'db>,
name: &'s str,
) -> impl Iterator<Item = (BindingWithConstraintsIterator<'db, 'db>, FileScopeId)> + use<'s, 'db> {
let file = class_body_scope.file(db);
let index = semantic_index(db, file);
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
let place_table = index.place_table(function_scope_id);
let member = place_table.member_id_by_instance_attribute_name(name)?;
let use_def = &index.use_def_maps[function_scope_id];
Some((use_def.reachable_member_bindings(member), function_scope_id))
})
}
/// Returns all attribute declarations (and their method scope IDs) with a symbol name matching
/// the one given for a specific class body scope.
///
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
/// introduces a direct dependency on that file's AST.
pub fn attribute_declarations<'db, 's>(
db: &'db dyn Db,
class_body_scope: ScopeId<'db>,
name: &'s str,
) -> impl Iterator<Item = (DeclarationsIterator<'db, 'db>, FileScopeId)> + use<'s, 'db> {
let file = class_body_scope.file(db);
let index = semantic_index(db, file);
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
let place_table = index.place_table(function_scope_id);
let member = place_table.member_id_by_instance_attribute_name(name)?;
let use_def = &index.use_def_maps[function_scope_id];
Some((
use_def.reachable_member_declarations(member),
function_scope_id,
))
})
}
/// Returns all attribute assignments as scope IDs for a specific class body scope.
///
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
@@ -376,6 +321,15 @@ impl<'db> SemanticIndex<'db> {
&self.use_def_maps[scope_id]
}
/// Returns the set of modules that are imported anywhere in this file.
///
/// This set only considers `import` statements, not `from...import` statements.
/// See `ModuleLiteralType::available_submodule_attributes` for discussion
/// of why this analysis is intentionally limited.
pub fn imported_modules(&self) -> &FxHashSet<ModuleName> {
&self.imported_modules
}
#[track_caller]
pub(crate) fn ast_ids(&self, scope_id: FileScopeId) -> &AstIds {
&self.ast_ids[scope_id]
+64
View File
@@ -10,6 +10,9 @@ use crate::suppression::{
};
pub use db::Db;
pub use diagnostic::add_inferred_python_version_hint_to_diagnostic;
use ruff_db::files::File;
use ruff_db::parsed::parsed_module;
use ruff_python_ast as ast;
use rustc_hash::FxHasher;
pub use semantic_model::{
Completion, HasDefinition, HasOptionalDefinition, HasType, MemberDefinition, NameKind,
@@ -21,6 +24,11 @@ pub use suppression::{
use ty_module_resolver::ModuleGlobSet;
use ty_python_core::platform::PythonPlatform;
use ty_python_core::program::Program;
use ty_python_core::scope::ScopeId;
use ty_python_core::{
BindingWithConstraintsIterator, DeclarationsIterator, FileScopeId, attribute_scopes,
semantic_index,
};
pub use ty_site_packages::{
PythonEnvironment, PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource,
SitePackagesPaths, SysPrefixPathOrigin,
@@ -97,3 +105,59 @@ impl Default for AnalysisSettings {
}
}
}
/// Returns all attribute assignments (and their method scope IDs) with a symbol name matching
/// the one given for a specific class body scope.
///
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
/// introduces a direct dependency on that file's AST.
pub(crate) fn attribute_assignments<'db, 's>(
db: &'db dyn Db,
class_body_scope: ScopeId<'db>,
name: &'s str,
) -> impl Iterator<Item = (BindingWithConstraintsIterator<'db, 'db>, FileScopeId)> + use<'s, 'db> {
let file = class_body_scope.file(db);
let index = semantic_index(db, file);
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
let place_table = index.place_table(function_scope_id);
let member = place_table.member_id_by_instance_attribute_name(name)?;
let use_def = index.use_def_map(function_scope_id);
Some((use_def.reachable_member_bindings(member), function_scope_id))
})
}
/// Returns all attribute declarations (and their method scope IDs) with a symbol name matching
/// the one given for a specific class body scope.
///
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
/// introduces a direct dependency on that file's AST.
pub(crate) fn attribute_declarations<'db, 's>(
db: &'db dyn Db,
class_body_scope: ScopeId<'db>,
name: &'s str,
) -> impl Iterator<Item = (DeclarationsIterator<'db, 'db>, FileScopeId)> + use<'s, 'db> {
let file = class_body_scope.file(db);
let index = semantic_index(db, file);
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
let place_table = index.place_table(function_scope_id);
let member = place_table.member_id_by_instance_attribute_name(name)?;
let use_def = index.use_def_map(function_scope_id);
Some((
use_def.reachable_member_declarations(member),
function_scope_id,
))
})
}
/// Get the module-level docstring for the given file.
pub(crate) fn module_docstring(db: &dyn Db, file: File) -> Option<String> {
let module = parsed_module(db, file).load(db);
let stmt = module.suite().first()?;
let ast::Stmt::Expr(ast::StmtExpr { value, .. }) = stmt else {
return None;
};
let docstring_expr = value.as_string_literal_expr()?;
Some(docstring_expr.value.to_str().to_owned())
}
+2 -2
View File
@@ -95,7 +95,7 @@ pub use special_form::SpecialFormType;
use ty_python_core::definition::Definition;
use ty_python_core::place::ScopedPlaceId;
use ty_python_core::scope::ScopeId;
use ty_python_core::{Truthiness, imported_modules, place_table, semantic_index};
use ty_python_core::{Truthiness, place_table, semantic_index};
mod bool;
mod bound_super;
@@ -7422,7 +7422,7 @@ impl<'db> ModuleLiteralType<'db> {
fn available_submodule_attributes(&self, db: &'db dyn Db) -> impl Iterator<Item = Name> {
self.importing_file(db)
.into_iter()
.flat_map(|file| imported_modules(db, file))
.flat_map(|file| semantic_index(db, file).imported_modules())
.filter_map(|submodule_name| submodule_name.relative_to(self.module(db).name(db)))
.filter_map(|relative_submodule| relative_submodule.components().next().map(Name::from))
}
@@ -52,8 +52,9 @@ use crate::{
visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard},
},
};
use crate::{attribute_assignments, attribute_declarations};
use ty_python_core::{
attribute_assignments, attribute_declarations, attribute_scopes,
attribute_scopes,
definition::{Definition, DefinitionKind, DefinitionState, TargetKind},
place_table,
scope::{Scope, ScopeId},
@@ -1324,7 +1324,8 @@ mod resolve_definition {
use ty_module_resolver::{ModuleName, file_to_module, resolve_module, resolve_real_module};
use crate::Db;
use ty_python_core::definition::{Definition, DefinitionKind, module_docstring};
use crate::module_docstring;
use ty_python_core::definition::{Definition, DefinitionKind};
use ty_python_core::scope::{NodeWithScopeKind, ScopeId};
use ty_python_core::{global_scope, place_table, semantic_index, use_def_map};
@@ -9,6 +9,7 @@ use ruff_python_ast as ast;
use ruff_text_size::{Ranged, TextRange, TextSize};
use rustc_hash::FxHashMap;
use crate::attribute_assignments;
use crate::{
TypeQualifiers,
diagnostic::format_enumeration,
@@ -49,9 +50,7 @@ use crate::{
visitor::find_over_type,
},
};
use ty_python_core::{
SemanticIndex, attribute_assignments, definition::DefinitionKind, scope::ScopeId,
};
use ty_python_core::{SemanticIndex, definition::DefinitionKind, scope::ScopeId};
/// Iterate over all static class definitions (created using `class` statements) to check that
/// the definition will not cause an exception to be raised at runtime. This needs to be done