]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use std::ffi::OsStr; |
2 | use std::path::PathBuf; | |
3 | ||
4 | use regex::RegexSet; | |
5 | ||
6 | #[derive(Debug)] | |
7 | struct Message { | |
8 | path: PathBuf, | |
9 | bad_lines: Vec<String>, | |
10 | } | |
11 | ||
12 | impl Message { | |
13 | fn new(path: PathBuf) -> Self { | |
14 | let content: String = std::fs::read_to_string(&path).unwrap(); | |
15 | // we don't want the first letter after "error: ", "help: " ... to be capitalized | |
16 | // also no puncutation (except for "?" ?) at the end of a line | |
17 | let regex_set: RegexSet = RegexSet::new(&[ | |
18 | r"error: [A-Z]", | |
19 | r"help: [A-Z]", | |
20 | r"warning: [A-Z]", | |
21 | r"note: [A-Z]", | |
22 | r"try this: [A-Z]", | |
23 | r"error: .*[.!]$", | |
24 | r"help: .*[.!]$", | |
25 | r"warning: .*[.!]$", | |
26 | r"note: .*[.!]$", | |
27 | r"try this: .*[.!]$", | |
28 | ]) | |
29 | .unwrap(); | |
30 | ||
31 | // sometimes the first character is capitalized and it is legal (like in "C-like enum variants") or | |
32 | // we want to ask a question ending in "?" | |
33 | let exceptions_set: RegexSet = RegexSet::new(&[ | |
34 | r".*C-like enum variant discriminant is not portable to 32-bit targets", | |
35 | r".*did you mean `unix`?", | |
36 | r".*the arguments may be inverted...", | |
37 | r".*Intel x86 assembly syntax used", | |
38 | r".*AT&T x86 assembly syntax used", | |
39 | r".*remove .*the return type...", | |
40 | r"note: Clippy version: .*", | |
41 | r"the compiler unexpectedly panicked. this is a bug.", | |
42 | ]) | |
43 | .unwrap(); | |
44 | ||
45 | let bad_lines = content | |
46 | .lines() | |
47 | .filter(|line| regex_set.matches(line).matched_any()) | |
48 | // ignore exceptions | |
49 | .filter(|line| !exceptions_set.matches(line).matched_any()) | |
50 | .map(ToOwned::to_owned) | |
51 | .collect::<Vec<String>>(); | |
52 | ||
53 | Message { path, bad_lines } | |
54 | } | |
55 | } | |
56 | ||
57 | #[test] | |
58 | fn lint_message_convention() { | |
59 | // disable the test inside the rustc test suite | |
60 | if option_env!("RUSTC_TEST_SUITE").is_some() { | |
61 | return; | |
62 | } | |
63 | ||
64 | // make sure that lint messages: | |
65 | // * are not capitalized | |
66 | // * don't have puncuation at the end of the last sentence | |
67 | ||
68 | // these directories have interesting tests | |
69 | let test_dirs = ["ui", "ui-cargo", "ui-internal", "ui-toml"] | |
70 | .iter() | |
71 | .map(PathBuf::from) | |
72 | .map(|p| { | |
73 | let base = PathBuf::from("tests"); | |
74 | base.join(p) | |
75 | }); | |
76 | ||
77 | // gather all .stderr files | |
78 | let tests = test_dirs | |
79 | .flat_map(|dir| { | |
80 | std::fs::read_dir(dir) | |
81 | .expect("failed to read dir") | |
82 | .map(|direntry| direntry.unwrap().path()) | |
83 | }) | |
84 | .filter(|file| matches!(file.extension().map(OsStr::to_str), Some(Some("stderr")))); | |
85 | ||
86 | // get all files that have any "bad lines" in them | |
87 | let bad_tests: Vec<Message> = tests | |
88 | .map(Message::new) | |
89 | .filter(|message| !message.bad_lines.is_empty()) | |
90 | .collect(); | |
91 | ||
cdc7bbd5 | 92 | for message in &bad_tests { |
f20569fa XL |
93 | eprintln!( |
94 | "error: the test '{}' contained the following nonconforming lines :", | |
95 | message.path.display() | |
96 | ); | |
97 | message.bad_lines.iter().for_each(|line| eprintln!("{}", line)); | |
98 | eprintln!("\n\n"); | |
cdc7bbd5 | 99 | } |
f20569fa XL |
100 | |
101 | eprintln!( | |
102 | "\n\n\nLint message should not start with a capital letter and should not have punctuation at the end of the message unless multiple sentences are needed." | |
103 | ); | |
104 | eprintln!("Check out the rustc-dev-guide for more information:"); | |
105 | eprintln!("https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-structure\n\n\n"); | |
106 | ||
107 | assert!(bad_tests.is_empty()); | |
108 | } |