diff --git a/crates/oxc_ast/src/ast_builder_impl.rs b/crates/oxc_ast/src/ast_builder_impl.rs index 3dc648715e040..e6afa07386b90 100644 --- a/crates/oxc_ast/src/ast_builder_impl.rs +++ b/crates/oxc_ast/src/ast_builder_impl.rs @@ -13,12 +13,25 @@ use oxc_syntax::{number::NumberBase, operator::UnaryOperator}; #[allow(clippy::wildcard_imports)] use crate::ast::*; -use crate::AstBuilder; +use crate::{ + stats::{Statistics, StatisticsCell}, + AstBuilder, +}; impl<'a> AstBuilder<'a> { #[inline] + #[must_use] pub fn new(allocator: &'a Allocator) -> Self { - Self { allocator } + Self { allocator, stats: None } + } + + #[inline] + #[must_use] + pub fn with_statistics(mut self) -> Self { + if self.stats.is_none() { + self.stats = Some(StatisticsCell::default()); + } + self } #[inline] @@ -58,11 +71,10 @@ impl<'a> AstBuilder<'a> { Atom::from(String::from_str_in(value, self.allocator).into_bump_str()) } - /// # SAFETY + /// # Safety /// This method is completely unsound and should not be used. /// We need to remove all uses of it. Please don't add any more! /// - #[allow(clippy::missing_safety_doc)] #[inline] pub unsafe fn copy(self, src: &T) -> T { // SAFETY: Not safe (see above) @@ -105,6 +117,36 @@ impl<'a> AstBuilder<'a> { mem::replace(decl, empty_decl) } + /* ---------- Statistics ---------- */ + + pub fn take_stats(mut self) -> Option { + self.stats.take().map(StatisticsCell::take) + } + + pub(crate) fn observe_node(self) { + if let Some(s) = self.stats { + s.observe_node(); + } + } + + pub(crate) fn observe_symbol(self) { + if let Some(s) = self.stats { + s.observe_symbol(); + } + } + + pub(crate) fn observe_scope(self) { + if let Some(s) = self.stats { + s.observe_scope(); + } + } + + pub(crate) fn observe_reference(self) { + if let Some(s) = self.stats { + s.observe_reference(); + } + } + /* ---------- Constructors ---------- */ /// `void 0` diff --git a/crates/oxc_ast/src/generated/ast_builder.rs b/crates/oxc_ast/src/generated/ast_builder.rs index ebaf45bf99641..29261b503d054 100644 --- a/crates/oxc_ast/src/generated/ast_builder.rs +++ b/crates/oxc_ast/src/generated/ast_builder.rs @@ -11,12 +11,14 @@ use oxc_allocator::{Allocator, Box, IntoIn, Vec}; #[allow(clippy::wildcard_imports)] use crate::ast::*; +use crate::stats::StatisticsCell; /// AST builder for creating AST nodes #[derive(Clone, Copy)] #[non_exhaustive] pub struct AstBuilder<'a> { pub allocator: &'a Allocator, + pub(crate) stats: Option>, } impl<'a> AstBuilder<'a> { @@ -29,6 +31,7 @@ impl<'a> AstBuilder<'a> { /// - value #[inline] pub fn boolean_literal(self, span: Span, value: bool) -> BooleanLiteral { + self.observe_node(); BooleanLiteral { span, value } } @@ -52,6 +55,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn null_literal(self, span: Span) -> NullLiteral { + self.observe_node(); NullLiteral { span } } @@ -86,6 +90,7 @@ impl<'a> AstBuilder<'a> { where S: IntoIn<'a, &'a str>, { + self.observe_node(); NumericLiteral { span, value, raw: raw.into_in(self.allocator), base } } @@ -125,6 +130,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); BigIntLiteral { span, raw: raw.into_in(self.allocator), base } } @@ -164,6 +170,7 @@ impl<'a> AstBuilder<'a> { value: EmptyObject, regex: RegExp<'a>, ) -> RegExpLiteral<'a> { + self.observe_node(); RegExpLiteral { span, value, regex } } @@ -197,6 +204,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); StringLiteral { span, value: value.into_in(self.allocator) } } @@ -234,6 +242,8 @@ impl<'a> AstBuilder<'a> { directives: Vec<'a, Directive<'a>>, body: Vec<'a, Statement<'a>>, ) -> Program<'a> { + self.observe_node(); + self.observe_scope(); Program { span, source_type, hashbang, directives, body, scope_id: Default::default() } } @@ -1475,6 +1485,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); IdentifierName { span, name: name.into_in(self.allocator) } } @@ -1505,6 +1516,8 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); + self.observe_reference(); IdentifierReference { span, name: name.into_in(self.allocator), @@ -1544,6 +1557,8 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); + self.observe_symbol(); BindingIdentifier { span, name: name.into_in(self.allocator), @@ -1578,6 +1593,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); LabelIdentifier { span, name: name.into_in(self.allocator) } } @@ -1604,6 +1620,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn this_expression(self, span: Span) -> ThisExpression { + self.observe_node(); ThisExpression { span } } @@ -1633,6 +1650,7 @@ impl<'a> AstBuilder<'a> { elements: Vec<'a, ArrayExpressionElement<'a>>, trailing_comma: Option, ) -> ArrayExpression<'a> { + self.observe_node(); ArrayExpression { span, elements, trailing_comma } } @@ -1716,6 +1734,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn elision(self, span: Span) -> Elision { + self.observe_node(); Elision { span } } @@ -1745,6 +1764,7 @@ impl<'a> AstBuilder<'a> { properties: Vec<'a, ObjectPropertyKind<'a>>, trailing_comma: Option, ) -> ObjectExpression<'a> { + self.observe_node(); ObjectExpression { span, properties, trailing_comma } } @@ -1857,6 +1877,7 @@ impl<'a> AstBuilder<'a> { shorthand: bool, computed: bool, ) -> ObjectProperty<'a> { + self.observe_node(); ObjectProperty { span, kind, key, value, init, method, shorthand, computed } } @@ -1959,6 +1980,7 @@ impl<'a> AstBuilder<'a> { quasis: Vec<'a, TemplateElement<'a>>, expressions: Vec<'a, Expression<'a>>, ) -> TemplateLiteral<'a> { + self.observe_node(); TemplateLiteral { span, quasis, expressions } } @@ -2000,6 +2022,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TaggedTemplateExpression { span, tag, @@ -2049,6 +2072,7 @@ impl<'a> AstBuilder<'a> { tail: bool, value: TemplateElementValue<'a>, ) -> TemplateElement<'a> { + self.observe_node(); TemplateElement { span, tail, value } } @@ -2183,6 +2207,7 @@ impl<'a> AstBuilder<'a> { expression: Expression<'a>, optional: bool, ) -> ComputedMemberExpression<'a> { + self.observe_node(); ComputedMemberExpression { span, object, expression, optional } } @@ -2226,6 +2251,7 @@ impl<'a> AstBuilder<'a> { property: IdentifierName<'a>, optional: bool, ) -> StaticMemberExpression<'a> { + self.observe_node(); StaticMemberExpression { span, object, property, optional } } @@ -2266,6 +2292,7 @@ impl<'a> AstBuilder<'a> { field: PrivateIdentifier<'a>, optional: bool, ) -> PrivateFieldExpression<'a> { + self.observe_node(); PrivateFieldExpression { span, object, field, optional } } @@ -2311,6 +2338,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); CallExpression { span, arguments, @@ -2368,6 +2396,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); NewExpression { span, callee, @@ -2414,6 +2443,7 @@ impl<'a> AstBuilder<'a> { meta: IdentifierName<'a>, property: IdentifierName<'a>, ) -> MetaProperty<'a> { + self.observe_node(); MetaProperty { span, meta, property } } @@ -2444,6 +2474,7 @@ impl<'a> AstBuilder<'a> { /// - argument: The expression being spread. #[inline] pub fn spread_element(self, span: Span, argument: Expression<'a>) -> SpreadElement<'a> { + self.observe_node(); SpreadElement { span, argument } } @@ -2506,6 +2537,7 @@ impl<'a> AstBuilder<'a> { prefix: bool, argument: SimpleAssignmentTarget<'a>, ) -> UpdateExpression<'a> { + self.observe_node(); UpdateExpression { span, operator, prefix, argument } } @@ -2544,6 +2576,7 @@ impl<'a> AstBuilder<'a> { operator: UnaryOperator, argument: Expression<'a>, ) -> UnaryExpression<'a> { + self.observe_node(); UnaryExpression { span, operator, argument } } @@ -2582,6 +2615,7 @@ impl<'a> AstBuilder<'a> { operator: BinaryOperator, right: Expression<'a>, ) -> BinaryExpression<'a> { + self.observe_node(); BinaryExpression { span, left, operator, right } } @@ -2622,6 +2656,7 @@ impl<'a> AstBuilder<'a> { operator: BinaryOperator, right: Expression<'a>, ) -> PrivateInExpression<'a> { + self.observe_node(); PrivateInExpression { span, left, operator, right } } @@ -2662,6 +2697,7 @@ impl<'a> AstBuilder<'a> { operator: LogicalOperator, right: Expression<'a>, ) -> LogicalExpression<'a> { + self.observe_node(); LogicalExpression { span, left, operator, right } } @@ -2702,6 +2738,7 @@ impl<'a> AstBuilder<'a> { consequent: Expression<'a>, alternate: Expression<'a>, ) -> ConditionalExpression<'a> { + self.observe_node(); ConditionalExpression { span, test, consequent, alternate } } @@ -2742,6 +2779,7 @@ impl<'a> AstBuilder<'a> { left: AssignmentTarget<'a>, right: Expression<'a>, ) -> AssignmentExpression<'a> { + self.observe_node(); AssignmentExpression { span, operator, left, right } } @@ -3075,6 +3113,7 @@ impl<'a> AstBuilder<'a> { rest: Option>, trailing_comma: Option, ) -> ArrayAssignmentTarget<'a> { + self.observe_node(); ArrayAssignmentTarget { span, elements, rest, trailing_comma } } @@ -3116,6 +3155,7 @@ impl<'a> AstBuilder<'a> { properties: Vec<'a, AssignmentTargetProperty<'a>>, rest: Option>, ) -> ObjectAssignmentTarget<'a> { + self.observe_node(); ObjectAssignmentTarget { span, properties, rest } } @@ -3150,6 +3190,7 @@ impl<'a> AstBuilder<'a> { span: Span, target: AssignmentTarget<'a>, ) -> AssignmentTargetRest<'a> { + self.observe_node(); AssignmentTargetRest { span, target } } @@ -3224,6 +3265,7 @@ impl<'a> AstBuilder<'a> { binding: AssignmentTarget<'a>, init: Expression<'a>, ) -> AssignmentTargetWithDefault<'a> { + self.observe_node(); AssignmentTargetWithDefault { span, binding, init } } @@ -3324,6 +3366,7 @@ impl<'a> AstBuilder<'a> { binding: IdentifierReference<'a>, init: Option>, ) -> AssignmentTargetPropertyIdentifier<'a> { + self.observe_node(); AssignmentTargetPropertyIdentifier { span, binding, init } } @@ -3360,6 +3403,7 @@ impl<'a> AstBuilder<'a> { name: PropertyKey<'a>, binding: AssignmentTargetMaybeDefault<'a>, ) -> AssignmentTargetPropertyProperty<'a> { + self.observe_node(); AssignmentTargetPropertyProperty { span, name, binding } } @@ -3394,6 +3438,7 @@ impl<'a> AstBuilder<'a> { span: Span, expressions: Vec<'a, Expression<'a>>, ) -> SequenceExpression<'a> { + self.observe_node(); SequenceExpression { span, expressions } } @@ -3421,6 +3466,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn super_(self, span: Span) -> Super { + self.observe_node(); Super { span } } @@ -3444,6 +3490,7 @@ impl<'a> AstBuilder<'a> { /// - argument #[inline] pub fn await_expression(self, span: Span, argument: Expression<'a>) -> AwaitExpression<'a> { + self.observe_node(); AwaitExpression { span, argument } } @@ -3472,6 +3519,7 @@ impl<'a> AstBuilder<'a> { /// - expression #[inline] pub fn chain_expression(self, span: Span, expression: ChainElement<'a>) -> ChainExpression<'a> { + self.observe_node(); ChainExpression { span, expression } } @@ -3549,6 +3597,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: Expression<'a>, ) -> ParenthesizedExpression<'a> { + self.observe_node(); ParenthesizedExpression { span, expression } } @@ -4057,6 +4106,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); Directive { span, expression, directive: directive.into_in(self.allocator) } } @@ -4093,6 +4143,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); Hashbang { span, value: value.into_in(self.allocator) } } @@ -4120,6 +4171,8 @@ impl<'a> AstBuilder<'a> { /// - body #[inline] pub fn block_statement(self, span: Span, body: Vec<'a, Statement<'a>>) -> BlockStatement<'a> { + self.observe_node(); + self.observe_scope(); BlockStatement { span, body, scope_id: Default::default() } } @@ -4526,6 +4579,7 @@ impl<'a> AstBuilder<'a> { declarations: Vec<'a, VariableDeclarator<'a>>, declare: bool, ) -> VariableDeclaration<'a> { + self.observe_node(); VariableDeclaration { span, kind, declarations, declare } } @@ -4568,6 +4622,7 @@ impl<'a> AstBuilder<'a> { init: Option>, definite: bool, ) -> VariableDeclarator<'a> { + self.observe_node(); VariableDeclarator { span, kind, id, init, definite } } @@ -4608,6 +4663,7 @@ impl<'a> AstBuilder<'a> { is_await: bool, declarations: Vec<'a, VariableDeclarator<'a>>, ) -> UsingDeclaration<'a> { + self.observe_node(); UsingDeclaration { span, is_await, declarations } } @@ -4637,6 +4693,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn empty_statement(self, span: Span) -> EmptyStatement { + self.observe_node(); EmptyStatement { span } } @@ -4664,6 +4721,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: Expression<'a>, ) -> ExpressionStatement<'a> { + self.observe_node(); ExpressionStatement { span, expression } } @@ -4700,6 +4758,7 @@ impl<'a> AstBuilder<'a> { consequent: Statement<'a>, alternate: Option>, ) -> IfStatement<'a> { + self.observe_node(); IfStatement { span, test, consequent, alternate } } @@ -4738,6 +4797,7 @@ impl<'a> AstBuilder<'a> { body: Statement<'a>, test: Expression<'a>, ) -> DoWhileStatement<'a> { + self.observe_node(); DoWhileStatement { span, body, test } } @@ -4774,6 +4834,7 @@ impl<'a> AstBuilder<'a> { test: Expression<'a>, body: Statement<'a>, ) -> WhileStatement<'a> { + self.observe_node(); WhileStatement { span, test, body } } @@ -4814,6 +4875,8 @@ impl<'a> AstBuilder<'a> { update: Option>, body: Statement<'a>, ) -> ForStatement<'a> { + self.observe_node(); + self.observe_scope(); ForStatement { span, init, test, update, body, scope_id: Default::default() } } @@ -4926,6 +4989,8 @@ impl<'a> AstBuilder<'a> { right: Expression<'a>, body: Statement<'a>, ) -> ForInStatement<'a> { + self.observe_node(); + self.observe_scope(); ForInStatement { span, left, right, body, scope_id: Default::default() } } @@ -5041,6 +5106,8 @@ impl<'a> AstBuilder<'a> { right: Expression<'a>, body: Statement<'a>, ) -> ForOfStatement<'a> { + self.observe_node(); + self.observe_scope(); ForOfStatement { span, r#await, left, right, body, scope_id: Default::default() } } @@ -5079,6 +5146,7 @@ impl<'a> AstBuilder<'a> { span: Span, label: Option>, ) -> ContinueStatement<'a> { + self.observe_node(); ContinueStatement { span, label } } @@ -5111,6 +5179,7 @@ impl<'a> AstBuilder<'a> { span: Span, label: Option>, ) -> BreakStatement<'a> { + self.observe_node(); BreakStatement { span, label } } @@ -5143,6 +5212,7 @@ impl<'a> AstBuilder<'a> { span: Span, argument: Option>, ) -> ReturnStatement<'a> { + self.observe_node(); ReturnStatement { span, argument } } @@ -5177,6 +5247,7 @@ impl<'a> AstBuilder<'a> { object: Expression<'a>, body: Statement<'a>, ) -> WithStatement<'a> { + self.observe_node(); WithStatement { span, object, body } } @@ -5213,6 +5284,8 @@ impl<'a> AstBuilder<'a> { discriminant: Expression<'a>, cases: Vec<'a, SwitchCase<'a>>, ) -> SwitchStatement<'a> { + self.observe_node(); + self.observe_scope(); SwitchStatement { span, discriminant, cases, scope_id: Default::default() } } @@ -5249,6 +5322,7 @@ impl<'a> AstBuilder<'a> { test: Option>, consequent: Vec<'a, Statement<'a>>, ) -> SwitchCase<'a> { + self.observe_node(); SwitchCase { span, test, consequent } } @@ -5285,6 +5359,7 @@ impl<'a> AstBuilder<'a> { label: LabelIdentifier<'a>, body: Statement<'a>, ) -> LabeledStatement<'a> { + self.observe_node(); LabeledStatement { span, label, body } } @@ -5315,6 +5390,7 @@ impl<'a> AstBuilder<'a> { /// - argument #[inline] pub fn throw_statement(self, span: Span, argument: Expression<'a>) -> ThrowStatement<'a> { + self.observe_node(); ThrowStatement { span, argument } } @@ -5356,6 +5432,7 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Option>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); TryStatement { span, block: block.into_in(self.allocator), @@ -5407,6 +5484,8 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, BlockStatement<'a>>>, { + self.observe_node(); + self.observe_scope(); CatchClause { span, param, @@ -5445,6 +5524,7 @@ impl<'a> AstBuilder<'a> { /// - pattern #[inline] pub fn catch_parameter(self, span: Span, pattern: BindingPattern<'a>) -> CatchParameter<'a> { + self.observe_node(); CatchParameter { span, pattern } } @@ -5472,6 +5552,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn debugger_statement(self, span: Span) -> DebuggerStatement { + self.observe_node(); DebuggerStatement { span } } @@ -5504,6 +5585,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); BindingPattern { kind, type_annotation: type_annotation.into_in(self.allocator), optional } } @@ -5660,6 +5742,7 @@ impl<'a> AstBuilder<'a> { left: BindingPattern<'a>, right: Expression<'a>, ) -> AssignmentPattern<'a> { + self.observe_node(); AssignmentPattern { span, left, right } } @@ -5699,6 +5782,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); ObjectPattern { span, properties, rest: rest.into_in(self.allocator) } } @@ -5742,6 +5826,7 @@ impl<'a> AstBuilder<'a> { shorthand: bool, computed: bool, ) -> BindingProperty<'a> { + self.observe_node(); BindingProperty { span, key, value, shorthand, computed } } @@ -5785,6 +5870,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); ArrayPattern { span, elements, rest: rest.into_in(self.allocator) } } @@ -5822,6 +5908,7 @@ impl<'a> AstBuilder<'a> { span: Span, argument: BindingPattern<'a>, ) -> BindingRestElement<'a> { + self.observe_node(); BindingRestElement { span, argument } } @@ -5878,6 +5965,8 @@ impl<'a> AstBuilder<'a> { T3: IntoIn<'a, Option>>>, T4: IntoIn<'a, Option>>>, { + self.observe_node(); + self.observe_scope(); Function { r#type, span, @@ -5969,6 +6058,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); FormalParameters { span, kind, items, rest: rest.into_in(self.allocator) } } @@ -6016,6 +6106,7 @@ impl<'a> AstBuilder<'a> { readonly: bool, r#override: bool, ) -> FormalParameter<'a> { + self.observe_node(); FormalParameter { span, decorators, pattern, accessibility, readonly, r#override } } @@ -6061,6 +6152,7 @@ impl<'a> AstBuilder<'a> { directives: Vec<'a, Directive<'a>>, statements: Vec<'a, Statement<'a>>, ) -> FunctionBody<'a> { + self.observe_node(); FunctionBody { span, directives, statements } } @@ -6111,6 +6203,8 @@ impl<'a> AstBuilder<'a> { T3: IntoIn<'a, Option>>>, T4: IntoIn<'a, Box<'a, FunctionBody<'a>>>, { + self.observe_node(); + self.observe_scope(); ArrowFunctionExpression { span, expression, @@ -6181,6 +6275,7 @@ impl<'a> AstBuilder<'a> { delegate: bool, argument: Option>, ) -> YieldExpression<'a> { + self.observe_node(); YieldExpression { span, delegate, argument } } @@ -6238,6 +6333,8 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Option>>>, T3: IntoIn<'a, Box<'a, ClassBody<'a>>>, { + self.observe_node(); + self.observe_scope(); Class { r#type, span, @@ -6317,6 +6414,7 @@ impl<'a> AstBuilder<'a> { /// - body #[inline] pub fn class_body(self, span: Span, body: Vec<'a, ClassElement<'a>>) -> ClassBody<'a> { + self.observe_node(); ClassBody { span, body } } @@ -6594,6 +6692,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, Function<'a>>>, { + self.observe_node(); MethodDefinition { r#type, span, @@ -6701,6 +6800,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); PropertyDefinition { r#type, span, @@ -6792,6 +6892,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); PrivateIdentifier { span, name: name.into_in(self.allocator) } } @@ -6819,6 +6920,8 @@ impl<'a> AstBuilder<'a> { /// - body #[inline] pub fn static_block(self, span: Span, body: Vec<'a, Statement<'a>>) -> StaticBlock<'a> { + self.observe_node(); + self.observe_scope(); StaticBlock { span, body, scope_id: Default::default() } } @@ -7072,6 +7175,7 @@ impl<'a> AstBuilder<'a> { computed: bool, r#static: bool, ) -> AccessorProperty<'a> { + self.observe_node(); AccessorProperty { r#type, span, decorators, key, value, computed, r#static } } @@ -7119,6 +7223,7 @@ impl<'a> AstBuilder<'a> { source: Expression<'a>, arguments: Vec<'a, Expression<'a>>, ) -> ImportExpression<'a> { + self.observe_node(); ImportExpression { span, source, arguments } } @@ -7159,6 +7264,7 @@ impl<'a> AstBuilder<'a> { with_clause: Option>, import_kind: ImportOrExportKind, ) -> ImportDeclaration<'a> { + self.observe_node(); ImportDeclaration { span, specifiers, source, with_clause, import_kind } } @@ -7301,6 +7407,7 @@ impl<'a> AstBuilder<'a> { local: BindingIdentifier<'a>, import_kind: ImportOrExportKind, ) -> ImportSpecifier<'a> { + self.observe_node(); ImportSpecifier { span, imported, local, import_kind } } @@ -7337,6 +7444,7 @@ impl<'a> AstBuilder<'a> { span: Span, local: BindingIdentifier<'a>, ) -> ImportDefaultSpecifier<'a> { + self.observe_node(); ImportDefaultSpecifier { span, local } } @@ -7369,6 +7477,7 @@ impl<'a> AstBuilder<'a> { span: Span, local: BindingIdentifier<'a>, ) -> ImportNamespaceSpecifier<'a> { + self.observe_node(); ImportNamespaceSpecifier { span, local } } @@ -7403,6 +7512,7 @@ impl<'a> AstBuilder<'a> { attributes_keyword: IdentifierName<'a>, with_entries: Vec<'a, ImportAttribute<'a>>, ) -> WithClause<'a> { + self.observe_node(); WithClause { span, attributes_keyword, with_entries } } @@ -7439,6 +7549,7 @@ impl<'a> AstBuilder<'a> { key: ImportAttributeKey<'a>, value: StringLiteral<'a>, ) -> ImportAttribute<'a> { + self.observe_node(); ImportAttribute { span, key, value } } @@ -7533,6 +7644,7 @@ impl<'a> AstBuilder<'a> { export_kind: ImportOrExportKind, with_clause: Option>, ) -> ExportNamedDeclaration<'a> { + self.observe_node(); ExportNamedDeclaration { span, declaration, specifiers, source, export_kind, with_clause } } @@ -7585,6 +7697,7 @@ impl<'a> AstBuilder<'a> { declaration: ExportDefaultDeclarationKind<'a>, exported: ModuleExportName<'a>, ) -> ExportDefaultDeclaration<'a> { + self.observe_node(); ExportDefaultDeclaration { span, declaration, exported } } @@ -7625,6 +7738,7 @@ impl<'a> AstBuilder<'a> { with_clause: Option>, export_kind: ImportOrExportKind, ) -> ExportAllDeclaration<'a> { + self.observe_node(); ExportAllDeclaration { span, exported, source, with_clause, export_kind } } @@ -7670,6 +7784,7 @@ impl<'a> AstBuilder<'a> { exported: ModuleExportName<'a>, export_kind: ImportOrExportKind, ) -> ExportSpecifier<'a> { + self.observe_node(); ExportSpecifier { span, local, exported, export_kind } } @@ -7958,6 +8073,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSThisParameter { span, this, type_annotation: type_annotation.into_in(self.allocator) } } @@ -8001,6 +8117,8 @@ impl<'a> AstBuilder<'a> { r#const: bool, declare: bool, ) -> TSEnumDeclaration<'a> { + self.observe_node(); + self.observe_scope(); TSEnumDeclaration { span, id, members, r#const, declare, scope_id: Default::default() } } @@ -8041,6 +8159,7 @@ impl<'a> AstBuilder<'a> { id: TSEnumMemberName<'a>, initializer: Option>, ) -> TSEnumMember<'a> { + self.observe_node(); TSEnumMember { span, id, initializer } } @@ -8193,6 +8312,7 @@ impl<'a> AstBuilder<'a> { span: Span, type_annotation: TSType<'a>, ) -> TSTypeAnnotation<'a> { + self.observe_node(); TSTypeAnnotation { span, type_annotation } } @@ -8221,6 +8341,7 @@ impl<'a> AstBuilder<'a> { /// - literal #[inline] pub fn ts_literal_type(self, span: Span, literal: TSLiteral<'a>) -> TSLiteralType<'a> { + self.observe_node(); TSLiteralType { span, literal } } @@ -9464,6 +9585,8 @@ impl<'a> AstBuilder<'a> { true_type: TSType<'a>, false_type: TSType<'a>, ) -> TSConditionalType<'a> { + self.observe_node(); + self.observe_scope(); TSConditionalType { span, check_type, @@ -9508,6 +9631,7 @@ impl<'a> AstBuilder<'a> { /// - types #[inline] pub fn ts_union_type(self, span: Span, types: Vec<'a, TSType<'a>>) -> TSUnionType<'a> { + self.observe_node(); TSUnionType { span, types } } @@ -9540,6 +9664,7 @@ impl<'a> AstBuilder<'a> { span: Span, types: Vec<'a, TSType<'a>>, ) -> TSIntersectionType<'a> { + self.observe_node(); TSIntersectionType { span, types } } @@ -9572,6 +9697,7 @@ impl<'a> AstBuilder<'a> { span: Span, type_annotation: TSType<'a>, ) -> TSParenthesizedType<'a> { + self.observe_node(); TSParenthesizedType { span, type_annotation } } @@ -9606,6 +9732,7 @@ impl<'a> AstBuilder<'a> { operator: TSTypeOperatorOperator, type_annotation: TSType<'a>, ) -> TSTypeOperator<'a> { + self.observe_node(); TSTypeOperator { span, operator, type_annotation } } @@ -9636,6 +9763,7 @@ impl<'a> AstBuilder<'a> { /// - element_type #[inline] pub fn ts_array_type(self, span: Span, element_type: TSType<'a>) -> TSArrayType<'a> { + self.observe_node(); TSArrayType { span, element_type } } @@ -9670,6 +9798,7 @@ impl<'a> AstBuilder<'a> { object_type: TSType<'a>, index_type: TSType<'a>, ) -> TSIndexedAccessType<'a> { + self.observe_node(); TSIndexedAccessType { span, object_type, index_type } } @@ -9704,6 +9833,7 @@ impl<'a> AstBuilder<'a> { span: Span, element_types: Vec<'a, TSTupleElement<'a>>, ) -> TSTupleType<'a> { + self.observe_node(); TSTupleType { span, element_types } } @@ -9740,6 +9870,7 @@ impl<'a> AstBuilder<'a> { label: IdentifierName<'a>, optional: bool, ) -> TSNamedTupleMember<'a> { + self.observe_node(); TSNamedTupleMember { span, element_type, label, optional } } @@ -9772,6 +9903,7 @@ impl<'a> AstBuilder<'a> { /// - type_annotation #[inline] pub fn ts_optional_type(self, span: Span, type_annotation: TSType<'a>) -> TSOptionalType<'a> { + self.observe_node(); TSOptionalType { span, type_annotation } } @@ -9800,6 +9932,7 @@ impl<'a> AstBuilder<'a> { /// - type_annotation #[inline] pub fn ts_rest_type(self, span: Span, type_annotation: TSType<'a>) -> TSRestType<'a> { + self.observe_node(); TSRestType { span, type_annotation } } @@ -9882,6 +10015,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_any_keyword(self, span: Span) -> TSAnyKeyword { + self.observe_node(); TSAnyKeyword { span } } @@ -9904,6 +10038,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_string_keyword(self, span: Span) -> TSStringKeyword { + self.observe_node(); TSStringKeyword { span } } @@ -9926,6 +10061,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_boolean_keyword(self, span: Span) -> TSBooleanKeyword { + self.observe_node(); TSBooleanKeyword { span } } @@ -9948,6 +10084,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_number_keyword(self, span: Span) -> TSNumberKeyword { + self.observe_node(); TSNumberKeyword { span } } @@ -9970,6 +10107,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_never_keyword(self, span: Span) -> TSNeverKeyword { + self.observe_node(); TSNeverKeyword { span } } @@ -9992,6 +10130,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_intrinsic_keyword(self, span: Span) -> TSIntrinsicKeyword { + self.observe_node(); TSIntrinsicKeyword { span } } @@ -10014,6 +10153,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_unknown_keyword(self, span: Span) -> TSUnknownKeyword { + self.observe_node(); TSUnknownKeyword { span } } @@ -10036,6 +10176,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_null_keyword(self, span: Span) -> TSNullKeyword { + self.observe_node(); TSNullKeyword { span } } @@ -10058,6 +10199,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_undefined_keyword(self, span: Span) -> TSUndefinedKeyword { + self.observe_node(); TSUndefinedKeyword { span } } @@ -10080,6 +10222,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_void_keyword(self, span: Span) -> TSVoidKeyword { + self.observe_node(); TSVoidKeyword { span } } @@ -10102,6 +10245,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_symbol_keyword(self, span: Span) -> TSSymbolKeyword { + self.observe_node(); TSSymbolKeyword { span } } @@ -10124,6 +10268,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_this_type(self, span: Span) -> TSThisType { + self.observe_node(); TSThisType { span } } @@ -10146,6 +10291,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_object_keyword(self, span: Span) -> TSObjectKeyword { + self.observe_node(); TSObjectKeyword { span } } @@ -10168,6 +10314,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn ts_big_int_keyword(self, span: Span) -> TSBigIntKeyword { + self.observe_node(); TSBigIntKeyword { span } } @@ -10200,6 +10347,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSTypeReference { span, type_name, @@ -10294,6 +10442,7 @@ impl<'a> AstBuilder<'a> { left: TSTypeName<'a>, right: IdentifierName<'a>, ) -> TSQualifiedName<'a> { + self.observe_node(); TSQualifiedName { span, left, right } } @@ -10328,6 +10477,7 @@ impl<'a> AstBuilder<'a> { span: Span, params: Vec<'a, TSType<'a>>, ) -> TSTypeParameterInstantiation<'a> { + self.observe_node(); TSTypeParameterInstantiation { span, params } } @@ -10370,6 +10520,7 @@ impl<'a> AstBuilder<'a> { out: bool, r#const: bool, ) -> TSTypeParameter<'a> { + self.observe_node(); TSTypeParameter { span, name, constraint, default, r#in, out, r#const } } @@ -10415,6 +10566,7 @@ impl<'a> AstBuilder<'a> { span: Span, params: Vec<'a, TSTypeParameter<'a>>, ) -> TSTypeParameterDeclaration<'a> { + self.observe_node(); TSTypeParameterDeclaration { span, params } } @@ -10456,6 +10608,8 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); + self.observe_scope(); TSTypeAliasDeclaration { span, id, @@ -10512,6 +10666,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSClassImplements { span, expression, @@ -10565,6 +10720,8 @@ impl<'a> AstBuilder<'a> { T1: IntoIn<'a, Option>>>, T2: IntoIn<'a, Box<'a, TSInterfaceBody<'a>>>, { + self.observe_node(); + self.observe_scope(); TSInterfaceDeclaration { span, id, @@ -10620,6 +10777,7 @@ impl<'a> AstBuilder<'a> { span: Span, body: Vec<'a, TSSignature<'a>>, ) -> TSInterfaceBody<'a> { + self.observe_node(); TSInterfaceBody { span, body } } @@ -10663,6 +10821,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSPropertySignature { span, computed, @@ -10938,6 +11097,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, TSTypeAnnotation<'a>>>, { + self.observe_node(); TSIndexSignature { span, parameters, @@ -10996,6 +11156,7 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Option>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); TSCallSignatureDeclaration { span, this_param, @@ -11073,6 +11234,8 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Option>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); + self.observe_scope(); TSMethodSignature { span, key, @@ -11157,6 +11320,8 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Option>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); + self.observe_scope(); TSConstructSignatureDeclaration { span, params: params.into_in(self.allocator), @@ -11213,6 +11378,7 @@ impl<'a> AstBuilder<'a> { A: IntoIn<'a, Atom<'a>>, T1: IntoIn<'a, Box<'a, TSTypeAnnotation<'a>>>, { + self.observe_node(); TSIndexSignatureName { span, name: name.into_in(self.allocator), @@ -11260,6 +11426,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSInterfaceHeritage { span, expression, @@ -11308,6 +11475,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSTypePredicate { span, parameter_name, @@ -11407,6 +11575,9 @@ impl<'a> AstBuilder<'a> { kind: TSModuleDeclarationKind, declare: bool, ) -> TSModuleDeclaration<'a> { + self.observe_node(); + self.observe_symbol(); + self.observe_scope(); TSModuleDeclaration { span, id, body, kind, declare, scope_id: Default::default() } } @@ -11573,6 +11744,7 @@ impl<'a> AstBuilder<'a> { directives: Vec<'a, Directive<'a>>, body: Vec<'a, Statement<'a>>, ) -> TSModuleBlock<'a> { + self.observe_node(); TSModuleBlock { span, directives, body } } @@ -11607,6 +11779,7 @@ impl<'a> AstBuilder<'a> { span: Span, members: Vec<'a, TSSignature<'a>>, ) -> TSTypeLiteral<'a> { + self.observe_node(); TSTypeLiteral { span, members } } @@ -11638,6 +11811,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, TSTypeParameter<'a>>>, { + self.observe_node(); TSInferType { span, type_parameter: type_parameter.into_in(self.allocator) } } @@ -11674,6 +11848,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSTypeQuery { span, expr_name, type_parameters: type_parameters.into_in(self.allocator) } } @@ -11773,6 +11948,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); TSImportType { span, is_type_of, @@ -11835,6 +12011,7 @@ impl<'a> AstBuilder<'a> { attributes_keyword: IdentifierName<'a>, elements: Vec<'a, TSImportAttribute<'a>>, ) -> TSImportAttributes<'a> { + self.observe_node(); TSImportAttributes { span, attributes_keyword, elements } } @@ -11871,6 +12048,7 @@ impl<'a> AstBuilder<'a> { name: TSImportAttributeName<'a>, value: Expression<'a>, ) -> TSImportAttribute<'a> { + self.observe_node(); TSImportAttribute { span, name, value } } @@ -11974,6 +12152,7 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Box<'a, TSTypeAnnotation<'a>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); TSFunctionType { span, this_param, @@ -12037,6 +12216,7 @@ impl<'a> AstBuilder<'a> { T2: IntoIn<'a, Box<'a, TSTypeAnnotation<'a>>>, T3: IntoIn<'a, Option>>>, { + self.observe_node(); TSConstructorType { span, r#abstract, @@ -12100,6 +12280,8 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, TSTypeParameter<'a>>>, { + self.observe_node(); + self.observe_scope(); TSMappedType { span, type_parameter: type_parameter.into_in(self.allocator), @@ -12163,6 +12345,7 @@ impl<'a> AstBuilder<'a> { quasis: Vec<'a, TemplateElement<'a>>, types: Vec<'a, TSType<'a>>, ) -> TSTemplateLiteralType<'a> { + self.observe_node(); TSTemplateLiteralType { span, quasis, types } } @@ -12199,6 +12382,7 @@ impl<'a> AstBuilder<'a> { expression: Expression<'a>, type_annotation: TSType<'a>, ) -> TSAsExpression<'a> { + self.observe_node(); TSAsExpression { span, expression, type_annotation } } @@ -12235,6 +12419,7 @@ impl<'a> AstBuilder<'a> { expression: Expression<'a>, type_annotation: TSType<'a>, ) -> TSSatisfiesExpression<'a> { + self.observe_node(); TSSatisfiesExpression { span, expression, type_annotation } } @@ -12271,6 +12456,7 @@ impl<'a> AstBuilder<'a> { expression: Expression<'a>, type_annotation: TSType<'a>, ) -> TSTypeAssertion<'a> { + self.observe_node(); TSTypeAssertion { span, expression, type_annotation } } @@ -12309,6 +12495,7 @@ impl<'a> AstBuilder<'a> { module_reference: TSModuleReference<'a>, import_kind: ImportOrExportKind, ) -> TSImportEqualsDeclaration<'a> { + self.observe_node(); TSImportEqualsDeclaration { span, id, module_reference, import_kind } } @@ -12383,6 +12570,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: StringLiteral<'a>, ) -> TSExternalModuleReference<'a> { + self.observe_node(); TSExternalModuleReference { span, expression } } @@ -12415,6 +12603,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: Expression<'a>, ) -> TSNonNullExpression<'a> { + self.observe_node(); TSNonNullExpression { span, expression } } @@ -12443,6 +12632,7 @@ impl<'a> AstBuilder<'a> { /// - expression #[inline] pub fn decorator(self, span: Span, expression: Expression<'a>) -> Decorator<'a> { + self.observe_node(); Decorator { span, expression } } @@ -12471,6 +12661,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: Expression<'a>, ) -> TSExportAssignment<'a> { + self.observe_node(); TSExportAssignment { span, expression } } @@ -12503,6 +12694,7 @@ impl<'a> AstBuilder<'a> { span: Span, id: IdentifierName<'a>, ) -> TSNamespaceExportDeclaration<'a> { + self.observe_node(); TSNamespaceExportDeclaration { span, id } } @@ -12540,6 +12732,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Box<'a, TSTypeParameterInstantiation<'a>>>, { + self.observe_node(); TSInstantiationExpression { span, expression, @@ -12586,6 +12779,7 @@ impl<'a> AstBuilder<'a> { type_annotation: TSType<'a>, postfix: bool, ) -> JSDocNullableType<'a> { + self.observe_node(); JSDocNullableType { span, type_annotation, postfix } } @@ -12622,6 +12816,7 @@ impl<'a> AstBuilder<'a> { type_annotation: TSType<'a>, postfix: bool, ) -> JSDocNonNullableType<'a> { + self.observe_node(); JSDocNonNullableType { span, type_annotation, postfix } } @@ -12651,6 +12846,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn js_doc_unknown_type(self, span: Span) -> JSDocUnknownType { + self.observe_node(); JSDocUnknownType { span } } @@ -12686,6 +12882,7 @@ impl<'a> AstBuilder<'a> { T1: IntoIn<'a, Box<'a, JSXOpeningElement<'a>>>, T2: IntoIn<'a, Option>>>, { + self.observe_node(); JSXElement { span, opening_element: opening_element.into_in(self.allocator), @@ -12743,6 +12940,7 @@ impl<'a> AstBuilder<'a> { where T1: IntoIn<'a, Option>>>, { + self.observe_node(); JSXOpeningElement { span, self_closing, @@ -12793,6 +12991,7 @@ impl<'a> AstBuilder<'a> { span: Span, name: JSXElementName<'a>, ) -> JSXClosingElement<'a> { + self.observe_node(); JSXClosingElement { span, name } } @@ -12829,6 +13028,7 @@ impl<'a> AstBuilder<'a> { closing_fragment: JSXClosingFragment, children: Vec<'a, JSXChild<'a>>, ) -> JSXFragment<'a> { + self.observe_node(); JSXFragment { span, opening_fragment, closing_fragment, children } } @@ -12952,6 +13152,7 @@ impl<'a> AstBuilder<'a> { namespace: JSXIdentifier<'a>, property: JSXIdentifier<'a>, ) -> JSXNamespacedName<'a> { + self.observe_node(); JSXNamespacedName { span, namespace, property } } @@ -12988,6 +13189,7 @@ impl<'a> AstBuilder<'a> { object: JSXMemberExpressionObject<'a>, property: JSXIdentifier<'a>, ) -> JSXMemberExpression<'a> { + self.observe_node(); JSXMemberExpression { span, object, property } } @@ -13085,6 +13287,7 @@ impl<'a> AstBuilder<'a> { span: Span, expression: JSXExpression<'a>, ) -> JSXExpressionContainer<'a> { + self.observe_node(); JSXExpressionContainer { span, expression } } @@ -13135,6 +13338,7 @@ impl<'a> AstBuilder<'a> { /// - span: The [`Span`] covering this node #[inline] pub fn jsx_empty_expression(self, span: Span) -> JSXEmptyExpression { + self.observe_node(); JSXEmptyExpression { span } } @@ -13216,6 +13420,7 @@ impl<'a> AstBuilder<'a> { name: JSXAttributeName<'a>, value: Option>, ) -> JSXAttribute<'a> { + self.observe_node(); JSXAttribute { span, name, value } } @@ -13250,6 +13455,7 @@ impl<'a> AstBuilder<'a> { span: Span, argument: Expression<'a>, ) -> JSXSpreadAttribute<'a> { + self.observe_node(); JSXSpreadAttribute { span, argument } } @@ -13464,6 +13670,8 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); + self.observe_reference(); JSXIdentifier { span, name: name.into_in(self.allocator) } } @@ -13637,6 +13845,7 @@ impl<'a> AstBuilder<'a> { /// - expression: The expression being spread. #[inline] pub fn jsx_spread_child(self, span: Span, expression: Expression<'a>) -> JSXSpreadChild<'a> { + self.observe_node(); JSXSpreadChild { span, expression } } @@ -13668,6 +13877,7 @@ impl<'a> AstBuilder<'a> { where A: IntoIn<'a, Atom<'a>>, { + self.observe_node(); JSXText { span, value: value.into_in(self.allocator) } } diff --git a/crates/oxc_ast/src/lib.rs b/crates/oxc_ast/src/lib.rs index 8ed15f752c5f9..a907a17b1c390 100644 --- a/crates/oxc_ast/src/lib.rs +++ b/crates/oxc_ast/src/lib.rs @@ -33,6 +33,7 @@ mod ast_builder_impl; mod ast_impl; mod ast_kind_impl; pub mod precedence; +mod stats; pub mod syntax_directed_operations; mod trivia; @@ -61,6 +62,7 @@ pub use num_bigint::BigUint; pub use crate::{ ast_builder::AstBuilder, ast_kind::{AstKind, AstType}, + stats::Statistics, trivia::{Comment, CommentKind, SortedComments, Trivias}, visit::{Visit, VisitMut}, }; diff --git a/crates/oxc_ast/src/stats.rs b/crates/oxc_ast/src/stats.rs new file mode 100644 index 0000000000000..1706147f73473 --- /dev/null +++ b/crates/oxc_ast/src/stats.rs @@ -0,0 +1,215 @@ +use std::{ + cell::Cell, marker::PhantomData, mem::ManuallyDrop, ops::Deref, panic::Location, ptr::NonNull, +}; + +/// Records the number of relevant features in the AST. +#[derive(Debug, Default, Clone)] +// should this be repr(align(8))? +pub struct Statistics { + /// Number of symbols created in a program + symbols: Cell, + /// Number of AST nodes in a program + nodes: Cell, + /// Number of nodes creating a scope in a program + scopes: Cell, + references: Cell, + /// Set to [`Some`] when the statistics are taken out of a [`StatisticsCell`]. + /// + /// The location of where statistics were taken from is stored to help with + /// debugging. If we wanted to, we could store an [`Option`] for + /// release builds. + taken: Cell>>, +} + +impl Statistics { + pub fn observe_symbol(&self) { + self.assert_not_taken(); + self.symbols.set(self.symbols.get() + 1); + } + + /// Increment the number of AST nodes seen. + pub fn observe_node(&self) { + self.assert_not_taken(); + self.nodes.set(self.nodes.get() + 1); + } + + /// Increment the number of scopes that have been created. + pub fn observe_scope(&self) { + self.assert_not_taken(); + self.scopes.set(self.scopes.get() + 1); + } + + /// Increment the number of symbol references that have been created. + pub fn observe_reference(&self) { + self.assert_not_taken(); + self.references.set(self.references.get() + 1); + } + + /// Get the number of symbols that have been created. + #[inline] + pub fn symbols(&self) -> u32 { + self.symbols.get() + } + + /// Get the number of AST nodes in the traversed program. + #[inline] + pub fn nodes(&self) -> u32 { + self.nodes.get() + } + + /// Get the number of created symbols. + #[inline] + pub fn scopes(&self) -> u32 { + self.scopes.get() + } + + /// Get the number of symbol references created in a program. + #[inline] + pub fn references(&self) -> u32 { + self.references.get() + } + + /// Have the contents of this [`Statistics`] been taken yet? + /// + /// See [`Statistics::take`] + #[inline] + fn is_taken(&self) -> bool { + self.taken.get().is_some() + } + + /// Mark these [`Statistics`] as taken from the given [`Location`]. + #[inline] + fn take(&mut self, location: &'static Location<'static>) { + self.taken.set(Some(location)); + } + + /// If Statistics have been taken, returns the [`Location`] where they were + /// taken from. + #[inline] + fn taken_from(&self) -> Option<&'static Location<'static>> { + self.taken.get() + } + + /// Assert that the statistics have not been taken yet. + /// + /// Note that "take" semantics only apply to statistics stored in a + /// [`StatisticsCell`]. Statistics used directly can be checked by the + /// compiler. + /// + /// # Panics + /// If this [`Statistics`] has been taken already + #[inline] + fn assert_not_taken(&self) { + if let Some(location) = self.taken_from() { + panic!("Statistics became read-only after being taken at {location:?}"); + } + } +} + +/// A [`Cell`]-like type that holds a reference to a [`Statistics`] instance. +/// +/// This structure acts as a safe way to share a reference to a +/// mutable set of statistics while preserving [`Copy`] semantics. Once created, +/// the underlying [`Statistics`] may be updated uding one of the various +/// `observe_*` methods, such as [`Statistics::observe_symbol`]. When AST +/// traversal is complete, you can call [`StatisticsCell::take`] to obtain the +/// finalized [`Statistics`] instance. +/// +/// ## Safety +/// While this type is safe to use, it **will leak memory** if +/// [`StatisticsCell::take`] is never called. +/// In order to preserve [`Copy`], cells will not [`Drop`] their [`Statistics`] +/// instances. The only way to prevent [`Statistics`] from leaking is to take it +/// out of the cell. +/// +/// The only valid way to use this type is in a situation like tree traversal, +/// where you are 100% confident that all copies of a cell will be dropped after +/// this cell has been passed to some method that uses it. +/// +/// ```ignore +/// struct CountVisitor { +/// pub cell: StatisticsCell, +/// } +/// let ret = Parser::new(/* ... */).parse(/* ... */); +/// let cell = StatisticsCell::default(); +/// l +/// let visit = CountVisitor { cell }; +/// visit.visit_program(&ret.program); +/// drop(visit); +/// // At this point, `stats` must be no other copies of `stats` in existence. +/// let statistics: Statistics = cell.take(); +/// ``` +/// +/// In order to prevent dereferences on freed memory, [`StatisticsCell::take`] +/// may only be called a single time, and statistics may not be mutated after +/// being taken. +/// +/// ```ignore +/// let cell = StatisticsCell::default(); +/// // fine, not taken yet +/// cell.observe_node(); +/// let stats = cell.take(); +/// // these will panic +/// cell.observe_node(); +/// let stats2 = cell.take(); +/// ``` +#[derive(Debug, Clone, Copy)] +pub(crate) struct StatisticsCell<'s>(NonNull>, PhantomData<&'s ()>); + +impl<'s> Deref for StatisticsCell<'s> { + type Target = Statistics; + + fn deref(&self) -> &Statistics { + // SAFETY: + // 1. Pointer is created by a Box, so it is well-aligneda and initialized, + // 2. Meets the requirements for valid pointer reads + // a. dereferenceable and non-null: created by Box + // c. non-atomic: Statistics is not Send or Sync. + unsafe { self.0.as_ref() } + } +} + +impl Default for StatisticsCell<'_> { + #[must_use = "Dropping a newly-created StatisticsCell without taking it is a memory leak."] + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<'s> StatisticsCell<'s> { + #[must_use = "Dropping a newly-created StatisticsCell without taking it is a memory leak."] + pub fn new() -> Self { + let stats = Box::default(); + let stats = Box::leak(stats); + Self(NonNull::new(stats).unwrap(), PhantomData) + } + + /// Take the [`Statistics`] out of this cell, consuming it. + /// + /// You _must_ call this method on the last copy of the cell in order to avoid + /// leaking memory. + /// + /// # Panics + /// - If the statistics have already been taken. + #[track_caller] + pub fn take(mut self) -> Statistics { + assert!(!self.is_taken(), "Statistics already taken at {:?}.", self.taken_from()); + let location = Location::caller(); + // SAFETY: + // - pointer is created from a Box, so it is well-aligned and + // initialized. + // - The only other time a mutable reference exists to this pointer is + // if this method is called on another StatisticsCell. If this + // happened, the above assertion would have already failed. + unsafe { self.0.as_mut().take(location) }; + + // SAFETY: + // - Pointer is created from Box::leak, so it is valid. + // - It is impossible for Box::from_raw to have been called already on + // this pointer, because if it had the statitiscs would already be + // taken and the above assertion would have failed. + let boxed = unsafe { Box::from_raw(self.0.as_ptr()) }; + ManuallyDrop::into_inner(*boxed) + } +} diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index 04e40760566ba..01048f8d2c52d 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -66,7 +66,7 @@ use context::{Context, StatementContext}; use oxc_allocator::Allocator; use oxc_ast::{ ast::{Expression, Program}, - AstBuilder, Trivias, + AstBuilder, Statistics, Trivias, }; use oxc_diagnostics::{OxcDiagnostic, Result}; use oxc_span::{ModuleKind, SourceType, Span}; @@ -101,6 +101,7 @@ pub struct ParserReturn<'a> { pub errors: Vec, pub trivias: Trivias, pub panicked: bool, + pub statistics: Option, } /// Parser options @@ -115,11 +116,16 @@ struct ParserOptions { /// /// Default: true pub preserve_parens: bool, + pub record_statistics: bool, } impl Default for ParserOptions { fn default() -> Self { - Self { allow_return_outside_function: false, preserve_parens: true } + Self { + allow_return_outside_function: false, + preserve_parens: true, + record_statistics: true, + } } } @@ -159,6 +165,12 @@ impl<'a> Parser<'a> { self.options.preserve_parens = allow; self } + + #[must_use] + pub fn record_statistics(mut self, yes: bool) -> Self { + self.options.record_statistics = yes; + self + } } mod parser_parse { @@ -282,6 +294,10 @@ impl<'a> ParserImpl<'a> { options: ParserOptions, unique: UniquePromise, ) -> Self { + let mut ast = AstBuilder::new(allocator); + if options.record_statistics { + ast = ast.with_statistics(); + } Self { lexer: Lexer::new(allocator, source_text, source_type, unique), source_type, @@ -291,7 +307,7 @@ impl<'a> ParserImpl<'a> { prev_token_end: 0, state: ParserState::default(), ctx: Self::default_context(source_type, options), - ast: AstBuilder::new(allocator), + ast, preserve_parens: options.preserve_parens, } } @@ -320,7 +336,7 @@ impl<'a> ParserImpl<'a> { }; let errors = self.lexer.errors.into_iter().chain(self.errors).collect(); let trivias = self.lexer.trivia_builder.build(); - ParserReturn { program, errors, trivias, panicked } + ParserReturn { program, errors, trivias, panicked, statistics: self.ast.take_stats() } } pub fn parse_expression(mut self) -> std::result::Result, Vec> { @@ -328,6 +344,8 @@ impl<'a> ParserImpl<'a> { self.bump_any(); let expr = self.parse_expr().map_err(|diagnostic| vec![diagnostic])?; let errors = self.lexer.errors.into_iter().chain(self.errors).collect::>(); + // must be taken to prevent a memory leak + let _ = self.ast.take_stats(); if !errors.is_empty() { return Err(errors); } diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 3e80027b6a1fc..7449e27539aa7 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -6,6 +6,7 @@ use std::{ sync::Arc, }; +use oxc_ast::Statistics; #[allow(clippy::wildcard_imports)] use oxc_ast::{ast::*, AstKind, Trivias, Visit}; use oxc_cfg::{ @@ -66,6 +67,7 @@ pub struct SemanticBuilder<'a> { pub(crate) source_type: SourceType, trivias: Trivias, + statistics: Option, /// Semantic early errors such as redeclaration errors. errors: RefCell>, @@ -127,6 +129,7 @@ impl<'a> SemanticBuilder<'a> { source_text, source_type, trivias: trivias.clone(), + statistics: None, errors: RefCell::new(vec![]), current_node_id: AstNodeId::new(0), current_node_flags: NodeFlags::empty(), @@ -158,6 +161,12 @@ impl<'a> SemanticBuilder<'a> { self } + #[must_use] + pub fn with_statistics(mut self, statistics: Option) -> Self { + self.statistics = statistics; + self + } + /// Enable/disable additional syntax checks. /// /// Set this to `true` to enable additional syntax checks. Without these, @@ -224,26 +233,34 @@ impl<'a> SemanticBuilder<'a> { // Avoiding this growth produces up to 30% perf boost on our benchmarks. // TODO: It would be even more efficient to calculate counts in parser to avoid // this extra AST traversal. - let mut counter = Counter::default(); - counter.visit_program(program); - self.nodes.reserve(counter.nodes_count); - self.scope.reserve(counter.scopes_count); - self.symbols.reserve(counter.symbols_count, counter.references_count); + // counter.visit_program(program); + let statistics = self.statistics.clone().unwrap_or_else(|| { + let mut counter = Counter::default(); + counter.visit_program(program); + counter.into_inner() + }); + // self.nodes.reserve(counter.nodes_count); + // self.scope.reserve(counter.scopes_count); + // self.symbols.reserve(counter.symbols_count, + // counter.references_count); + self.nodes.reserve(statistics.nodes() as usize); + self.scope.reserve(statistics.scopes() as usize); + self.symbols.reserve(statistics.symbols() as usize, statistics.references() as usize); // Visit AST to generate scopes tree etc self.visit_program(program); // Check that `Counter` got accurate counts - debug_assert_eq!(self.nodes.len(), counter.nodes_count); - debug_assert_eq!(self.scope.len(), counter.scopes_count); - debug_assert_eq!(self.symbols.references.len(), counter.references_count); + debug_assert_eq!(self.nodes.len(), statistics.nodes() as usize); + debug_assert_eq!(self.scope.len(), statistics.scopes() as usize); + debug_assert_eq!(self.symbols.references.len(), statistics.references() as usize); // `Counter` may overestimate number of symbols, because multiple `BindingIdentifier`s // can result in only a single symbol. // e.g. `var x; var x;` = 2 x `BindingIdentifier` but 1 x symbol. // This is not a big problem - allocating a `Vec` with excess capacity is cheap. // It's allocating with *not enough* capacity which is costly, as then the `Vec` // will grow and reallocate. - debug_assert!(self.symbols.len() <= counter.symbols_count); + debug_assert!(self.symbols.len() <= statistics.symbols() as usize); // Checking syntax error on module record requires scope information from the previous AST pass if self.check_syntax_error { diff --git a/crates/oxc_semantic/src/counter.rs b/crates/oxc_semantic/src/counter.rs index 4d8f8d7b82715..05d2cff2d64de 100644 --- a/crates/oxc_semantic/src/counter.rs +++ b/crates/oxc_semantic/src/counter.rs @@ -2,7 +2,7 @@ //! These counts can be used to pre-allocate sufficient capacity in `AstNodes`, //! `ScopeTree`, and `SymbolTable` to store info for all these items. -use std::cell::Cell; +use std::{cell::Cell, ops::Deref}; use oxc_ast::{ ast::{ @@ -10,63 +10,77 @@ use oxc_ast::{ TSEnumMemberName, TSModuleDeclarationName, }, visit::walk::{walk_ts_enum_member_name, walk_ts_module_declaration_name}, - AstKind, Visit, + AstKind, Statistics, Visit, }; use oxc_syntax::scope::{ScopeFlags, ScopeId}; #[allow(clippy::struct_field_names)] #[derive(Default, Debug)] pub(crate) struct Counter { - pub nodes_count: usize, - pub scopes_count: usize, - pub symbols_count: usize, - pub references_count: usize, + statistics: Statistics, +} +impl Deref for Counter { + type Target = Statistics; + fn deref(&self) -> &Self::Target { + &self.statistics + } +} +impl Counter { + pub fn into_inner(self) -> Statistics { + self.statistics + } } impl<'a> Visit<'a> for Counter { #[inline] fn enter_node(&mut self, _: AstKind<'a>) { - self.nodes_count += 1; + self.observe_node(); } #[inline] fn enter_scope(&mut self, _: ScopeFlags, _: &Cell>) { - self.scopes_count += 1; + // self.scopes_count += 1; + self.observe_scope(); } #[inline] fn visit_binding_identifier(&mut self, _: &BindingIdentifier<'a>) { - self.nodes_count += 1; - self.symbols_count += 1; + // self.nodes_count += 1; + // self.symbols_count += 1; + self.observe_symbol(); + self.observe_node(); } #[inline] fn visit_identifier_reference(&mut self, _: &IdentifierReference<'a>) { - self.nodes_count += 1; - self.references_count += 1; + // self.nodes_count += 1; + // self.references_count += 1; + self.observe_node(); + self.observe_reference(); } #[inline] fn visit_jsx_member_expression_object(&mut self, it: &JSXMemberExpressionObject<'a>) { - self.nodes_count += 1; + // self.nodes_count += 1; + self.observe_node(); match it { JSXMemberExpressionObject::MemberExpression(expr) => { self.visit_jsx_member_expression(expr); } JSXMemberExpressionObject::Identifier(_) => { - self.nodes_count += 1; - self.references_count += 1; + self.observe_node(); + self.observe_reference(); } } } #[inline] fn visit_jsx_element_name(&mut self, it: &JSXElementName<'a>) { - self.nodes_count += 1; + self.observe_node(); match it { JSXElementName::Identifier(ident) => { - self.nodes_count += 1; + self.observe_node(); if ident.name.chars().next().is_some_and(char::is_uppercase) { - self.references_count += 1; + self.observe_reference(); } } JSXElementName::NamespacedName(name) => self.visit_jsx_namespaced_name(name), @@ -77,14 +91,14 @@ impl<'a> Visit<'a> for Counter { #[inline] fn visit_ts_enum_member_name(&mut self, it: &TSEnumMemberName<'a>) { if !it.is_expression() { - self.symbols_count += 1; + self.observe_symbol(); } walk_ts_enum_member_name(self, it); } #[inline] fn visit_ts_module_declaration_name(&mut self, it: &TSModuleDeclarationName<'a>) { - self.symbols_count += 1; + self.observe_symbol(); walk_ts_module_declaration_name(self, it); } } diff --git a/crates/oxc_semantic/tests/integration/util/mod.rs b/crates/oxc_semantic/tests/integration/util/mod.rs index 38d13714d5597..a7c411ef26e75 100644 --- a/crates/oxc_semantic/tests/integration/util/mod.rs +++ b/crates/oxc_semantic/tests/integration/util/mod.rs @@ -162,6 +162,7 @@ impl<'a> SemanticTester<'a> { SemanticBuilder::new(self.source_text, self.source_type) .with_check_syntax_error(true) .with_trivias(parse.trivias) + .with_statistics(parse.statistics) .with_cfg(self.cfg) .build(program) } diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 5709cfb79ac00..5cb3dee146b5a 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -107,7 +107,7 @@ impl<'a> Transformer<'a> { .build(program) .semantic .into_symbol_table_and_scope_tree(); - let allocator: &'a Allocator = self.ctx.ast.allocator; + let allocator = self.ctx.ast.allocator; let (symbols, scopes) = traverse_mut(&mut self, allocator, program, symbols, scopes); TransformerReturn { errors: self.ctx.take_errors(), symbols, scopes } } @@ -118,7 +118,7 @@ impl<'a> Transformer<'a> { scopes: ScopeTree, program: &mut Program<'a>, ) -> TransformerReturn { - let allocator: &'a Allocator = self.ctx.ast.allocator; + let allocator = self.ctx.ast.allocator; let (symbols, scopes) = traverse_mut(&mut self, allocator, program, symbols, scopes); TransformerReturn { errors: self.ctx.take_errors(), symbols, scopes } } diff --git a/tasks/ast_tools/src/generators/ast_builder.rs b/tasks/ast_tools/src/generators/ast_builder.rs index dee73cb70710c..110e0f853d21b 100644 --- a/tasks/ast_tools/src/generators/ast_builder.rs +++ b/tasks/ast_tools/src/generators/ast_builder.rs @@ -53,6 +53,7 @@ impl Generator for AstBuilderGenerator { ///@@line_break #[allow(clippy::wildcard_imports)] use crate::ast::*; + use crate::stats::StatisticsCell; ///@@line_break /// AST builder for creating AST nodes @@ -60,6 +61,7 @@ impl Generator for AstBuilderGenerator { #[non_exhaustive] pub struct AstBuilder<'a> { pub allocator: &'a Allocator, + pub(crate) stats: Option>, } ///@@line_break @@ -141,6 +143,7 @@ fn generate_enum_variant_builder_fn( ) -> TokenStream { assert_eq!(variant.fields.len(), 1); let enum_ident = enum_.ident(); + let enum_ident_string = enum_ident.to_string(); let enum_type = &enum_.to_type(); let var_ident = &variant.ident(); let var_type = &variant.fields.first().expect("we have already asserted this one!").typ; @@ -169,7 +172,7 @@ fn generate_enum_variant_builder_fn( } let from_variant_builder = generate_enum_from_variant_builder_fn(enum_, variant, ctx); - let article = article_for(enum_ident.to_string()); + let article = article_for(&enum_ident_string); let mut docs = DocComment::new(format!(" Build {article} [`{enum_ident}::{var_ident}`]")) .with_params(¶ms); if does_alloc { @@ -180,11 +183,18 @@ fn generate_enum_variant_builder_fn( )); } + // // enum variants do not create identifiers, instead they contain structs + // // that do. + // let (observe_node, _observe_symbol, observe_scope, _observe_reference) = + // get_statistics_calls(ty); + quote! { ///@@line_break #docs #[inline] pub fn #fn_name #generic_params (self, #(#params),*) -> #enum_type #where_clause { + // #observe_node + // #observe_scope #enum_ident::#var_ident(#inner) } @@ -279,7 +289,8 @@ fn generate_struct_builder_fn(ty: &StructDef, ctx: &LateCtx) -> TokenStream { let alloc_fn_name = format_ident!("alloc_{fn_name}"); - let article = article_for(ident.to_string()); + let ident_string = ident.to_string(); + let article = article_for(&ident_string); let fn_docs = DocComment::new(format!("Builds {article} [`{ident}`]")) .with_description(format!("If you want the built node to be allocated in the memory arena, use [`AstBuilder::{alloc_fn_name}`] instead.")) .with_params(¶ms); @@ -289,11 +300,19 @@ fn generate_struct_builder_fn(ty: &StructDef, ctx: &LateCtx) -> TokenStream { .with_description(format!("Returns a [`Box`] containing the newly-allocated node. If you want a stack-allocated node, use [`AstBuilder::{fn_name}`] instead.")) .with_params(¶ms); + // NOTE: do not record nodes in alloc methods, since they call the non-alloc + // methods. + let (observe_node, observe_symbol, observe_scope, observe_reference) = get_statistics_calls(ty); + quote! { ///@@line_break #fn_docs #[inline] pub fn #fn_name #generic_params (self, #(#params),*) -> #as_type #where_clause { + #observe_node + #observe_symbol + #observe_scope + #observe_reference #ident { #(#fields),* } } @@ -564,3 +583,65 @@ fn get_struct_params(struct_: &StructDef, ctx: &LateCtx) -> Vec { acc }) } + +fn get_statistics_calls( + def: &StructDef, +) -> ( + /* nodes */ TokenStream, + /* symbols */ TokenStream, + /* scopes */ TokenStream, + /* references */ TokenStream, +) { + let observe_node = if def.visitable { + quote! { + self.observe_node(); + } + } else { + quote! {} + }; + + let (symbol, reference) = creates_symbol_or_reference(def); + let observe_symbol = if symbol { + quote! { + self.observe_symbol(); + } + } else { + quote! {} + }; + let observe_reference = if reference { + quote! { + self.observe_reference(); + } + } else { + quote! {} + }; + + let observe_scope = if def.markers.scope.is_some() { + quote! { + self.observe_scope(); + } + } else { + quote! {} + }; + + (observe_node, observe_symbol, observe_scope, observe_reference) +} + +fn creates_symbol_or_reference(it: &StructDef) -> (bool, bool) { + // it.fields.iter().any(|field| field.ident().map_or(false, |ident| + // ident == "symbol_id")) + // statically-known computed properties also create symbols. FIXME: this + // observes two nodes for identifier properties, and reserves a symbol for + // unidentifiable computed properties. + let name_creates_symbol = it.name == "TSEnumMemberName" || it.name == "TSModuleDeclaration"; + let name_creates_reference = it.name == "JSXIdentifier"; + it.fields.iter().fold( + (name_creates_symbol, name_creates_reference), + |(symbol, reference), field| { + ( + symbol || field.ident().map_or(false, |ident| ident == "symbol_id"), + reference || field.ident().map_or(false, |ident| ident == "reference_id"), + ) + }, + ) +} diff --git a/tasks/ast_tools/src/schema/defs.rs b/tasks/ast_tools/src/schema/defs.rs index cfa9bc1695f9a..d768b38911945 100644 --- a/tasks/ast_tools/src/schema/defs.rs +++ b/tasks/ast_tools/src/schema/defs.rs @@ -36,6 +36,13 @@ impl TypeDef { let generated_derives = self.generated_derives(); generated_derives.iter().any(|it| it == derive) } + + pub fn is_visitable(&self) -> bool { + match self { + Self::Struct(it) => it.visitable, + Self::Enum(it) => it.visitable, + } + } } #[derive(Debug, Serialize)] diff --git a/tasks/benchmark/benches/isolated_declarations.rs b/tasks/benchmark/benches/isolated_declarations.rs index e4911c85a7b8f..1b3ea7209a693 100644 --- a/tasks/benchmark/benches/isolated_declarations.rs +++ b/tasks/benchmark/benches/isolated_declarations.rs @@ -19,7 +19,7 @@ fn bench_isolated_declarations(criterion: &mut Criterion) { b.iter_with_large_drop(|| { let allocator = Allocator::default(); let ParserReturn { program, .. } = - Parser::new(&allocator, source_text, source_type).parse(); + Parser::new(&allocator, source_text, source_type).record_statistics(false).parse(); IsolatedDeclarations::new(&allocator).build(&program); }); }); diff --git a/tasks/benchmark/benches/linter.rs b/tasks/benchmark/benches/linter.rs index 901d5fbe858f7..62305cb418d66 100644 --- a/tasks/benchmark/benches/linter.rs +++ b/tasks/benchmark/benches/linter.rs @@ -36,6 +36,7 @@ fn bench_linter(criterion: &mut Criterion) { .with_trivias(ret.trivias) .with_cfg(true) .build_module_record(PathBuf::new(), program) + .with_statistics(ret.statistics) .build(program); let filter = vec![ (AllowWarnDeny::Deny, "all".into()), diff --git a/tasks/benchmark/benches/semantic.rs b/tasks/benchmark/benches/semantic.rs index 3d2d23d2e003d..2a554eab10937 100644 --- a/tasks/benchmark/benches/semantic.rs +++ b/tasks/benchmark/benches/semantic.rs @@ -22,6 +22,7 @@ fn bench_semantic(criterion: &mut Criterion) { SemanticBuilder::new(source_text, source_type) .with_trivias(ret.trivias.clone()) .with_build_jsdoc(true) + .with_statistics(ret.statistics.clone()) .build_module_record(PathBuf::new(), program) .build(program) }); diff --git a/tasks/benchmark/benches/sourcemap.rs b/tasks/benchmark/benches/sourcemap.rs index 839c3cbcdaab0..aecbb1784fb61 100644 --- a/tasks/benchmark/benches/sourcemap.rs +++ b/tasks/benchmark/benches/sourcemap.rs @@ -15,7 +15,8 @@ fn bench_sourcemap(criterion: &mut Criterion) { let source_type = SourceType::from_path(&file.file_name).unwrap(); group.bench_with_input(id, &file.source_text, |b, source_text| { let allocator = Allocator::default(); - let ret = Parser::new(&allocator, source_text, source_type).parse(); + let ret = + Parser::new(&allocator, source_text, source_type).record_statistics(false).parse(); let CodegenReturn { source_text: output_txt, .. } = CodeGenerator::new() .enable_source_map(file.file_name.as_str(), source_text) diff --git a/tasks/benchmark/benches/transformer.rs b/tasks/benchmark/benches/transformer.rs index 2cabd95cce92d..51aaff5fedc6f 100644 --- a/tasks/benchmark/benches/transformer.rs +++ b/tasks/benchmark/benches/transformer.rs @@ -20,7 +20,9 @@ fn bench_transformer(criterion: &mut Criterion) { b.iter_with_large_drop(|| { let allocator = Allocator::default(); let ParserReturn { trivias, program, .. } = - Parser::new(&allocator, source_text, source_type).parse(); + Parser::new(&allocator, source_text, source_type) + .record_statistics(false) + .parse(); let transform_options = TransformOptions::default(); let program = allocator.alloc(program); Transformer::new( diff --git a/tasks/coverage/src/driver.rs b/tasks/coverage/src/driver.rs index f351e58c50a20..955bf26e8bf83 100644 --- a/tasks/coverage/src/driver.rs +++ b/tasks/coverage/src/driver.rs @@ -53,7 +53,7 @@ impl Driver { pub fn run(&mut self, source_text: &str, source_type: SourceType) { let allocator = Allocator::default(); - let ParserReturn { mut program, errors, trivias, panicked } = + let ParserReturn { mut program, errors, trivias, panicked, .. } = Parser::new(&allocator, source_text, source_type) .allow_return_outside_function(self.allow_return_outside_function) .parse();