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)") && !in_comment {
40            error = true;
41            log::error!(
42                "unjustified `expect(unsafe_code)`: {}:{}",
43                path.display(),
44                i + 1
45            );
46        }
47
48        if !line.starts_with("//") || (line.len() > 2 && line.as_bytes()[2] != b' ') {
49            in_comment = false;
50        }
51    }
52
53    if error {
54        Err(anyhow!(
55            "found unjustified uses of `expect(unsafe_code)` in {}",
56            path.display()
57        ))
58    } else {
59        Ok(())
60    }
61}