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