mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(traverse): speed up tests (#4538)
Closes #4537. `oxc_traverse`'s tests to ensure code which would be undefined behavior will not compile were using `trybuild`. This is a thorough way to run these tests, but requires running a lengthy compilation each time tests run. Implement these tests as `compile_fail` doc tests instead. This is not quite as thorough - now only testing that they don't compile, rather than also *why* they don't compile - but acceptable given the outsized cost of doing it "properly".
This commit is contained in:
parent
d6974d4ff7
commit
e6a8af6112
12 changed files with 86 additions and 178 deletions
76
Cargo.lock
generated
76
Cargo.lock
generated
|
|
@ -1847,7 +1847,6 @@ dependencies = [
|
|||
"oxc_semantic",
|
||||
"oxc_span",
|
||||
"oxc_syntax",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2449,15 +2448,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
|
|
@ -2586,15 +2576,6 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.1"
|
||||
|
|
@ -2713,40 +2694,6 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
|
@ -2864,20 +2811,6 @@ dependencies = [
|
|||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b55265878356bdd85c9baa15859c87de93b2bf1f33acf752040a561e4a228f62"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tsify"
|
||||
version = "0.4.5"
|
||||
|
|
@ -3296,15 +3229,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
|
|
|
|||
|
|
@ -178,7 +178,6 @@ textwrap = "0.16.1"
|
|||
tokio = "1.38.0"
|
||||
tower-lsp = "0.20.0"
|
||||
tracing-subscriber = "0.3.18"
|
||||
trybuild = "1.0.96"
|
||||
tsify = "0.4.5"
|
||||
unicode-id-start = "1" # Relaxed version so the user can decide which unicode version to use.
|
||||
unicode-width = "0.1.13"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ include = ["/src"]
|
|||
workspace = true
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
test = false
|
||||
# Doctests must be enabled for this crate as they are used to run tests
|
||||
# which check the soundness of its code
|
||||
doctest = true
|
||||
|
||||
[dependencies]
|
||||
|
|
@ -29,6 +31,3 @@ oxc_syntax = { workspace = true }
|
|||
|
||||
compact_str = { workspace = true }
|
||||
memoffset = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = { workspace = true }
|
||||
|
|
|
|||
81
crates/oxc_traverse/src/compile_fail_tests.rs
Normal file
81
crates/oxc_traverse/src/compile_fail_tests.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#![cfg(doctest)]
|
||||
|
||||
//! Tests to ensure lifetimes prevent references to escape visitor functions.
|
||||
//! If they could, it'd allow aliasing, which would be undefined behavior.
|
||||
//!
|
||||
//! These tests were originally implemented using `trybuild` crate,
|
||||
//! but it disproportionately hurt time taken to run tests.
|
||||
//! So using `compile_fail` doc tests instead.
|
||||
//! <https://github.com/oxc-project/oxc/issues/4537>
|
||||
|
||||
/**
|
||||
```compile_fail
|
||||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
ancestor: Option<&'b Ancestor<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.ancestor = Some(ctx.parent());
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
const CANNOT_HOLD_ONTO_ANCESTOR: () = ();
|
||||
|
||||
/**
|
||||
```compile_fail
|
||||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{ancestor::ProgramWithoutDirectives, Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
program: Option<&'b ProgramWithoutDirectives<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
self.program = Some(program);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
const CANNOT_HOLD_ONTO_ANCESTOR_NODE: () = ();
|
||||
|
||||
/**
|
||||
```compile_fail
|
||||
use oxc_ast::ast::{IdentifierReference, Statement};
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
stmt: Option<&'b Statement<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
let body = program.body();
|
||||
let stmt = &body[0];
|
||||
self.stmt = Some(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
const CANNOT_HOLD_ONTO_AST_NODE: () = ();
|
||||
|
|
@ -73,6 +73,8 @@ mod traverse;
|
|||
pub use traverse::Traverse;
|
||||
mod walk;
|
||||
|
||||
mod compile_fail_tests;
|
||||
|
||||
/// Traverse AST with a [`Traverse`] impl.
|
||||
///
|
||||
/// This allows:
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
#[test]
|
||||
fn compile_fail() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/compile_fail/*.rs");
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
ancestor: Option<&'b Ancestor<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.ancestor = Some(ctx.parent());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime1.rs:14:9
|
||||
|
|
||||
8 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
12 | ctx: &mut TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
13 | ) {
|
||||
14 | self.ancestor = Some(ctx.parent());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{ancestor::ProgramWithoutDirectives, Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
program: Option<&'b ProgramWithoutDirectives<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
self.program = Some(program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime2.rs:15:13
|
||||
|
|
||||
8 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
12 | ctx: &mut TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
...
|
||||
15 | self.program = Some(program);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::{IdentifierReference, Statement};
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
program_body: Option<&'b Vec<'a, Statement<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
self.program_body = Some(program.body());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime3.rs:16:13
|
||||
|
|
||||
9 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
13 | ctx: &mut TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
...
|
||||
16 | self.program_body = Some(program.body());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
Loading…
Reference in a new issue