tidy/
target_specific_tests.rs

1//! Tidy check to ensure that all target specific tests (those that require a `--target` flag)
2//! also require the pre-requisite LLVM components to run.
3
4use std::collections::BTreeMap;
5use std::path::Path;
6
7use crate::iter_header::{HeaderLine, iter_header};
8use crate::walk::filter_not_rust;
9
10const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:";
11const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
12
13#[derive(Default, Debug)]
14struct RevisionInfo<'a> {
15    target_arch: Option<&'a str>,
16    llvm_components: Option<Vec<&'a str>>,
17}
18
19pub fn check(tests_path: &Path, bad: &mut bool) {
20    crate::walk::walk(tests_path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
21        let file = entry.path().display();
22        let mut header_map = BTreeMap::new();
23        iter_header(content, &mut |HeaderLine { revision, directive, .. }| {
24            if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) {
25                let info = header_map.entry(revision).or_insert(RevisionInfo::default());
26                let comp_vec = info.llvm_components.get_or_insert(Vec::new());
27                for component in value.split(' ') {
28                    let component = component.trim();
29                    if !component.is_empty() {
30                        comp_vec.push(component);
31                    }
32                }
33            } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER) {
34                if let Some((_, v)) = compile_flags.split_once("--target") {
35                    let v = v.trim_start_matches([' ', '=']);
36                    let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
37                    if let Some((arch, _)) = v {
38                        let info = header_map.entry(revision).or_insert(RevisionInfo::default());
39                        info.target_arch.replace(arch);
40                    } else {
41                        eprintln!("{file}: seems to have a malformed --target value");
42                        *bad = true;
43                    }
44                }
45            }
46        });
47
48        // Skip run-make tests as revisions are not supported.
49        if entry.path().strip_prefix(tests_path).is_ok_and(|rest| rest.starts_with("run-make")) {
50            return;
51        }
52
53        for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map {
54            let rev = rev.unwrap_or("[unspecified]");
55            match (target_arch, llvm_components) {
56                (None, None) => {}
57                (Some(_), None) => {
58                    eprintln!(
59                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER}` as it has `--target` set"
60                    );
61                    *bad = true;
62                }
63                (None, Some(_)) => {
64                    eprintln!(
65                        "{file}: revision {rev} should not specify `{LLVM_COMPONENTS_HEADER}` as it doesn't need `--target`"
66                    );
67                    *bad = true;
68                }
69                (Some(_), Some(_)) => {
70                    // FIXME: check specified components against the target architectures we
71                    // gathered.
72                }
73            }
74        }
75    });
76}