xtask\tasks\fmt\house_rules/
unsafe_code_comment.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use anyhow::anyhow;
5use fs_err::File;
6use std::io::BufRead;
7use std::io::BufReader;
8use std::path::Path;
9
10pub fn check_unsafe_code_comment(path: &Path, _fix: bool) -> anyhow::Result<()> {
11    let ext = path
12        .extension()
13        .and_then(|e| e.to_str())
14        .unwrap_or_default();
15
16    if !matches!(ext, "rs") {
17        return Ok(());
18    }
19
20    // need to exclude self (and house_rules.rs, which includes help-text) from the lint
21    if path == Path::new(file!()) || path == Path::new(super::PATH_TO_HOUSE_RULES_RS) {
22        return Ok(());
23    }
24
25    let mut error = false;
26
27    // TODO: this lint really ought to be a dynlint / clippy lint
28    let f = BufReader::new(File::open(path)?);
29    let mut in_comment = false;
30
31    for (i, line) in f.lines().enumerate() {
32        let line = line?;
33        let line = line.trim();
34        if line.starts_with("// UNSAFETY: ") {
35            in_comment = true;
36            continue;
37        }
38
39        if (line.contains("expect(unsafe_code)") || line.contains("allow(unsafe_code)"))
40            && !in_comment
41        {
42            error = true;
43            log::error!(
44                "unjustified `expect(unsafe_code)`: {}:{}",
45                path.display(),
46                i + 1
47            );
48        }
49
50        if !line.starts_with("//") || (line.len() > 2 && line.as_bytes()[2] != b' ') {
51            in_comment = false;
52        }
53    }
54
55    if error {
56        Err(anyhow!(
57            "found unjustified uses of `expect(unsafe_code)` in {}",
58            path.display()
59        ))
60    } else {
61        Ok(())
62    }
63}