12add0d91Sopenharmony_ci//! Simple script to verify the coding style of this library
22add0d91Sopenharmony_ci//!
32add0d91Sopenharmony_ci//! ## How to run
42add0d91Sopenharmony_ci//!
52add0d91Sopenharmony_ci//! The first argument to this script is the directory to run on, so running
62add0d91Sopenharmony_ci//! this script should be as simple as:
72add0d91Sopenharmony_ci//!
82add0d91Sopenharmony_ci//! ```notrust
92add0d91Sopenharmony_ci//! rustc ci/style.rs
102add0d91Sopenharmony_ci//! ./style src
112add0d91Sopenharmony_ci//! ```
122add0d91Sopenharmony_ci//!
132add0d91Sopenharmony_ci//! ## Guidelines
142add0d91Sopenharmony_ci//!
152add0d91Sopenharmony_ci//! The current style is:
162add0d91Sopenharmony_ci//!
172add0d91Sopenharmony_ci//! * Specific module layout:
182add0d91Sopenharmony_ci//!     1. use directives
192add0d91Sopenharmony_ci//!     2. typedefs
202add0d91Sopenharmony_ci//!     3. structs
212add0d91Sopenharmony_ci//!     4. constants
222add0d91Sopenharmony_ci//!     5. f! { ... } functions
232add0d91Sopenharmony_ci//!     6. extern functions
242add0d91Sopenharmony_ci//!     7. modules + pub use
252add0d91Sopenharmony_ci//!
262add0d91Sopenharmony_ci//! Things not verified:
272add0d91Sopenharmony_ci//!
282add0d91Sopenharmony_ci//! * alignment
292add0d91Sopenharmony_ci//! * leading colons on paths
302add0d91Sopenharmony_ci
312add0d91Sopenharmony_ciuse std::env;
322add0d91Sopenharmony_ciuse std::fs;
332add0d91Sopenharmony_ciuse std::io::prelude::*;
342add0d91Sopenharmony_ciuse std::path::Path;
352add0d91Sopenharmony_ci
362add0d91Sopenharmony_cimacro_rules! t {
372add0d91Sopenharmony_ci    ($e:expr) => {
382add0d91Sopenharmony_ci        match $e {
392add0d91Sopenharmony_ci            Ok(e) => e,
402add0d91Sopenharmony_ci            Err(e) => panic!("{} failed with {}", stringify!($e), e),
412add0d91Sopenharmony_ci        }
422add0d91Sopenharmony_ci    };
432add0d91Sopenharmony_ci}
442add0d91Sopenharmony_ci
452add0d91Sopenharmony_cifn main() {
462add0d91Sopenharmony_ci    let arg = env::args().skip(1).next().unwrap_or(".".to_string());
472add0d91Sopenharmony_ci
482add0d91Sopenharmony_ci    let mut errors = Errors { errs: false };
492add0d91Sopenharmony_ci    walk(Path::new(&arg), &mut errors);
502add0d91Sopenharmony_ci
512add0d91Sopenharmony_ci    if errors.errs {
522add0d91Sopenharmony_ci        panic!("found some lint errors");
532add0d91Sopenharmony_ci    } else {
542add0d91Sopenharmony_ci        println!("good style!");
552add0d91Sopenharmony_ci    }
562add0d91Sopenharmony_ci}
572add0d91Sopenharmony_ci
582add0d91Sopenharmony_cifn walk(path: &Path, err: &mut Errors) {
592add0d91Sopenharmony_ci    for entry in t!(path.read_dir()).map(|e| t!(e)) {
602add0d91Sopenharmony_ci        let path = entry.path();
612add0d91Sopenharmony_ci        if t!(entry.file_type()).is_dir() {
622add0d91Sopenharmony_ci            walk(&path, err);
632add0d91Sopenharmony_ci            continue;
642add0d91Sopenharmony_ci        }
652add0d91Sopenharmony_ci
662add0d91Sopenharmony_ci        let name = entry.file_name().into_string().unwrap();
672add0d91Sopenharmony_ci        match &name[..] {
682add0d91Sopenharmony_ci            n if !n.ends_with(".rs") => continue,
692add0d91Sopenharmony_ci
702add0d91Sopenharmony_ci            "lib.rs" | "macros.rs" => continue,
712add0d91Sopenharmony_ci
722add0d91Sopenharmony_ci            _ => {}
732add0d91Sopenharmony_ci        }
742add0d91Sopenharmony_ci
752add0d91Sopenharmony_ci        let mut contents = String::new();
762add0d91Sopenharmony_ci        t!(t!(fs::File::open(&path)).read_to_string(&mut contents));
772add0d91Sopenharmony_ci
782add0d91Sopenharmony_ci        check_style(&contents, &path, err);
792add0d91Sopenharmony_ci    }
802add0d91Sopenharmony_ci}
812add0d91Sopenharmony_ci
822add0d91Sopenharmony_cistruct Errors {
832add0d91Sopenharmony_ci    errs: bool,
842add0d91Sopenharmony_ci}
852add0d91Sopenharmony_ci
862add0d91Sopenharmony_ci#[derive(Clone, Copy, PartialEq)]
872add0d91Sopenharmony_cienum State {
882add0d91Sopenharmony_ci    Start,
892add0d91Sopenharmony_ci    Imports,
902add0d91Sopenharmony_ci    Typedefs,
912add0d91Sopenharmony_ci    Structs,
922add0d91Sopenharmony_ci    Constants,
932add0d91Sopenharmony_ci    FunctionDefinitions,
942add0d91Sopenharmony_ci    Functions,
952add0d91Sopenharmony_ci    Modules,
962add0d91Sopenharmony_ci}
972add0d91Sopenharmony_ci
982add0d91Sopenharmony_cifn check_style(file: &str, path: &Path, err: &mut Errors) {
992add0d91Sopenharmony_ci    let mut state = State::Start;
1002add0d91Sopenharmony_ci    let mut s_macros = 0;
1012add0d91Sopenharmony_ci    let mut f_macros = 0;
1022add0d91Sopenharmony_ci    let mut in_impl = false;
1032add0d91Sopenharmony_ci
1042add0d91Sopenharmony_ci    for (i, line) in file.lines().enumerate() {
1052add0d91Sopenharmony_ci        if line.contains("#[cfg(")
1062add0d91Sopenharmony_ci            && line.contains(']')
1072add0d91Sopenharmony_ci            && !line.contains(" if ")
1082add0d91Sopenharmony_ci            && !(line.contains("target_endian") || line.contains("target_arch"))
1092add0d91Sopenharmony_ci        {
1102add0d91Sopenharmony_ci            if state != State::Structs {
1112add0d91Sopenharmony_ci                err.error(path, i, "use cfg_if! and submodules instead of #[cfg]");
1122add0d91Sopenharmony_ci            }
1132add0d91Sopenharmony_ci        }
1142add0d91Sopenharmony_ci        if line.contains("#[derive(") && (line.contains("Copy") || line.contains("Clone")) {
1152add0d91Sopenharmony_ci            err.error(path, i, "impl ::Copy and ::Clone manually");
1162add0d91Sopenharmony_ci        }
1172add0d91Sopenharmony_ci        if line.contains("impl") {
1182add0d91Sopenharmony_ci            in_impl = true;
1192add0d91Sopenharmony_ci        }
1202add0d91Sopenharmony_ci        if in_impl && line.starts_with('}') {
1212add0d91Sopenharmony_ci            in_impl = false;
1222add0d91Sopenharmony_ci        }
1232add0d91Sopenharmony_ci
1242add0d91Sopenharmony_ci        let orig_line = line;
1252add0d91Sopenharmony_ci        let line = line.trim_start();
1262add0d91Sopenharmony_ci        let is_pub = line.starts_with("pub ");
1272add0d91Sopenharmony_ci        let line = if is_pub { &line[4..] } else { line };
1282add0d91Sopenharmony_ci
1292add0d91Sopenharmony_ci        let line_state = if line.starts_with("use ") {
1302add0d91Sopenharmony_ci            if line.contains("c_void") {
1312add0d91Sopenharmony_ci                continue;
1322add0d91Sopenharmony_ci            }
1332add0d91Sopenharmony_ci            if is_pub {
1342add0d91Sopenharmony_ci                State::Modules
1352add0d91Sopenharmony_ci            } else {
1362add0d91Sopenharmony_ci                State::Imports
1372add0d91Sopenharmony_ci            }
1382add0d91Sopenharmony_ci        } else if line.starts_with("const ") {
1392add0d91Sopenharmony_ci            State::Constants
1402add0d91Sopenharmony_ci        } else if line.starts_with("type ") && !in_impl {
1412add0d91Sopenharmony_ci            State::Typedefs
1422add0d91Sopenharmony_ci        } else if line.starts_with("s! {") {
1432add0d91Sopenharmony_ci            s_macros += 1;
1442add0d91Sopenharmony_ci            State::Structs
1452add0d91Sopenharmony_ci        } else if line.starts_with("s_no_extra_traits! {") {
1462add0d91Sopenharmony_ci            // multiple macros of this type are allowed
1472add0d91Sopenharmony_ci            State::Structs
1482add0d91Sopenharmony_ci        } else if line.starts_with("s_paren! {") {
1492add0d91Sopenharmony_ci            // multiple macros of this type are allowed
1502add0d91Sopenharmony_ci            State::Structs
1512add0d91Sopenharmony_ci        } else if line.starts_with("f! {") {
1522add0d91Sopenharmony_ci            f_macros += 1;
1532add0d91Sopenharmony_ci            State::FunctionDefinitions
1542add0d91Sopenharmony_ci        } else if line.starts_with("extern ") && !orig_line.starts_with(" ") {
1552add0d91Sopenharmony_ci            State::Functions
1562add0d91Sopenharmony_ci        } else if line.starts_with("mod ") {
1572add0d91Sopenharmony_ci            State::Modules
1582add0d91Sopenharmony_ci        } else {
1592add0d91Sopenharmony_ci            continue;
1602add0d91Sopenharmony_ci        };
1612add0d91Sopenharmony_ci
1622add0d91Sopenharmony_ci        if state as usize > line_state as usize {
1632add0d91Sopenharmony_ci            err.error(
1642add0d91Sopenharmony_ci                path,
1652add0d91Sopenharmony_ci                i,
1662add0d91Sopenharmony_ci                &format!(
1672add0d91Sopenharmony_ci                    "{} found after {} when it belongs before",
1682add0d91Sopenharmony_ci                    line_state.desc(),
1692add0d91Sopenharmony_ci                    state.desc()
1702add0d91Sopenharmony_ci                ),
1712add0d91Sopenharmony_ci            );
1722add0d91Sopenharmony_ci        }
1732add0d91Sopenharmony_ci
1742add0d91Sopenharmony_ci        if f_macros == 2 {
1752add0d91Sopenharmony_ci            f_macros += 1;
1762add0d91Sopenharmony_ci            err.error(path, i, "multiple f! macros in one module");
1772add0d91Sopenharmony_ci        }
1782add0d91Sopenharmony_ci        if s_macros == 2 {
1792add0d91Sopenharmony_ci            s_macros += 1;
1802add0d91Sopenharmony_ci            err.error(path, i, "multiple s! macros in one module");
1812add0d91Sopenharmony_ci        }
1822add0d91Sopenharmony_ci
1832add0d91Sopenharmony_ci        state = line_state;
1842add0d91Sopenharmony_ci    }
1852add0d91Sopenharmony_ci}
1862add0d91Sopenharmony_ci
1872add0d91Sopenharmony_ciimpl State {
1882add0d91Sopenharmony_ci    fn desc(&self) -> &str {
1892add0d91Sopenharmony_ci        match *self {
1902add0d91Sopenharmony_ci            State::Start => "start",
1912add0d91Sopenharmony_ci            State::Imports => "import",
1922add0d91Sopenharmony_ci            State::Typedefs => "typedef",
1932add0d91Sopenharmony_ci            State::Structs => "struct",
1942add0d91Sopenharmony_ci            State::Constants => "constant",
1952add0d91Sopenharmony_ci            State::FunctionDefinitions => "function definition",
1962add0d91Sopenharmony_ci            State::Functions => "extern function",
1972add0d91Sopenharmony_ci            State::Modules => "module",
1982add0d91Sopenharmony_ci        }
1992add0d91Sopenharmony_ci    }
2002add0d91Sopenharmony_ci}
2012add0d91Sopenharmony_ci
2022add0d91Sopenharmony_ciimpl Errors {
2032add0d91Sopenharmony_ci    fn error(&mut self, path: &Path, line: usize, msg: &str) {
2042add0d91Sopenharmony_ci        self.errs = true;
2052add0d91Sopenharmony_ci        println!("{}:{}: {}", path.display(), line + 1, msg);
2062add0d91Sopenharmony_ci    }
2072add0d91Sopenharmony_ci}
208