@@ -57,9 +57,9 @@ impl Lint {
5757 }
5858 }
5959
60- /// Returns all non-deprecated lints
61- pub fn active_lints ( lints : impl Iterator < Item =Self > ) -> impl Iterator < Item =Self > {
62- lints. filter ( |l| l. deprecation . is_none ( ) )
60+ /// Returns all non-deprecated lints and non-internal lints
61+ pub fn usable_lints ( lints : impl Iterator < Item =Self > ) -> impl Iterator < Item =Self > {
62+ lints. filter ( |l| l. deprecation . is_none ( ) && !l . group . starts_with ( "internal" ) )
6363 }
6464
6565 /// Returns the lints in a HashMap, grouped by the different lint groups
@@ -101,6 +101,89 @@ fn lint_files() -> impl Iterator<Item=walkdir::DirEntry> {
101101 . filter ( |f| f. path ( ) . extension ( ) == Some ( OsStr :: new ( "rs" ) ) )
102102}
103103
104+ /// Replace a region in a file delimited by two lines matching regexes.
105+ ///
106+ /// `path` is the relative path to the file on which you want to perform the replacement.
107+ ///
108+ /// See `replace_region_in_text` for documentation of the other options.
109+ #[ allow( clippy:: expect_fun_call) ]
110+ pub fn replace_region_in_file < F > ( path : & str , start : & str , end : & str , replace_start : bool , replacements : F ) where F : Fn ( ) -> Vec < String > {
111+ let mut f = fs:: File :: open ( path) . expect ( & format ! ( "File not found: {}" , path) ) ;
112+ let mut contents = String :: new ( ) ;
113+ f. read_to_string ( & mut contents) . expect ( "Something went wrong reading the file" ) ;
114+ let replaced = replace_region_in_text ( & contents, start, end, replace_start, replacements) ;
115+
116+ let mut f = fs:: File :: create ( path) . expect ( & format ! ( "File not found: {}" , path) ) ;
117+ f. write_all ( replaced. as_bytes ( ) ) . expect ( "Unable to write file" ) ;
118+ // Ensure we write the changes with a trailing newline so that
119+ // the file has the proper line endings.
120+ f. write_all ( b"\n " ) . expect ( "Unable to write file" ) ;
121+ }
122+
123+ /// Replace a region in a text delimited by two lines matching regexes.
124+ ///
125+ /// * `text` is the input text on which you want to perform the replacement
126+ /// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
127+ /// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
128+ /// * `end` is a `&str` that describes the delimiter line until where the replacement should
129+ /// happen. As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
130+ /// * If `replace_start` is true, the `start` delimiter line is replaced as well.
131+ /// The `end` delimiter line is never replaced.
132+ /// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
133+ ///
134+ /// If you want to perform the replacement on files instead of already parsed text,
135+ /// use `replace_region_in_file`.
136+ ///
137+ /// # Example
138+ ///
139+ /// ```
140+ /// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
141+ /// let result = clippy_dev::replace_region_in_text(
142+ /// the_text,
143+ /// r#"replace_start"#,
144+ /// r#"replace_end"#,
145+ /// false,
146+ /// || {
147+ /// vec!["a different".to_string(), "text".to_string()]
148+ /// }
149+ /// );
150+ /// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
151+ /// ```
152+ pub fn replace_region_in_text < F > ( text : & str , start : & str , end : & str , replace_start : bool , replacements : F ) -> String where F : Fn ( ) -> Vec < String > {
153+ let lines = text. lines ( ) ;
154+ let mut in_old_region = false ;
155+ let mut found = false ;
156+ let mut new_lines = vec ! [ ] ;
157+ let start = Regex :: new ( start) . unwrap ( ) ;
158+ let end = Regex :: new ( end) . unwrap ( ) ;
159+
160+ for line in lines {
161+ if in_old_region {
162+ if end. is_match ( & line) {
163+ in_old_region = false ;
164+ new_lines. extend ( replacements ( ) ) ;
165+ new_lines. push ( line. to_string ( ) ) ;
166+ }
167+ } else if start. is_match ( & line) {
168+ if !replace_start {
169+ new_lines. push ( line. to_string ( ) ) ;
170+ }
171+ in_old_region = true ;
172+ found = true ;
173+ } else {
174+ new_lines. push ( line. to_string ( ) ) ;
175+ }
176+ }
177+
178+ if !found {
179+ // This happens if the provided regex in `clippy_dev/src/main.rs` is not found in the
180+ // given text or file. Most likely this is an error on the programmer's side and the Regex
181+ // is incorrect.
182+ println ! ( "regex {:?} not found. You may have to update it." , start) ;
183+ }
184+ new_lines. join ( "\n " )
185+ }
186+
104187#[ test]
105188fn test_parse_contents ( ) {
106189 let result: Vec < Lint > = parse_contents (
@@ -141,15 +224,54 @@ declare_deprecated_lint! {
141224}
142225
143226#[ test]
144- fn test_active_lints ( ) {
227+ fn test_replace_region ( ) {
228+ let text = r#"
229+ abc
230+ 123
231+ 789
232+ def
233+ ghi"# ;
234+ let expected = r#"
235+ abc
236+ hello world
237+ def
238+ ghi"# ;
239+ let result = replace_region_in_text ( text, r#"^\s*abc$"# , r#"^\s*def"# , false , || {
240+ vec ! [ "hello world" . to_string( ) ]
241+ } ) ;
242+ assert_eq ! ( expected, result) ;
243+ }
244+
245+ #[ test]
246+ fn test_replace_region_with_start ( ) {
247+ let text = r#"
248+ abc
249+ 123
250+ 789
251+ def
252+ ghi"# ;
253+ let expected = r#"
254+ hello world
255+ def
256+ ghi"# ;
257+ let result = replace_region_in_text ( text, r#"^\s*abc$"# , r#"^\s*def"# , true , || {
258+ vec ! [ "hello world" . to_string( ) ]
259+ } ) ;
260+ assert_eq ! ( expected, result) ;
261+ }
262+
263+ #[ test]
264+ fn test_usable_lints ( ) {
145265 let lints = vec ! [
146266 Lint :: new( "should_assert_eq" , "Deprecated" , "abc" , Some ( "Reason" ) , "module_name" ) ,
147- Lint :: new( "should_assert_eq2" , "Not Deprecated" , "abc" , None , "module_name" )
267+ Lint :: new( "should_assert_eq2" , "Not Deprecated" , "abc" , None , "module_name" ) ,
268+ Lint :: new( "should_assert_eq2" , "internal" , "abc" , None , "module_name" ) ,
269+ Lint :: new( "should_assert_eq2" , "internal_style" , "abc" , None , "module_name" )
148270 ] ;
149271 let expected = vec ! [
150272 Lint :: new( "should_assert_eq2" , "Not Deprecated" , "abc" , None , "module_name" )
151273 ] ;
152- assert_eq ! ( expected, Lint :: active_lints ( lints. into_iter( ) ) . collect:: <Vec <Lint >>( ) ) ;
274+ assert_eq ! ( expected, Lint :: usable_lints ( lints. into_iter( ) ) . collect:: <Vec <Lint >>( ) ) ;
153275}
154276
155277#[ test]
0 commit comments