99//! * No `TODO` or `XXX` directives.
1010//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
1111//!
12- //! A number of these checks can be opted-out of with various directives like
13- //! `// ignore-tidy-copyright `.
12+ //! A number of these checks can be opted-out of with various directives of the form:
13+ //! `// ignore-tidy-CHECK-NAME `.
1414
1515use std:: fs:: File ;
1616use std:: io:: prelude:: * ;
@@ -90,9 +90,34 @@ fn long_line_is_ok(line: &str) -> bool {
9090 false
9191}
9292
93- fn contains_ignore_directive ( contents : & String , check : & str ) -> bool {
94- contents. contains ( & format ! ( "// ignore-tidy-{}" , check) ) ||
95- contents. contains ( & format ! ( "# ignore-tidy-{}" , check) )
93+ enum Directive {
94+ /// By default, tidy always warns against style issues.
95+ Deny ,
96+
97+ /// `Ignore(false)` means that an `ignore-tidy-*` directive
98+ /// has been provided, but is unnecessary. `Ignore(true)`
99+ /// means that it is necessary (i.e. a warning would be
100+ /// produced if `ignore-tidy-*` was not present).
101+ Ignore ( bool ) ,
102+ }
103+
104+ fn contains_ignore_directive ( contents : & String , check : & str ) -> Directive {
105+ if contents. contains ( & format ! ( "// ignore-tidy-{}" , check) ) ||
106+ contents. contains ( & format ! ( "# ignore-tidy-{}" , check) ) {
107+ Directive :: Ignore ( false )
108+ } else {
109+ Directive :: Deny
110+ }
111+ }
112+
113+ macro_rules! suppressible_tidy_err {
114+ ( $err: ident, $skip: ident, $msg: expr) => {
115+ if let Directive :: Deny = $skip {
116+ $err( $msg) ;
117+ } else {
118+ $skip = Directive :: Ignore ( true ) ;
119+ }
120+ } ;
96121}
97122
98123pub fn check ( path : & Path , bad : & mut bool ) {
@@ -112,32 +137,32 @@ pub fn check(path: &Path, bad: &mut bool) {
112137 tidy_error ! ( bad, "{}: empty file" , file. display( ) ) ;
113138 }
114139
115- let skip_cr = contains_ignore_directive ( & contents, "cr" ) ;
116- let skip_tab = contains_ignore_directive ( & contents, "tab" ) ;
117- let skip_length = contains_ignore_directive ( & contents, "linelength" ) ;
118- let skip_end_whitespace = contains_ignore_directive ( & contents, "end-whitespace" ) ;
119- let skip_copyright = contains_ignore_directive ( & contents, "copyright" ) ;
140+ let mut skip_cr = contains_ignore_directive ( & contents, "cr" ) ;
141+ let mut skip_tab = contains_ignore_directive ( & contents, "tab" ) ;
142+ let mut skip_length = contains_ignore_directive ( & contents, "linelength" ) ;
143+ let mut skip_end_whitespace = contains_ignore_directive ( & contents, "end-whitespace" ) ;
144+ let mut skip_copyright = contains_ignore_directive ( & contents, "copyright" ) ;
120145 let mut leading_new_lines = false ;
121146 let mut trailing_new_lines = 0 ;
122- let mut contained_long_line = false ;
123147 for ( i, line) in contents. split ( '\n' ) . enumerate ( ) {
124148 let mut err = |msg : & str | {
125149 tidy_error ! ( bad, "{}:{}: {}" , file. display( ) , i + 1 , msg) ;
126150 } ;
127151 if line. chars ( ) . count ( ) > COLS && !long_line_is_ok ( line) {
128- contained_long_line = true ;
129- if !skip_length {
130- err ( & format ! ( "line longer than {} chars" , COLS ) ) ;
131- }
152+ suppressible_tidy_err ! (
153+ err,
154+ skip_length,
155+ & format!( "line longer than {} chars" , COLS )
156+ ) ;
132157 }
133- if !skip_tab && line. contains ( '\t' ) {
134- err ( "tab character" ) ;
158+ if line. contains ( '\t' ) {
159+ suppressible_tidy_err ! ( err , skip_tab , "tab character" ) ;
135160 }
136- if !skip_end_whitespace && ( line. ends_with ( ' ' ) || line. ends_with ( '\t' ) ) {
137- err ( "trailing whitespace" ) ;
161+ if line. ends_with ( ' ' ) || line. ends_with ( '\t' ) {
162+ suppressible_tidy_err ! ( err , skip_end_whitespace , "trailing whitespace" ) ;
138163 }
139- if !skip_cr && line. contains ( '\r' ) {
140- err ( "CR character" ) ;
164+ if line. contains ( '\r' ) {
165+ suppressible_tidy_err ! ( err , skip_cr , "CR character" ) ;
141166 }
142167 if filename != "style.rs" {
143168 if line. contains ( "TODO" ) {
@@ -147,12 +172,16 @@ pub fn check(path: &Path, bad: &mut bool) {
147172 err ( "XXX is deprecated; use FIXME" )
148173 }
149174 }
150- if !skip_copyright && ( line. starts_with ( "// Copyright" ) ||
151- line. starts_with ( "# Copyright" ) ||
152- line. starts_with ( "Copyright" ) )
153- && ( line. contains ( "Rust Developers" ) ||
154- line. contains ( "Rust Project Developers" ) ) {
155- err ( "copyright notices attributed to the Rust Project Developers are deprecated" ) ;
175+ if ( line. starts_with ( "// Copyright" ) ||
176+ line. starts_with ( "# Copyright" ) ||
177+ line. starts_with ( "Copyright" ) )
178+ && ( line. contains ( "Rust Developers" ) ||
179+ line. contains ( "Rust Project Developers" ) ) {
180+ suppressible_tidy_err ! (
181+ err,
182+ skip_copyright,
183+ "copyright notices attributed to the Rust Project Developers are deprecated"
184+ ) ;
156185 }
157186 if line. ends_with ( "```ignore" ) || line. ends_with ( "```rust,ignore" ) {
158187 err ( UNEXPLAINED_IGNORE_DOCTEST_INFO ) ;
@@ -177,8 +206,21 @@ pub fn check(path: &Path, bad: &mut bool) {
177206 1 => { }
178207 n => tidy_error ! ( bad, "{}: too many trailing newlines ({})" , file. display( ) , n) ,
179208 } ;
180- if !contained_long_line && skip_length {
209+
210+ if let Directive :: Ignore ( false ) = skip_cr {
211+ tidy_error ! ( bad, "{}: ignoring CR characters unnecessarily" , file. display( ) ) ;
212+ }
213+ if let Directive :: Ignore ( false ) = skip_tab {
214+ tidy_error ! ( bad, "{}: ignoring tab characters unnecessarily" , file. display( ) ) ;
215+ }
216+ if let Directive :: Ignore ( false ) = skip_length {
181217 tidy_error ! ( bad, "{}: ignoring line length unnecessarily" , file. display( ) ) ;
182218 }
219+ if let Directive :: Ignore ( false ) = skip_end_whitespace {
220+ tidy_error ! ( bad, "{}: ignoring trailing whitespace unnecessarily" , file. display( ) ) ;
221+ }
222+ if let Directive :: Ignore ( false ) = skip_copyright {
223+ tidy_error ! ( bad, "{}: ignoring copyright unnecessarily" , file. display( ) ) ;
224+ }
183225 } )
184226}
0 commit comments