@@ -31,13 +31,15 @@ struct TomlCrate {
31
31
versions : Option < Vec < String > > ,
32
32
git_url : Option < String > ,
33
33
git_hash : Option < String > ,
34
+ path : Option < String > ,
34
35
}
35
36
36
- // represents an archive we download from crates.io
37
+ // represents an archive we download from crates.io, or a git repo, or a local repo
37
38
#[ derive( Debug , Serialize , Deserialize , Eq , Hash , PartialEq ) ]
38
39
enum CrateSource {
39
40
CratesIo { name : String , version : String } ,
40
41
Git { name : String , url : String , commit : String } ,
42
+ Path { name : String , path : PathBuf } ,
41
43
}
42
44
43
45
// represents the extracted sourcecode of a crate
@@ -60,6 +62,7 @@ struct ClippyWarning {
60
62
column : String ,
61
63
linttype : String ,
62
64
message : String ,
65
+ ice : bool ,
63
66
}
64
67
65
68
impl std:: fmt:: Display for ClippyWarning {
@@ -111,7 +114,7 @@ impl CrateSource {
111
114
} ,
112
115
CrateSource :: Git { name, url, commit } => {
113
116
let repo_path = {
114
- let mut repo_path = PathBuf :: from ( "target/lintcheck/downloads " ) ;
117
+ let mut repo_path = PathBuf :: from ( "target/lintcheck/crates " ) ;
115
118
// add a -git suffix in case we have the same crate from crates.io and a git repo
116
119
repo_path. push ( format ! ( "{}-git" , name) ) ;
117
120
repo_path
@@ -139,6 +142,37 @@ impl CrateSource {
139
142
path : repo_path,
140
143
}
141
144
} ,
145
+ CrateSource :: Path { name, path } => {
146
+ use fs_extra:: dir;
147
+
148
+ // simply copy the entire directory into our target dir
149
+ let copy_dest = PathBuf :: from ( "target/lintcheck/crates/" ) ;
150
+
151
+ // the source path of the crate we copied, ${copy_dest}/crate_name
152
+ let crate_root = copy_dest. join ( name) ; // .../crates/local_crate
153
+
154
+ if !crate_root. exists ( ) {
155
+ println ! ( "Copying {} to {}" , path. display( ) , copy_dest. display( ) ) ;
156
+
157
+ dir:: copy ( path, & copy_dest, & dir:: CopyOptions :: new ( ) ) . expect ( & format ! (
158
+ "Failed to copy from {}, to {}" ,
159
+ path. display( ) ,
160
+ crate_root. display( )
161
+ ) ) ;
162
+ } else {
163
+ println ! (
164
+ "Not copying {} to {}, destination already exists" ,
165
+ path. display( ) ,
166
+ crate_root. display( )
167
+ ) ;
168
+ }
169
+
170
+ Crate {
171
+ version : String :: from ( "local" ) ,
172
+ name : name. clone ( ) ,
173
+ path : crate_root,
174
+ }
175
+ } ,
142
176
}
143
177
}
144
178
}
@@ -176,8 +210,8 @@ impl Crate {
176
210
let output_lines = stdout. lines ( ) ;
177
211
let warnings: Vec < ClippyWarning > = output_lines
178
212
. into_iter ( )
179
- // get all clippy warnings
180
- . filter ( |line| line. contains ( "clippy::" ) )
213
+ // get all clippy warnings and ICEs
214
+ . filter ( |line| line. contains ( "clippy::" ) || line . contains ( "internal compiler error: " ) )
181
215
. map ( |json_msg| parse_json_message ( json_msg, & self ) )
182
216
. collect ( ) ;
183
217
warnings
@@ -192,8 +226,10 @@ fn build_clippy() {
192
226
}
193
227
194
228
// get a list of CrateSources we want to check from a "lintcheck_crates.toml" file.
195
- fn read_crates ( toml_path : Option < & str > ) -> Vec < CrateSource > {
229
+ fn read_crates ( toml_path : Option < & str > ) -> ( String , Vec < CrateSource > ) {
196
230
let toml_path = PathBuf :: from ( toml_path. unwrap_or ( "clippy_dev/lintcheck_crates.toml" ) ) ;
231
+ // save it so that we can use the name of the sources.toml as name for the logfile later.
232
+ let toml_filename = toml_path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
197
233
let toml_content: String =
198
234
std:: fs:: read_to_string ( & toml_path) . unwrap_or_else ( |_| panic ! ( "Failed to read {}" , toml_path. display( ) ) ) ;
199
235
let crate_list: CrateList =
@@ -209,6 +245,13 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
209
245
// multiple Cratesources)
210
246
let mut crate_sources = Vec :: new ( ) ;
211
247
tomlcrates. into_iter ( ) . for_each ( |tk| {
248
+ if let Some ( ref path) = tk. path {
249
+ crate_sources. push ( CrateSource :: Path {
250
+ name : tk. name . clone ( ) ,
251
+ path : PathBuf :: from ( path) ,
252
+ } ) ;
253
+ }
254
+
212
255
// if we have multiple versions, save each one
213
256
if let Some ( ref versions) = tk. versions {
214
257
versions. iter ( ) . for_each ( |ver| {
@@ -232,12 +275,15 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
232
275
{
233
276
eprintln ! ( "tomlkrate: {:?}" , tk) ;
234
277
if tk. git_hash . is_some ( ) != tk. git_url . is_some ( ) {
235
- panic ! ( "Encountered TomlCrate with only one of git_hash and git_url!" )
278
+ panic ! ( "Error: Encountered TomlCrate with only one of git_hash and git_url!" ) ;
279
+ }
280
+ if tk. path . is_some ( ) && ( tk. git_hash . is_some ( ) || tk. versions . is_some ( ) ) {
281
+ panic ! ( "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" ) ;
236
282
}
237
283
unreachable ! ( "Failed to translate TomlCrate into CrateSource!" ) ;
238
284
}
239
285
} ) ;
240
- crate_sources
286
+ ( toml_filename , crate_sources)
241
287
}
242
288
243
289
// extract interesting data from a json lint message
@@ -261,6 +307,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
261
307
. into ( ) ,
262
308
linttype : jmsg[ "message" ] [ "code" ] [ "code" ] . to_string ( ) . trim_matches ( '"' ) . into ( ) ,
263
309
message : jmsg[ "message" ] [ "message" ] . to_string ( ) . trim_matches ( '"' ) . into ( ) ,
310
+ ice : json_message. contains ( "internal compiler error: " ) ,
264
311
}
265
312
}
266
313
@@ -288,14 +335,15 @@ pub fn run(clap_config: &ArgMatches) {
288
335
// download and extract the crates, then run clippy on them and collect clippys warnings
289
336
// flatten into one big list of warnings
290
337
291
- let crates = read_crates ( clap_config. value_of ( "crates-toml" ) ) ;
338
+ let ( filename , crates) = read_crates ( clap_config. value_of ( "crates-toml" ) ) ;
292
339
293
340
let clippy_warnings: Vec < ClippyWarning > = if let Some ( only_one_crate) = clap_config. value_of ( "only" ) {
294
341
// if we don't have the specified crate in the .toml, throw an error
295
342
if !crates. iter ( ) . any ( |krate| {
296
343
let name = match krate {
297
344
CrateSource :: CratesIo { name, .. } => name,
298
345
CrateSource :: Git { name, .. } => name,
346
+ CrateSource :: Path { name, .. } => name,
299
347
} ;
300
348
name == only_one_crate
301
349
} ) {
@@ -326,6 +374,13 @@ pub fn run(clap_config: &ArgMatches) {
326
374
327
375
// generate some stats:
328
376
377
+ // grab crashes/ICEs, save the crate name and the ice message
378
+ let ices: Vec < ( & String , & String ) > = clippy_warnings
379
+ . iter ( )
380
+ . filter ( |warning| warning. ice )
381
+ . map ( |w| ( & w. crate_name , & w. message ) )
382
+ . collect ( ) ;
383
+
329
384
// count lint type occurrences
330
385
let mut counter: HashMap < & String , usize > = HashMap :: new ( ) ;
331
386
clippy_warnings
@@ -351,5 +406,10 @@ pub fn run(clap_config: &ArgMatches) {
351
406
// save the text into lintcheck-logs/logs.txt
352
407
let mut text = clippy_ver; // clippy version number on top
353
408
text. push_str ( & format ! ( "\n {}" , all_msgs. join( "" ) ) ) ;
354
- write ( "lintcheck-logs/logs.txt" , text) . unwrap ( ) ;
409
+ text. push_str ( "ICEs:\n " ) ;
410
+ ices. iter ( )
411
+ . for_each ( |( cratename, msg) | text. push_str ( & format ! ( "{}: '{}'" , cratename, msg) ) ) ;
412
+
413
+ let file = format ! ( "lintcheck-logs/{}_logs.txt" , filename) ;
414
+ write ( file, text) . unwrap ( ) ;
355
415
}
0 commit comments