Set `reference_id` for references to new imported bindings. e.g. `_jsx`
in `_jsx(Foo, {})` where JSX transform has inserted `import {jsx as
_jsx} from "react/jsx-runtime";`.
Add `TraverseCtx::generate_uid` method.
This is modelled on Babel's `scope.generateUid()` method. As discussed
in
https://github.com/oxc-project/oxc/discussions/3251#discussioncomment-9416826,
this is required to fix most of the remaining failing tests in
transformer Milestone 1.
I have implemented this to work as closely as possible to Babel, so that
it will generate same output as Babel for our tests. However, as
mentioned in the code comments, this means it's a pretty expensive
function to call. Those code comments suggest 2 ways in which we could
make it much more efficient, but we'd need to decide how we're going to
handle divergence from Babel before we can decide which route to go.
I've left it as a `TODO(improve-on-babel)` for now.
Allow mutable access to scopes tree and symbol table.
Closes#3189.
This completes the v1 scopes-in-traverse implementation, and provides all the primitives required to implement the missing APIs listed in https://github.com/oxc-project/oxc/discussions/3251.
Performance is abysmal, as noted in #3304, but we can fix that later on by taking `Semantic` out of the picture, or optimizing it.
Pass `&mut TraverseCtx` to `Traverse::enter_*` and `Traverse::exit_*` visitor methods. Previously was immutable `&TraverseCtx`.
This is a step towards exposing mutable scope tree + symbol table to visitors.
Move the ancestry stack into it's own type `TraverseAncestry`, and expose it via `ctx.ancestry` "namespace".
The "namespaced" way of getting parent etc (`ctx.ancestry.parent()` rather than just `ctx.parent()`) will come in useful once we introduce methods which require a `&mut TraverseCtx`.
`Traverse` use `Semantic` to construct scopes tree and expose it to visitors via `TraverseCtx`.
Currently scopes tree is immutable. Will expose it as a mutable in a follow-on.
This is extremely inefficient. Semantic does all kinds of stuff (control flow graph etc) which `Traverse` doesn't need, and `Traverse` just throws away all that work after semantic has done it. Intent here is to get a working implementation first, and then to do another pass later on to improve performance.
Fixes a bug in #3229.
The logic to prevent a duplicate scope being created for a `Function` which is a `MethodDefinition` would also stop a scope being created for inner function in:
```rs
class X {
foo() {
function bar() {}
}
}
```
or
```rs
class X {
foo( bar = function() {} ) {}
}
```
This PR fixes that. This change also allows removing `ScopeFlags::Method` which #3229 added.
Add scope flags to `TraverseCtx`.
Closes#3189.
`walk_*` functions build a stack of `ScopeFlags` as AST is traversed, and they can be queried from within visitors with `ctx.scope()`, `ctx.ancestor_scope()` and `ctx.find_scope()`.
The codegen which generates `walk_*` functions gets the info about which AST types have scopes, and how to check for strict mode from the `#[visited_node]` attrs on AST type definitions in `oxc_ast`.
A few notes:
Each scope inherits the strict mode flag from the level before it in the stack, so if you need to know "am I in strict mode context here?", `ctx.scope().is_strict_mode()` will tell you - no need to travel back up the stack to find out.
Scopes do *not* inherit any other flags from level before it. So `ctx.scope()` in a block nested in a function will return `ScopeFlags::empty()` not `ScopeFlags::Function`.
I had to add an extra flag `ScopeFlags::Method`. The reason for this is to deal with when a `Function` is actually a `MethodDefinition`, and to avoid creating 2 scopes in this case. The principle I'm trying to follow is to encode as little logic in the codegen as possible, as it's rather hidden away. Instead the codegen follows a standard logic for every node, guided by attributes which are visible next to the types in `oxc_ast`. This hopefully makes how `Traverse`'s visitors are generated less mysterious, and easier to change.
The case of `Function` within `MethodDefinition` is a weird one and would not be possible to implement without encoding a magic "special case" within the codegen without this extra `ScopeFlags::Method` variant. Its existence does not alter the operation of any other code in Oxc which uses `ScopeFlags`.
In my view `ScopeFlags` might benefit from a little bit of an overhaul anyway. I believe we could pack more information into the bits and make it more useful.
Reorder the fields in a couple of AST types.
`walk_*` functions in `oxc_traverse` visit the fields in the order they appear in AST. So this change means that decorators are visited before classes and methods that they decorate.
Make the code for `retag_stack` in `walk_*` functions more
comprehensible, by replacing hard-coded enum discriminants as integers
with an `AncestorType` type.
Alternative solution to the problem raised in #3170.
close: #3170
First part of #3152.
This adds a crate `oxc_traverse`, but doesn't connect it up to the
transformer or anything else yet.
I think we could merge this now - as it doesn't affect any code that's
in use - and then iterate on it to add scopes before using it in
transformer. Please see
https://github.com/oxc-project/oxc/pull/3152#issuecomment-2094965406 for
the broader picture.