]> git.proxmox.com Git - rustc.git/blob - src/liblibc/ci/style.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / liblibc / ci / style.rs
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
36 use std::env;
37 use std::fs;
38 use std::io::prelude::*;
39 use std::path::Path;
40
41 macro_rules! t {
42 ($e:expr) => (match $e {
43 Ok(e) => e,
44 Err(e) => panic!("{} failed with {}", stringify!($e), e),
45 })
46 }
47
48 fn 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
61 fn 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
87 struct Errors {
88 errs: bool,
89 }
90
91 #[derive(Clone, Copy, PartialEq)]
92 enum State {
93 Start,
94 Imports,
95 Typedefs,
96 Structs,
97 Constants,
98 FunctionDefinitions,
99 Functions,
100 Modules,
101 }
102
103 fn 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
184 impl 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
199 impl 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 }