2
2
3
3
use clap:: { App , Arg , SubCommand } ;
4
4
use clippy_dev:: * ;
5
+ use std:: fs:: { File , OpenOptions } ;
6
+ use std:: io;
7
+ use std:: io:: prelude:: * ;
8
+ use std:: io:: ErrorKind ;
9
+ use std:: path:: PathBuf ;
5
10
6
11
mod fmt;
7
12
mod stderr_length_check;
@@ -51,6 +56,26 @@ fn main() {
51
56
. help ( "Checks that util/dev update_lints has been run. Used on CI." ) ,
52
57
) ,
53
58
)
59
+ . subcommand (
60
+ SubCommand :: with_name ( "new_lint" )
61
+ . about ( "Create new lint and run util/dev update_lints" )
62
+ . arg (
63
+ Arg :: with_name ( "type" )
64
+ . long ( "type" )
65
+ . help ( "Create early or late lint" )
66
+ . takes_value ( true )
67
+ . possible_values ( & [ "early" , "late" ] )
68
+ . required ( true ) ,
69
+ )
70
+ . arg (
71
+ Arg :: with_name ( "name" )
72
+ . short ( "n" )
73
+ . long ( "name" )
74
+ . help ( "Name of the new lint in snake case, ex: fn_too_long" )
75
+ . takes_value ( true )
76
+ . required ( true ) ,
77
+ ) ,
78
+ )
54
79
. arg (
55
80
Arg :: with_name ( "limit-stderr-length" )
56
81
. long ( "limit-stderr-length" )
@@ -75,10 +100,103 @@ fn main() {
75
100
update_lints ( & UpdateMode :: Change ) ;
76
101
}
77
102
} ,
103
+ ( "new_lint" , Some ( matches) ) => {
104
+ create_new_lint ( matches. value_of ( "type" ) , matches. value_of ( "name" ) ) ;
105
+ } ,
78
106
_ => { } ,
79
107
}
80
108
}
81
109
110
+ fn project_root ( ) -> Result < PathBuf , io:: Error > {
111
+ let current_dir = std:: env:: current_dir ( ) ?;
112
+ for path in current_dir. ancestors ( ) {
113
+ let result = std:: fs:: read_to_string ( path. join ( "Cargo.toml" ) ) ;
114
+ if let Err ( err) = & result {
115
+ if err. kind ( ) == io:: ErrorKind :: NotFound {
116
+ continue ;
117
+ }
118
+ }
119
+
120
+ let content = result?;
121
+ if content. contains ( "[package]\n name = \" clippy\" " ) {
122
+ return Ok ( path. to_path_buf ( ) ) ;
123
+ }
124
+ }
125
+ Err ( io:: Error :: new ( ErrorKind :: Other , "Unable to find project root" ) )
126
+ }
127
+
128
+ fn open_files ( lint_name : & str ) -> Result < ( File , File ) , io:: Error > {
129
+ let project_root = project_root ( ) ?;
130
+
131
+ let test_file_path = project_root. join ( format ! ( "tests/ui/{}.rs" , lint_name) ) ;
132
+ let test_file = OpenOptions :: new ( ) . write ( true ) . create_new ( true ) . open ( test_file_path) ?;
133
+
134
+ let lint_file_path = project_root. join ( format ! ( "clippy_lints/src/{}.rs" , lint_name) ) ;
135
+ let lint_file = OpenOptions :: new ( ) . write ( true ) . create_new ( true ) . open ( lint_file_path) ?;
136
+
137
+ Ok ( ( test_file, lint_file) )
138
+ }
139
+
140
+ fn create_new_lint ( lint_type : Option < & str > , lint_name : Option < & str > ) {
141
+ // lint_type and lint_name are validated by clap
142
+ let lint_type = lint_type. unwrap ( ) ;
143
+ let lint_name = lint_name. unwrap ( ) ;
144
+
145
+ match open_files ( lint_name) {
146
+ Ok ( ( mut test_file, mut lint_file) ) => {
147
+ let pass_type = match lint_type {
148
+ "early" => "EarlyLintPass" ,
149
+ _ => "LateLintPass" ,
150
+ } ;
151
+
152
+ let camel_case_name = lint_name
153
+ . split ( '_' )
154
+ . map ( |s| [ & s[ 0 ..1 ] . to_uppercase ( ) , & s[ 1 ..] ] . concat ( ) )
155
+ . collect :: < std:: string:: String > ( ) ;
156
+
157
+ test_file
158
+ . write_all (
159
+ format ! (
160
+ "#![warn(clippy::{})]
161
+
162
+ fn main() {{
163
+ // test code goes here
164
+ }}" ,
165
+ lint_name
166
+ )
167
+ . as_bytes ( ) ,
168
+ )
169
+ . unwrap ( ) ;
170
+
171
+ lint_file
172
+ . write_all (
173
+ format ! (
174
+ "use rustc::lint::{{LintArray, LintPass, {0}}};
175
+ use rustc::declare_lint_pass;
176
+ use rustc_session::declare_tool_lint;
177
+
178
+ declare_clippy_lint! {{
179
+ pub {1},
180
+ pedantic,
181
+ \" Default lint description\"
182
+ }}
183
+
184
+ declare_lint_pass!({2} => [{1}]);
185
+
186
+ impl {0} for {2} {{}}" ,
187
+ pass_type,
188
+ lint_name. to_uppercase( ) ,
189
+ camel_case_name
190
+ )
191
+ . as_bytes ( ) ,
192
+ )
193
+ . unwrap ( ) ;
194
+ update_lints ( & UpdateMode :: Change ) ;
195
+ } ,
196
+ Err ( e) => eprintln ! ( "Unable to create lint: {}" , e) ,
197
+ }
198
+ }
199
+
82
200
fn print_lints ( ) {
83
201
let lint_list = gather_all ( ) ;
84
202
let usable_lints: Vec < Lint > = Lint :: usable_lints ( lint_list) . collect ( ) ;
0 commit comments