summaryrefslogtreecommitdiff
path: root/third_party/libc/ci/style.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libc/ci/style.rs')
-rw-r--r--third_party/libc/ci/style.rs204
1 files changed, 204 insertions, 0 deletions
diff --git a/third_party/libc/ci/style.rs b/third_party/libc/ci/style.rs
new file mode 100644
index 0000000..32e4ba7
--- /dev/null
+++ b/third_party/libc/ci/style.rs
@@ -0,0 +1,204 @@
1//! Simple script to verify the coding style of this library
2//!
3//! ## How to run
4//!
5//! The first argument to this script is the directory to run on, so running
6//! this script should be as simple as:
7//!
8//! ```notrust
9//! rustc ci/style.rs
10//! ./style src
11//! ```
12//!
13//! ## Guidelines
14//!
15//! The current style is:
16//!
17//! * No trailing whitespace
18//! * No tabs
19//! * 80-character lines
20//! * `extern` instead of `extern "C"`
21//! * Specific module layout:
22//! 1. use directives
23//! 2. typedefs
24//! 3. structs
25//! 4. constants
26//! 5. f! { ... } functions
27//! 6. extern functions
28//! 7. modules + pub use
29//!
30//! Things not verified:
31//!
32//! * alignment
33//! * 4-space tabs
34//! * leading colons on paths
35
36use std::env;
37use std::fs;
38use std::io::prelude::*;
39use std::path::Path;
40
41macro_rules! t {
42 ($e:expr) => (match $e {
43 Ok(e) => e,
44 Err(e) => panic!("{} failed with {}", stringify!($e), e),
45 })
46}
47
48fn main() {
49 let arg = env::args().skip(1).next().unwrap_or(".".to_string());
50
51 let mut errors = Errors { errs: false };
52 walk(Path::new(&arg), &mut errors);
53
54 if errors.errs {
55 panic!("found some lint errors");
56 } else {
57 println!("good style!");
58 }
59}
60
61fn walk(path: &Path, err: &mut Errors) {
62 for entry in t!(path.read_dir()).map(|e| t!(e)) {
63 let path = entry.path();
64 if t!(entry.file_type()).is_dir() {
65 walk(&path, err);
66 continue
67 }
68
69 let name = entry.file_name().into_string().unwrap();
70 match &name[..] {
71 n if !n.ends_with(".rs") => continue,
72
73 "dox.rs" |
74 "lib.rs" |
75 "macros.rs" => continue,
76
77 _ => {}
78 }
79
80 let mut contents = String::new();
81 t!(t!(fs::File::open(&path)).read_to_string(&mut contents));
82
83 check_style(&contents, &path, err);
84 }
85}
86
87struct Errors {
88 errs: bool,
89}
90
91#[derive(Clone, Copy, PartialEq)]
92enum State {
93 Start,
94 Imports,
95 Typedefs,
96 Structs,
97 Constants,
98 FunctionDefinitions,
99 Functions,
100 Modules,
101}
102
103fn check_style(file: &str, path: &Path, err: &mut Errors) {
104 let mut state = State::Start;
105 let mut s_macros = 0;
106 let mut f_macros = 0;
107 let mut prev_blank = false;
108
109 for (i, line) in file.lines().enumerate() {
110 if line == "" {
111 if prev_blank {
112 err.error(path, i, "double blank line");
113 }
114 prev_blank = true;
115 } else {
116 prev_blank = false;
117 }
118 if line != line.trim_right() {
119 err.error(path, i, "trailing whitespace");
120 }
121 if line.contains("\t") {
122 err.error(path, i, "tab character");
123 }
124 if line.len() > 80 {
125 err.error(path, i, "line longer than 80 chars");
126 }
127 if line.contains("extern \"C\"") {
128 err.error(path, i, "use `extern` instead of `extern \"C\"");
129 }
130 if line.contains("#[cfg(") && !line.contains(" if ") {
131 if state != State::Structs {
132 err.error(path, i, "use cfg_if! and submodules \
133 instead of #[cfg]");
134 }
135 }
136
137 let line = line.trim_left();
138 let is_pub = line.starts_with("pub ");
139 let line = if is_pub {&line[4..]} else {line};
140
141 let line_state = if line.starts_with("use ") {
142 if is_pub {
143 State::Modules
144 } else {
145 State::Imports
146 }
147 } else if line.starts_with("const ") {
148 State::Constants
149 } else if line.starts_with("type ") {
150 State::Typedefs
151 } else if line.starts_with("s! {") {
152 s_macros += 1;
153 State::Structs
154 } else if line.starts_with("f! {") {
155 f_macros += 1;
156 State::FunctionDefinitions
157 } else if line.starts_with("extern ") {
158 State::Functions
159 } else if line.starts_with("mod ") {
160 State::Modules
161 } else {
162 continue
163 };
164
165 if state as usize > line_state as usize {
166 err.error(path, i, &format!("{} found after {} when \
167 it belongs before",
168 line_state.desc(), state.desc()));
169 }
170
171 if f_macros == 2 {
172 f_macros += 1;
173 err.error(path, i, "multiple f! macros in one module");
174 }
175 if s_macros == 2 {
176 s_macros += 1;
177 err.error(path, i, "multiple s! macros in one module");
178 }
179
180 state = line_state;
181 }
182}
183
184impl State {
185 fn desc(&self) -> &str {
186 match *self {
187 State::Start => "start",
188 State::Imports => "import",
189 State::Typedefs => "typedef",
190 State::Structs => "struct",
191 State::Constants => "constant",
192 State::FunctionDefinitions => "function definition",
193 State::Functions => "extern function",
194 State::Modules => "module",
195 }
196 }
197}
198
199impl Errors {
200 fn error(&mut self, path: &Path, line: usize, msg: &str) {
201 self.errs = true;
202 println!("{}:{} - {}", path.display(), line + 1, msg);
203 }
204}