Commit graph

128 commits

Author SHA1 Message Date
Boshen
1bed5ce2a5 chore: run cargo +nightly fmt to sort imports (#5503)
They are never going to be stable are they ... cedf7a4daa/.rustfmt.toml (L8-L16)
2024-09-06 04:04:26 +00:00
rzvxa
ccc8a27e4f refactor(ast, ast_tools): use full method path for generated derives trait calls. (#5462)
As of now if we remove the implementation of a trait for a type and implement the method on that type directly it wouldn't break while it isn't the original trait anymore so that method might do something entirely different.
This change is more explicit on trait calls so we hit compile errors on these kinds of changes.
2024-09-05 05:36:50 +00:00
rzvxa
90facd3657 feat(ast): add ContentHash trait; remove noop Hash implementation from Span (#5451)
closes #5283

Also removes the noop Hash implementation on `Span` in favor of a real implementation.
2024-09-05 07:20:04 +03:30
Dunqing
e4ed41d4fa refactor(semantic): change the reference flag to ReferenceFlags::Type if it is used within a TSTypeQuery (#5444)
So far, the `ReferenceFlags::TSTypeQuery` only used indicates it is referenced by `TSTypeQuery` that we can confirm the reference should be regarded as a type reference, namely `ReferenceFlags::Type`.

This PR adds a `ReferenceFlags::ValueAsType` instead of `ReferenceFlags::TSTypeQuery`.  The new flag has the same behavior as the previous one. But it looks more general and is not only used in `TSTypeQuery`. But now it is a temporary flag. We use it to resolve the symbol correctly and replace `ReferenceFlags::ValueAsTyoe` with `ReferenceFlags::Type` after resolved.

Also, this change eliminates the inconsistency in behavior between the `Reference::is_type` and `ReferenceFlags::is_type` methods.
2024-09-05 01:50:20 +00:00
rzvxa
23285f431d feat(ast): add ContentEq trait. (#5427)
Part of #5283
2024-09-04 11:53:50 +00:00
overlookmotel
bfabd8facc perf(syntax): further optimize is_identifier_name (#5426)
Follow-on after #5425. Further optimize `oxc_syntax::identifier::is_identifier_name` by processing string in blocks of 8 bytes, and checking if all bytes in a block are ASCII in one go, rather than testing each byte individually.
2024-09-03 13:48:36 +00:00
overlookmotel
aeda84f904 perf(syntax): optimize is_identifier_name (#5425)
Optimize `oxc_syntax::identifier::is_identifier_name`. Add a fast path for ASCII, which will be the common case. Only fall back to iterating over `char`s and using the more expensive test functions e.g. `is_identifier_start_unicode` if non-ASCII chars are found.
2024-09-03 12:48:32 +00:00
rzvxa
b47aca0e88 refactor(syntax): use generate_derive for CloneIn in types outside of oxc_ast crate. (#5280)
Removes the temporary `CloneIn` derive macro used for "foreign" types - as in types outside of the `oxc_ast` crate - since now we have support for multiple derive outputs - one per each crate - that allows us to use `generate_derive` across multiple crates.
2024-09-03 02:36:37 +00:00
overlookmotel
d262a58eb5 refactor(syntax)!: rename ReferenceFlag to ReferenceFlags (#5023)
Part of #4991.
2024-08-21 00:19:56 +00:00
DonIsaac
48821c0110 feat(semantic,syntax): add SymbolFlags::ArrowFunction (#4946)
There are many cases in lint rules where we want to see if a symbol is a
function by checking its SymbolFlags. This is currently not fully possible,
since variables assigned to arrow functions are not distinguished from any other
kind of variable. This PR adds `SymbolFlags::ArrowFunction` for variables that
are initialized to arrow functions. Symbols that are re-assigned to arrow
functions will not have this flag, but this is acceptable for lint rules.
2024-08-18 05:54:23 +00:00
overlookmotel
48a1c32ed3 refactor(syntax): inline trivial bitflags methods (#4877)
Add `#[inline]` to trivial bitflags methods. Very likely this makes no difference within Oxc, as we compile with LTO enabled, but for external consumers of Oxc who don't use LTO, this will enable cross-crate inlining.
2024-08-13 12:43:09 +00:00
DonIsaac
0a01a4729a docs(semantic): improve documentation (#4850) 2024-08-13 02:14:07 +00:00
rzvxa
6a36616289 feat(syntax): derive CloneIn for the AST-related items. (#4730)
Follow-on after #4276, related to #4284.
2024-08-07 17:38:08 +00:00
overlookmotel
3f3cb629af refactor(syntax, span): reduce #[cfg_attr] boilerplate in type defs (#4698)
Similar to #4375. #4694 added `#[ast]` attribute to types in `oxc_syntax`, so these types can use `#[serde]` attrs without the `#[cfg_attr(feature = "serialize", ...)]` guard.
2024-08-06 17:37:07 +00:00
rzvxa
82e2f6b924 feat(ast_codegen): process AST-related syntax types. (#4694) 2024-08-06 17:14:35 +00:00
rzvxa
e24fb5b093 refactor(syntax): add explicit enum discriminants to AST related types. (#4691) 2024-08-06 17:09:15 +00:00
overlookmotel
9f8f2997c4 fix(syntax): prevent creating invalid u32 IDs (#4675)
Panic if try to create an `AstNodeId`, `ReferenceId`, `ScopeId` or `SymbolId` from a `usize` which can't be stored as a `u32`.

Previously we checked for `u32::MAX`, but didn't check for numbers larger than that.
2024-08-06 01:04:07 +00:00
Boshen
a558492bf9 feat(codegen): implement BinaryExpressionVisitor (#4548)
part of https://github.com/oxc-project/backlog/issues/58

`monitor-oxc` run: https://github.com/oxc-project/monitor-oxc/actions/runs/10179047831
binary expression stack length tally using `counts` in top 100 npm packages from monitor-oxc:

```
29772 counts
(  1)    17652 (59.3%, 59.3%): 0
(  2)     5772 (19.4%, 78.7%): 1
(  3)     3204 (10.8%, 89.4%): 2
(  4)     1276 ( 4.3%, 93.7%): 3
(  5)      616 ( 2.1%, 95.8%): 4
(  6)      308 ( 1.0%, 96.8%): 5
(  7)      202 ( 0.7%, 97.5%): 6
(  8)      168 ( 0.6%, 98.1%): 7
(  9)      114 ( 0.4%, 98.5%): 9
( 10)       90 ( 0.3%, 98.8%): 8
( 11)       84 ( 0.3%, 99.0%): 13
( 12)       58 ( 0.2%, 99.2%): 10
( 13)       48 ( 0.2%, 99.4%): 12
( 14)       32 ( 0.1%, 99.5%): 11
( 15)       20 ( 0.1%, 99.6%): 134
( 16)       16 ( 0.1%, 99.6%): 18
( 17)       16 ( 0.1%, 99.7%): 20
( 18)       12 ( 0.0%, 99.7%): 19
( 19)       12 ( 0.0%, 99.8%): 35
( 20)       12 ( 0.0%, 99.8%): 51
( 21)       10 ( 0.0%, 99.8%): 15
( 22)        6 ( 0.0%, 99.9%): 17
( 23)        6 ( 0.0%, 99.9%): 21
( 24)        6 ( 0.0%, 99.9%): 45
( 25)        4 ( 0.0%, 99.9%): 14
( 26)        4 ( 0.0%, 99.9%): 26
( 27)        4 ( 0.0%, 99.9%): 53
( 28)        2 ( 0.0%, 99.9%): 172
( 29)        2 ( 0.0%, 99.9%): 214
( 30)        2 ( 0.0%,100.0%): 22
( 31)        2 ( 0.0%,100.0%): 27
( 32)        2 ( 0.0%,100.0%): 28
( 33)        2 ( 0.0%,100.0%): 29
( 34)        2 ( 0.0%,100.0%): 31
( 35)        2 ( 0.0%,100.0%): 36
( 36)        2 ( 0.0%,100.0%): 46
( 37)        2 ( 0.0%,100.0%): 55
```
2024-07-31 12:44:19 +00:00
DonIsaac
b952942993 feat(linter): add eslint/no-unused-vars ( attempt 3.2) (#4445)
> Re-creation of #4427 due to rebasing issues. Original attempt: #642
-----

Third time's the charm?

Each time I attempt this rule, I find a bunch of bugs in `Semantic`, and I expect this attempt to be no different. Expect sidecar issues+PRs stemming from this PR here.

## Not Supported
These are cases supported in the original eslint rule, but that I'm intentionally deciding not to support
- export comments in scripts
  ```js
  /* exported a */ var a;
  ```
- global comments
  ```js
  /* global a */ var a;
   ```

## Behavior Changes
These are intentional deviations from the original rule's behavior:
- logical re-assignments are not considered usages
  ```js
  // passes in eslint/no-unused-vars, fails in this implementation
  let a = 0; a ||= 1;
  let b = 0; b &&= 2;
  let c = undefined; c ??= []
  ```

## Known Limitations
- Lint rules do not have babel or tsconfig information, meaning we can't determine if `React` imports are being used or not. The relevant tsconfig settings here are `jsx`, `jsxPragma`, and `jsxFragmentName`. To accommodate this, all imports to symbols named `React` or `h` are ignored in JSX files.
- References to symbols used in JSDoc `{@link}` tags are not created, so symbols that are only used in doc comments will be reported as unused. See: #4443
- `.vue` files are skipped completely, since variables can be used in templates in ways we cannot detect
  > note: `.d.ts` files are skipped as well.

## Todo
- [x] Skip unused TS enum members on used enums
- [x] Skip unused parameters followed by used variables in object/array spreads
- [x] Re-assignments to array/object spreads do not respect `destructuredArrayIgnorePattern` (related to: https://github.com/oxc-project/oxc/issues/4435)
- [x] #4493
- [x] References inside a nested scope are not considered usages (#4447)
- [x] Port over typescript-eslint test cases _(wip, they've been copied and I'm slowly enabling them)_
- [x] Handle constructor properties
  ```ts
  class Foo {
    constructor(public a) {} // `a` should be allowed
  }
  ```
- [x] Read references in sequence expressions (that are not in the last position) should not count as a usage
  ```js
  let a = 0; let b = (a++, 0); console.log(b)
  ```
  > Honestly, is anyone even writing code like this?
- [x] function overload signatures should not be reported
- [x] Named functions returned from other functions get incorrectly reported as unused (found by @camc314)
  ```js
  function foo() {
    return function bar() { }
  }
  Foo()()
  ```
- [x] false positive for TS modules within ambient modules
  ```ts
  declare global {
    // incorrectly marked as unused
    namespace jest { }
  }
  ```

## Blockers
- https://github.com/oxc-project/oxc/issues/4436
- https://github.com/oxc-project/oxc/issues/4437
- #4446
- #4447
- #4494
- #4495

## Non-Blocking Issues
- #4443
- #4475 (prevents checks on exported symbols from namespaces)
2024-07-31 03:22:16 +00:00
Boshen
35654e665c feat(codegen): align operator precedence with esbuild (#4509)
closes #4339
2024-07-28 11:48:51 +00:00
Ethan Goh
1667491868
fix(syntax): correct is_reserved_keyword_or_global_object's incorrect function calling. (#4484)
It may be a problem, but doesn't matter previously.

Formerly, the `is_reserved_keyword_or_global_object` is
`is_reserved_keyword(s) || is_reserved_keyword(s)`. I think it should be
`is_reserved_keyword(s) || is_global_object(s)` according to its name.

Also, the `.idea` may be because I am using RustRover, which may
automatically create `.idea` folder. So I ignore it in `.gitignore`.

I think I can contribute to `oxc` more when I am free.
2024-07-26 17:20:10 -04:00
overlookmotel
24beaeb4ee perf(semantic): give AstNodeId a niche (#4469)
Make `AstNodeId` a type with a niche, using `NonMaxU32` as its internal storage. This makes `Option<AstNodeId>` 4 bytes instead of 8. That halves the size of the `Vec` for parent IDs in `AstNodes` (which gets pretty big).
2024-07-26 00:14:53 +00:00
overlookmotel
c99b3eb464 refactor(syntax): give ScopeId a niche (#4468)
Make `ScopeId` a type with a niche, like `SymbolId` and `ReferenceId`. This makes `Option<ScopeId>` 4 bytes instead of 8, and shrinks various AST types e.g. `ArrowFunctionExpression` by 8 bytes, and halves the size of the `Vec` in `ScopeTree::parent_ids`.

The snapshot change on `prefer-hooks-in-order` lint rule appears incidental - it doesn't alter what errors are reported, only the order they're reported in. This appears to be because it changes the order of keys in a hashmap keyed by `ScopeId` that [the rule uses](a49f4915de/crates/oxc_linter/src/rules/jest/prefer_hooks_in_order.rs (L143)).
2024-07-26 00:14:50 +00:00
overlookmotel
96fc94f61e refactor(syntax): use NonMaxU32 for IDs (#4467)
`SymbolId` and `ReferenceId` are stored as `NonZeroU32`, but with a wrapper to make `u32::MAX` the illegal value, instead of `0`.

Use the existing `nonmax` crate for this. Our current implementation uses `idx + 1` to avoid the zero value, whereas `nonmax` crate uses XOR `idx ^ u32::MAX`, which is a cheaper operation.

Initially I made this change manually instead of pulling in a dependency, but it's a pain because it requires implementing `Debug` and `PartialOrd` by hand to handle the difference between the "actual" value and its stored representation. So I thought better to use a crate which does this for us.
2024-07-26 00:14:47 +00:00
overlookmotel
82ba2a073f fix(syntax): fix unsound use of NonZeroU32 (#4466)
`NonZeroU32::new_unchecked(idx as u32 + 1)` is unsound because if `idx == u32::MAX`, `idx + 1` wraps around back to zero. So unfortunately we need to use the checked version `NonZeroU32::new(idx as u32 + 1).unwrap()` to avoid UB in this edge case.
2024-07-26 00:14:44 +00:00
overlookmotel
6a9f4db609 perf(semantic): reduce storage size for symbol redeclarations (#4463)
Most symbols don't have redeclarations.

So instead of storing `Vec<Span>` directly in `redeclare_variables` (24 bytes per symbol), store `Option<RedeclarationId>` (4 bytes).

`RedeclarationId` indexes into `redeclarations` where the actual `Vec<Span>` is stored. But for symbols with no redeclarations (the vast majority), it takes 4 bytes per symbol only.
2024-07-26 00:14:35 +00:00
DonIsaac
e8071e3db4 feat(syntax): add boolean check methods for typescript-related symbol flags (#4426) 2024-07-23 22:23:08 +00:00
Dunqing
f8565ae3cd fix(transformer/typescript): unexpectedly removed class binding from ExportNamedDeclaration (#4351)
The original `SymbolFlags` methods were a bit confusing I renamed and re-implemented them.
2024-07-18 16:44:38 +00:00
Dunqing
95e15b6dc5 fix(semantic): incorrect resolve references for ExportSpecifier (#4320)
```ts
type A = any;
const B = 0;
export { A, B }
       ^^^^^^^^ ExportSpecifiers

export { A }
       ^^^^^ type-only ExportSpecifiers

```

non-type-only `ExportSpecifier` can reference value and type symbols. but currently, `IdentifierReference` in ExportSpecifier only has a `ReferenceFlags::Read`
2024-07-17 09:52:58 +00:00
Dunqing
a88d588a07 feat(semantic): add ReferenceFlags::TSTypeQuery to indicate referenced by TSTypeQuery (#4317)
`ReferenceFlags::TSTypeQuery` can be used to help us insist on whether the reference is referenced by the type or not.
2024-07-17 09:52:57 +00:00
Dunqing
1108f2a700 fix(semantic): resolve references to the incorrect symbol (#4280)
close: #3799
related: #3863
2024-07-17 02:50:48 +00:00
rzvxa
fc0b17d5a0 refactor(syntax): turn the AstNodeId::dummy into a constant field. (#4308) 2024-07-16 22:43:21 +00:00
overlookmotel
8fad7dbac3 perf(semantic): reduce AstNodeId to u32 (#4264)
`AstNodeId` was a `usize`. This seems excessive.

Parser has a limit on size of a JS file of 4 GiB. While it is *possible* for a JS file of that size to create an AST with more than `1 << 32` (~4 billion) AST nodes, that would be insanely large.

So make `AstNodeId` `u32` instead.
2024-07-15 04:31:51 +00:00
Boshen
a71787572e
chore: remove unsafe_code = "warn" rust lint
Feels too verbose as we already have unsafe comment turned on
2024-07-15 10:39:08 +08:00
Dunqing
92ee77487f feat(semantic): add ScopeFlags::CatchClause for use in CatchClause (#4205) 2024-07-12 03:47:07 +00:00
Dunqing
d995f94280 fix(semantic): resolve reference incorrectly when a parameter references a parameter that hasn't been defined yet (#4004)
close: #3682

The TypeScript code that handles this is [here](d8086f14b6/src/compiler/utilities.ts (L11515-L11577)). It looks complicated.
2024-07-02 02:12:15 +00:00
Boshen
0c81fbeac6
perf(syntax): use NonZeroU32 for SymbolId and ReferenceId (#3970)
closes https://github.com/oxc-project/backlog/issues/55
closes https://github.com/oxc-project/oxc/issues/3318
2024-06-29 17:29:02 +08:00
Boshen
99a40ce6ac fix(semantic): export default foo should have ExportLocalName::Default(NameSpan) entry (#3823) 2024-06-22 11:09:23 +00:00
Boshen
051ceb6539
chore: improve some format by running cargo +nightly fmt 2024-06-19 00:48:30 +08:00
overlookmotel
c00598b9d4
fix(transformer): JSX set reference_id on refs to imports (#3524)
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";`.
2024-06-05 10:57:05 +08:00
Boshen
e2dd8ac8fc feat(syntax): export is_reserved_keyword and is_global_object method (#3384) 2024-05-22 04:58:04 +00:00
Boshen
bd8a0ddb7f feat(linter): no-barrel-file (#3275)
![image](https://github.com/oxc-project/oxc/assets/1430279/524c8afa-a4c0-45a3-b95d-f8efd359a84f)
2024-05-16 07:54:09 +00:00
Dunqing
b4fa27a2ee
fix(transformer): do no add __self when the jsx is inside constructor (#3258) 2024-05-14 16:12:49 +01:00
overlookmotel
4e20b04acc fix(traverse): create scope for function nested in class method (#3234)
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.
2024-05-11 12:07:00 +00:00
overlookmotel
46c02aee61 feat(traverse): add scope flags to TraverseCtx (#3229)
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.
2024-05-11 04:39:42 +00:00
Boshen
f1ccbd4856
feat(syntax): add ToJsInt32 trait for f64 (#3132) 2024-04-29 21:13:04 +08:00
Boshen
870d11f1bb
feat(syntax): add ToJsString trait for f64 (#3131) 2024-04-29 21:00:04 +08:00
Boshen
a8af5de8f5
refactor(syntax): move number related functions to number module (#3130) 2024-04-29 18:54:35 +08:00
Boshen
ae6561308c
refactor(syntax): use FxHashMap for ModuleRecord::request_modules (#3124)
closes #3121

The ordering is not important here.
2024-04-29 03:37:34 +00:00
Ali Rezvani
e6d11c6190
feat(syntax): module graph visitor. (#3062)
I've tried too hard to make it into a full-fledged depth first iterator, But had no success with it; It is the next best thing that I could've thought of.

Provides a way to visit the module graph from a ModuleRecord as its entry point.
2024-04-22 10:10:27 +08:00