Use scope-tracking logic for parents

This commit is contained in:
Charlie Marsh 2022-09-07 22:40:32 -04:00
parent a8f4faa6e4
commit 268c80c115
2 changed files with 47 additions and 30 deletions

View File

@ -27,15 +27,16 @@ struct Checker<'a> {
path: &'a str, path: &'a str,
// Computed checks. // Computed checks.
checks: Vec<Check>, checks: Vec<Check>,
// Scope tracking: retain all scopes, along with a stack of indexes to track which scopes are // Retain all scopes and parent nodes, along with a stack of indexes to track which are active
// active. // at various points in time.
parents: Vec<&'a Stmt>,
parent_stack: Vec<usize>,
scopes: Vec<Scope>, scopes: Vec<Scope>,
scope_stack: Vec<usize>, scope_stack: Vec<usize>,
parents: Vec<&'a Stmt>,
dead_scopes: Vec<usize>, dead_scopes: Vec<usize>,
deferred_annotations: Vec<&'a str>, deferred_annotations: Vec<&'a str>,
deferred_functions: Vec<(&'a Stmt, Vec<usize>)>, deferred_functions: Vec<(&'a Stmt, Vec<usize>, Vec<usize>)>,
deferred_lambdas: Vec<(&'a Expr, Vec<usize>)>, deferred_lambdas: Vec<(&'a Expr, Vec<usize>, Vec<usize>)>,
// Derivative state. // Derivative state.
in_f_string: bool, in_f_string: bool,
in_annotation: bool, in_annotation: bool,
@ -56,13 +57,14 @@ impl<'a> Checker<'a> {
path, path,
locator: SourceCodeLocator::new(content), locator: SourceCodeLocator::new(content),
checks: vec![], checks: vec![],
scope_stack: vec![], parents: vec![],
parent_stack: vec![],
scopes: vec![], scopes: vec![],
scope_stack: vec![],
dead_scopes: vec![], dead_scopes: vec![],
deferred_annotations: vec![], deferred_annotations: vec![],
deferred_functions: vec![], deferred_functions: vec![],
deferred_lambdas: vec![], deferred_lambdas: vec![],
parents: vec![],
in_f_string: false, in_f_string: false,
in_annotation: false, in_annotation: false,
seen_non_import: false, seen_non_import: false,
@ -90,7 +92,7 @@ where
'b: 'a, 'b: 'a,
{ {
fn visit_stmt(&mut self, stmt: &'b Stmt) { fn visit_stmt(&mut self, stmt: &'b Stmt) {
self.parents.push(stmt); self.push_parent(stmt);
// Pre-visit. // Pre-visit.
match &stmt.node { match &stmt.node {
@ -458,8 +460,11 @@ where
// Recurse. // Recurse.
match &stmt.node { match &stmt.node {
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => { StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
self.deferred_functions self.deferred_functions.push((
.push((stmt, self.scope_stack.clone())); stmt,
self.scope_stack.clone(),
self.parent_stack.clone(),
));
} }
StmtKind::ClassDef { body, .. } => { StmtKind::ClassDef { body, .. } => {
for stmt in body { for stmt in body {
@ -482,7 +487,7 @@ where
); );
}; };
self.parents.pop(); self.pop_parent();
} }
fn visit_annotation(&mut self, expr: &'b Expr) { fn visit_annotation(&mut self, expr: &'b Expr) {
@ -500,11 +505,9 @@ where
ExprKind::Name { ctx, .. } => match ctx { ExprKind::Name { ctx, .. } => match ctx {
ExprContext::Load => self.handle_node_load(expr), ExprContext::Load => self.handle_node_load(expr),
ExprContext::Store => { ExprContext::Store => {
let parent = self.parents.pop(); let parent =
self.handle_node_store(expr, parent); self.parents[*(self.parent_stack.last().expect("No parent found."))];
if let Some(parent) = parent { self.handle_node_store(expr, Some(parent));
self.parents.push(parent);
}
} }
ExprContext::Del => self.handle_node_delete(expr), ExprContext::Del => self.handle_node_delete(expr),
}, },
@ -747,7 +750,11 @@ where
// Recurse. // Recurse.
match &expr.node { match &expr.node {
ExprKind::Lambda { .. } => { ExprKind::Lambda { .. } => {
self.deferred_lambdas.push((expr, self.scope_stack.clone())); self.deferred_lambdas.push((
expr,
self.scope_stack.clone(),
self.parent_stack.clone(),
));
} }
_ => visitor::walk_expr(self, expr), _ => visitor::walk_expr(self, expr),
} }
@ -774,7 +781,8 @@ where
let scope = let scope =
&self.scopes[*(self.scope_stack.last().expect("No current scope found."))]; &self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
if scope.values.contains_key(name) { if scope.values.contains_key(name) {
let parent = self.parents.pop(); let parent =
self.parents[*(self.parent_stack.last().expect("No parent found."))];
self.handle_node_store( self.handle_node_store(
&Expr::new( &Expr::new(
excepthandler.location, excepthandler.location,
@ -783,14 +791,13 @@ where
ctx: ExprContext::Store, ctx: ExprContext::Store,
}, },
), ),
parent, Some(parent),
); );
if let Some(parent) = parent { self.parents.push(parent);
self.parents.push(parent);
}
} }
let parent = self.parents.pop(); let parent =
self.parents[*(self.parent_stack.last().expect("No parent found."))];
let scope = let scope =
&self.scopes[*(self.scope_stack.last().expect("No current scope found."))]; &self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
let definition = scope.values.get(name).cloned(); let definition = scope.values.get(name).cloned();
@ -802,11 +809,9 @@ where
ctx: ExprContext::Store, ctx: ExprContext::Store,
}, },
), ),
parent, Some(parent),
); );
if let Some(parent) = parent { self.parents.push(parent);
self.parents.push(parent);
}
walk_excepthandler(self, excepthandler); walk_excepthandler(self, excepthandler);
@ -881,6 +886,17 @@ where
} }
impl<'a> Checker<'a> { impl<'a> Checker<'a> {
fn push_parent(&mut self, parent: &'a Stmt) {
self.parent_stack.push(self.parents.len());
self.parents.push(parent);
}
fn pop_parent(&mut self) {
self.parent_stack
.pop()
.expect("Attempted to pop without scope.");
}
fn push_scope(&mut self, scope: Scope) { fn push_scope(&mut self, scope: Scope) {
self.scope_stack.push(self.scopes.len()); self.scope_stack.push(self.scopes.len());
self.scopes.push(scope); self.scopes.push(scope);
@ -1062,8 +1078,9 @@ impl<'a> Checker<'a> {
fn check_deferred_functions(&mut self) { fn check_deferred_functions(&mut self) {
while !self.deferred_functions.is_empty() { while !self.deferred_functions.is_empty() {
let (stmt, scopes) = self.deferred_functions.pop().unwrap(); let (stmt, scopes, parents) = self.deferred_functions.pop().unwrap();
self.parent_stack = parents;
self.scope_stack = scopes; self.scope_stack = scopes;
self.push_scope(Scope::new(ScopeKind::Function)); self.push_scope(Scope::new(ScopeKind::Function));
@ -1102,8 +1119,9 @@ impl<'a> Checker<'a> {
fn check_deferred_lambdas(&mut self) { fn check_deferred_lambdas(&mut self) {
while !self.deferred_lambdas.is_empty() { while !self.deferred_lambdas.is_empty() {
let (expr, scopes) = self.deferred_lambdas.pop().unwrap(); let (expr, scopes, parents) = self.deferred_lambdas.pop().unwrap();
self.parent_stack = parents;
self.scope_stack = scopes; self.scope_stack = scopes;
self.push_scope(Scope::new(ScopeKind::Function)); self.push_scope(Scope::new(ScopeKind::Function));

View File

@ -13,7 +13,6 @@ use crate::settings::Settings;
use crate::{autofix, cache, fs}; use crate::{autofix, cache, fs};
fn check_path(path: &Path, settings: &Settings, autofix: &autofix::Mode) -> Result<Vec<Check>> { fn check_path(path: &Path, settings: &Settings, autofix: &autofix::Mode) -> Result<Vec<Check>> {
println!("{:?}", path);
// Read the file from disk. // Read the file from disk.
let contents = fs::read_file(path)?; let contents = fs::read_file(path)?;