Skip to content

Commit d82e51b

Browse files
committed
Test that all interned symbols are referenced in Clippy sources
1 parent c12bc22 commit d82e51b

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

clippy_utils/src/sym.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ generate! {
132132
enum_glob_use,
133133
enumerate,
134134
err,
135-
error,
136135
exp,
137136
expect_err,
138137
expn_data,

tests/symbols-used.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// This test checks that all symbols defined in Clippy's `sym.rs` file
2+
// are used in Clippy. Otherwise, it will fail with a list of symbols
3+
// which are unused.
4+
//
5+
// This test is a no-op if run as part of the compiler test suite
6+
// and will always succeed.
7+
8+
use std::collections::HashSet;
9+
use std::ffi::OsStr;
10+
use std::fs;
11+
12+
use regex::Regex;
13+
use walkdir::{DirEntry, WalkDir};
14+
15+
const SYM_FILE: &str = "clippy_utils/src/sym.rs";
16+
17+
type Result<T, E = AnyError> = std::result::Result<T, E>;
18+
type AnyError = Box<dyn std::error::Error>;
19+
20+
#[test]
21+
#[allow(clippy::case_sensitive_file_extension_comparisons)]
22+
fn all_symbols_are_used() -> Result<()> {
23+
if option_env!("RUSTC_TEST_SUITE").is_some() {
24+
return Ok(());
25+
}
26+
27+
// Load all symbols defined in `SYM_FILE`.
28+
let content = fs::read_to_string(SYM_FILE)?;
29+
let content = content
30+
.split_once("generate! {")
31+
.ok_or("cannot find symbols start")?
32+
.1
33+
.split_once("\n}\n")
34+
.ok_or("cannot find symbols end")?
35+
.0;
36+
let mut interned: HashSet<String> = Regex::new(r"(?m)^ (\w+)")
37+
.unwrap()
38+
.captures_iter(content)
39+
.map(|m| m[1].to_owned())
40+
.collect();
41+
42+
// Remove symbols used as `sym::*`.
43+
let used_re = Regex::new(r"\bsym::(\w+)\b").unwrap();
44+
let rs_ext = OsStr::new("rs");
45+
for dir in ["clippy_lints", "clippy_lints_internal", "clippy_utils", "src"] {
46+
for file in WalkDir::new(dir)
47+
.into_iter()
48+
.flatten()
49+
.map(DirEntry::into_path)
50+
.filter(|p| p.extension() == Some(rs_ext))
51+
{
52+
for cap in used_re.captures_iter(&fs::read_to_string(file)?) {
53+
interned.remove(&cap[1]);
54+
}
55+
}
56+
}
57+
58+
// Remove symbols used as part of paths.
59+
let paths_re = Regex::new(r"path!\(([\w:]+)\)").unwrap();
60+
for path in [
61+
"clippy_utils/src/paths.rs",
62+
"clippy_lints_internal/src/internal_paths.rs",
63+
] {
64+
for cap in paths_re.captures_iter(&fs::read_to_string(path)?) {
65+
for sym in cap[1].split("::") {
66+
interned.remove(sym);
67+
}
68+
}
69+
}
70+
71+
let mut extra = interned.iter().collect::<Vec<_>>();
72+
if !extra.is_empty() {
73+
extra.sort_unstable();
74+
eprintln!("Unused symbols defined in {SYM_FILE}:");
75+
for sym in extra {
76+
eprintln!(" - {sym}");
77+
}
78+
Err(format!("extra symbols found — remove them {SYM_FILE}"))?;
79+
}
80+
Ok(())
81+
}

0 commit comments

Comments
 (0)