Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(linter): add eslint/no-unused-vars (⭐ attempt 3.2) #4445

Merged
merged 1 commit into from
Jul 31, 2024

Conversation

DonIsaac
Copy link
Collaborator

@DonIsaac DonIsaac commented Jul 24, 2024

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
    /* exported a */ var a;
  • global comments
    /* global a */ var a;

Behavior Changes

These are intentional deviations from the original rule's behavior:

  • logical re-assignments are not considered usages
    // 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: (proposal) feat(semantic): add ReferenceFlag::JSDoc #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

  • Skip unused TS enum members on used enums
  • Skip unused parameters followed by used variables in object/array spreads
  • Re-assignments to array/object spreads do not respect destructuredArrayIgnorePattern (related to: bug(semantic): incorrect parents for ArrayAssignmentTarget #4435)
  • fix(semantic): non-exported namespace member symbols flagged as exported #4493
  • References inside a nested scope are not considered usages (bug(semantic): Reference has incorrect span, node_id, and symbol_id #4447)
  • Port over typescript-eslint test cases (wip, they've been copied and I'm slowly enabling them)
  • Handle constructor properties
    class Foo {
      constructor(public a) {} // `a` should be allowed
    }
  • Read references in sequence expressions (that are not in the last position) should not count as a usage
    let a = 0; let b = (a++, 0); console.log(b)

    Honestly, is anyone even writing code like this?

  • function overload signatures should not be reported
  • Named functions returned from other functions get incorrectly reported as unused (found by @camc314)
    function foo() {
      return function bar() { }
    }
    Foo()()
  • false positive for TS modules within ambient modules
    declare global {
      // incorrectly marked as unused
      namespace jest { }
    }

Blockers

Non-Blocking Issues

@DonIsaac DonIsaac added C-enhancement Category - New feature or request E-Help Wanted Experience level - For the experienced collaborators A-linter Area - Linter labels Jul 24, 2024
@github-actions github-actions bot added the A-semantic Area - Semantic label Jul 24, 2024
Copy link

codspeed-hq bot commented Jul 24, 2024

CodSpeed Performance Report

Merging #4445 will not alter performance

Comparing don/linter/feat/no-unused-vars-3.2 (b952942) with main (6543958)

Summary

✅ 32 untouched benchmarks

DonIsaac added a commit that referenced this pull request Jul 25, 2024
Dunqing pushed a commit that referenced this pull request Jul 25, 2024
@github-actions github-actions bot added the A-ast Area - AST label Jul 26, 2024
@DonIsaac DonIsaac changed the title feat(linter): add eslint/no-unused-vars (attempt 3.2) feat(linter): add eslint/no-unused-vars (⭐ attempt 3.2) Jul 26, 2024
@Dunqing
Copy link
Member

Dunqing commented Jul 26, 2024

Nice performance! I'll review this PR this weekend.

@camc314
Copy link
Collaborator

camc314 commented Jul 26, 2024

this is great!

i get a false positive with:

function test() {
    return function Baz() {
        return 'Baz';
    };
}

test()();

output:

  × eslint(no-unused-vars): Function 'Baz' is declared but never used.
   ╭─[./test.ts:2:21]
 1  function test() {
 2      return function Baz() {
   ·                     ─┬─
   ·                      ╰── 'Baz' is declared here
 3          return 'Baz';
   ╰────
  help: Consider removing this declaration.

Finished in 7ms on 1 file with 1 rules using 12 threads.
Found 0 warnings and 1 error.

also:

input:

import type { mySchema } from './my-schema';

function test(arg: ReturnType<typeof mySchema>) {
    arg;
}

test('');

output:

  × eslint(no-unused-vars): Type 'mySchema' is imported but never used.
   ╭─[./test.tsx:1:15]
 1  import type { mySchema } from './my-schema';
   ·               ────┬───
   ·                   ╰── 'mySchema' is imported here
 2  
   ╰────
  help: Consider removing this import.

Finished in 7ms on 1 file with 1 rules using 12 threads.
Found 0 warnings and 1 error.

DonIsaac added a commit that referenced this pull request Jul 26, 2024
> Part of #4445

Fixes a bug where non-exported functions and variables inside of exported TS namespaces were being flagged with `SymbolFlags::Export`

```ts
export namespace Foo {
  // incorrectly flagged as exported
  function foo() { }
}
```
@DonIsaac
Copy link
Collaborator Author

@camc314 thank you so much for the feedback! I'll add those cases and fix it up.

Dunqing pushed a commit that referenced this pull request Jul 27, 2024
…ted (#4493)

> Part of #4445

Fixes a bug where non-exported functions and variables inside of
exported TS namespaces were being flagged with `SymbolFlags::Export`

```ts
export namespace Foo {
  // incorrectly flagged as exported
  function foo() { }
}
```
Boshen pushed a commit that referenced this pull request Jul 27, 2024
Part of #4445, broken into a separate PR.
@mysteryven
Copy link
Member

mysteryven commented Jul 30, 2024

This is impressive work!!


Found several cases should fail:

  1. https://github.com/preactjs/preact/blob/f7f9d9bf4309d09bcd0a432acd72787b7d9baecb/compat/src/index.d.ts#L674-L680
// SS is unused
export abstract class PureComponent<P = {}, S = {}, SS = any> extends preact.Component<P, S> {
    isPureReactComponent: boolean;
}
  1. https://github.com/DefinitelyTyped/DefinitelyTyped/blob/87ffcec0275bcded1270f737deb0bc675129a7f6/types/angular-material/index.d.ts#L1
import * as angular from "angular";
  1. https://github.com/DefinitelyTyped/DefinitelyTyped/blob/87ffcec0275bcded1270f737deb0bc675129a7f6/types/antlr4/CommonTokenStream.d.ts#L3-L4

  2. Looks like some test files are not lint, they are in diff.txt: https://stackblitz.com/edit/stackblitz-starters-7d4upf?file=diff.txt.

@DonIsaac
Copy link
Collaborator Author

@mysteryven those examples are located in .d.ts files, which I am currently skipping checks on completely.

@Dunqing
Copy link
Member

Dunqing commented Jul 30, 2024

@mysteryven those examples are located in .d.ts files, which I am currently skipping checks on completely.

You are right. The semantic doesn't handle .d.ts files either currently.

Copy link
Member

@Dunqing Dunqing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Let's merge it after all requested changes are resolved!

DonIsaac added a commit that referenced this pull request Jul 30, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
DonIsaac added a commit that referenced this pull request Jul 30, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
DonIsaac added a commit that referenced this pull request Jul 30, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
@DonIsaac
Copy link
Collaborator Author

DonIsaac commented Jul 30, 2024

@Dunqing I think we're good to go, should we send it?

NOTE: I'm pretty confident this will cause failures in Preact's lint CI job. Lemme make a PR into their codebase first.

EDIT: PRs have been made into offending codebases. Depending on how much time we have between merging this PR and our next release, we should be ok to merge.

DonIsaac added a commit to DonIsaac/preact that referenced this pull request Jul 30, 2024
Oxlint's [no-unused-vars](oxc-project/oxc#4445) PR will
be merged soon. This PR updates `oxlint.json` to support some limitations of its
implementation.

- `@jsx` pragmas are not currently recognized as a usage, so `createElement` has
  been added to `varsIgnorePattern`
- `Fragment` imports used via `<></>` syntax is not recognized as a usage, so
  `Fragment` has been added to `varsIgnorePattern`

Note that there are still some unused variables and catch parameters that, when
`no-unused-vars` gets merged, will cause lint CI to fail.
DonIsaac added a commit that referenced this pull request Jul 30, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
hyf0 added a commit to rolldown/rolldown that referenced this pull request Jul 31, 2024
### Description
Oxlint will be adding
[no-unused-vars](oxc-project/oxc#4445) soon,
which will add warnings to all unused variables. This PR updates
Rolldown's `.oxlintrc.json` and cleans up some code to prevent your CI
from failing.

---------

Co-authored-by: Yunfei <i.heyunfei@gmail.com>
Copy link

graphite-app bot commented Jul 31, 2024

Merge activity

> 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: #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
- #4436
- #4437
- #4446
- #4447
- #4494
- #4495

## Non-Blocking Issues
- #4443
- #4475 (prevents checks on exported symbols from namespaces)
@Dunqing Dunqing force-pushed the don/linter/feat/no-unused-vars-3.2 branch from e97aa72 to b952942 Compare July 31, 2024 03:22
@graphite-app graphite-app bot merged commit b952942 into main Jul 31, 2024
22 checks passed
@graphite-app graphite-app bot deleted the don/linter/feat/no-unused-vars-3.2 branch July 31, 2024 03:27
@Dunqing
Copy link
Member

Dunqing commented Jul 31, 2024

@DonIsaac Can you take a look at https://github.com/oxc-project/oxlint-ecosystem-ci/actions/runs/10173564561/job/28137965651. This case seems a false positive

  x eslint(no-unused-vars): Function 'onMessage' is declared but never used.
    ,-[wasm-runtime/fs-proxy.cjs:78:51]
 77 |  */
 78 | module.exports.createOnMessage = (fs) => function onMessage(e) {
    :                                                   ^^^^|^^^^
    :                                                       `-- 'onMessage' is declared here
 79 |   if (e.data.__fs__) {
    `----
  help: Consider removing this declaration.

@trigaten
Copy link

Congrats!

@oxc-bot oxc-bot mentioned this pull request Aug 1, 2024
Boshen added a commit that referenced this pull request Aug 1, 2024
## [0.23.0] - 2024-08-01

- 27fd062 sourcemap: [**BREAKING**] Avoid passing `Result`s (#4541)
(overlookmotel)

### Features

- a558492 codegen: Implement `BinaryExpressionVisitor` (#4548) (Boshen)
- 7446e98 codegen: Align more esbuild implementations (#4510) (Boshen)
- 35654e6 codegen: Align operator precedence with esbuild (#4509)
(Boshen)
- b952942 linter: Add eslint/no-unused-vars (⭐ attempt 3.2) (#4445)
(DonIsaac)
- 85e8418 linter: Add react/jsx-curly-brace-presence (#3949) (Don Isaac)
- cf1854b semantic: Remove `ReferenceFlags::Value` from non-type-only
exports that referenced type binding (#4511) (Dunqing)

### Bug Fixes

- b58ed80 codegen: Enable more test cases (#4585) (Boshen)
- 6a94e3f codegen: Fixes for esbuild test cases (#4503) (Boshen)
- d5c4b19 parser: Fix enum member parsing (#4543) (DonIsaac)

### Performance

- 4c6d19d allocator: Use capacity hint (#4584) (Luca Bruno)
- 7585e16 linter: Remove allocations for string comparisons (#4570)
(DonIsaac)
- 55a8763 parser: Faster decoding unicode escapes in identifiers (#4579)
(overlookmotel)
- ae1d38f parser: Fast path for ASCII when checking char after numeric
literal (#4577) (overlookmotel)
- 56ae615 parser: Make not at EOF the hot path in `Source` methods
(#4576) (overlookmotel)
- 25679e6 parser: Optimize `Lexer::hex_digit` (#4572) (overlookmotel)
- bb33bcc parser: Speed up lexing non-decimal numbers (#4571)
(overlookmotel)
- ab8509e parser: Use `-` not `saturating_sub` (#4561) (overlookmotel)
- c9c38a1 parser: Support peeking over bytes (#4304) (lucab)
- 0870ee1 parser: Get and check lookahead token (#4534) (lucab)
- d00014e sourcemap: Elide bounds checks in VLQ encoding (#4583)
(overlookmotel)
- 1fd9dd0 sourcemap: Use simd to escape JSON string (#4487)
(Brooooooklyn)

### Documentation

- 0914e47 ast: Add doc comments to literal nodes (#4551) (DonIsaac)
- c6a11be ast: Auto-generate doc comments for AstBuilder methods (#4471)
(DonIsaac)

### Refactor

- e68ed62 parser: Convert lexer byte handler for `|` to a single match
(#4575) (overlookmotel)
- bba824b parser: Convert `Lexer::read_minus` to a single match (#4574)
(overlookmotel)
- ef5418a parser: Convert `Lexer::read_left_angle` to a single match
(#4573) (overlookmotel)
- 9e5be78 parser: Add `Lexer::consume_2_chars` (#4569) (overlookmotel)
- 649913e parser: Extract `u8` not `&u8` when iterating over bytes
(#4568) (overlookmotel)
- 59f00c0 parser: Rename function (#4566) (overlookmotel)
- 8e3e910 parser: Rename vars (#4565) (overlookmotel)
- 0c0601f parser: Rename function (#4564) (overlookmotel)
- 0acc4a7 parser: Fetch 2 bytes in `?` byte handler (#4563)
(overlookmotel)
- 565eccf parser: Shorten lexer code (#4562) (overlookmotel)
- 148bdb5 parser: Adjust function inlining (#4530) (overlookmotel)
- 16c7b98 semantic: Move CatchClause scope binding logic to
visit_block_statement (#4505) (Dunqing)
- d6974d4 semantic: `AstNodeParentIter` fetch nodes lazily (#4533)
(overlookmotel)
- d914b14 semantic: Reusing the same reference (#4529) (Dunqing)
- 7b5e1f5 semantic: Use `is_empty()` instead of `len() == 0` (#4532)
(overlookmotel)
- 9db4259 semantic: Inline trivial methods (#4531) (overlookmotel)
- 7c42ffc sourcemap: Align Base64 chars lookup table to cache line
(#4535) (overlookmotel)
- 96602bf transformer/typescript: Determine whether to remove
`ExportSpeicifer` by `ReferenceFlags` (#4513) (Dunqing)
- e6a8af6 traverse: Speed up tests (#4538) (overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
rzvxa pushed a commit that referenced this pull request Aug 3, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
overlookmotel pushed a commit that referenced this pull request Aug 3, 2024
> Part of #4445

Improve `debug_name` to show identifier names for more AST kinds.
@oxc-bot oxc-bot mentioned this pull request Aug 5, 2024
Boshen added a commit that referenced this pull request Aug 5, 2024
## [0.7.0] - 2024-08-05

- 85a7cea semantic: [**BREAKING**] Remove name from `reference` (#4329)
(Dunqing)

### Features

- aaee07e ast: Add `AstKind::AssignmentTargetPattern`,
`AstKind::ArrayAssignmentTarget` and `AstKind::ObjectAssignmentTarget`
(#4456) (Dunqing)
- 9df7b56 jsx-a11y/no-autofocus: Implement fixer support (#4171) (Jelle
van der Waa)
- b87bf70 linter: Add fix capabilties to existing lint rules (#4560)
(DonIsaac)
- ddd8b27 linter: Support conditional fix capabilities (#4559)
(DonIsaac)
- b952942 linter: Add eslint/no-unused-vars (⭐ attempt 3.2) (#4445)
(DonIsaac)
- 6543958 linter: Add auto-fix metadata to RuleMeta (#4557) (Don Isaac)
- 85e8418 linter: Add react/jsx-curly-brace-presence (#3949) (Don Isaac)
- 4c4da56 linter: Add typescript-eslint/prefer-keyword-namespce (#4438)
(Aza Walker)
- d8c2a83 linter: Eslint-plugin-vitest/no-import-node-test (#4440)
(cinchen)
- e3b0c40 linter: Eslint-plugin-vitest/no-identical-title (#4422)
(cinchen)
- c936782 linter: Eslint-plugin-vitest/no-conditional-expect (#4425)
(cinchen)
- 27fdd69 linter: Eslint-plugin-vitest/no-commented-out-tests (#4424)
(cinchen)
- 51f5025 linter: Add fixer for unicorn/prefer-string-starts-ends-with
(#4378) (DonIsaac)
- 3c0c709 linter: Add typescript-eslint/no-extraneous-class (#4357)
(Jaden Rodriguez)
- 7afa1f0 linter: Support suggestions and dangerous fixes (#4223)
(DonIsaac)
- acc5729 linter: Eslint-plugin-vitest/expect-expect (#4299) (cinchen)
- 2213f93 linter: Eslint-plugin-vitest/no-alias-methods (#4301)
(cinchen)
- c296bc3 linter/eslint: Implement func-names (#4618) (Alexander S.)
- e116ae0 linter/eslint: Implement fixer for prefer-numeric-literals
(#4591) (Jelle van der Waa)
- eaf834f linter/eslint: Implement prefer-numeric-literals (#4109)
(Jelle van der Waa)
- db2fd70 linter/eslint-plugin-promise: Implement
no-webpack-loader-syntax (#4331) (Jelle van der Waa)
- 5f1e070 linter/eslint-plugin-unicorn: Add fixer for prefer-code-point
(#4353) (Jelle van der Waa)
- ed49e16 linter/eslint-plugin-unicorn: Implement fixer for
prefer-dom-node-append (#4306) (Jelle van der Waa)
- e2b15ac linter/react: Implement react-jsx-boolean-value (#4613) (Jelle
van der Waa)
- 68efcd4 linter/react-perf: Handle new objects and arrays in prop
assignment patterns (#4396) (DonIsaac)

### Bug Fixes

- 368112c ast: Remove `#[visit(ignore)]` from
`ExportDefaultDeclarationKind`'s `TSInterfaceDeclaration` (#4497)
(Dunqing)
- d384f60 ci: Remove unused(?) .html file (#4545) (Yuji Sugiura)
- 06aec77 linter: Invalid binary expression with overflow (#4647)
(DonIsaac)
- b2da22b linter: Invalid tags in rule docs (#4646) (DonIsaac)
- 94440ad linter: Panic on invalid lang in `a11y/lang`. (#4630) (rzvxa)
- e0b03f8 linter: Improve the boundary for eslint/for-direction (#4590)
(heygsc)
- 70b8cfa linter: Missing return in no-obj-calls recursion (#4594)
(DonIsaac)
- fe1356d linter: Change no-unused-vars to nursery (#4588) (DonIsaac)
- 72337b1 linter: Change typescript-eslint/no-namespace to restriction
(#4539) (Don Isaac)
- 732f4e2 linter: Fix `oxlint` allocator cfg (#4527) (overlookmotel)
- 289dc39 linter: Overflow in no-obj-calls (#4397) (DonIsaac)
- a664715 linter/eslint: Fix invalid regexp in no_regex_spaces test
(#4605) (Yuji Sugiura)
- 74fa75a linter/eslint: Drop quotes around max-params lint warning
(#4608) (Jelle van der Waa)
- 9fcd9ae linter/eslint: Fix invalid regexp in no_control_regex test
(#4544) (leaysgur)
- ac08de8 linter/react_perf: Allow new objects, array, fns, etc in top
scope (#4395) (DonIsaac)
- 0fba738 npm: SyntaxError caused by optional chaining in low version
node (#4650) (heygsc)
- 73d2558 oxlint: Fix oxlint failed to build due to missing feature
(Boshen)

### Performance

- 6ff200d linter: Change react rules and utils to use `Cow` and
`CompactStr` instead of `String` (#4603) (DonIsaac)
- f259df0 linter: Make img-redundant-alt only build a regex once (#4604)
(DonIsaac)
- 7585e16 linter: Remove allocations for string comparisons (#4570)
(DonIsaac)
- b60bdf1 linter: `no_shadow_restricted_names` only look up name in
hashmap once (#4472) (overlookmotel)
- 81384f5 linter: Avoid unnecessary work in `nextjs:no_duplicate_head`
rule (#4465) (overlookmotel)
- f7da22d linter: Disable lint rules by file type (#4380) (DonIsaac)
- 348c1ad semantic: Remove `span` field from `Reference` (#4464)
(overlookmotel)
- 6a9f4db semantic: Reduce storage size for symbol redeclarations
(#4463) (overlookmotel)- a207923 Replace some CompactStr usages with
Cows (#4377) (DonIsaac)

### Refactor

- 7a75e0f linter: Use diagnostic codes in lint rules (#4349) (DonIsaac)
- ccb1835 semantic: Methods take `Span` as param, not `&Span` (#4470)
(overlookmotel)
- 7cd53f3 semantic: Var hoisting (#4379) (Dunqing)
- c99b3eb syntax: Give `ScopeId` a niche (#4468) (overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ast Area - AST A-cli Area - CLI A-linter Area - Linter A-semantic Area - Semantic C-enhancement Category - New feature or request E-Help Wanted Experience level - For the experienced collaborators
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants