Skip to content

fix(linter/plugins): reset ancestors if error during AST walk#17207

Merged
graphite-app[bot] merged 1 commit intomainfrom
om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk
Dec 21, 2025
Merged

fix(linter/plugins): reset ancestors if error during AST walk#17207
graphite-app[bot] merged 1 commit intomainfrom
om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk

Conversation

@overlookmotel
Copy link
Member

@overlookmotel overlookmotel commented Dec 21, 2025

While walking the AST, ancestors array is pushed to when entering a node, and popped again when exiting. ancestors is empty at start of AST traversal and, because each push is followed by a pop, ancestors is empty again at the end of AST traversal.

ancestors is a singleton, reused for every AST traversal.

ancestors is used by esquery when determining if a node matches a selector. Note that it's not the same as what's returned from sourceCode.getAncestors(). ancestors is used only internally by esquery, so only way to see what it contains is by observing the behavior of selectors.

This PR fixes a bug where ancestors was not reset (emptied) if an error is thrown during AST traversal. In that case ancestors was left in the state it was in at time that the error was thrown, and this affects behavior of selectors when visiting the next AST.

Fix it by resetting ancestors if there's an error. Also add a bunch of debug assertions to ensure ancestors remains in sync with AST traversal at all times.

@github-actions github-actions bot added A-linter Area - Linter A-cli Area - CLI A-ast-tools Area - AST tools A-linter-plugins Area - Linter JS plugins C-bug Category - Bug labels Dec 21, 2025
Copy link
Member Author

overlookmotel commented Dec 21, 2025


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@overlookmotel overlookmotel force-pushed the om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk branch from 387bfc9 to b5ac1d4 Compare December 21, 2025 13:23
@overlookmotel overlookmotel force-pushed the om/12-20-refactor_linter_plugins_refactor_state_reset_after_errors_during_linting branch from 10800a6 to 1fbf13b Compare December 21, 2025 13:23
@overlookmotel overlookmotel marked this pull request as ready for review December 21, 2025 13:35
Copilot AI review requested due to automatic review settings December 21, 2025 13:35
@overlookmotel overlookmotel self-assigned this Dec 21, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug where the ancestors array (used internally by esquery for selector matching) was not being reset after an error during AST traversal. This caused the array to retain state from the failed file, affecting selector behavior when processing subsequent files.

Key changes:

  • Added debug assertions to verify ancestors is in sync during AST traversal
  • Reset ancestors array in resetStateAfterError() function
  • Added comprehensive test to verify the fix works correctly with multi-file scenarios

Reviewed changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tasks/ast_tools/src/generators/estree_visit.rs Added generator code for debug check function and ancestorsLen tracking
apps/oxlint/src-js/generated/walk.js Generated JavaScript with debug assertions for each AST node walker
apps/oxlint/src-js/plugins/lint.ts Added ancestors array reset in error handler and debug assertions before/after AST walk
apps/oxlint/test/fixtures/lint_visit_error/plugin.ts Updated test to verify ancestors is properly reset after errors
apps/oxlint/test/fixtures/lint_visit_error/output.snap.md Updated expected test output
apps/oxlint/test/fixtures/lint_visit_error/options.json Added single-thread option for deterministic test execution
apps/oxlint/test/fixtures/lint_visit_error/files/1.js Added first test file that triggers error
apps/oxlint/test/fixtures/lint_visit_error/files/2.js Added second test file to verify reset works

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@overlookmotel overlookmotel force-pushed the om/12-20-refactor_linter_plugins_refactor_state_reset_after_errors_during_linting branch from 1fbf13b to ebd3750 Compare December 21, 2025 14:23
@overlookmotel overlookmotel force-pushed the om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk branch from b5ac1d4 to 059ddae Compare December 21, 2025 14:23
@overlookmotel overlookmotel added the 0-merge Merge with Graphite Merge Queue label Dec 21, 2025
Copy link
Member Author

overlookmotel commented Dec 21, 2025

Merge activity

While walking the AST, `ancestors` array is pushed to when entering a node, and popped again when exiting. `ancestors` is empty at start of AST traversal and, because each push is followed by a pop, `ancestors` is empty again at the end of AST traversal.

`ancestors` is a singleton, reused for every AST traversal.

`ancestors` is used by `esquery` when determining if a node matches a selector. Note that it's not the same as what's returned from `sourceCode.getAncestors()`. `ancestors` is used only internally by `esquery`, so only way to see what it contains is by observing the behavior of selectors.

This PR fixes a bug where `ancestors` was not reset (emptied) if an error is thrown during AST traversal. In that case `ancestors` was left in the state it was in at time that the error was thrown, and this affects behavior of selectors when visiting the *next* AST.

Fix it by resetting `ancestors` of there's an error. Also add a bunch of debug assertions to ensure `ancestors` remains in sync with AST traversal at all times.
graphite-app bot pushed a commit that referenced this pull request Dec 21, 2025
#17205)

In JS plugins tests, it's sometimes required to ensure that files are linted in deterministic order.

For example, #17207 fixes a bug where some internal global state was not reset correctly after an error is thrown during visiting the AST. This affects what happens when linting the *next* file.

In order to write a test for this, and produces deterministic output in the snapshot file, the order files are linted in needs to be deterministic.

This PR provides this determinism by:

1. Adding a `force_deterministic_order` cargo feature which is enabled in test build.
2. When this feature is enabled *and* Oxlint is run with `--threads 1`, file paths are sorted before linting.
3. Adding an option for test fixtures `singleThread`. When `true`, the fixture is run with `--threads 1`.

Aim is to only enable deterministic ordering in test fixtures which *need* determinism, so that most test fixtures are still testing Oxlint running as it does usually for a user.
@graphite-app graphite-app bot force-pushed the om/12-20-refactor_linter_plugins_refactor_state_reset_after_errors_during_linting branch from ebd3750 to 6f05a99 Compare December 21, 2025 14:33
@graphite-app graphite-app bot force-pushed the om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk branch from 059ddae to 4027039 Compare December 21, 2025 14:34
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Dec 21, 2025
Base automatically changed from om/12-20-refactor_linter_plugins_refactor_state_reset_after_errors_during_linting to main December 21, 2025 14:39
@graphite-app graphite-app bot merged commit 4027039 into main Dec 21, 2025
19 checks passed
@graphite-app graphite-app bot deleted the om/12-20-fix_linter_plugins_reset_ancestors_if_error_during_ast_walk branch December 21, 2025 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ast-tools Area - AST tools A-cli Area - CLI A-linter Area - Linter A-linter-plugins Area - Linter JS plugins C-bug Category - Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants