diff --git a/.gitignore b/.gitignore index bbbad4bc51532..8d889ea9bd19e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target Cargo.lock *~ style +!style/ diff --git a/libc-test/Cargo.toml b/libc-test/Cargo.toml index 5bad7118240db..a5384c7ba2498 100644 --- a/libc-test/Cargo.toml +++ b/libc-test/Cargo.toml @@ -98,5 +98,10 @@ harness = true [[test]] name = "style" -path = "test/style.rs" +path = "test/check_style.rs" +harness = true + +[[test]] +name = "style_tests" +path = "test/style_tests.rs" harness = true diff --git a/libc-test/test/check_style.rs b/libc-test/test/check_style.rs new file mode 100644 index 0000000000000..0db22a5bdd000 --- /dev/null +++ b/libc-test/test/check_style.rs @@ -0,0 +1,63 @@ +//! Simple script to verify the coding style of this library +//! +//! ## How to run +//! +//! The first argument to this script is the directory to run on, so running +//! this script should be as simple as: +//! +//! ```notrust +//! cargo test --test style +//! ``` +//! +//! ## Guidelines +//! +//! The current style is: +//! +//! * Specific module layout: +//! 1. use directives +//! 2. typedefs +//! 3. structs +//! 4. constants +//! 5. f! { ... } functions +//! 6. extern functions +//! 7. modules + pub use + +pub mod style; + +use std::env; +use std::path::Path; + +use style::{Result, StyleChecker}; + +#[test] +fn check_style() { + let root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../src"); + walk(&root_dir).unwrap(); + eprintln!("good style!"); +} + +fn walk(root_dir: &Path) -> Result<()> { + let mut style_checker = StyleChecker::new(); + + for entry in glob::glob(&format!( + "{}/**/*.rs", + root_dir.to_str().expect("dir should be valid UTF-8") + ))? { + let entry = entry?; + + let name = entry + .file_name() + .expect("file name should not end in ..") + .to_str() + .expect("file name should be valid UTF-8"); + if let "lib.rs" | "macros.rs" = &name[..] { + continue; + } + + let path = entry.as_path(); + style_checker.check_file(path)?; + style_checker.reset_state(); + } + + style_checker.finalize() +} diff --git a/libc-test/test/style.rs b/libc-test/test/style/mod.rs similarity index 84% rename from libc-test/test/style.rs rename to libc-test/test/style/mod.rs index 246376326f922..67c99118f5719 100644 --- a/libc-test/test/style.rs +++ b/libc-test/test/style/mod.rs @@ -1,75 +1,24 @@ -//! Simple script to verify the coding style of this library +//! Provides the [StyleChecker] visitor to verify the coding style of +//! this library. //! -//! ## How to run -//! -//! The first argument to this script is the directory to run on, so running -//! this script should be as simple as: -//! -//! ```notrust -//! cargo test --test style -//! ``` -//! -//! ## Guidelines -//! -//! The current style is: -//! -//! * Specific module layout: -//! 1. use directives -//! 2. typedefs -//! 3. structs -//! 4. constants -//! 5. f! { ... } functions -//! 6. extern functions -//! 7. modules + pub use +//! This is split out so that the implementation itself can be tested +//! separately, see test/check_style.rs for how it's used. use std::fmt::Display; +use std::fs; use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::{env, fs}; use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; use syn::visit::{self, Visit}; use syn::Token; -type Error = Box; -type Result = std::result::Result; - -#[test] -fn check_style() { - let root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../src"); - walk(&root_dir).unwrap(); - eprintln!("good style!"); -} - -fn walk(root_dir: &Path) -> Result<()> { - let mut style_checker = StyleChecker::new(); - - for entry in glob::glob(&format!( - "{}/**/*.rs", - root_dir.to_str().expect("dir should be valid UTF-8") - ))? { - let entry = entry?; - - let name = entry - .file_name() - .expect("file name should not end in ..") - .to_str() - .expect("file name should be valid UTF-8"); - if let "lib.rs" | "macros.rs" = &name[..] { - continue; - } - - let path = entry.as_path(); - style_checker.check_file(path)?; - style_checker.reset_state(); - } - - style_checker.finalize() -} +pub type Error = Box; +pub type Result = std::result::Result; #[derive(Default)] -struct StyleChecker { +pub struct StyleChecker { state: State, // FIXME: see StyleChecker::set_state _s_macros: usize, @@ -106,24 +55,27 @@ enum ExprCfgElse { } impl StyleChecker { - fn new() -> Self { + pub fn new() -> Self { Self::default() } /// Reads and parses the file at the given path and checks /// for any style violations. - fn check_file(&mut self, path: &Path) -> Result<()> { + pub fn check_file(&mut self, path: &Path) -> Result<()> { let contents = fs::read_to_string(path)?; - let file = syn::parse_file(&contents)?; self.path = PathBuf::from(path); - self.visit_file(&file); + self.check_string(contents) + } + pub fn check_string(&mut self, contents: String) -> Result<()> { + let file = syn::parse_file(&contents)?; + self.visit_file(&file); Ok(()) } /// Resets the state of the [StyleChecker]. - fn reset_state(&mut self) { + pub fn reset_state(&mut self) { *self = Self { errors: std::mem::take(&mut self.errors), ..Self::default() @@ -131,7 +83,7 @@ impl StyleChecker { } /// Collect all errors into a single error, reporting them if any. - fn finalize(self) -> Result<()> { + pub fn finalize(self) -> Result<()> { if self.errors.is_empty() { return Ok(()); } diff --git a/libc-test/test/style_tests.rs b/libc-test/test/style_tests.rs new file mode 100644 index 0000000000000..7a19afd0c4861 --- /dev/null +++ b/libc-test/test/style_tests.rs @@ -0,0 +1,157 @@ +//! Verifies the implementation of the style checker in [style] + +use style::StyleChecker; + +pub mod style; + +#[test] +fn correct_module_layout() { + let contents = r#" +use core::mem::size_of; +pub type foo_t = u32; +struct Foo {} +pub const FOO: u32 = 0x20000; +f! {} +extern "C" {} +mod foolib; +pub use self::foolib::*; +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + checker.finalize().unwrap(); +} + +#[test] +fn incorrect_module_layout() { + let contents = r#" +use core::mem::size_of; +pub type foo_t = u32; +struct Foo {} +pub const FOO: u32 = 0x20000; +extern "C" {} +f! {} +mod foolib; +pub use self::foolib::*; +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +} + +#[test] +fn incorrect_cfg_if_layout() { + let contents = r#" +cfg_if! { + if #[cfg(foo)] { + pub type foo_t = u32; + use core::mem::size_of; + } +} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +} + +#[test] +fn cfg_if_branch_resets_state() { + let contents = r#" +cfg_if! { + if #[cfg(foo)] { + use core::mem::size_of; + pub type foo_t = u32; + } else { + use core::mem::align_of; + } +} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + checker.finalize().unwrap(); +} + +#[test] +fn multiple_f_macros() { + let contents = r#" +f! {} +f! {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +} + +#[test] +fn cfg_if_over_cfg() { + let contents = r#" +#[cfg(foo)] +pub struct Foo {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +} + +#[test] +fn cfg_if_ignore_target_arch() { + let contents = r#" +#[cfg(target_arch = "x86")] +pub struct Foo {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + checker.finalize().unwrap(); +} + +#[test] +fn cfg_if_ignore_target_endian_nested() { + let contents = r#" +#[cfg(all(target_endian = "little"))] +pub struct Foo {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + checker.finalize().unwrap(); +} + +#[test] +fn manual_copy() { + let contents = r#" +#[derive(Copy)] +pub struct Foo {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +} + +#[test] +fn manual_clone() { + let contents = r#" +#[derive(Clone)] +pub struct Foo {} +"# + .to_string(); + + let mut checker = StyleChecker::new(); + checker.check_string(contents).unwrap(); + assert!(checker.finalize().is_err()); +}