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(
left,
right,
&checker.semantic.statements,
checker.semantic.statements(),
)
})
}) {
@ -172,12 +172,14 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
continue;
}
let Some(source) = shadowed.source else {
continue;
};
// If this is an overloaded function, abort.
if shadowed.kind.is_function_definition()
&& visibility::is_overload(
cast::decorator_list(
checker.semantic.statements[shadowed.source.unwrap()],
),
cast::decorator_list(checker.semantic.statement(source)),
&checker.semantic,
)
{
@ -202,7 +204,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
branch_detection::different_forks(
left,
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.
pub(crate) fn isolation(&self, parent: Option<&Stmt>) -> IsolationLevel {
parent
.and_then(|stmt| self.semantic.statements.node_id(stmt))
.and_then(|stmt| self.semantic.statement_id(stmt))
.map_or(IsolationLevel::default(), |node_id| {
IsolationLevel::Group(node_id.into())
})

View file

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

View file

@ -193,11 +193,13 @@ struct ImportBinding<'a> {
/// Generate a [`Fix`] to remove runtime imports from a type-checking block.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id];
let parent = checker.semantic().statements.parent(statement);
let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports
.iter()
.map(|ImportBinding { import, .. }| import.member_name())
.map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect();
// 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.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id];
let parent = checker.semantic().statements.parent(statement);
let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports
.iter()
.map(|ImportBinding { import, .. }| import.member_name())
.map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect();
// 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);
if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() {
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, .. })
| Stmt::AnnAssign(ast::StmtAnnAssign {
value: Some(value), ..

View file

@ -226,12 +226,13 @@ struct ImportBinding<'a> {
/// Generate a [`Fix`] to remove unused imports from a statement.
fn fix_imports(checker: &Checker, statement_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statements[statement_id];
let parent = checker.semantic().statements.parent(statement);
let statement = checker.semantic().statement(statement_id);
let parent = checker.semantic().parent_statement(statement);
let member_names: Vec<Cow<'_, str>> = imports
.iter()
.map(|ImportBinding { import, .. }| import.member_name())
.map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect();
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);
if checker.patch(diagnostic.kind.rule()) {
if let Some(source) = source {
let stmt = checker.semantic().statements[source];
let parent = checker.semantic().statements.parent(stmt);
if let Some(fix) = remove_unused_variable(stmt, parent, range, checker) {
let statement = checker.semantic().statement(source);
let parent = checker.semantic().parent_statement(statement);
if let Some(fix) = remove_unused_variable(statement, parent, range, checker) {
diagnostic.set_fix(fix);
}
}

View file

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

View file

@ -31,7 +31,7 @@ pub struct SemanticModel<'a> {
module_path: Option<&'a [String]>,
/// Stack of all visited statements.
pub statements: Nodes<'a, Stmt>,
statements: Nodes<'a, Stmt>,
/// The identifier of the current statement.
statement_id: Option<NodeId>,
@ -919,6 +919,29 @@ impl<'a> SemanticModel<'a> {
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`].
pub fn set_globals(&mut self, globals: Globals<'a>) {
// If any global bindings don't already exist in the global scope, add them.