summaryrefslogtreecommitdiff
path: root/libc/ci/style.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libc/ci/style.rs')
-rw-r--r--libc/ci/style.rs204
1 files changed, 204 insertions, 0 deletions
diff --git a/libc/ci/style.rs b/libc/ci/style.rs
new file mode 100644
index 0000000..32e4ba7
--- /dev/null
+++ b/libc/ci/style.rs
@@ -0,0 +1,204 @@
+//! 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
+//! rustc ci/style.rs
+//! ./style src
+//! ```
+//!
+//! ## Guidelines
+//!
+//! The current style is:
+//!
+//! * No trailing whitespace
+//! * No tabs
+//! * 80-character lines
+//! * `extern` instead of `extern "C"`
+//! * Specific module layout:
+//! 1. use directives
+//! 2. typedefs
+//! 3. structs
+//! 4. constants
+//! 5. f! { ... } functions
+//! 6. extern functions
+//! 7. modules + pub use
+//!
+//! Things not verified:
+//!
+//! * alignment
+//! * 4-space tabs
+//! * leading colons on paths
+
+use std::env;
+use std::fs;
+use std::io::prelude::*;
+use std::path::Path;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ })
+}
+
+fn main() {
+ let arg = env::args().skip(1).next().unwrap_or(".".to_string());
+
+ let mut errors = Errors { errs: false };
+ walk(Path::new(&arg), &mut errors);
+
+ if errors.errs {
+ panic!("found some lint errors");
+ } else {
+ println!("good style!");
+ }
+}
+
+fn walk(path: &Path, err: &mut Errors) {
+ for entry in t!(path.read_dir()).map(|e| t!(e)) {
+ let path = entry.path();
+ if t!(entry.file_type()).is_dir() {
+ walk(&path, err);
+ continue
+ }
+
+ let name = entry.file_name().into_string().unwrap();
+ match &name[..] {
+ n if !n.ends_with(".rs") => continue,
+
+ "dox.rs" |
+ "lib.rs" |
+ "macros.rs" => continue,
+
+ _ => {}
+ }
+
+ let mut contents = String::new();
+ t!(t!(fs::File::open(&path)).read_to_string(&mut contents));
+
+ check_style(&contents, &path, err);
+ }
+}
+
+struct Errors {
+ errs: bool,
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum State {
+ Start,
+ Imports,
+ Typedefs,
+ Structs,
+ Constants,
+ FunctionDefinitions,
+ Functions,
+ Modules,
+}
+
+fn check_style(file: &str, path: &Path, err: &mut Errors) {
+ let mut state = State::Start;
+ let mut s_macros = 0;
+ let mut f_macros = 0;
+ let mut prev_blank = false;
+
+ for (i, line) in file.lines().enumerate() {
+ if line == "" {
+ if prev_blank {
+ err.error(path, i, "double blank line");
+ }
+ prev_blank = true;
+ } else {
+ prev_blank = false;
+ }
+ if line != line.trim_right() {
+ err.error(path, i, "trailing whitespace");
+ }
+ if line.contains("\t") {
+ err.error(path, i, "tab character");
+ }
+ if line.len() > 80 {
+ err.error(path, i, "line longer than 80 chars");
+ }
+ if line.contains("extern \"C\"") {
+ err.error(path, i, "use `extern` instead of `extern \"C\"");
+ }
+ if line.contains("#[cfg(") && !line.contains(" if ") {
+ if state != State::Structs {
+ err.error(path, i, "use cfg_if! and submodules \
+ instead of #[cfg]");
+ }
+ }
+
+ let line = line.trim_left();
+ let is_pub = line.starts_with("pub ");
+ let line = if is_pub {&line[4..]} else {line};
+
+ let line_state = if line.starts_with("use ") {
+ if is_pub {
+ State::Modules
+ } else {
+ State::Imports
+ }
+ } else if line.starts_with("const ") {
+ State::Constants
+ } else if line.starts_with("type ") {
+ State::Typedefs
+ } else if line.starts_with("s! {") {
+ s_macros += 1;
+ State::Structs
+ } else if line.starts_with("f! {") {
+ f_macros += 1;
+ State::FunctionDefinitions
+ } else if line.starts_with("extern ") {
+ State::Functions
+ } else if line.starts_with("mod ") {
+ State::Modules
+ } else {
+ continue
+ };
+
+ if state as usize > line_state as usize {
+ err.error(path, i, &format!("{} found after {} when \
+ it belongs before",
+ line_state.desc(), state.desc()));
+ }
+
+ if f_macros == 2 {
+ f_macros += 1;
+ err.error(path, i, "multiple f! macros in one module");
+ }
+ if s_macros == 2 {
+ s_macros += 1;
+ err.error(path, i, "multiple s! macros in one module");
+ }
+
+ state = line_state;
+ }
+}
+
+impl State {
+ fn desc(&self) -> &str {
+ match *self {
+ State::Start => "start",
+ State::Imports => "import",
+ State::Typedefs => "typedef",
+ State::Structs => "struct",
+ State::Constants => "constant",
+ State::FunctionDefinitions => "function definition",
+ State::Functions => "extern function",
+ State::Modules => "module",
+ }
+ }
+}
+
+impl Errors {
+ fn error(&mut self, path: &Path, line: usize, msg: &str) {
+ self.errs = true;
+ println!("{}:{} - {}", path.display(), line + 1, msg);
+ }
+}