tests/no_second_parser.rs
//! **THE GUARD**: Mímir v2 has ONE parser (the rustc driver) and ONE graph engine
//! (GraphBLAS). The old roads must not come back.
//!
//! PLAN-MIMIR-V2 §7.4, same shape as `no_dwarves_edge` / the errcode-registry
//! guards. The removal commits on `mimir-v2` deleted three parse roads (`syn`, the
//! `rust-analyzer scip` subprocess, the in-process `ra_ap_*` load), one in-process
//! graph engine (`petgraph`), and the jera lens/feed chains. This test is RED the
//! moment any of them is typed back in:
//!
//! 1. no Cargo manifest of nornir's workspace (the root crate AND every member)
//! declares `syn`, `petgraph` or any `ra_ap_*` crate — in any dependency table;
//! 2. no `.rs` under `src/` (root or member crates) uses a `syn::` path;
//! 3. nothing spawns `rust-analyzer` (`Command::new("rust-analyzer")`) or asks it
//! for an index (`.arg("scip")`);
//! 4. the `lens_chain` / `feed_chain` modules do not exist;
//! 5. no other Rust token/parse crate comes in: `quote`, `rowan`, `tree-sitter*`,
//! `rustc-ap-*` and `rustc_lexer` are forbidden, and `proc-macro2` is the ONE
//! allowed token crate, in exactly TWO files, each with its reason — see
//! [`TOKEN_CRATE`] and [`TOKEN_CRATE_USERS`];
//! 6. the LLVM-IR call-edge producer (`nornir-introspect::callgraph_llvm`, a third
//! call-edge road next to the driver and the binary layer) does not exist;
//! 7. no crate escapes 1–3 by sitting outside the workspace: every crate
//! directory on disk is a `[workspace].members` entry, except the ONE excluded
//! crate — and the six stable Mímir v2 crates (`mimir-schema`, `mimir-ingest`,
//! `mimir-binary`, `graphblas-sys`, `mimir-graph`, `mimir-room`) are members
//! BY NAME. For member crates the source scan reads every `.rs` they own
//! (`src/`, `tests/`, `examples/`, `benches/`, `build.rs`), not `src/` alone;
//! 8. **`crates/mimir-driver` is the ONE user of compiler internals**
//! (`#![feature(rustc_private)]`, `extern crate rustc_*`). It IS the one
//! parser of rule 1's "ONE parser": a rustc driver on a pinned, dated nightly.
//! It is `[workspace].exclude`d (the stable workspace must never build it),
//! carries its own `[workspace]` table and `rust-toolchain.toml`, and is read
//! by this guard all the same — its manifest and sources obey rules 1–3 and 5.
//! Nothing else in the repo may name `rustc_private`, and no member pins a
//! toolchain of its own. See [`COMPILER_INTERNALS_USER`].
//!
//! A TEXT scan, deliberately — fast, no `cargo metadata`, no network, and it
//! catches the offender the instant it is typed.
use std::path::{Path, PathBuf};
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
/// Every manifest of the workspace: the root plus each `[workspace].members` entry.
fn workspace_manifests() -> Vec<PathBuf> {
let root = repo_root();
let text = std::fs::read_to_string(root.join("Cargo.toml")).expect("read Cargo.toml");
let doc: toml::Table = text.parse().expect("Cargo.toml parses");
let members = doc
.get("workspace")
.and_then(|w| w.get("members"))
.and_then(|m| m.as_array())
.expect("[workspace].members");
let mut out = vec![root.join("Cargo.toml")];
for m in members {
let m = m.as_str().expect("member is a string");
if m != "." {
out.push(root.join(m).join("Cargo.toml"));
}
}
out
}
/// **The ONE crate allowed compiler internals** — the Mímir v2 producer, a rustc
/// driver (the clippy-driver shape). It links `rustc_private`, so it builds only
/// on the dated nightly its own `rust-toolchain.toml` pins, and it is therefore
/// the ONE entry of `[workspace].exclude`. Everything else in this repo is
/// stable Rust and reaches the compiler's view of the code ONLY through the
/// Arrow rows this crate dumps (`mimir-schema` is the contract between them).
const COMPILER_INTERNALS_USER: &str = "crates/mimir-driver";
/// The stable Mímir v2 crates. Named here so the guard covers them BY NAME:
/// dropping one from `[workspace].members` (which is what the manifest and
/// source scans iterate) is red, not a silent hole in the scan.
const MIMIR_V2_MEMBERS: &[&str] = &[
"crates/mimir-schema",
"crates/mimir-ingest",
"crates/mimir-binary",
"crates/graphblas-sys",
"crates/mimir-graph",
"crates/mimir-room",
];
/// `[workspace].<key>` of the root manifest as a list of strings (`members` /
/// `exclude`); a missing key is an empty list.
fn workspace_list(key: &str) -> Vec<String> {
let text = std::fs::read_to_string(repo_root().join("Cargo.toml")).expect("read Cargo.toml");
let doc: toml::Table = text.parse().expect("Cargo.toml parses");
doc.get("workspace")
.and_then(|w| w.get(key))
.and_then(|m| m.as_array())
.map(|a| a.iter().filter_map(|v| v.as_str()).map(str::to_string).collect())
.unwrap_or_default()
}
/// Every crate directory on disk the workspace could own, repo-relative: each
/// `crates/<dir>` with a `Cargo.toml`, plus the top-level crate dirs.
fn crate_dirs_on_disk() -> Vec<String> {
let root = repo_root();
let mut out = Vec::new();
if let Ok(rd) = std::fs::read_dir(root.join("crates")) {
for e in rd.flatten() {
if e.path().join("Cargo.toml").is_file() {
out.push(format!("crates/{}", e.file_name().to_string_lossy()));
}
}
}
if let Ok(rd) = std::fs::read_dir(&root) {
for e in rd.flatten() {
let name = e.file_name().to_string_lossy().to_string();
if name != "target" && !name.starts_with('.') && e.path().join("Cargo.toml").is_file() {
out.push(name);
}
}
}
out.sort();
out
}
/// The lines of one source text that reach into the compiler: the
/// `rustc_private` feature gate (without it no `rustc_*` crate links) or an
/// `extern crate rustc_<internal>`. `rustc_demangle` / `rustc_hash` are ordinary
/// crates.io crates, not compiler internals.
fn compiler_internals_lines(text: &str) -> Vec<(usize, String)> {
let mut out = Vec::new();
for (i, line) in text.lines().enumerate() {
let squashed: String = code_of(line).split_whitespace().collect();
let extern_internal = squashed.strip_prefix("externcraterustc_").is_some_and(|rest| {
!(rest.starts_with("demangle") || rest.starts_with("hash"))
});
if squashed.contains("rustc_private") || extern_internal {
out.push((i + 1, line.trim().to_string()));
}
}
out
}
/// The ONE token crate Mímir v2 keeps. `proc-macro2` (with `span-locations`) is a
/// LEXER — it never builds a syntax tree, so it is not a second parser next to
/// the rustc driver. It may be DECLARED in the `[dependencies]` of exactly the
/// manifests in [`TOKEN_CRATE_MANIFESTS`] and NAMED (`proc_macro2`) in exactly
/// the files in [`TOKEN_CRATE_USERS`], so nothing else sneaks in under it (no
/// other crate, no other module, no `quote`).
const TOKEN_CRATE: &str = "proc-macro2";
/// The files allowed to name the token crate, each with WHY a token stream —
/// and not the rustc driver's rows — is the only thing that can answer it:
///
/// 1. `src/mimir_subclone.rs` — the subclone lens (`walk_tokens`) hashes
/// windows of Rust TOKENS with line numbers. Token shape is the question
/// itself; the driver's graph has no tokens.
/// 2. `crates/mimir-driver/src/cfg_scan.rs` — the inactive side of GATED_BY.
/// An item whose `#[cfg(…)]` is false in the build is stripped before rustc
/// builds HIR: the driver has no DefId for it, so "which items does feature
/// X gate when X is OFF" cannot be read from the compiler at all. The scan
/// lexes the crate's source files and reports item keyword + name + line +
/// predicate for `#[cfg]` attributes ONLY; whether an item is active is
/// still decided by rustc (its `CfgTrace` positions), and what comes out is
/// a `cfg_gated_out` STUB row, never a resolved item. A lexer is enough for
/// that, and a second parser would be a second truth about items rustc DID
/// keep — which is exactly what this guard forbids.
const TOKEN_CRATE_USERS: &[&str] = &["src/mimir_subclone.rs", "crates/mimir-driver/src/cfg_scan.rs"];
/// The manifests allowed to declare the token crate (their `[dependencies]`
/// only): one per entry of [`TOKEN_CRATE_USERS`], the manifest that file is
/// compiled by.
const TOKEN_CRATE_MANIFESTS: &[&str] = &["Cargo.toml", "crates/mimir-driver/Cargo.toml"];
/// `true` when `manifest` (an absolute path) may declare [`TOKEN_CRATE`].
fn may_declare_token_crate(manifest: &Path) -> bool {
TOKEN_CRATE_MANIFESTS.iter().any(|m| repo_root().join(m) == manifest)
}
/// `true` when `file` (an absolute path) may name `proc_macro2`.
fn may_use_token_crate(file: &Path) -> bool {
TOKEN_CRATE_USERS.iter().any(|f| repo_root().join(f) == file)
}
/// `true` for a crate name the guard forbids outright (a parser, a second token
/// crate, or a graph engine).
fn forbidden_dep(name: &str) -> bool {
let n = name.replace('_', "-");
n == "syn"
|| n == "petgraph"
|| n == "quote"
|| n == "rowan"
|| n == "rustc-lexer"
|| n.starts_with("ra-ap-")
|| n.starts_with("rustc-ap-")
|| n.starts_with("tree-sitter")
}
/// Every dependency NAME declared in `table` (a `[dependencies]`-shaped table),
/// honouring `package = "…"` renames so an alias cannot hide the real crate.
fn dep_names(table: &toml::Table) -> Vec<String> {
table
.iter()
.map(|(key, val)| {
val.get("package")
.and_then(|p| p.as_str())
.map(str::to_string)
.unwrap_or_else(|| key.clone())
})
.collect()
}
/// The offending `(table, crate)` pairs of one manifest's text. `token_crate_ok`
/// = the manifest is one of [`TOKEN_CRATE_MANIFESTS`] — the only ones allowed to
/// declare [`TOKEN_CRATE`], and only in `[dependencies]`.
fn manifest_offenders(text: &str, token_crate_ok: bool) -> Vec<(String, String)> {
let doc: toml::Table = text.parse().expect("manifest parses");
let mut tables: Vec<(String, &toml::Table)> = Vec::new();
for key in ["dependencies", "dev-dependencies", "build-dependencies"] {
if let Some(t) = doc.get(key).and_then(|t| t.as_table()) {
tables.push((key.to_string(), t));
}
}
if let Some(ws) = doc.get("workspace").and_then(|w| w.get("dependencies")).and_then(|t| t.as_table()) {
tables.push(("workspace.dependencies".to_string(), ws));
}
if let Some(targets) = doc.get("target").and_then(|t| t.as_table()) {
for (cfg, tt) in targets {
for key in ["dependencies", "dev-dependencies", "build-dependencies"] {
if let Some(t) = tt.get(key).and_then(|t| t.as_table()) {
tables.push((format!("target.{cfg}.{key}"), t));
}
}
}
}
let mut out = Vec::new();
for (where_, t) in tables {
for name in dep_names(t) {
let stray_token_crate =
name.replace('_', "-") == TOKEN_CRATE && !(token_crate_ok && where_ == "dependencies");
if forbidden_dep(&name) || stray_token_crate {
out.push((where_.clone(), name));
}
}
}
out
}
/// Every `.rs` file under `dir` (recursively).
fn rust_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(rd) = std::fs::read_dir(dir) else { return };
for e in rd.flatten() {
let p = e.path();
if p.is_dir() {
if p.file_name().is_some_and(|n| n == "target") {
continue;
}
rust_files(&p, out);
} else if p.extension().is_some_and(|x| x == "rs") {
out.push(p);
}
}
}
/// The source trees the guard reads: the root crate's `src/`, and for every
/// MEMBER crate each `.rs` it owns — `src/`, `tests/`, `examples/`, `benches/`
/// and `build.rs` (a parser typed into a member's test or build script is the
/// same road). The root crate's own `tests/` are not read: this file spells the
/// forbidden paths as detector fixtures.
fn source_files() -> Vec<PathBuf> {
let mut out = Vec::new();
let root_manifest = repo_root().join("Cargo.toml");
for manifest in workspace_manifests() {
let dir = manifest.parent().unwrap();
rust_files(&dir.join("src"), &mut out);
if manifest != root_manifest {
for sub in ["tests", "examples", "benches"] {
rust_files(&dir.join(sub), &mut out);
}
let build = dir.join("build.rs");
if build.is_file() {
out.push(build);
}
}
}
out
}
/// The code part of a line (a `//` comment, doc comments included, is dropped).
fn code_of(line: &str) -> &str {
match line.find("//") {
Some(i) => &line[..i],
None => line,
}
}
/// The offending `(file:line, text)` pairs of one source file's text.
/// `token_user` = the file is one of [`TOKEN_CRATE_USERS`] — the only files
/// allowed `proc_macro2`.
fn source_offenders(text: &str, token_user: bool) -> Vec<(usize, String)> {
let mut out = Vec::new();
for (i, line) in text.lines().enumerate() {
let code = code_of(line);
let squashed: String = code.split_whitespace().collect();
if code.contains("syn::")
|| squashed.starts_with("usesyn;")
|| squashed.starts_with("usesyn::")
|| squashed.contains("Command::new(\"rust-analyzer\")")
|| squashed.contains(".arg(\"scip\")")
|| squashed.contains("callgraph_llvm")
|| squashed.contains("quote::")
|| squashed.starts_with("usequote")
|| (!token_user && squashed.contains("proc_macro2"))
{
out.push((i + 1, line.trim().to_string()));
}
}
out
}
#[test]
fn no_manifest_in_the_workspace_declares_a_second_parser_or_graph_engine() {
let mut bad = Vec::new();
for m in workspace_manifests() {
let text = std::fs::read_to_string(&m).unwrap_or_else(|e| panic!("read {}: {e}", m.display()));
for (table, name) in manifest_offenders(&text, may_declare_token_crate(&m)) {
bad.push(format!("{} [{table}] {name}", m.display()));
}
}
assert!(
bad.is_empty(),
"Mímir v2 has ONE parser (the rustc driver) and ONE graph engine (GraphBLAS); \
these manifests declare an old road back in:\n {}",
bad.join("\n ")
);
}
#[test]
fn no_source_uses_syn_or_spawns_rust_analyzer() {
let mut bad = Vec::new();
for f in source_files() {
let text = std::fs::read_to_string(&f).unwrap_or_default();
for (line, code) in source_offenders(&text, may_use_token_crate(&f)) {
bad.push(format!("{}:{line}: {code}", f.display()));
}
}
assert!(
bad.is_empty(),
"a removed parse road is back in the source:\n {}",
bad.join("\n ")
);
}
#[test]
fn the_lens_and_feed_chains_do_not_exist() {
let root = repo_root();
for gone in ["src/lens_chain.rs", "src/feed_chain.rs", "src/warehouse/lens_cache.rs", "src/warehouse/feed_cache.rs"] {
assert!(!root.join(gone).exists(), "{gone} is back — the jera chain/cache was removed with Mímir v2");
}
let lib = std::fs::read_to_string(root.join("src/lib.rs")).expect("read src/lib.rs");
for line in lib.lines() {
let squashed: String = code_of(line).split_whitespace().collect();
assert!(
!(squashed.contains("modlens_chain") || squashed.contains("modfeed_chain")),
"src/lib.rs declares a removed chain module again: {line}"
);
}
}
#[test]
fn the_llvm_call_edge_road_does_not_exist() {
let root = repo_root();
let gone = "crates/nornir-introspect/src/callgraph_llvm.rs";
assert!(
!root.join(gone).exists(),
"{gone} is back — a third call-edge road; the rustc driver and the binary layer replace it"
);
let lib = std::fs::read_to_string(root.join("crates/nornir-introspect/src/lib.rs"))
.expect("read nornir-introspect lib.rs");
for line in lib.lines() {
let squashed: String = code_of(line).split_whitespace().collect();
assert!(!squashed.contains("modcallgraph_llvm"), "nornir-introspect declares callgraph_llvm again: {line}");
}
}
/// Rule 7: nothing sits outside the scan. A crate dir on disk that is neither a
/// member nor THE excluded driver would be compiled by nobody's `cargo check
/// --workspace` and read by none of the scans above.
#[test]
fn every_crate_on_disk_is_a_member_or_the_one_excluded_driver() {
let members = workspace_list("members");
let exclude = workspace_list("exclude");
assert_eq!(
exclude,
vec![COMPILER_INTERNALS_USER.to_string()],
"[workspace].exclude must hold exactly the rustc driver — an excluded crate is outside \
`cargo check --workspace`, so every entry is a decision this guard has to know"
);
assert!(
!members.iter().any(|m| m == COMPILER_INTERNALS_USER),
"{COMPILER_INTERNALS_USER} is a workspace member: the stable workspace would try to build a rustc_private crate"
);
let stray: Vec<String> = crate_dirs_on_disk()
.into_iter()
.filter(|d| !members.contains(d) && d != COMPILER_INTERNALS_USER)
.collect();
assert!(
stray.is_empty(),
"crate dirs on disk that are neither workspace members nor the excluded driver (the guard does not read them):\n {}",
stray.join("\n ")
);
for m in MIMIR_V2_MEMBERS {
assert!(members.iter().any(|x| x == m), "{m} left [workspace].members — the Mímir v2 crates must stay under the guard");
assert!(
workspace_manifests().contains(&repo_root().join(m).join("Cargo.toml")),
"{m} is not among the manifests the guard scans"
);
}
}
/// Rule 8: the rustc driver is the ONE user of compiler internals, on its own
/// pinned nightly, and still a citizen of rules 1–3 and 5.
#[test]
fn mimir_driver_is_the_one_user_of_compiler_internals() {
let root = repo_root();
let driver = root.join(COMPILER_INTERNALS_USER);
// The exemption is real: the driver does link rustc_private. (When it stops,
// this allow-list entry goes with it.)
let main = std::fs::read_to_string(driver.join("src/main.rs")).expect("read mimir-driver src/main.rs");
assert!(
!compiler_internals_lines(&main).is_empty(),
"{COMPILER_INTERNALS_USER}/src/main.rs no longer names rustc_private — drop the exemption instead of keeping a stale one"
);
// It stands alone: its own [workspace] table and a DATED nightly pin.
let manifest = std::fs::read_to_string(driver.join("Cargo.toml")).expect("read mimir-driver Cargo.toml");
let doc: toml::Table = manifest.parse().expect("mimir-driver manifest parses");
assert!(doc.get("workspace").is_some(), "mimir-driver must carry its own [workspace] table (it is not built by the stable workspace)");
let pin = std::fs::read_to_string(driver.join("rust-toolchain.toml")).expect("mimir-driver pins its toolchain");
let pin: toml::Table = pin.parse().expect("rust-toolchain.toml parses");
let channel = pin.get("toolchain").and_then(|t| t.get("channel")).and_then(|c| c.as_str()).unwrap_or_default();
let date = channel.strip_prefix("nightly-").unwrap_or_default();
assert!(
date.len() == 10 && date.chars().all(|c| c.is_ascii_digit() || c == '-'),
"mimir-driver must pin ONE dated nightly (`nightly-YYYY-MM-DD`), got `{channel}`"
);
// Still under rules 1–3 and 5: no second parser or graph engine rides in
// with the driver, in its manifest or anywhere in its sources.
// The token crate rides in for ONE file (the cfg scan, see TOKEN_CRATE_USERS).
let bad: Vec<String> = manifest_offenders(&manifest, may_declare_token_crate(&driver.join("Cargo.toml")))
.into_iter()
.map(|(t, n)| format!("[{t}] {n}"))
.collect();
assert!(bad.is_empty(), "mimir-driver declares a forbidden crate: {bad:?}");
let mut files = Vec::new();
rust_files(&driver.join("src"), &mut files);
assert!(!files.is_empty(), "no source found under {COMPILER_INTERNALS_USER}/src");
let mut bad = Vec::new();
for f in &files {
let text = std::fs::read_to_string(f).unwrap_or_default();
for (line, code) in source_offenders(&text, may_use_token_crate(f)) {
bad.push(format!("{}:{line}: {code}", f.display()));
}
}
assert!(bad.is_empty(), "a removed parse road is in the rustc driver:\n {}", bad.join("\n "));
// Nobody else: no member source reaches into the compiler, no member
// manifest asks for rustc_private, no member (nor the root) pins a toolchain.
let mut bad = Vec::new();
for f in source_files() {
let text = std::fs::read_to_string(&f).unwrap_or_default();
for (line, code) in compiler_internals_lines(&text) {
bad.push(format!("{}:{line}: {code}", f.display()));
}
}
for m in workspace_manifests() {
let text = std::fs::read_to_string(&m).unwrap_or_default();
for (i, line) in text.lines().enumerate() {
let code = line.split('#').next().unwrap_or_default();
if code.contains("rustc_private") || code.contains("rustc-private") {
bad.push(format!("{}:{}: {}", m.display(), i + 1, line.trim()));
}
}
let dir = m.parent().unwrap();
for pin in ["rust-toolchain.toml", "rust-toolchain"] {
if dir.join(pin).exists() {
bad.push(format!("{}: a workspace member pins its own toolchain", dir.join(pin).display()));
}
}
}
assert!(
bad.is_empty(),
"compiler internals outside {COMPILER_INTERNALS_USER} (the ONE rustc_private user):\n {}",
bad.join("\n ")
);
}
/// The detectors themselves, on known text — so a guard that silently matches
/// nothing cannot pass for a clean tree.
#[test]
fn the_detectors_see_what_they_are_for() {
assert_eq!(
manifest_offenders("[dependencies]\nsyn = \"2\"\n[dev-dependencies]\npetgraph = \"0.8\"\n[target.'cfg(unix)'.dependencies]\nra_ap_ide = \"0\"\nalias = { package = \"syn\", version = \"2\" }\n", true).len(),
4
);
assert!(manifest_offenders("[dependencies]\nsynstructure = \"0.13\"\nscip = \"0.10\"\n", true).is_empty());
// A second token crate is red anywhere; proc-macro2 only in the root's [dependencies].
assert_eq!(
manifest_offenders("[dependencies]\nquote = \"1\"\ntree-sitter-rust = \"0.23\"\nrowan = \"0.16\"\nrustc_lexer = \"0\"\n", true).len(),
4
);
assert!(manifest_offenders("[dependencies]\nproc-macro2 = \"1\"\n", true).is_empty());
assert_eq!(manifest_offenders("[dependencies]\nproc-macro2 = \"1\"\n", false).len(), 1);
assert_eq!(manifest_offenders("[dev-dependencies]\nproc-macro2 = \"1\"\n", true).len(), 1);
assert_eq!(source_offenders("let f = syn::parse_file(s);\n", false).len(), 1);
assert_eq!(source_offenders("use syn::visit::Visit;\n", false).len(), 1);
assert_eq!(source_offenders("Command::new( \"rust-analyzer\" ).arg(\"scip\")\n", false).len(), 1);
assert!(source_offenders("// syn::parse_file was removed\nlet x = 1;\n", false).is_empty());
assert_eq!(source_offenders("let e = introspect::callgraph_llvm::extract_from_dir(p);\n", false).len(), 1);
assert_eq!(source_offenders("let t = quote::quote!(x);\n", false).len(), 1);
assert_eq!(source_offenders("use proc_macro2::TokenStream;\n", false).len(), 1);
assert!(source_offenders("use proc_macro2::TokenStream;\n", true).is_empty());
// The allow-list is two files and the two manifests that compile them —
// nothing next to them, in either crate.
let root = repo_root();
assert!(may_use_token_crate(&root.join("src/mimir_subclone.rs")));
assert!(may_use_token_crate(&root.join("crates/mimir-driver/src/cfg_scan.rs")));
assert!(!may_use_token_crate(&root.join("crates/mimir-driver/src/walk.rs")));
assert!(!may_use_token_crate(&root.join("crates/mimir-driver/src/walk/gates.rs")));
assert!(!may_use_token_crate(&root.join("crates/mimir-ingest/src/cfg_scan.rs")));
assert!(may_declare_token_crate(&root.join("Cargo.toml")));
assert!(may_declare_token_crate(&root.join("crates/mimir-driver/Cargo.toml")));
assert!(!may_declare_token_crate(&root.join("crates/mimir-ingest/Cargo.toml")));
assert_eq!(TOKEN_CRATE_USERS.len(), TOKEN_CRATE_MANIFESTS.len());
for f in TOKEN_CRATE_USERS {
assert!(root.join(f).is_file(), "{f} is allow-listed for the token crate but does not exist — drop the entry");
}
// Compiler internals: the feature gate and an internal extern crate are seen;
// a comment and the crates.io `rustc_demangle` are not.
assert_eq!(compiler_internals_lines("#![feature(rustc_private)]\nextern crate rustc_middle;\n").len(), 2);
assert_eq!(compiler_internals_lines("#! [ feature ( rustc_private ) ]\n").len(), 1);
assert!(compiler_internals_lines("// #![feature(rustc_private)]\nextern crate rustc_demangle;\nuse rustc_demangle::demangle;\n").is_empty());
}