1use std::path::Path;
4use std::path::PathBuf;
5
6use rayon::prelude::*;
7use rootcause::report;
8
9use crate::cmds::rsl::rules::RuleViolation;
10
11pub struct FileContext<'ast> {
12 pub path: &'ast Path,
13 pub file: &'ast syn::File,
14 pub(super) module_item_lists: Vec<Vec<crate::cmds::rsl::ast::ModuleItem<'ast>>>,
15}
16
17pub(super) fn check_paths(paths: &[PathBuf]) -> rootcause::Result<Vec<Box<dyn RuleViolation>>> {
18 let file_results: Vec<_> = paths.par_iter().map(|path| self::check_path(path)).collect();
20 let mut violations = Vec::new();
21
22 for file_result in file_results {
23 violations.extend(file_result?);
24 }
25
26 Ok(violations)
27}
28
29fn check_path(path: &Path) -> rootcause::Result<Vec<Box<dyn RuleViolation>>> {
30 let source = std::fs::read_to_string(path).map_err(|error| {
31 report!("could not read Rust source")
32 .attach(format!("path={}", path.display()))
33 .attach(format!("error={error}"))
34 })?;
35 let syntax = syn::parse_file(&source).map_err(|error| {
36 report!("could not parse Rust source")
37 .attach(format!("path={}", path.display()))
38 .attach(format!("error={error}"))
39 })?;
40 let module_item_lists = crate::cmds::rsl::ast::module_item_lists(&syntax);
41
42 Ok(crate::cmds::rsl::rules::check(&FileContext {
43 path,
44 file: &syntax,
45 module_item_lists,
46 }))
47}