refactor(traverse): codegen ChildScopeCollector (#5119)

Codegen `ChildScopeCollector`, so that if more types have scopes added, we don't forget to add them (like the problem #5118 fixed).

The methods are in different order in the generated version, but otherwise identical to before this PR.

`visit_finally_clause` has to be added manually, as `oxc_traverse` codegen does not read or understand `#[visit(as)]` attrs.
This commit is contained in:
overlookmotel 2024-08-23 12:49:33 +00:00
parent 25d6e20bba
commit eba5033a58
5 changed files with 186 additions and 122 deletions

View file

@ -19,6 +19,7 @@ import getTypesFromCode from './lib/parse.mjs';
import generateTraverseTraitCode from './lib/traverse.mjs';
import generateAncestorsCode from './lib/ancestor.mjs';
import generateWalkFunctionsCode from './lib/walk.mjs';
import generateScopesCollectorCode from './lib/scopes_collector.mjs';
const execAsync = promisify(exec);
@ -32,6 +33,7 @@ const outputDirPath = pathJoin(fileURLToPath(import.meta.url), '../../src/genera
await writeToFile('traverse.rs', generateTraverseTraitCode(types));
await writeToFile('ancestor.rs', generateAncestorsCode(types));
await writeToFile('walk.rs', generateWalkFunctionsCode(types));
await writeToFile('scopes_collector.rs', generateScopesCollectorCode(types));
async function writeToFile(filename, code) {
code = `${PREAMBLE}${code}`;

View file

@ -0,0 +1,50 @@
import {camelToSnake} from './utils.mjs';
export default function generateScopesCollectorCode(types) {
let methods = '';
for (const type of Object.values(types)) {
if (type.kind === 'enum' || !type.scopeArgs) continue;
const extraParams = type.scopeArgs.flags === 'flags' ? ', _flags: ScopeFlags' : '';
methods += `
#[inline]
fn visit_${camelToSnake(type.name)}(&mut self, it: &${type.rawName}${extraParams}) {
self.add_scope(&it.scope_id);
}
`;
}
return `
use std::cell::Cell;
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, visit::Visit};
use oxc_syntax::scope::{ScopeFlags, ScopeId};
/// Visitor that locates all child scopes.
/// NB: Child scopes only, not grandchild scopes.
/// Does not do full traversal - stops each time it hits a node with a scope.
pub(crate) struct ChildScopeCollector {
pub(crate) scope_ids: Vec<ScopeId>,
}
impl ChildScopeCollector {
pub(crate) fn new() -> Self {
Self { scope_ids: vec![] }
}
pub(crate) fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
self.scope_ids.push(scope_id.get().unwrap());
}
}
impl<'a> Visit<'a> for ChildScopeCollector {
${methods}
#[inline]
fn visit_finally_clause(&mut self, it: &BlockStatement<'a>) {
self.add_scope(&it.scope_id);
}
}
`;
}

View file

@ -12,6 +12,7 @@ use oxc_syntax::{
};
use super::ast_operations::GatherNodeParts;
use crate::scopes_collector::ChildScopeCollector;
/// Traverse scope context.
///
@ -516,125 +517,3 @@ fn create_uid_name_base(name: &str) -> CompactString {
str.push_str(name);
str
}
/// Visitor that locates all child scopes.
/// NB: Child scopes only, not grandchild scopes.
/// Does not do full traversal - stops each time it hits a node with a scope.
struct ChildScopeCollector {
scope_ids: Vec<ScopeId>,
}
impl ChildScopeCollector {
fn new() -> Self {
Self { scope_ids: vec![] }
}
fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
self.scope_ids.push(scope_id.get().unwrap());
}
}
impl<'a> Visit<'a> for ChildScopeCollector {
#[inline]
fn visit_program(&mut self, program: &Program<'a>) {
self.add_scope(&program.scope_id);
}
#[inline]
fn visit_block_statement(&mut self, stmt: &BlockStatement<'a>) {
self.add_scope(&stmt.scope_id);
}
#[inline]
fn visit_for_statement(&mut self, stmt: &ForStatement<'a>) {
self.add_scope(&stmt.scope_id);
}
#[inline]
fn visit_for_in_statement(&mut self, stmt: &ForInStatement<'a>) {
self.add_scope(&stmt.scope_id);
}
#[inline]
fn visit_for_of_statement(&mut self, stmt: &ForOfStatement<'a>) {
self.add_scope(&stmt.scope_id);
}
#[inline]
fn visit_switch_statement(&mut self, stmt: &SwitchStatement<'a>) {
self.add_scope(&stmt.scope_id);
}
#[inline]
fn visit_catch_clause(&mut self, clause: &CatchClause<'a>) {
self.add_scope(&clause.scope_id);
}
#[inline]
fn visit_finally_clause(&mut self, block: &BlockStatement<'a>) {
self.add_scope(&block.scope_id);
}
#[inline]
fn visit_function(&mut self, func: &Function<'a>, _flags: ScopeFlags) {
self.add_scope(&func.scope_id);
}
#[inline]
fn visit_class(&mut self, class: &Class<'a>) {
self.add_scope(&class.scope_id);
}
#[inline]
fn visit_static_block(&mut self, block: &StaticBlock<'a>) {
self.add_scope(&block.scope_id);
}
#[inline]
fn visit_arrow_function_expression(&mut self, expr: &ArrowFunctionExpression<'a>) {
self.add_scope(&expr.scope_id);
}
#[inline]
fn visit_ts_enum_declaration(&mut self, decl: &TSEnumDeclaration<'a>) {
self.add_scope(&decl.scope_id);
}
#[inline]
fn visit_ts_module_declaration(&mut self, decl: &TSModuleDeclaration<'a>) {
self.add_scope(&decl.scope_id);
}
#[inline]
fn visit_ts_interface_declaration(&mut self, it: &TSInterfaceDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_mapped_type(&mut self, it: &TSMappedType<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_conditional_type(&mut self, it: &TSConditionalType<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_type_alias_declaration(&mut self, it: &TSTypeAliasDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_method_signature(&mut self, it: &TSMethodSignature<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_construct_signature_declaration(
&mut self,
it: &TSConstructSignatureDeclaration<'a>,
) {
self.add_scope(&it.scope_id);
}
}

View file

@ -0,0 +1,131 @@
// Auto-generated code, DO NOT EDIT DIRECTLY!
// Generated by `oxc_traverse/scripts/build.mjs`.
// To alter this generated file you have to edit the codegen.
use std::cell::Cell;
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, visit::Visit};
use oxc_syntax::scope::{ScopeFlags, ScopeId};
/// Visitor that locates all child scopes.
/// NB: Child scopes only, not grandchild scopes.
/// Does not do full traversal - stops each time it hits a node with a scope.
pub(crate) struct ChildScopeCollector {
pub(crate) scope_ids: Vec<ScopeId>,
}
impl ChildScopeCollector {
pub(crate) fn new() -> Self {
Self { scope_ids: vec![] }
}
pub(crate) fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
self.scope_ids.push(scope_id.get().unwrap());
}
}
impl<'a> Visit<'a> for ChildScopeCollector {
#[inline]
fn visit_program(&mut self, it: &Program<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_block_statement(&mut self, it: &BlockStatement<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_for_statement(&mut self, it: &ForStatement<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_for_in_statement(&mut self, it: &ForInStatement<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_for_of_statement(&mut self, it: &ForOfStatement<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_switch_statement(&mut self, it: &SwitchStatement<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_catch_clause(&mut self, it: &CatchClause<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_function(&mut self, it: &Function<'a>, _flags: ScopeFlags) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_arrow_function_expression(&mut self, it: &ArrowFunctionExpression<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_class(&mut self, it: &Class<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_static_block(&mut self, it: &StaticBlock<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_enum_declaration(&mut self, it: &TSEnumDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_conditional_type(&mut self, it: &TSConditionalType<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_type_alias_declaration(&mut self, it: &TSTypeAliasDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_interface_declaration(&mut self, it: &TSInterfaceDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_method_signature(&mut self, it: &TSMethodSignature<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_construct_signature_declaration(
&mut self,
it: &TSConstructSignatureDeclaration<'a>,
) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_module_declaration(&mut self, it: &TSModuleDeclaration<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_ts_mapped_type(&mut self, it: &TSMappedType<'a>) {
self.add_scope(&it.scope_id);
}
#[inline]
fn visit_finally_clause(&mut self, it: &BlockStatement<'a>) {
self.add_scope(&it.scope_id);
}
}

View file

@ -69,11 +69,13 @@ pub use context::{TraverseAncestry, TraverseCtx, TraverseScoping};
mod generated {
pub mod ancestor;
pub(super) mod scopes_collector;
pub mod traverse;
pub(super) mod walk;
}
pub use generated::ancestor;
pub use generated::ancestor::Ancestor;
use generated::scopes_collector;
pub use generated::traverse::Traverse;
use generated::walk;