#[allow(unused_imports)]
use std::{collections::HashSet, fs, path::Path};
const OUT_OF_SCOPE_FILES: &[&str] = &[
"src/lib.rs",
"src/server.rs",
"src/timer.rs",
"src/backends.rs",
"src/pool.rs",
"src/splice.rs",
"src/features.rs",
"src/metrics/mod.rs",
"src/metrics/local_drain.rs",
"src/metrics/network_drain.rs",
];
const CONTEXT_MACROS: &[&str] = &[
"log_context!",
"log_context_lite!",
"log_context_stream!",
"log_module_context!",
"log_socket_context!",
"log_socket_module_prefix",
];
const CONTEXT_METHOD_NEEDLE: &str = ".log_context(";
const LOOKAHEAD_LINES: usize = 12;
const LOOKBEHIND_LINES: usize = 24;
#[allow(dead_code)]
fn is_log_call_open(trimmed: &str) -> bool {
const LEVELS: &[&str] = &["error!", "warn!", "info!", "debug!", "trace!"];
LEVELS.iter().any(|prefix| {
trimmed.starts_with(prefix)
&& trimmed
.as_bytes()
.get(prefix.len())
.map(|b| *b == b'(')
.unwrap_or(false)
})
}
#[allow(dead_code)]
fn walk_dir(dir: &Path, visit: &mut dyn FnMut(&Path)) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
walk_dir(&path, visit);
} else {
visit(&path);
}
}
}
#[allow(dead_code)]
fn scan_violations(manifest_dir: &str, on_violation: &mut dyn FnMut(&str, usize, &str)) {
let src_root = Path::new(manifest_dir).join("src");
let allowlist: HashSet<&str> = OUT_OF_SCOPE_FILES.iter().copied().collect();
walk_dir(&src_root, &mut |path| {
if path.extension().map(|e| e != "rs").unwrap_or(true) {
return;
}
let rel = path
.strip_prefix(manifest_dir)
.unwrap_or(path)
.to_string_lossy()
.replace('\\', "/");
if allowlist.contains(rel.as_str()) {
return;
}
let Ok(contents) = fs::read_to_string(path) else {
return;
};
let lines: Vec<&str> = contents.lines().collect();
let mut in_test_cfg_depth: i32 = 0;
for (idx, raw_line) in lines.iter().enumerate() {
let trimmed = raw_line.trim_start();
if trimmed.starts_with("#[cfg(test)]") || trimmed.starts_with("#[cfg(any(test") {
for next in lines.iter().skip(idx + 1).take(4) {
let next_trim = next.trim();
if next_trim.starts_with("mod ") && next_trim.ends_with('{') {
in_test_cfg_depth += 1;
break;
}
if !next_trim.is_empty() && !next_trim.starts_with("//") {
break;
}
}
continue;
}
if in_test_cfg_depth > 0 && raw_line.starts_with('}') {
in_test_cfg_depth -= 1;
continue;
}
if in_test_cfg_depth > 0 {
continue;
}
if !is_log_call_open(trimmed) {
continue;
}
let start = idx.saturating_sub(LOOKBEHIND_LINES);
let end = (idx + 1 + LOOKAHEAD_LINES).min(lines.len());
let window = &lines[start..end];
let has_context = window.iter().any(|l| {
CONTEXT_MACROS.iter().any(|m| l.contains(m)) || l.contains(CONTEXT_METHOD_NEEDLE)
});
if !has_context {
on_violation(&rel, idx + 1, trimmed);
}
}
});
}