Make the statement vector private on SemanticModel (#6348)

## Summary

Instead, expose these as methods, now that we can use a reasonable
nomenclature on the API.
This commit is contained in:
Charlie Marsh 2023-08-07 11:02:14 -04:00 committed by GitHub
parent bae87fa016
commit 61d3977f95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 25 deletions

View file

@ -115,7 +115,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
branch_detection::different_forks( branch_detection::different_forks(
left, left,
right, right,
&checker.semantic.statements, checker.semantic.statements(),
) )
}) })
}) { }) {
@ -172,12 +172,14 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
continue; continue;
} }
let Some(source) = shadowed.source else {
continue;
};
// If this is an overloaded function, abort. // If this is an overloaded function, abort.
if shadowed.kind.is_function_definition() if shadowed.kind.is_function_definition()
&& visibility::is_overload( && visibility::is_overload(
cast::decorator_list( cast::decorator_list(checker.semantic.statement(source)),
checker.semantic.statements[shadowed.source.unwrap()],
),
&checker.semantic, &checker.semantic,
) )
{ {
@ -202,7 +204,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
branch_detection::different_forks( branch_detection::different_forks(
left, left,
right, right,
&checker.semantic.statements, checker.semantic.statements(),
) )
}) })
}) { }) {

View file

@ -202,7 +202,7 @@ impl<'a> Checker<'a> {
/// thus be applied whenever we delete a statement, but can otherwise be omitted. /// thus be applied whenever we delete a statement, but can otherwise be omitted.
pub(crate) fn isolation(&self, parent: Option<&Stmt>) -> IsolationLevel { pub(crate) fn isolation(&self, parent: Option<&Stmt>) -> IsolationLevel {
parent parent
.and_then(|stmt| self.semantic.statements.node_id(stmt)) .and_then(|stmt| self.semantic.statement_id(stmt))
.map_or(IsolationLevel::default(), |node_id| { .map_or(IsolationLevel::default(), |node_id| {
IsolationLevel::Group(node_id.into()) IsolationLevel::Group(node_id.into())
}) })

View file

@ -174,7 +174,7 @@ pub(crate) fn unused_private_type_var(
continue; continue;
}; };
let Stmt::Assign(ast::StmtAssign { targets, value, .. }) = let Stmt::Assign(ast::StmtAssign { targets, value, .. }) =
checker.semantic().statements[source] checker.semantic().statement(source)
else { else {
continue; continue;
}; };
@ -218,7 +218,7 @@ pub(crate) fn unused_private_protocol(
continue; continue;
}; };
let Stmt::ClassDef(class_def) = checker.semantic().statements[source] else { let Stmt::ClassDef(class_def) = checker.semantic().statement(source) else {
continue; continue;
}; };
@ -261,7 +261,7 @@ pub(crate) fn unused_private_type_alias(
}; };
let Stmt::AnnAssign(ast::StmtAnnAssign { let Stmt::AnnAssign(ast::StmtAnnAssign {
target, annotation, .. target, annotation, ..
}) = checker.semantic().statements[source] }) = checker.semantic().statement(source)
else { else {
continue; continue;
}; };
@ -305,7 +305,7 @@ pub(crate) fn unused_private_typed_dict(
let Some(source) = binding.source else { let Some(source) = binding.source else {
continue; continue;
}; };
let Stmt::ClassDef(class_def) = checker.semantic().statements[source] else { let Stmt::ClassDef(class_def) = checker.semantic().statement(source) else {
continue; continue;
}; };

View file

@ -193,11 +193,13 @@ struct ImportBinding<'a> {
/// Generate a [`Fix`] to remove runtime imports from a type-checking block. /// Generate a [`Fix`] to remove runtime imports from a type-checking block.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> { fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id]; let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().statements.parent(statement); let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports let member_names: Vec<Cow<'_, str>> = imports
.iter() .iter()
.map(|ImportBinding { import, .. }| import.member_name()) .map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect(); .collect();
// Find the first reference across all imports. // Find the first reference across all imports.

View file

@ -403,11 +403,13 @@ fn is_exempt(name: &str, exempt_modules: &[&str]) -> bool {
/// Generate a [`Fix`] to remove typing-only imports from a runtime context. /// Generate a [`Fix`] to remove typing-only imports from a runtime context.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> { fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id]; let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().statements.parent(statement); let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports let member_names: Vec<Cow<'_, str>> = imports
.iter() .iter()
.map(|ImportBinding { import, .. }| import.member_name()) .map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect(); .collect();
// Find the first reference across all imports. // Find the first reference across all imports.

View file

@ -107,7 +107,7 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
let binding = checker.semantic().binding(binding_id); let binding = checker.semantic().binding(binding_id);
if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() { if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() {
if let Some(parent_id) = binding.source { if let Some(parent_id) = binding.source {
let parent = checker.semantic().statements[parent_id]; let parent = checker.semantic().statement(parent_id);
if let Stmt::Assign(ast::StmtAssign { value, .. }) if let Stmt::Assign(ast::StmtAssign { value, .. })
| Stmt::AnnAssign(ast::StmtAnnAssign { | Stmt::AnnAssign(ast::StmtAnnAssign {
value: Some(value), .. value: Some(value), ..

View file

@ -226,12 +226,13 @@ struct ImportBinding<'a> {
/// Generate a [`Fix`] to remove unused imports from a statement. /// Generate a [`Fix`] to remove unused imports from a statement.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> { fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id]; let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().statements.parent(statement); let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports let member_names: Vec<Cow<'_, str>> = imports
.iter() .iter()
.map(|ImportBinding { import, .. }| import.member_name()) .map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect(); .collect();
let edit = autofix::edits::remove_unused_imports( let edit = autofix::edits::remove_unused_imports(

View file

@ -326,9 +326,9 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope, diagnostics: &mu
let mut diagnostic = Diagnostic::new(UnusedVariable { name }, range); let mut diagnostic = Diagnostic::new(UnusedVariable { name }, range);
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
if let Some(source) = source { if let Some(source) = source {
let stmt = checker.semantic().statements[source]; let statement = checker.semantic().statement(source);
let parent = checker.semantic().statements.parent(stmt); let parent = checker.semantic().parent_statement(statement);
if let Some(fix) = remove_unused_variable(stmt, parent, range, checker) { if let Some(fix) = remove_unused_variable(statement, parent, range, checker) {
diagnostic.set_fix(fix); diagnostic.set_fix(fix);
} }
} }

View file

@ -185,7 +185,7 @@ impl<'a> Binding<'a> {
/// Returns the range of the binding's parent. /// Returns the range of the binding's parent.
pub fn parent_range(&self, semantic: &SemanticModel) -> Option<TextRange> { pub fn parent_range(&self, semantic: &SemanticModel) -> Option<TextRange> {
self.source self.source
.map(|node_id| semantic.statements[node_id]) .map(|statement_id| semantic.statement(statement_id))
.and_then(|parent| { .and_then(|parent| {
if parent.is_import_from_stmt() { if parent.is_import_from_stmt() {
Some(parent.range()) Some(parent.range())

View file

@ -31,7 +31,7 @@ pub struct SemanticModel<'a> {
module_path: Option<&'a [String]>, module_path: Option<&'a [String]>,
/// Stack of all visited statements. /// Stack of all visited statements.
pub statements: Nodes<'a, Stmt>, statements: Nodes<'a, Stmt>,
/// The identifier of the current statement. /// The identifier of the current statement.
statement_id: Option<NodeId>, statement_id: Option<NodeId>,
@ -919,6 +919,29 @@ impl<'a> SemanticModel<'a> {
None None
} }
/// Return the [`Nodes`] vector of all statements.
pub const fn statements(&self) -> &Nodes<'a, Stmt> {
&self.statements
}
/// Return the [`NodeId`] corresponding to the given [`Stmt`].
#[inline]
pub fn statement_id(&self, statement: &Stmt) -> Option<NodeId> {
self.statements.node_id(statement)
}
/// Return the [`Stmt]` corresponding to the given [`NodeId`].
#[inline]
pub fn statement(&self, statement_id: NodeId) -> &'a Stmt {
self.statements[statement_id]
}
/// Given a [`Stmt`], return its parent, if any.
#[inline]
pub fn parent_statement(&self, statement: &'a Stmt) -> Option<&'a Stmt> {
self.statements.parent(statement)
}
/// Set the [`Globals`] for the current [`Scope`]. /// Set the [`Globals`] for the current [`Scope`].
pub fn set_globals(&mut self, globals: Globals<'a>) { pub fn set_globals(&mut self, globals: Globals<'a>) {
// If any global bindings don't already exist in the global scope, add them. // If any global bindings don't already exist in the global scope, add them.