Skip to main content

tidy/
codegen.rs

1//! Tidy check for codegen backend TODO policy.
2
3use std::ffi::OsStr;
4use std::path::Path;
5
6use crate::diagnostics::{CheckId, TidyCtx};
7use crate::walk::walk;
8
9fn is_codegen_repo_path(path: &Path) -> bool {
10    const CODEGEN_REPO_PATHS: &[&str] =
11        &["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"];
12
13    CODEGEN_REPO_PATHS.iter().any(|repo| path.ancestors().any(|p| p.ends_with(Path::new(repo))))
14}
15
16fn has_supported_extension(path: &Path) -> bool {
17    const EXTENSIONS: &[&str] =
18        &["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"];
19    path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e)))
20}
21
22pub fn check(path: &Path, tidy_ctx: TidyCtx) {
23    let mut check = tidy_ctx.start_check(CheckId::new("codegen").path(path));
24
25    fn skip(path: &Path, is_dir: bool) -> bool {
26        if path.file_name().is_some_and(|name| name.to_string_lossy().starts_with(".#")) {
27            // Editor temp file.
28            return true;
29        }
30
31        if is_dir {
32            return false;
33        }
34
35        // Scan only selected text file types.
36        !has_supported_extension(path)
37    }
38
39    walk(path, skip, &mut |entry, contents| {
40        let file = entry.path();
41
42        if !is_codegen_repo_path(file) {
43            return;
44        }
45
46        for (i, line) in contents.split('\n').enumerate() {
47            let trimmed = line.trim();
48
49            // TODO policy for codegen-only trees.
50            if trimmed.contains("TODO") {
51                check.error(format!(
52                    "{}:{}: TODO is used for tasks that should be done before merging a PR; \
53                     if you want to leave a message in the codebase use FIXME",
54                    file.display(),
55                    i + 1
56                ));
57            }
58        }
59    });
60}