xtask\tasks\fmt\house_rules/
repr_packed.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::io::Write;
9use std::path::Path;
10
11pub fn check_repr_packed(path: &Path, fix: bool) -> anyhow::Result<()> {
12    let ext = path
13        .extension()
14        .and_then(|e| e.to_str())
15        .unwrap_or_default();
16
17    if !matches!(ext, "rs") {
18        return Ok(());
19    }
20
21    let mut needs_fixing = false;
22    let f = BufReader::new(File::open(path)?);
23    for (i, line) in f.lines().enumerate() {
24        let line = line?;
25        if line.trim() == "#[repr(packed)]" {
26            needs_fixing = true;
27
28            let msg = format!("#[repr(packed)]: {}:{}", path.display(), i + 1);
29            if fix {
30                log::info!("fixing {}", msg);
31            } else {
32                log::error!("found {}", msg);
33            }
34        }
35    }
36
37    if fix && needs_fixing {
38        let path_fix = &{
39            let mut p = path.to_path_buf();
40            let ok = p.set_extension(format!("{}.fix", ext));
41            assert!(ok);
42            p
43        };
44
45        let f = BufReader::new(File::open(path)?);
46        let mut f_fixed = File::create(path_fix)?;
47
48        for line in f.lines() {
49            let line = line?;
50            if line.trim() == "#[repr(packed)]" {
51                let whitespace = line.split('#').next().unwrap();
52                writeln!(f_fixed, "{whitespace}#[repr(C, packed)]")?;
53            } else {
54                writeln!(f_fixed, "{}", line)?;
55            }
56        }
57
58        // swap the file with the newly fixed file
59        fs_err::rename(path_fix, path)?;
60    }
61
62    if needs_fixing && !fix {
63        Err(anyhow!(
64            "found uses of #[repr(packed)] in {}",
65            path.display()
66        ))
67    } else {
68        Ok(())
69    }
70}