@@ -31,13 +31,15 @@ struct TomlCrate {
3131 versions : Option < Vec < String > > ,
3232 git_url : Option < String > ,
3333 git_hash : Option < String > ,
34+ path : Option < String > ,
3435}
3536
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
3738#[ derive( Debug , Serialize , Deserialize , Eq , Hash , PartialEq ) ]
3839enum CrateSource {
3940 CratesIo { name : String , version : String } ,
4041 Git { name : String , url : String , commit : String } ,
42+ Path { name : String , path : PathBuf } ,
4143}
4244
4345// represents the extracted sourcecode of a crate
@@ -60,6 +62,7 @@ struct ClippyWarning {
6062 column : String ,
6163 linttype : String ,
6264 message : String ,
65+ ice : bool ,
6366}
6467
6568impl std:: fmt:: Display for ClippyWarning {
@@ -111,7 +114,7 @@ impl CrateSource {
111114 } ,
112115 CrateSource :: Git { name, url, commit } => {
113116 let repo_path = {
114- let mut repo_path = PathBuf :: from ( "target/lintcheck/downloads " ) ;
117+ let mut repo_path = PathBuf :: from ( "target/lintcheck/crates " ) ;
115118 // add a -git suffix in case we have the same crate from crates.io and a git repo
116119 repo_path. push ( format ! ( "{}-git" , name) ) ;
117120 repo_path
@@ -139,6 +142,37 @@ impl CrateSource {
139142 path : repo_path,
140143 }
141144 } ,
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+ } ,
142176 }
143177 }
144178}
@@ -176,8 +210,8 @@ impl Crate {
176210 let output_lines = stdout. lines ( ) ;
177211 let warnings: Vec < ClippyWarning > = output_lines
178212 . 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: " ) )
181215 . map ( |json_msg| parse_json_message ( json_msg, & self ) )
182216 . collect ( ) ;
183217 warnings
@@ -192,8 +226,10 @@ fn build_clippy() {
192226}
193227
194228// 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 > ) {
196230 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 ( ) ;
197233 let toml_content: String =
198234 std:: fs:: read_to_string ( & toml_path) . unwrap_or_else ( |_| panic ! ( "Failed to read {}" , toml_path. display( ) ) ) ;
199235 let crate_list: CrateList =
@@ -209,6 +245,13 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
209245 // multiple Cratesources)
210246 let mut crate_sources = Vec :: new ( ) ;
211247 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+
212255 // if we have multiple versions, save each one
213256 if let Some ( ref versions) = tk. versions {
214257 versions. iter ( ) . for_each ( |ver| {
@@ -232,12 +275,15 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
232275 {
233276 eprintln ! ( "tomlkrate: {:?}" , tk) ;
234277 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" ) ;
236282 }
237283 unreachable ! ( "Failed to translate TomlCrate into CrateSource!" ) ;
238284 }
239285 } ) ;
240- crate_sources
286+ ( toml_filename , crate_sources)
241287}
242288
243289// extract interesting data from a json lint message
@@ -261,6 +307,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
261307 . into ( ) ,
262308 linttype : jmsg[ "message" ] [ "code" ] [ "code" ] . to_string ( ) . trim_matches ( '"' ) . into ( ) ,
263309 message : jmsg[ "message" ] [ "message" ] . to_string ( ) . trim_matches ( '"' ) . into ( ) ,
310+ ice : json_message. contains ( "internal compiler error: " ) ,
264311 }
265312}
266313
@@ -288,14 +335,15 @@ pub fn run(clap_config: &ArgMatches) {
288335 // download and extract the crates, then run clippy on them and collect clippys warnings
289336 // flatten into one big list of warnings
290337
291- let crates = read_crates ( clap_config. value_of ( "crates-toml" ) ) ;
338+ let ( filename , crates) = read_crates ( clap_config. value_of ( "crates-toml" ) ) ;
292339
293340 let clippy_warnings: Vec < ClippyWarning > = if let Some ( only_one_crate) = clap_config. value_of ( "only" ) {
294341 // if we don't have the specified crate in the .toml, throw an error
295342 if !crates. iter ( ) . any ( |krate| {
296343 let name = match krate {
297344 CrateSource :: CratesIo { name, .. } => name,
298345 CrateSource :: Git { name, .. } => name,
346+ CrateSource :: Path { name, .. } => name,
299347 } ;
300348 name == only_one_crate
301349 } ) {
@@ -326,6 +374,13 @@ pub fn run(clap_config: &ArgMatches) {
326374
327375 // generate some stats:
328376
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+
329384 // count lint type occurrences
330385 let mut counter: HashMap < & String , usize > = HashMap :: new ( ) ;
331386 clippy_warnings
@@ -351,5 +406,10 @@ pub fn run(clap_config: &ArgMatches) {
351406 // save the text into lintcheck-logs/logs.txt
352407 let mut text = clippy_ver; // clippy version number on top
353408 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 ( ) ;
355415}
0 commit comments