]> git.lizzy.rs Git - rust.git/blob - src/tools/tidy/src/errors.rs
Auto merge of #102700 - oli-obk:0xDEAD_TAIT, r=compiler-errors
[rust.git] / src / tools / tidy / src / errors.rs
1 //! Tidy check to verify the validity of long error diagnostic codes.
2 //!
3 //! This ensures that error codes are used at most once and also prints out some
4 //! statistics about the error codes.
5
6 use crate::walk::{filter_dirs, walk};
7 use std::collections::HashMap;
8 use std::path::Path;
9
10 pub fn check(path: &Path, bad: &mut bool) {
11     let mut map: HashMap<_, Vec<_>> = HashMap::new();
12     walk(
13         path,
14         &mut |path| filter_dirs(path) || path.ends_with("src/test"),
15         &mut |entry, contents| {
16             let file = entry.path();
17             let filename = file.file_name().unwrap().to_string_lossy();
18             if filename != "error_codes.rs" {
19                 return;
20             }
21
22             // In the `register_long_diagnostics!` macro, entries look like this:
23             //
24             // ```
25             // EXXXX: r##"
26             // <Long diagnostic message>
27             // "##,
28             // ```
29             //
30             // and these long messages often have error codes themselves inside
31             // them, but we don't want to report duplicates in these cases. This
32             // variable keeps track of whether we're currently inside one of these
33             // long diagnostic messages.
34             let mut inside_long_diag = false;
35             for (num, line) in contents.lines().enumerate() {
36                 if inside_long_diag {
37                     inside_long_diag = !line.contains("\"##");
38                     continue;
39                 }
40
41                 let mut search = line;
42                 while let Some(i) = search.find('E') {
43                     search = &search[i + 1..];
44                     let code = if search.len() > 4 { search[..4].parse::<u32>() } else { continue };
45                     let code = match code {
46                         Ok(n) => n,
47                         Err(..) => continue,
48                     };
49                     map.entry(code).or_default().push((file.to_owned(), num + 1, line.to_owned()));
50                     break;
51                 }
52
53                 inside_long_diag = line.contains("r##\"");
54             }
55         },
56     );
57
58     let mut max = 0;
59     for (&code, entries) in map.iter() {
60         if code > max {
61             max = code;
62         }
63         if entries.len() == 1 {
64             continue;
65         }
66
67         tidy_error!(bad, "duplicate error code: {}", code);
68         for &(ref file, line_num, ref line) in entries.iter() {
69             tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line);
70         }
71     }
72
73     if !*bad {
74         println!("* {} error codes", map.len());
75         println!("* highest error code: E{:04}", max);
76     }
77 }