From 562cfa8409b6edd32621f1b9493e279f4ddabbb3 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:18:18 +0200 Subject: [PATCH 001/298] Hello World From e82ff8225dc8fca484e0e6fad4714ccd965763da Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:18:43 +0200 Subject: [PATCH 002/298] Add Boilerplate --- .editorconfig | 25 +++++++++++++++++++++++++ .gitignore | 2 ++ Cargo.toml | 9 +++++++++ LICENSE | 21 +++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 LICENSE diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..3c1f41bdc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.rs] +indent_style = space +indent_size = 4 + +[*.toml] +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a9d37c560 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..2e91ea3b5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["Pascal Hertleif "] +name = "rustfix" +version = "0.1.0" + +[dependencies] +serde = "0.7.13" +serde_json = "0.7.4" +serde_macros = "0.7.13" diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..458e9c6ce --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Pascal Hertleif + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From fddc60985069d8019013eac73ce17f92e617920b Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:20:37 +0200 Subject: [PATCH 003/298] Add Clippy Example Output $ git clone https://github.com/pcwalton/libui-rs.git # HEAD is at 13299d28f69f8009be8e08e453a9b0024f153a60 $ cd libui-rs/ui/ $ cargo clippy -- -Z unstable-options --error-format json 2> clippy.json --- tests/fixtures/clippy.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/fixtures/clippy.json diff --git a/tests/fixtures/clippy.json b/tests/fixtures/clippy.json new file mode 100644 index 000000000..3ddb19613 --- /dev/null +++ b/tests/fixtures/clippy.json @@ -0,0 +1,19 @@ +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Button)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":7710,"byte_end":7771,"line_start":245,"line_end":245,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&button)","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":7710,"byte_end":7771,"line_start":245,"line_end":245,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&button)","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Button)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Button)>)(&button)"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Entry)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":10752,"byte_end":10812,"line_start":350,"line_end":350,"column_start":17,"column_end":77,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&entry);","highlight_start":17,"highlight_end":77}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":10752,"byte_end":10812,"line_start":350,"line_end":350,"column_start":17,"column_end":77,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&entry);","highlight_start":17,"highlight_end":77}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Entry)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Entry)>)(&entry);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::Entry`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":11302,"byte_end":11456,"line_start":373,"line_end":378,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Entry {","highlight_start":5,"highlight_end":28},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Entry::from_ui_control(ui_sys::uiNewEntry())","highlight_start":1,"highlight_end":57},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":11302,"byte_end":11456,"line_start":373,"line_end":378,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Entry {","highlight_start":5,"highlight_end":28},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Entry::from_ui_control(ui_sys::uiNewEntry())","highlight_start":1,"highlight_end":57},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Entry { fn default() -> Self { controls::Entry::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Entry { fn default() -> Self { controls::Entry::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Checkbox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":12643,"byte_end":12706,"line_start":415,"line_end":415,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":12643,"byte_end":12706,"line_start":415,"line_end":415,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Checkbox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Checkbox)>)(&checkbox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::Tab`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":15808,"byte_end":15956,"line_start":526,"line_end":531,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Tab {","highlight_start":5,"highlight_end":26},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Tab::from_ui_control(ui_sys::uiNewTab())","highlight_start":1,"highlight_end":53},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":15808,"byte_end":15956,"line_start":526,"line_end":531,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Tab {","highlight_start":5,"highlight_end":26},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Tab::from_ui_control(ui_sys::uiNewTab())","highlight_start":1,"highlight_end":53},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Tab { fn default() -> Self { controls::Tab::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Tab { fn default() -> Self { controls::Tab::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Spinbox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":18423,"byte_end":18485,"line_start":621,"line_end":621,"column_start":17,"column_end":79,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox);","highlight_start":17,"highlight_end":79}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":18423,"byte_end":18485,"line_start":621,"line_end":621,"column_start":17,"column_end":79,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox);","highlight_start":17,"highlight_end":79}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Spinbox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Spinbox)>)(&spinbox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::ProgressBar`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":19068,"byte_end":19240,"line_start":648,"line_end":653,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ProgressBar {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ProgressBar::from_ui_control(ui_sys::uiNewProgressBar())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":19068,"byte_end":19240,"line_start":648,"line_end":653,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ProgressBar {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ProgressBar::from_ui_control(ui_sys::uiNewProgressBar())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::ProgressBar { fn default() -> Self { controls::ProgressBar::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::ProgressBar { fn default() -> Self { controls::ProgressBar::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Slider)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":20291,"byte_end":20352,"line_start":689,"line_end":689,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&slider);","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":20291,"byte_end":20352,"line_start":689,"line_end":689,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&slider);","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Slider)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Slider)>)(&slider);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Combobox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":22291,"byte_end":22354,"line_start":758,"line_end":758,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&combobox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":22291,"byte_end":22354,"line_start":758,"line_end":758,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&combobox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Combobox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Combobox)>)(&combobox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::Combobox`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":22455,"byte_end":22618,"line_start":765,"line_end":770,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Combobox {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Combobox::from_ui_control(ui_sys::uiNewCombobox())","highlight_start":1,"highlight_end":63},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":22455,"byte_end":22618,"line_start":765,"line_end":770,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Combobox {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Combobox::from_ui_control(ui_sys::uiNewCombobox())","highlight_start":1,"highlight_end":63},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Combobox { fn default() -> Self { controls::Combobox::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Combobox { fn default() -> Self { controls::Combobox::new() } }"}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::RadioButtons`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":23357,"byte_end":23532,"line_start":796,"line_end":801,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> RadioButtons {","highlight_start":5,"highlight_end":35},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons())","highlight_start":1,"highlight_end":71},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":23357,"byte_end":23532,"line_start":796,"line_end":801,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> RadioButtons {","highlight_start":5,"highlight_end":35},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons())","highlight_start":1,"highlight_end":71},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::RadioButtons { fn default() -> Self { controls::RadioButtons::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::RadioButtons { fn default() -> Self { controls::RadioButtons::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::MultilineEntry)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":25729,"byte_end":25831,"line_start":866,"line_end":867,"column_start":17,"column_end":73,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&multiline_entry);","highlight_start":1,"highlight_end":73}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":25729,"byte_end":25831,"line_start":866,"line_end":867,"column_start":17,"column_end":73,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&multiline_entry);","highlight_start":1,"highlight_end":73}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::MultilineEntry)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::MultilineEntry)>)(&multiline_entry);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::MultilineEntry`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":26379,"byte_end":26560,"line_start":890,"line_end":895,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> MultilineEntry {","highlight_start":5,"highlight_end":37},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry())","highlight_start":1,"highlight_end":75},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":26379,"byte_end":26560,"line_start":890,"line_end":895,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> MultilineEntry {","highlight_start":5,"highlight_end":37},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry())","highlight_start":1,"highlight_end":75},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::MultilineEntry { fn default() -> Self { controls::MultilineEntry::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::MultilineEntry { fn default() -> Self { controls::MultilineEntry::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::FontButton)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":36403,"byte_end":36468,"line_start":1182,"line_end":1182,"column_start":17,"column_end":82,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&font_button);","highlight_start":17,"highlight_end":82}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":36403,"byte_end":36468,"line_start":1182,"line_end":1182,"column_start":17,"column_end":82,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&font_button);","highlight_start":17,"highlight_end":82}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::FontButton)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::FontButton)>)(&font_button);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::FontButton`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":36575,"byte_end":36744,"line_start":1189,"line_end":1194,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> FontButton {","highlight_start":5,"highlight_end":33},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" FontButton::from_ui_control(ui_sys::uiNewFontButton())","highlight_start":1,"highlight_end":67},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":36575,"byte_end":36744,"line_start":1189,"line_end":1194,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> FontButton {","highlight_start":5,"highlight_end":33},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" FontButton::from_ui_control(ui_sys::uiNewFontButton())","highlight_start":1,"highlight_end":67},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::FontButton { fn default() -> Self { controls::FontButton::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::FontButton { fn default() -> Self { controls::FontButton::new() } }"}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::ColorButton)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":38273,"byte_end":38339,"line_start":1237,"line_end":1237,"column_start":17,"column_end":83,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&color_button);","highlight_start":17,"highlight_end":83}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":38273,"byte_end":38339,"line_start":1237,"line_end":1237,"column_start":17,"column_end":83,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&color_button);","highlight_start":17,"highlight_end":83}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::ColorButton)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::ColorButton)>)(&color_button);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"you should consider adding a `Default` implementation for `controls::ColorButton`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":38447,"byte_end":38619,"line_start":1244,"line_end":1249,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ColorButton {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ColorButton::from_ui_control(ui_sys::uiNewColorButton())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":38447,"byte_end":38619,"line_start":1244,"line_end":1249,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ColorButton {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ColorButton::from_ui_control(ui_sys::uiNewColorButton())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::ColorButton { fn default() -> Self { controls::ColorButton::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::ColorButton { fn default() -> Self { controls::ColorButton::new() } }"}],"rendered":null} +{"message":"item `draw::FontFamilies` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. Consider adding one, #[warn(len_without_is_empty)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/draw.rs","byte_start":53542,"byte_end":53720,"line_start":504,"line_end":509,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn len(&self) -> u64 {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ui_sys::uiDrawFontFamiliesNumFamilies(self.ui_draw_font_families)","highlight_start":1,"highlight_end":78},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} +{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/menus.rs","byte_start":63327,"byte_end":63432,"line_start":50,"line_end":51,"column_start":17,"column_end":76,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&menu_item, &window);","highlight_start":1,"highlight_end":76}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/menus.rs","byte_start":63327,"byte_end":63432,"line_start":50,"line_end":51,"column_start":17,"column_end":76,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&menu_item, &window);","highlight_start":1,"highlight_end":76}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>)(&menu_item, &window);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} From d452574d063a8c870f8340e2cb635c1c4eb254e9 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:21:19 +0200 Subject: [PATCH 004/298] Copy Diagnostic Structs from rustc --- src/diagnostics.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 9 ++++++ src/tests.rs | 18 +++++++++++ 3 files changed, 105 insertions(+) create mode 100644 src/diagnostics.rs create mode 100644 src/lib.rs create mode 100644 src/tests.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 000000000..d1db59ec9 --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,78 @@ +//! Rustc Diagnostic JSON Output +//! +//! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) + +#[derive(Serialize, Deserialize, Debug)] +pub struct Diagnostic { + /// The primary error message. + message: String, + code: Option, + /// "error: internal compiler error", "error", "warning", "note", "help". + level: String, + spans: Vec, + /// Associated diagnostic messages. + children: Vec, + /// The message as rustc would render it. Currently this is only + /// `Some` for "suggestions", but eventually it will include all + /// snippets. + rendered: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +struct DiagnosticSpan { + file_name: String, + byte_start: u32, + byte_end: u32, + /// 1-based. + line_start: usize, + line_end: usize, + /// 1-based, character offset. + column_start: usize, + column_end: usize, + /// Is this a "primary" span -- meaning the point, or one of the points, + /// where the error occurred? + is_primary: bool, + /// Source text from the start of line_start to the end of line_end. + text: Vec, + /// Label that should be placed at this location (if any) + label: Option, + /// If we are suggesting a replacement, this will contain text + /// that should be sliced in atop this span. You may prefer to + /// load the fully rendered version from the parent `Diagnostic`, + /// however. + suggested_replacement: Option, + /// Macro invocations that created the code at this span, if any. + expansion: Option>, +} + +#[derive(Serialize, Deserialize, Debug)] +struct DiagnosticSpanLine { + text: String, + + /// 1-based, character offset in self.text. + highlight_start: usize, + + highlight_end: usize, +} + +#[derive(Serialize, Deserialize, Debug)] +struct DiagnosticSpanMacroExpansion { + /// span where macro was applied to generate this code; note that + /// this may itself derive from a macro (if + /// `span.expansion.is_some()`) + span: DiagnosticSpan, + + /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") + macro_decl_name: String, + + /// span where macro was defined (if known) + def_site_span: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +struct DiagnosticCode { + /// The code itself. + code: String, + /// An explanation for the code. + explanation: Option, +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..9e0e8e561 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +#![feature(custom_derive, plugin)] +#![plugin(serde_macros)] + +extern crate serde_json; + +pub mod diagnostics; + +#[cfg(test)] +mod tests; diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 000000000..675b93739 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,18 @@ +use std::fs::File; +use serde_json; + +fn not_empty(s: &str) -> bool { + s.trim().len() > 0 +} + +#[test] +fn clippy() { + let file = File::open("tests/fixtures/clippy.json"); + let mut buffer = String::new(); + file.read_to_string(&mut buffer); + + for line in buffer.lines().filter(not_empty) { + let deserialized: ::diagnostics::Diagnostic = serde_json::from_str(&line).unwrap(); + println!("{:?}", deserialized.message); + } +} From 66c95726874ade6e729c96a79c552a3f7b87667a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:22:54 +0200 Subject: [PATCH 005/298] Write simple prototype in JS Couldn't get serde to work with recursive `Diagnostic`, so I pushed that out in JS instead. Code structure should work pretty much the same in Rust. --- src/main.js | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/main.js diff --git a/src/main.js b/src/main.js new file mode 100644 index 000000000..f5fe8a1df --- /dev/null +++ b/src/main.js @@ -0,0 +1,72 @@ +/// Just a prototype, the final thing should be in Rust + +const fs = require('fs'); +const args = process.argv.slice(2); + +if (!args[0]) { + console.log("Usage: node src/main.js json-file"); + process.exit(1); +} + +/// Strips the indent of the first line form all other lines +function normalizeIndent(lines) { + if (!lines || !lines[0]) { return []; } + const matches = lines[0].match(/^(\s*)(.*)$/); + const leadingWhitespace = matches[1]; + + return lines + .map(line => line.replace(new RegExp("^" + leadingWhitespace), "")); +} + +function collectSpan(acc, message, span) { + if (!span.suggested_replacement) { return; } + acc.push({ + message: message, + file_name: span.file_name, + range: [ + [span.line_start, span.column_start], + [span.line_end, span.column_end], + ], + text: normalizeIndent((span.text || []).map(x => x.text)), + replacement: span.suggested_replacement, + }) +} + +function collectSuggestions(acc, diagnostic, parent_message) { + const message = typeof parent_message === 'string' ? + parent_message : + diagnostic.message; + + (diagnostic.spans || []) + .forEach(span => collectSpan(acc, message, span)); + + (diagnostic.children || []) + .forEach(child => collectSuggestions(acc, child, message)); + + return acc; +} + + +const file = fs.readFileSync(args[0]).toString('utf8'); +const lines = file.split('\n'); +const diagnostics = lines + .filter(line => line.trim().length > 0) + .map(line => JSON.parse(line)); +const suggestions = diagnostics + .reduce(collectSuggestions, []); + +suggestions.forEach(suggestion => { + console.log("___________________________________________"); + console.log(""); + console.log(suggestion.message); + console.log(""); + console.log("You might want to replace"); + console.log(""); + console.log(suggestion.text + .map(line => "- " + line).join("\n")); + console.log(""); + console.log("with"); + console.log(""); + console.log("+ " + suggestion.replacement); + console.log(""); +}); From 0052c87b13896082a639487ea459cfea71acf9d0 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 11:42:01 +0200 Subject: [PATCH 006/298] Comments --- src/main.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main.js b/src/main.js index f5fe8a1df..8c2a7bc0d 100644 --- a/src/main.js +++ b/src/main.js @@ -1,12 +1,9 @@ -/// Just a prototype, the final thing should be in Rust +//! Read rustc JSON output and parse out the lints' suggestions to automatically +//! apply them. +//! +//! Just a prototype, the final thing should be in Rust const fs = require('fs'); -const args = process.argv.slice(2); - -if (!args[0]) { - console.log("Usage: node src/main.js json-file"); - process.exit(1); -} /// Strips the indent of the first line form all other lines function normalizeIndent(lines) { @@ -18,6 +15,7 @@ function normalizeIndent(lines) { .map(line => line.replace(new RegExp("^" + leadingWhitespace), "")); } +/// Map a span to a suggestion. function collectSpan(acc, message, span) { if (!span.suggested_replacement) { return; } acc.push({ @@ -27,11 +25,13 @@ function collectSpan(acc, message, span) { [span.line_start, span.column_start], [span.line_end, span.column_end], ], + byte_range: [span.byte_start, span.byte_end], text: normalizeIndent((span.text || []).map(x => x.text)), replacement: span.suggested_replacement, - }) + }); } +/// Collect suggestions from diagnostic messages, and their spans and children. function collectSuggestions(acc, diagnostic, parent_message) { const message = typeof parent_message === 'string' ? parent_message : @@ -46,6 +46,14 @@ function collectSuggestions(acc, diagnostic, parent_message) { return acc; } +// Read some JSON file and parse its suggestions + +const args = process.argv.slice(2); + +if (!args[0]) { + console.log("Usage: node src/main.js json-file"); + process.exit(1); +} const file = fs.readFileSync(args[0]).toString('utf8'); const lines = file.split('\n'); From a1245c324e68be1a506943a68448908fcb1947b5 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 12:04:15 +0200 Subject: [PATCH 007/298] Make Serde Deserialize Our Nice Diagnostics --- src/diagnostics.rs | 62 +++++++++++++++++++++++----------------------- src/tests.rs | 7 +++--- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d1db59ec9..4b7a7b1d9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -5,74 +5,74 @@ #[derive(Serialize, Deserialize, Debug)] pub struct Diagnostic { /// The primary error message. - message: String, - code: Option, + pub message: String, + pub code: Option, /// "error: internal compiler error", "error", "warning", "note", "help". - level: String, - spans: Vec, + pub level: String, + pub spans: Vec, /// Associated diagnostic messages. - children: Vec, + pub children: Vec, /// The message as rustc would render it. Currently this is only /// `Some` for "suggestions", but eventually it will include all /// snippets. - rendered: Option, + pub rendered: Option, } #[derive(Serialize, Deserialize, Debug)] -struct DiagnosticSpan { - file_name: String, - byte_start: u32, - byte_end: u32, +pub struct DiagnosticSpan { + pub file_name: String, + pub byte_start: u32, + pub byte_end: u32, /// 1-based. - line_start: usize, - line_end: usize, + pub line_start: usize, + pub line_end: usize, /// 1-based, character offset. - column_start: usize, - column_end: usize, + pub column_start: usize, + pub column_end: usize, /// Is this a "primary" span -- meaning the point, or one of the points, /// where the error occurred? - is_primary: bool, + pub is_primary: bool, /// Source text from the start of line_start to the end of line_end. - text: Vec, + pub text: Vec, /// Label that should be placed at this location (if any) - label: Option, + pub label: Option, /// If we are suggesting a replacement, this will contain text /// that should be sliced in atop this span. You may prefer to /// load the fully rendered version from the parent `Diagnostic`, /// however. - suggested_replacement: Option, + pub suggested_replacement: Option, /// Macro invocations that created the code at this span, if any. - expansion: Option>, + #[serde(bound="")] + pub expansion: Option>, } #[derive(Serialize, Deserialize, Debug)] -struct DiagnosticSpanLine { - text: String, +pub struct DiagnosticSpanLine { + pub text: String, /// 1-based, character offset in self.text. - highlight_start: usize, - - highlight_end: usize, + pub highlight_start: usize, + pub highlight_end: usize, } #[derive(Serialize, Deserialize, Debug)] -struct DiagnosticSpanMacroExpansion { +pub struct DiagnosticSpanMacroExpansion { /// span where macro was applied to generate this code; note that /// this may itself derive from a macro (if /// `span.expansion.is_some()`) - span: DiagnosticSpan, + pub span: DiagnosticSpan, /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") - macro_decl_name: String, + pub macro_decl_name: String, /// span where macro was defined (if known) - def_site_span: Option, + pub def_site_span: Option, } #[derive(Serialize, Deserialize, Debug)] -struct DiagnosticCode { +pub struct DiagnosticCode { /// The code itself. - code: String, + pub code: String, /// An explanation for the code. - explanation: Option, + pub explanation: Option, } diff --git a/src/tests.rs b/src/tests.rs index 675b93739..852e4d5ec 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,15 +1,16 @@ use std::fs::File; +use std::io::Read; use serde_json; -fn not_empty(s: &str) -> bool { +fn not_empty(s: &&str) -> bool { s.trim().len() > 0 } #[test] fn clippy() { - let file = File::open("tests/fixtures/clippy.json"); + let mut file = File::open("tests/fixtures/clippy.json").unwrap(); let mut buffer = String::new(); - file.read_to_string(&mut buffer); + file.read_to_string(&mut buffer).unwrap(); for line in buffer.lines().filter(not_empty) { let deserialized: ::diagnostics::Diagnostic = serde_json::from_str(&line).unwrap(); From 75c8a9821d4cce2db5dc3f3291d1c8fda0fabaed Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 14:52:01 +0200 Subject: [PATCH 008/298] Trivial collection of suggestions --- Cargo.toml | 1 + src/diagnostics.rs | 4 +-- src/lib.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++ src/tests.rs | 4 +-- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2e91ea3b5..7f01ae645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ name = "rustfix" version = "0.1.0" [dependencies] +quick-error = "1.1.0" serde = "0.7.13" serde_json = "0.7.4" serde_macros = "0.7.13" diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4b7a7b1d9..50a4551bf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -21,8 +21,8 @@ pub struct Diagnostic { #[derive(Serialize, Deserialize, Debug)] pub struct DiagnosticSpan { pub file_name: String, - pub byte_start: u32, - pub byte_end: u32, + pub byte_start: usize, + pub byte_end: usize, /// 1-based. pub line_start: usize, pub line_end: usize, diff --git a/src/lib.rs b/src/lib.rs index 9e0e8e561..475975266 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,69 @@ extern crate serde_json; pub mod diagnostics; +use diagnostics::{Diagnostic, DiagnosticSpan}; + +#[derive(Debug)] +struct LinePosition(usize, usize); + +#[derive(Debug)] +pub struct Suggestion { + message: String, + file_name: String, + line_range: (LinePosition, LinePosition), + byte_range: (usize, usize), + text: String, + replacement: String, +} + +// fn normalize_indent<'a, T: Iterator>(lines: &T) +// -> Option +// { +// if let Some(first_line) = lines.clone().next() { +// let leading_whitespace = +// first_line.text.chars() +// .take_while(|&c| char::is_whitespace(c)) +// .count(); + +// Some(lines.clone() +// .map(|line| String::from(&line.text[leading_whitespace..])) +// .collect::>() +// .join("\n")) +// } else { +// None +// } +// } + +fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { + if let Some(replacement) = span.suggested_replacement.clone() { + Some(Suggestion { + message: message.into(), + file_name: span.file_name.clone(), + line_range: (LinePosition(span.line_start, span.column_start), + LinePosition(span.line_end, span.column_end)), + byte_range: (span.byte_start, span.byte_end), + text: span.text.iter().map(|ref x| x.text.clone()).collect::>().join("\n"), + replacement: replacement, + }) + } else { + None + } +} + +pub fn collect_suggestions(diagnostic: &Diagnostic, parent_message: Option) + -> Vec +{ + let message = parent_message.unwrap_or(diagnostic.message.clone()); + let mut suggestions = vec![]; + + suggestions.extend(diagnostic.spans.iter() + .flat_map(|span| collect_span(&message, span))); + + suggestions.extend(diagnostic.children.iter() + .flat_map(|children| collect_suggestions(children, Some(message.clone())))); + + suggestions +} #[cfg(test)] mod tests; diff --git a/src/tests.rs b/src/tests.rs index 852e4d5ec..d356e5de6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -13,7 +13,7 @@ fn clippy() { file.read_to_string(&mut buffer).unwrap(); for line in buffer.lines().filter(not_empty) { - let deserialized: ::diagnostics::Diagnostic = serde_json::from_str(&line).unwrap(); - println!("{:?}", deserialized.message); + let deserialized: super::diagnostics::Diagnostic = serde_json::from_str(&line).unwrap(); + println!("{:?}", super::collect_suggestions(&deserialized, None)); } } From 70526f09068d6a15af1ec74e94b1c228dbe62bbc Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 14:52:07 +0200 Subject: [PATCH 009/298] Add simple CLI --- src/main.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/main.rs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 000000000..f584702c6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,57 @@ +#[macro_use] +extern crate quick_error; +extern crate serde_json; + +extern crate rustfix; + +use std::fs::File; +use std::io::{Read, Write}; + +quick_error! { + /// All possible errors in programm lifecycle + #[derive(Debug)] + pub enum ProgramError { + /// Missing File + NoFile { + description("No input file given") + } + /// Error while dealing with file or stdin/stdout + Io(err: std::io::Error) { + from() + cause(err) + description(err.description()) + } + /// Error with deserialization + Serde(err: serde_json::Error) { + from() + cause(err) + description(err.description()) + } + } +} + +fn try_main() -> Result<(), ProgramError> { + let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); + let mut file = try!(File::open(file_name)); + let mut buffer = String::new(); + try!(file.read_to_string(&mut buffer)); + + for line in buffer.lines().filter(not_empty) { + let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); + println!("{:?}", rustfix::collect_suggestions(&deserialized, None)); + } + + Ok(()) +} + +fn main() { + if let Err(error) = try_main() { + writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); + std::process::exit(1); + } +} + + +fn not_empty(s: &&str) -> bool { + s.trim().len() > 0 +} From 9d1efe05924f9af3bc15668dd249b03fb398c79f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 15:32:05 +0200 Subject: [PATCH 010/298] Fancy Output in Color --- Cargo.toml | 1 + src/lib.rs | 33 ++++++++++++++------ src/main.rs | 87 ++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 95 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f01ae645..0a90650e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ name = "rustfix" version = "0.1.0" [dependencies] +colored = "1.2.0" quick-error = "1.1.0" serde = "0.7.13" serde_json = "0.7.4" diff --git a/src/lib.rs b/src/lib.rs index 475975266..df7194c27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,16 +7,31 @@ pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; #[derive(Debug)] -struct LinePosition(usize, usize); +pub struct LinePosition(pub usize, pub usize); + +impl std::fmt::Display for LinePosition { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}:{}", self.0, self.1) + } +} + +#[derive(Debug)] +pub struct LineRange(pub LinePosition, pub LinePosition); + +impl std::fmt::Display for LineRange { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}-{}", self.0, self.1) + } +} #[derive(Debug)] pub struct Suggestion { - message: String, - file_name: String, - line_range: (LinePosition, LinePosition), - byte_range: (usize, usize), - text: String, - replacement: String, + pub message: String, + pub file_name: String, + pub line_range: LineRange, + pub byte_range: (usize, usize), + pub text: String, + pub replacement: String, } // fn normalize_indent<'a, T: Iterator>(lines: &T) @@ -42,8 +57,8 @@ fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { Some(Suggestion { message: message.into(), file_name: span.file_name.clone(), - line_range: (LinePosition(span.line_start, span.column_start), - LinePosition(span.line_end, span.column_end)), + line_range: LineRange(LinePosition(span.line_start, span.column_start), + LinePosition(span.line_end, span.column_end)), byte_range: (span.byte_start, span.byte_end), text: span.text.iter().map(|ref x| x.text.clone()).collect::>().join("\n"), replacement: replacement, diff --git a/src/main.rs b/src/main.rs index f584702c6..cdd2abf08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,49 @@ #[macro_use] extern crate quick_error; extern crate serde_json; +extern crate colored; extern crate rustfix; use std::fs::File; use std::io::{Read, Write}; +use colored::Colorize; + +fn main() { + if let Err(error) = try_main() { + writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); + std::process::exit(1); + } +} + +fn try_main() -> Result<(), ProgramError> { + let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); + let file = try!(read_file_to_string(&file_name)); + + for line in file.lines().filter(not_empty) { + let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); + for suggestion in &rustfix::collect_suggestions(&deserialized, None) { + println!( + "\n{info}: {message}\n\ + {arrow} {file}:{range}\n\ + {suggestion}\n\n\ + {text}\n\n\ + {with}\n\n\ + {replacement}\n", + info="Info".green().bold(), + message=split_at_lint_name(&suggestion.message), + arrow="-->".blue().bold(), + suggestion="Suggestion - Replace:".yellow().bold(), + file=suggestion.file_name, range=suggestion.line_range, + text=indent(&reset_indent(&suggestion.text)), + with="with:".yellow().bold(), + replacement=indent(&suggestion.replacement) + ); + } + } + + Ok(()) +} quick_error! { /// All possible errors in programm lifecycle @@ -30,28 +68,43 @@ quick_error! { } } -fn try_main() -> Result<(), ProgramError> { - let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); +// Helpers +// ------- + +fn read_file_to_string(file_name: &str) -> Result { let mut file = try!(File::open(file_name)); let mut buffer = String::new(); try!(file.read_to_string(&mut buffer)); - - for line in buffer.lines().filter(not_empty) { - let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); - println!("{:?}", rustfix::collect_suggestions(&deserialized, None)); - } - - Ok(()) + Ok(buffer) } -fn main() { - if let Err(error) = try_main() { - writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); - std::process::exit(1); - } -} - - fn not_empty(s: &&str) -> bool { s.trim().len() > 0 } + +fn split_at_lint_name(s: &str) -> String { + s.split(", #[") + .collect::>() + .join("\n #[") +} + +fn reset_indent(s: &str) -> String { + let leading_whitespace = + s.lines() + .nth(0).unwrap_or("") + .chars() + .take_while(|&c| char::is_whitespace(c)) + .count(); + + s.lines() + .map(|line| String::from(&line[leading_whitespace..])) + .collect::>() + .join("\n") +} + +fn indent(s: &str) -> String { + s.lines() + .map(|l| format!(" {}", l)) + .collect::>() + .join("\n") +} From 89b2cc1b55c751b5dc6ff1f53774483eac6fca99 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 15:49:35 +0200 Subject: [PATCH 011/298] Interactivity Now only the hard part is missing! --- src/main.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index cdd2abf08..eec8dc0b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ use std::fs::File; use std::io::{Read, Write}; use colored::Colorize; +const USER_OPTIONS: &'static str = "What do you want to do? [r]eplace/[s]kip/[q]uit"; + fn main() { if let Err(error) = try_main() { writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); @@ -20,9 +22,9 @@ fn try_main() -> Result<(), ProgramError> { let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); let file = try!(read_file_to_string(&file_name)); - for line in file.lines().filter(not_empty) { + 'diagnostics: for line in file.lines().filter(not_empty) { let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); - for suggestion in &rustfix::collect_suggestions(&deserialized, None) { + 'suggestions: for suggestion in &rustfix::collect_suggestions(&deserialized, None) { println!( "\n{info}: {message}\n\ {arrow} {file}:{range}\n\ @@ -39,6 +41,33 @@ fn try_main() -> Result<(), ProgramError> { with="with:".yellow().bold(), replacement=indent(&suggestion.replacement) ); + + 'userinput: loop { + println!("{prompt} {user_options}", + prompt="==>".green().bold(), user_options=USER_OPTIONS.green()); + + let mut input = String::new(); + try!(std::io::stdin().read_line(&mut input)); + + match input.trim() { + "q" => { + println!("Thanks for playing."); + break 'diagnostics; + } + "s" => { + println!("Skipped."); + continue 'suggestions; + } + "r" => { + unimplemented!(); + }, + _ => { + println!("{error}: I didn't get that. {user_options}", + error="Error".red().bold(), user_options=USER_OPTIONS); + continue 'userinput; + } + } + } } } From f9370d2a368f8b556332ab2af6cfe5d5e464b6de Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 16:29:47 +0200 Subject: [PATCH 012/298] Add Complete libui-rs sources as fixture Probably not the best idea, but it works for now --- src/lib.rs | 21 - src/tests.rs | 19 - tests/fixtures/{ => libui-rs}/clippy.json | 0 tests/fixtures/libui-rs/src/controls.rs | 1259 +++++++++++++++++++++ tests/fixtures/libui-rs/src/draw.rs | 710 ++++++++++++ tests/fixtures/libui-rs/src/ffi_utils.rs | 74 ++ tests/fixtures/libui-rs/src/lib.rs | 28 + tests/fixtures/libui-rs/src/menus.rs | 144 +++ tests/fixtures/libui-rs/src/ui.rs | 134 +++ tests/fixtures/libui-rs/src/windows.rs | 119 ++ tests/libui.rs | 3 + 11 files changed, 2471 insertions(+), 40 deletions(-) delete mode 100644 src/tests.rs rename tests/fixtures/{ => libui-rs}/clippy.json (100%) create mode 100644 tests/fixtures/libui-rs/src/controls.rs create mode 100644 tests/fixtures/libui-rs/src/draw.rs create mode 100644 tests/fixtures/libui-rs/src/ffi_utils.rs create mode 100644 tests/fixtures/libui-rs/src/lib.rs create mode 100644 tests/fixtures/libui-rs/src/menus.rs create mode 100644 tests/fixtures/libui-rs/src/ui.rs create mode 100644 tests/fixtures/libui-rs/src/windows.rs create mode 100644 tests/libui.rs diff --git a/src/lib.rs b/src/lib.rs index df7194c27..f5df264cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,24 +34,6 @@ pub struct Suggestion { pub replacement: String, } -// fn normalize_indent<'a, T: Iterator>(lines: &T) -// -> Option -// { -// if let Some(first_line) = lines.clone().next() { -// let leading_whitespace = -// first_line.text.chars() -// .take_while(|&c| char::is_whitespace(c)) -// .count(); - -// Some(lines.clone() -// .map(|line| String::from(&line.text[leading_whitespace..])) -// .collect::>() -// .join("\n")) -// } else { -// None -// } -// } - fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { if let Some(replacement) = span.suggested_replacement.clone() { Some(Suggestion { @@ -82,6 +64,3 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, parent_message: Option bool { - s.trim().len() > 0 -} - -#[test] -fn clippy() { - let mut file = File::open("tests/fixtures/clippy.json").unwrap(); - let mut buffer = String::new(); - file.read_to_string(&mut buffer).unwrap(); - - for line in buffer.lines().filter(not_empty) { - let deserialized: super::diagnostics::Diagnostic = serde_json::from_str(&line).unwrap(); - println!("{:?}", super::collect_suggestions(&deserialized, None)); - } -} diff --git a/tests/fixtures/clippy.json b/tests/fixtures/libui-rs/clippy.json similarity index 100% rename from tests/fixtures/clippy.json rename to tests/fixtures/libui-rs/clippy.json diff --git a/tests/fixtures/libui-rs/src/controls.rs b/tests/fixtures/libui-rs/src/controls.rs new file mode 100644 index 000000000..569927633 --- /dev/null +++ b/tests/fixtures/libui-rs/src/controls.rs @@ -0,0 +1,1259 @@ +//! Functions and types related to widgets. + +use draw; +use ffi_utils::{self, Text}; +use libc::{c_int, c_void}; +use std::ffi::CString; +use std::mem; +use std::ptr; +use ui_sys::{self, uiArea, uiAreaDrawParams, uiAreaHandler, uiAreaKeyEvent, uiAreaMouseEvent}; +use ui_sys::{uiBox, uiButton, uiCheckbox, uiColorButton, uiCombobox, uiControl, uiDateTimePicker}; +use ui_sys::{uiEntry, uiFontButton, uiGroup, uiLabel, uiMultilineEntry, uiProgressBar}; +use ui_sys::{uiRadioButtons, uiSeparator, uiSlider, uiSpinbox, uiTab}; + +pub use ui_sys::uiExtKey as ExtKey; + +// Defines a new control, creating a Rust wrapper, a `Deref` implementation, and a destructor. +// An example of use: +// +// define_control!(Slider, uiSlider, ui_slider) +#[macro_export] +macro_rules! define_control { + ($rust_type:ident, $ui_type:ident, $ui_field:ident) => { + pub struct $rust_type { + $ui_field: *mut $ui_type, + } + + impl ::std::ops::Deref for $rust_type { + type Target = ::controls::Control; + + #[inline] + fn deref(&self) -> &::controls::Control { + // FIXME(pcwalton): $10 says this is undefined behavior. How do I make it not so? + unsafe { + mem::transmute::<&$rust_type, &::controls::Control>(self) + } + } + } + + impl Drop for $rust_type { + #[inline] + fn drop(&mut self) { + // For now this does nothing, but in the future, when `libui` supports proper + // memory management, this will likely need to twiddle reference counts. + } + } + + impl Clone for $rust_type { + #[inline] + fn clone(&self) -> $rust_type { + $rust_type { + $ui_field: self.$ui_field, + } + } + } + + impl Into for $rust_type { + #[inline] + fn into(self) -> Control { + unsafe { + let control = Control::from_ui_control(self.$ui_field as *mut uiControl); + mem::forget(self); + control + } + } + } + + impl $rust_type { + #[inline] + pub unsafe fn from_ui_control($ui_field: *mut $ui_type) -> $rust_type { + $rust_type { + $ui_field: $ui_field + } + } + } + } +} + +pub struct Control { + ui_control: *mut uiControl, +} + +impl Drop for Control { + #[inline] + fn drop(&mut self) { + // For now this does nothing, but in the future, when `libui` supports proper memory + // management, this will likely need to twiddle reference counts. + } +} + +impl Clone for Control { + #[inline] + fn clone(&self) -> Control { + Control { + ui_control: self.ui_control, + } + } +} + +impl Control { + /// Creates a new `Control` object from an existing `uiControl`. + #[inline] + pub unsafe fn from_ui_control(ui_control: *mut uiControl) -> Control { + Control { + ui_control: ui_control, + } + } + + #[inline] + pub fn as_ui_control(&self) -> *mut uiControl { + self.ui_control + } + + /// Destroys a control. Any use of the control after this is use-after-free; therefore, this + /// is marked unsafe. + #[inline] + pub unsafe fn destroy(&self) { + // Don't check for initialization here since this can be run during deinitialization. + ui_sys::uiControlDestroy(self.ui_control) + } + + #[inline] + pub fn handle(&self) -> usize { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlHandle(self.ui_control) + } + } + + #[inline] + pub fn parent(&self) -> Option { + ffi_utils::ensure_initialized(); + unsafe { + let ui_control = ui_sys::uiControlParent(self.ui_control); + if ui_control.is_null() { + None + } else { + Some(Control::from_ui_control(ui_control)) + } + } + } + + #[inline] + pub unsafe fn set_parent(&self, parent: Option<&Control>) { + ffi_utils::ensure_initialized(); + ui_sys::uiControlSetParent(self.ui_control, + match parent { + None => ptr::null_mut(), + Some(parent) => parent.ui_control, + }) + } + + #[inline] + pub fn toplevel(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlToplevel(self.ui_control) != 0 + } + } + + #[inline] + pub fn visible(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlVisible(self.ui_control) != 0 + } + } + + #[inline] + pub fn show(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlShow(self.ui_control) + } + } + + #[inline] + pub fn hide(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlHide(self.ui_control) + } + } + + #[inline] + pub fn enabled(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlEnabled(self.ui_control) != 0 + } + } + + #[inline] + pub fn enable(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlEnable(self.ui_control) + } + } + + #[inline] + pub fn disable(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiControlDisable(self.ui_control) + } + } +} + +define_control!(Button, uiButton, ui_button); + +impl Button { + #[inline] + pub fn text(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiButtonText(self.ui_button)) + } + } + + #[inline] + pub fn set_text(&self, text: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + ui_sys::uiButtonSetText(self.ui_button, c_string.as_ptr()) + } + } + + #[inline] + pub fn on_clicked(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiButtonOnClicked(self.ui_button, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(button: *mut uiButton, data: *mut c_void) { + unsafe { + let button = Button { + ui_button: button, + }; + mem::transmute::<*mut c_void, &mut Box>(data)(&button) + } + } + } + + #[inline] + pub fn new(text: &str) -> Button { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + Button::from_ui_control(ui_sys::uiNewButton(c_string.as_ptr())) + } + } +} + +define_control!(BoxControl, uiBox, ui_box); + +impl BoxControl { + #[inline] + pub fn append(&self, child: Control, stretchy: bool) { + ffi_utils::ensure_initialized(); + unsafe { + assert!(child.parent().is_none()); + ui_sys::uiBoxAppend(self.ui_box, child.ui_control, stretchy as c_int) + } + } + + /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it + /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a + /// separate list of children ourselves… + #[inline] + pub fn delete(&self, index: u64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiBoxDelete(self.ui_box, index) + } + } + + #[inline] + pub fn padded(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiBoxPadded(self.ui_box) != 0 + } + } + + #[inline] + pub fn set_padded(&self, padded: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiBoxSetPadded(self.ui_box, padded as c_int) + } + } + + #[inline] + pub fn new_horizontal() -> BoxControl { + ffi_utils::ensure_initialized(); + unsafe { + BoxControl::from_ui_control(ui_sys::uiNewHorizontalBox()) + } + } + + #[inline] + pub fn new_vertical() -> BoxControl { + ffi_utils::ensure_initialized(); + unsafe { + BoxControl::from_ui_control(ui_sys::uiNewVerticalBox()) + } + } +} + +define_control!(Entry, uiEntry, ui_entry); + +impl Entry { + #[inline] + pub fn text(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiEntryText(self.ui_entry)) + } + } + + #[inline] + pub fn set_text(&self, text: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + ui_sys::uiEntrySetText(self.ui_entry, c_string.as_ptr()) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiEntryOnChanged(self.ui_entry, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { + unsafe { + let entry = Entry::from_ui_control(entry); + mem::transmute::<*mut c_void, &mut Box>(data)(&entry); + mem::forget(entry); + } + } + } + + #[inline] + pub fn read_only(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiEntryReadOnly(self.ui_entry) != 0 + } + } + + #[inline] + pub fn set_read_only(&self, readonly: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiEntrySetReadOnly(self.ui_entry, readonly as c_int) + } + } + + #[inline] + pub fn new() -> Entry { + ffi_utils::ensure_initialized(); + unsafe { + Entry::from_ui_control(ui_sys::uiNewEntry()) + } + } +} + +define_control!(Checkbox, uiCheckbox, ui_checkbox); + +impl Checkbox { + #[inline] + pub fn text(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiCheckboxText(self.ui_checkbox)) + } + } + + #[inline] + pub fn set_text(&self, text: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + ui_sys::uiCheckboxSetText(self.ui_checkbox, c_string.as_ptr()) + } + } + + #[inline] + pub fn on_toggled(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiCheckboxOnToggled(self.ui_checkbox, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(checkbox: *mut uiCheckbox, data: *mut c_void) { + unsafe { + let checkbox = Checkbox::from_ui_control(checkbox); + mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); + mem::forget(checkbox) + } + } + } + + #[inline] + pub fn checked(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiCheckboxChecked(self.ui_checkbox) != 0 + } + } + + #[inline] + pub fn set_checked(&self, checked: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiCheckboxSetChecked(self.ui_checkbox, checked as c_int) + } + } + + #[inline] + pub fn new(text: &str) -> Checkbox { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + Checkbox::from_ui_control(ui_sys::uiNewCheckbox(c_string.as_ptr())) + } + } +} + +define_control!(Label, uiLabel, ui_label); + +impl Label { + #[inline] + pub fn text(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiLabelText(self.ui_label)) + } + } + + #[inline] + pub fn set_text(&self, text: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + ui_sys::uiLabelSetText(self.ui_label, c_string.as_ptr()) + } + } + + #[inline] + pub fn new(text: &str) -> Label { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + Label::from_ui_control(ui_sys::uiNewLabel(c_string.as_ptr())) + } + } +} + +define_control!(Tab, uiTab, ui_tab); + +impl Tab { + #[inline] + pub fn append(&self, name: &str, control: Control) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + ui_sys::uiTabAppend(self.ui_tab, c_string.as_ptr(), control.ui_control) + } + } + + #[inline] + pub fn insert_at(&self, name: &str, before: u64, control: Control) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + ui_sys::uiTabInsertAt(self.ui_tab, c_string.as_ptr(), before, control.ui_control) + } + } + + /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it + /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a + /// separate list of children ourselves… + #[inline] + pub fn delete(&self, index: u64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiTabDelete(self.ui_tab, index) + } + } + + #[inline] + pub fn margined(&self, page: u64) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiTabMargined(self.ui_tab, page) != 0 + } + } + + #[inline] + pub fn set_margined(&self, page: u64, margined: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiTabSetMargined(self.ui_tab, page, margined as c_int) + } + } + + #[inline] + pub fn new() -> Tab { + ffi_utils::ensure_initialized(); + unsafe { + Tab::from_ui_control(ui_sys::uiNewTab()) + } + } +} + +define_control!(Group, uiGroup, ui_group); + +impl Group { + #[inline] + pub fn title(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiGroupTitle(self.ui_group)) + } + } + + #[inline] + pub fn set_title(&self, title: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); + ui_sys::uiGroupSetTitle(self.ui_group, c_string.as_ptr()) + } + } + + #[inline] + pub fn set_child(&self, child: Control) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiGroupSetChild(self.ui_group, child.ui_control) + } + } + + #[inline] + pub fn margined(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiGroupMargined(self.ui_group) != 0 + } + } + + #[inline] + pub fn set_margined(&self, margined: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiGroupSetMargined(self.ui_group, margined as c_int) + } + } + + #[inline] + pub fn new(title: &str) -> Group { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); + Group::from_ui_control(ui_sys::uiNewGroup(c_string.as_ptr())) + } + } +} + +define_control!(Spinbox, uiSpinbox, ui_spinbox); + +impl Spinbox { + #[inline] + pub fn value(&self) -> i64 { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiSpinboxValue(self.ui_spinbox) + } + } + + #[inline] + pub fn set_value(&self, value: i64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiSpinboxSetValue(self.ui_spinbox, value) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiSpinboxOnChanged(self.ui_spinbox, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) { + unsafe { + let spinbox = Spinbox::from_ui_control(spinbox); + mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); + mem::forget(spinbox); + } + } + } + + #[inline] + pub fn new(min: i64, max: i64) -> Spinbox { + ffi_utils::ensure_initialized(); + unsafe { + Spinbox::from_ui_control(ui_sys::uiNewSpinbox(min, max)) + } + } +} + +define_control!(ProgressBar, uiProgressBar, ui_progress_bar); + +impl ProgressBar { + #[inline] + pub fn set_value(&self, n: i32) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiProgressBarSetValue(self.ui_progress_bar, n) + } + } + + #[inline] + pub fn new() -> ProgressBar { + ffi_utils::ensure_initialized(); + unsafe { + ProgressBar::from_ui_control(ui_sys::uiNewProgressBar()) + } + } +} + +define_control!(Slider, uiSlider, ui_slider); + +impl Slider { + #[inline] + pub fn value(&self) -> i64 { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiSliderValue(self.ui_slider) + } + } + + #[inline] + pub fn set_value(&self, value: i64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiSliderSetValue(self.ui_slider, value) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiSliderOnChanged(self.ui_slider, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) { + unsafe { + let slider = Slider::from_ui_control(slider); + mem::transmute::<*mut c_void, &mut Box>(data)(&slider); + mem::forget(slider); + } + } + } + + #[inline] + pub fn new(min: i64, max: i64) -> Slider { + ffi_utils::ensure_initialized(); + unsafe { + Slider::from_ui_control(ui_sys::uiNewSlider(min, max)) + } + } +} + +define_control!(Separator, uiSeparator, ui_separator); + +impl Separator { + #[inline] + pub fn new_horizontal() -> Separator { + ffi_utils::ensure_initialized(); + unsafe { + Separator::from_ui_control(ui_sys::uiNewHorizontalSeparator()) + } + } +} + +define_control!(Combobox, uiCombobox, ui_combobox); + +impl Combobox { + #[inline] + pub fn append(&self, name: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + ui_sys::uiComboboxAppend(self.ui_combobox, c_string.as_ptr()) + } + } + + #[inline] + pub fn selected(&self) -> i64 { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiComboboxSelected(self.ui_combobox) + } + } + + #[inline] + pub fn set_selected(&self, n: i64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiComboboxSetSelected(self.ui_combobox, n) + } + } + + #[inline] + pub fn on_selected(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiComboboxOnSelected(self.ui_combobox, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(combobox: *mut uiCombobox, data: *mut c_void) { + unsafe { + let combobox = Combobox::from_ui_control(combobox); + mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); + mem::forget(combobox); + } + } + } + + #[inline] + pub fn new() -> Combobox { + ffi_utils::ensure_initialized(); + unsafe { + Combobox::from_ui_control(ui_sys::uiNewCombobox()) + } + } + + #[inline] + pub fn new_editable() -> Combobox { + ffi_utils::ensure_initialized(); + unsafe { + Combobox::from_ui_control(ui_sys::uiNewEditableCombobox()) + } + } +} + +// FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable +// with just the `uiRadioButtons*` methods… +define_control!(RadioButtons, uiRadioButtons, ui_radio_buttons); + +impl RadioButtons { + #[inline] + pub fn append(&self, name: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + ui_sys::uiRadioButtonsAppend(self.ui_radio_buttons, c_string.as_ptr()) + } + } + + #[inline] + pub fn new() -> RadioButtons { + ffi_utils::ensure_initialized(); + unsafe { + RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons()) + } + } +} + +// FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable +// with just the `uiDatetimePicker*` methods… +define_control!(DateTimePicker, uiDateTimePicker, ui_date_time_picker); + +impl DateTimePicker { + pub fn new_date_time_picker() -> DateTimePicker { + ffi_utils::ensure_initialized(); + unsafe { + DateTimePicker::from_ui_control(ui_sys::uiNewDateTimePicker()) + } + } + + pub fn new_date_picker() -> DateTimePicker { + ffi_utils::ensure_initialized(); + unsafe { + DateTimePicker::from_ui_control(ui_sys::uiNewDatePicker()) + } + } + + pub fn new_time_picker() -> DateTimePicker { + ffi_utils::ensure_initialized(); + unsafe { + DateTimePicker::from_ui_control(ui_sys::uiNewTimePicker()) + } + } +} + +define_control!(MultilineEntry, uiMultilineEntry, ui_multiline_entry); + +impl MultilineEntry { + #[inline] + pub fn text(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiMultilineEntryText(self.ui_multiline_entry)) + } + } + + #[inline] + pub fn set_text(&self, text: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + ui_sys::uiMultilineEntrySetText(self.ui_multiline_entry, c_string.as_ptr()) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiMultilineEntryOnChanged(self.ui_multiline_entry, + c_callback, + &mut *data as *mut Box as + *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(multiline_entry: *mut uiMultilineEntry, data: *mut c_void) { + unsafe { + let multiline_entry = MultilineEntry::from_ui_control(multiline_entry); + mem::transmute::<*mut c_void, + &mut Box>(data)(&multiline_entry); + mem::forget(multiline_entry); + } + } + } + + #[inline] + pub fn read_only(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiMultilineEntryReadOnly(self.ui_multiline_entry) != 0 + } + } + + #[inline] + pub fn set_read_only(&self, readonly: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiMultilineEntrySetReadOnly(self.ui_multiline_entry, readonly as c_int) + } + } + + #[inline] + pub fn new() -> MultilineEntry { + ffi_utils::ensure_initialized(); + unsafe { + MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry()) + } + } +} + +pub trait AreaHandler { + fn draw(&mut self, _area: &Area, _area_draw_params: &AreaDrawParams) {} + fn mouse_event(&mut self, _area: &Area, _area_mouse_event: &AreaMouseEvent) {} + fn mouse_crossed(&mut self, _area: &Area, _left: bool) {} + fn drag_broken(&mut self, _area: &Area) {} + fn key_event(&mut self, _area: &Area, _area_key_event: &AreaKeyEvent) -> bool { + true + } +} + +#[repr(C)] +struct RustAreaHandler { + ui_area_handler: uiAreaHandler, + trait_object: Box, +} + +impl RustAreaHandler { + #[inline] + fn new(trait_object: Box) -> Box { + ffi_utils::ensure_initialized(); + return Box::new(RustAreaHandler { + ui_area_handler: uiAreaHandler { + Draw: draw, + MouseEvent: mouse_event, + MouseCrossed: mouse_crossed, + DragBroken: drag_broken, + KeyEvent: key_event, + }, + trait_object: trait_object, + }); + + extern "C" fn draw(ui_area_handler: *mut uiAreaHandler, + ui_area: *mut uiArea, + ui_area_draw_params: *mut uiAreaDrawParams) { + unsafe { + let area = Area::from_ui_area(ui_area); + let area_draw_params = + AreaDrawParams::from_ui_area_draw_params(&*ui_area_draw_params); + (*(ui_area_handler as *mut RustAreaHandler)).trait_object.draw(&area, + &area_draw_params); + mem::forget(area_draw_params); + mem::forget(area); + } + } + + extern "C" fn mouse_event(ui_area_handler: *mut uiAreaHandler, + ui_area: *mut uiArea, + ui_area_mouse_event: *mut uiAreaMouseEvent) { + unsafe { + let area = Area::from_ui_area(ui_area); + let area_mouse_event = + AreaMouseEvent::from_ui_area_mouse_event(&*ui_area_mouse_event); + (*(ui_area_handler as *mut RustAreaHandler)).trait_object + .mouse_event(&area, &area_mouse_event); + mem::forget(area_mouse_event); + mem::forget(area); + } + } + + extern "C" fn mouse_crossed(ui_area_handler: *mut uiAreaHandler, + ui_area: *mut uiArea, + left: c_int) { + unsafe { + let area = Area::from_ui_area(ui_area); + (*(ui_area_handler as *mut RustAreaHandler)).trait_object.mouse_crossed(&area, + left != 0); + mem::forget(area); + } + } + + extern "C" fn drag_broken(ui_area_handler: *mut uiAreaHandler, ui_area: *mut uiArea) { + unsafe { + let area = Area::from_ui_area(ui_area); + (*(ui_area_handler as *mut RustAreaHandler)).trait_object.drag_broken(&area); + mem::forget(area); + } + } + + extern "C" fn key_event(ui_area_handler: *mut uiAreaHandler, + ui_area: *mut uiArea, + ui_area_key_event: *mut uiAreaKeyEvent) + -> c_int { + unsafe { + let area = Area::from_ui_area(ui_area); + let area_key_event = AreaKeyEvent::from_ui_area_key_event(&*ui_area_key_event); + let result = + (*(ui_area_handler as *mut RustAreaHandler)).trait_object + .key_event(&area, &area_key_event); + mem::forget(area_key_event); + mem::forget(area); + result as c_int + } + } + } +} + +define_control!(Area, uiArea, ui_area); + +impl Area { + #[inline] + pub unsafe fn from_ui_area(ui_area: *mut uiArea) -> Area { + Area { + ui_area: ui_area, + } + } + + #[inline] + pub fn set_size(&self, width: i64, height: i64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiAreaSetSize(self.ui_area, width, height) + } + } + + #[inline] + pub fn queue_redraw_all(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiAreaQueueRedrawAll(self.ui_area) + } + } + + #[inline] + pub fn scroll_to(&self, x: f64, y: f64, width: f64, height: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiAreaScrollTo(self.ui_area, x, y, width, height) + } + } + + #[inline] + pub fn new(area_handler: Box) -> Area { + ffi_utils::ensure_initialized(); + unsafe { + let mut rust_area_handler = RustAreaHandler::new(area_handler); + let area = + Area::from_ui_control(ui_sys::uiNewArea(&mut *rust_area_handler as + *mut RustAreaHandler as + *mut uiAreaHandler)); + mem::forget(rust_area_handler); + area + } + } + + #[inline] + pub fn new_scrolling(area_handler: Box, width: i64, height: i64) -> Area { + ffi_utils::ensure_initialized(); + unsafe { + let mut rust_area_handler = RustAreaHandler::new(area_handler); + let area = + Area::from_ui_control(ui_sys::uiNewScrollingArea(&mut *rust_area_handler as + *mut RustAreaHandler as + *mut uiAreaHandler, + width, + height)); + mem::forget(rust_area_handler); + area + } + } +} + +pub struct AreaDrawParams { + pub context: draw::Context, + + pub area_width: f64, + pub area_height: f64, + + pub clip_x: f64, + pub clip_y: f64, + pub clip_width: f64, + pub clip_height: f64, +} + +impl AreaDrawParams { + #[inline] + unsafe fn from_ui_area_draw_params(ui_area_draw_params: &uiAreaDrawParams) -> AreaDrawParams { + ffi_utils::ensure_initialized(); + AreaDrawParams { + context: draw::Context::from_ui_draw_context(ui_area_draw_params.Context), + area_width: ui_area_draw_params.AreaWidth, + area_height: ui_area_draw_params.AreaHeight, + clip_x: ui_area_draw_params.ClipX, + clip_y: ui_area_draw_params.ClipY, + clip_width: ui_area_draw_params.ClipWidth, + clip_height: ui_area_draw_params.ClipHeight, + } + } +} + +bitflags! { + pub flags Modifiers: u8 { + const MODIFIER_CTRL = 1 << 0, + const MODIFIER_ALT = 1 << 1, + const MODIFIER_SHIFT = 1 << 2, + const MODIFIER_SUPER = 1 << 3, + } +} + +#[derive(Copy, Clone, Debug)] +pub struct AreaMouseEvent { + pub x: f64, + pub y: f64, + + pub area_width: f64, + pub area_height: f64, + + pub down: u64, + pub up: u64, + + pub count: u64, + + pub modifiers: Modifiers, + + pub held_1_to_64: u64, +} + +impl AreaMouseEvent { + #[inline] + pub fn from_ui_area_mouse_event(ui_area_mouse_event: &uiAreaMouseEvent) -> AreaMouseEvent { + ffi_utils::ensure_initialized(); + AreaMouseEvent { + x: ui_area_mouse_event.X, + y: ui_area_mouse_event.Y, + area_width: ui_area_mouse_event.AreaWidth, + area_height: ui_area_mouse_event.AreaHeight, + down: ui_area_mouse_event.Down, + up: ui_area_mouse_event.Up, + count: ui_area_mouse_event.Count, + modifiers: Modifiers::from_bits(ui_area_mouse_event.Modifiers as u8).unwrap(), + held_1_to_64: ui_area_mouse_event.Held1To64, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct AreaKeyEvent { + pub key: u8, + pub ext_key: ExtKey, + pub modifier: Modifiers, + pub modifiers: Modifiers, + pub up: bool, +} + +impl AreaKeyEvent { + #[inline] + pub fn from_ui_area_key_event(ui_area_key_event: &uiAreaKeyEvent) -> AreaKeyEvent { + ffi_utils::ensure_initialized(); + AreaKeyEvent { + key: ui_area_key_event.Key as u8, + ext_key: ui_area_key_event.ExtKey, + modifier: Modifiers::from_bits(ui_area_key_event.Modifier as u8).unwrap(), + modifiers: Modifiers::from_bits(ui_area_key_event.Modifiers as u8).unwrap(), + up: ui_area_key_event.Up != 0, + } + } +} + +define_control!(FontButton, uiFontButton, ui_font_button); + +impl FontButton { + /// Returns a new font. + #[inline] + pub fn font(&self) -> draw::text::Font { + ffi_utils::ensure_initialized(); + unsafe { + draw::text::Font::from_ui_draw_text_font(ui_sys::uiFontButtonFont(self.ui_font_button)) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiFontButtonOnChanged(self.ui_font_button, + c_callback, + &mut *data as *mut Box as + *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(ui_font_button: *mut uiFontButton, data: *mut c_void) { + unsafe { + let font_button = FontButton::from_ui_control(ui_font_button); + mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); + mem::forget(font_button); + } + } + } + + #[inline] + pub fn new() -> FontButton { + ffi_utils::ensure_initialized(); + unsafe { + FontButton::from_ui_control(ui_sys::uiNewFontButton()) + } + } +} + +define_control!(ColorButton, uiColorButton, ui_color_button); + +impl ColorButton { + #[inline] + pub fn color(&self) -> Color { + ffi_utils::ensure_initialized(); + unsafe { + let mut color: Color = mem::uninitialized(); + ui_sys::uiColorButtonColor(self.ui_color_button, + &mut color.r, + &mut color.g, + &mut color.b, + &mut color.a); + color + } + } + + #[inline] + pub fn set_color(&self, color: &Color) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiColorButtonSetColor(self.ui_color_button, color.r, color.g, color.b, color.a) + } + } + + #[inline] + pub fn on_changed(&self, callback: Box) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiColorButtonOnChanged(self.ui_color_button, + c_callback, + &mut *data as *mut Box as + *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(ui_color_button: *mut uiColorButton, data: *mut c_void) { + unsafe { + let color_button = ColorButton::from_ui_control(ui_color_button); + mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); + mem::forget(color_button) + } + } + } + + #[inline] + pub fn new() -> ColorButton { + ffi_utils::ensure_initialized(); + unsafe { + ColorButton::from_ui_control(ui_sys::uiNewColorButton()) + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Color { + r: f64, + g: f64, + b: f64, + a: f64, +} + diff --git a/tests/fixtures/libui-rs/src/draw.rs b/tests/fixtures/libui-rs/src/draw.rs new file mode 100644 index 000000000..61857a4c2 --- /dev/null +++ b/tests/fixtures/libui-rs/src/draw.rs @@ -0,0 +1,710 @@ +//! Functions and types related to 2D vector graphics. + +use ffi_utils::{self, Text}; +use libc::{c_double, c_int}; +use std::marker::PhantomData; +use std::mem; +use std::ops::Mul; +use std::ptr; +use ui_sys::{self, uiDrawBrush, uiDrawBrushType, uiDrawContext, uiDrawFontFamilies, uiDrawMatrix}; +use ui_sys::{uiDrawPath, uiDrawStrokeParams}; + +pub use ui_sys::uiDrawBrushGradientStop as BrushGradientStop; +pub use ui_sys::uiDrawLineCap as LineCap; +pub use ui_sys::uiDrawLineJoin as LineJoin; +pub use ui_sys::uiDrawDefaultMiterLimit as DEFAULT_MITER_LIMIT; +pub use ui_sys::uiDrawFillMode as FillMode; + +pub struct Context { + ui_draw_context: *mut uiDrawContext, +} + +impl Context { + #[inline] + pub unsafe fn from_ui_draw_context(ui_draw_context: *mut uiDrawContext) -> Context { + ffi_utils::ensure_initialized(); + Context { + ui_draw_context: ui_draw_context, + } + } + + #[inline] + pub fn stroke(&self, path: &Path, brush: &Brush, stroke_params: &StrokeParams) { + ffi_utils::ensure_initialized(); + unsafe { + let brush = brush.as_ui_draw_brush_ref(); + let stroke_params = stroke_params.as_ui_draw_stroke_params_ref(); + ui_sys::uiDrawStroke(self.ui_draw_context, + path.ui_draw_path, + &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush, + &stroke_params.ui_draw_stroke_params as *const uiDrawStrokeParams + as *mut uiDrawStrokeParams) + } + } + + #[inline] + pub fn fill(&self, path: &Path, brush: &Brush) { + ffi_utils::ensure_initialized(); + unsafe { + let brush = brush.as_ui_draw_brush_ref(); + ui_sys::uiDrawFill(self.ui_draw_context, + path.ui_draw_path, + &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush) + } + } + + #[inline] + pub fn transform(&self, matrix: &Matrix) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawTransform(self.ui_draw_context, + &matrix.ui_matrix as *const uiDrawMatrix as *mut uiDrawMatrix) + } + } + + #[inline] + pub fn save(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawSave(self.ui_draw_context) + } + } + + #[inline] + pub fn restore(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawRestore(self.ui_draw_context) + } + } + + #[inline] + pub fn draw_text(&self, x: f64, y: f64, layout: &text::Layout) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawText(self.ui_draw_context, x, y, layout.as_ui_draw_text_layout()) + } + } +} + +#[derive(Clone, Debug)] +pub enum Brush { + Solid(SolidBrush), + LinearGradient(LinearGradientBrush), + RadialGradient(RadialGradientBrush), + Image, +} + +#[derive(Clone, Debug)] +pub struct UiDrawBrushRef<'a> { + ui_draw_brush: uiDrawBrush, + phantom: PhantomData<&'a uiDrawBrush>, +} + +impl Brush { + pub fn as_ui_draw_brush_ref(&self) -> UiDrawBrushRef { + ffi_utils::ensure_initialized(); + match *self { + Brush::Solid(ref solid_brush) => { + UiDrawBrushRef { + ui_draw_brush: uiDrawBrush { + Type: uiDrawBrushType::Solid, + + R: solid_brush.r, + G: solid_brush.g, + B: solid_brush.b, + A: solid_brush.a, + + X0: 0.0, + Y0: 0.0, + X1: 0.0, + Y1: 0.0, + OuterRadius: 0.0, + Stops: ptr::null_mut(), + NumStops: 0, + }, + phantom: PhantomData, + } + } + Brush::LinearGradient(ref linear_gradient_brush) => { + UiDrawBrushRef { + ui_draw_brush: uiDrawBrush { + Type: uiDrawBrushType::LinearGradient, + + R: 0.0, + G: 0.0, + B: 0.0, + A: 0.0, + + X0: linear_gradient_brush.start_x, + Y0: linear_gradient_brush.start_y, + X1: linear_gradient_brush.end_x, + Y1: linear_gradient_brush.end_y, + OuterRadius: 0.0, + Stops: linear_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, + NumStops: linear_gradient_brush.stops.len(), + }, + phantom: PhantomData, + } + } + Brush::RadialGradient(ref radial_gradient_brush) => { + UiDrawBrushRef { + ui_draw_brush: uiDrawBrush { + Type: uiDrawBrushType::RadialGradient, + + R: 0.0, + G: 0.0, + B: 0.0, + A: 0.0, + + X0: radial_gradient_brush.start_x, + Y0: radial_gradient_brush.start_y, + X1: radial_gradient_brush.outer_circle_center_x, + Y1: radial_gradient_brush.outer_circle_center_y, + OuterRadius: radial_gradient_brush.outer_radius, + Stops: radial_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, + NumStops: radial_gradient_brush.stops.len(), + }, + phantom: PhantomData, + } + } + Brush::Image => { + // These don't work yet in `libui`, but just for completeness' sake… + UiDrawBrushRef { + ui_draw_brush: uiDrawBrush { + Type: uiDrawBrushType::Image, + + R: 0.0, + G: 0.0, + B: 0.0, + A: 0.0, + + X0: 0.0, + Y0: 0.0, + X1: 0.0, + Y1: 0.0, + OuterRadius: 0.0, + Stops: ptr::null_mut(), + NumStops: 0, + }, + phantom: PhantomData, + } + } + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct SolidBrush { + pub r: f64, + pub g: f64, + pub b: f64, + pub a: f64, +} + +#[derive(Clone, Debug)] +pub struct LinearGradientBrush { + pub start_x: f64, + pub start_y: f64, + pub end_x: f64, + pub end_y: f64, + pub stops: Vec, +} + +#[derive(Clone, Debug)] +pub struct RadialGradientBrush { + pub start_x: f64, + pub start_y: f64, + pub outer_circle_center_x: f64, + pub outer_circle_center_y: f64, + pub outer_radius: f64, + pub stops: Vec, +} + +#[derive(Clone, Debug)] +pub struct StrokeParams { + pub cap: LineCap, + pub join: LineJoin, + pub thickness: f64, + pub miter_limit: f64, + pub dashes: Vec, + pub dash_phase: f64, +} + +#[derive(Clone, Debug)] +pub struct UiDrawStrokeParamsRef<'a> { + ui_draw_stroke_params: uiDrawStrokeParams, + phantom: PhantomData<&'a uiDrawStrokeParams>, +} + +impl StrokeParams { + pub fn as_ui_draw_stroke_params_ref(&self) -> UiDrawStrokeParamsRef { + ffi_utils::ensure_initialized(); + UiDrawStrokeParamsRef { + ui_draw_stroke_params: uiDrawStrokeParams { + Cap: self.cap, + Join: self.join, + Thickness: self.thickness, + MiterLimit: self.miter_limit, + Dashes: self.dashes.as_ptr() as *mut c_double, + NumDashes: self.dashes.len(), + DashPhase: self.dash_phase, + }, + phantom: PhantomData, + } + } +} + +pub struct Path { + ui_draw_path: *mut uiDrawPath, +} + +impl Drop for Path { + #[inline] + fn drop(&mut self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawFreePath(self.ui_draw_path) + } + } +} + +impl Path { + #[inline] + pub fn new(fill_mode: FillMode) -> Path { + ffi_utils::ensure_initialized(); + unsafe { + Path { + ui_draw_path: ui_sys::uiDrawNewPath(fill_mode), + } + } + } + + #[inline] + pub fn new_figure(&self, x: f64, y: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathNewFigure(self.ui_draw_path, x, y) + } + } + + #[inline] + pub fn new_figure_with_arc(&self, + x_center: f64, + y_center: f64, + radius: f64, + start_angle: f64, + sweep: f64, + negative: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathNewFigureWithArc(self.ui_draw_path, + x_center, + y_center, + radius, + start_angle, + sweep, + negative as c_int) + } + } + + #[inline] + pub fn line_to(&self, x: f64, y: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathLineTo(self.ui_draw_path, x, y) + } + } + + #[inline] + pub fn arc_to(&self, + x_center: f64, + y_center: f64, + radius: f64, + start_angle: f64, + sweep: f64, + negative: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathArcTo(self.ui_draw_path, + x_center, + y_center, + radius, + start_angle, + sweep, + negative as c_int) + } + } + + #[inline] + pub fn bezier_to(&self, c1x: f64, c1y: f64, c2x: f64, c2y: f64, end_x: f64, end_y: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathBezierTo(self.ui_draw_path, c1x, c1y, c2x, c2y, end_x, end_y) + } + } + + #[inline] + pub fn close_figure(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathCloseFigure(self.ui_draw_path) + } + } + + #[inline] + pub fn add_rectangle(&self, x: f64, y: f64, width: f64, height: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathAddRectangle(self.ui_draw_path, x, y, width, height) + } + } + + #[inline] + pub fn end(&self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawPathEnd(self.ui_draw_path) + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Matrix { + pub ui_matrix: uiDrawMatrix, +} + +impl Matrix { + #[inline] + pub fn from_ui_matrix(ui_matrix: &uiDrawMatrix) -> Matrix { + Matrix { + ui_matrix: *ui_matrix, + } + } + + #[inline] + pub fn identity() -> Matrix { + unsafe { + let mut matrix = mem::uninitialized(); + ui_sys::uiDrawMatrixSetIdentity(&mut matrix); + Matrix::from_ui_matrix(&matrix) + } + } + + #[inline] + pub fn translate(&mut self, x: f64, y: f64) { + unsafe { + ui_sys::uiDrawMatrixTranslate(&mut self.ui_matrix, x, y) + } + } + + #[inline] + pub fn scale(&mut self, x_center: f64, y_center: f64, x: f64, y: f64) { + unsafe { + ui_sys::uiDrawMatrixScale(&mut self.ui_matrix, x_center, y_center, x, y) + } + } + + #[inline] + pub fn rotate(&mut self, x: f64, y: f64, angle: f64) { + unsafe { + ui_sys::uiDrawMatrixRotate(&mut self.ui_matrix, x, y, angle) + } + } + + #[inline] + pub fn skew(&mut self, x: f64, y: f64, xamount: f64, yamount: f64) { + unsafe { + ui_sys::uiDrawMatrixSkew(&mut self.ui_matrix, x, y, xamount, yamount) + } + } + + #[inline] + pub fn multiply(&mut self, src: &Matrix) { + unsafe { + ui_sys::uiDrawMatrixMultiply(&mut self.ui_matrix, + &src.ui_matrix as *const uiDrawMatrix + as *mut uiDrawMatrix) + } + } + + #[inline] + pub fn invertible(&self) -> bool { + unsafe { + ui_sys::uiDrawMatrixInvertible(&self.ui_matrix as *const uiDrawMatrix + as *mut uiDrawMatrix) != 0 + } + } + + #[inline] + pub fn invert(&mut self) -> bool { + unsafe { + ui_sys::uiDrawMatrixInvert(&mut self.ui_matrix) != 0 + } + } + + #[inline] + pub fn transform_point(&self, mut point: (f64, f64)) -> (f64, f64) { + unsafe { + ui_sys::uiDrawMatrixTransformPoint(&self.ui_matrix as *const uiDrawMatrix as + *mut uiDrawMatrix, + &mut point.0, + &mut point.1); + point + } + } + + #[inline] + pub fn transform_size(&self, mut size: (f64, f64)) -> (f64, f64) { + unsafe { + ui_sys::uiDrawMatrixTransformSize(&self.ui_matrix as *const uiDrawMatrix as + *mut uiDrawMatrix, + &mut size.0, + &mut size.1); + size + } + } +} + +impl Mul for Matrix { + type Output = Matrix; + + fn mul(mut self, other: Matrix) -> Matrix { + self.multiply(&other); + self + } +} + +pub struct FontFamilies { + ui_draw_font_families: *mut uiDrawFontFamilies, +} + +impl Drop for FontFamilies { + #[inline] + fn drop(&mut self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawFreeFontFamilies(self.ui_draw_font_families) + } + } +} + +impl FontFamilies { + #[inline] + pub fn list() -> FontFamilies { + ffi_utils::ensure_initialized(); + unsafe { + FontFamilies { + ui_draw_font_families: ui_sys::uiDrawListFontFamilies(), + } + } + } + + #[inline] + pub fn len(&self) -> u64 { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawFontFamiliesNumFamilies(self.ui_draw_font_families) + } + } + + #[inline] + pub fn family(&self, index: u64) -> Text { + ffi_utils::ensure_initialized(); + assert!(index < self.len()); + unsafe { + Text::new(ui_sys::uiDrawFontFamiliesFamily(self.ui_draw_font_families, index)) + } + } +} + +pub mod text { + use ffi_utils; + use libc::c_char; + use std::ffi::{CStr, CString}; + use std::mem; + use ui_sys::{self, uiDrawTextFont, uiDrawTextFontDescriptor, uiDrawTextLayout}; + + pub use ui_sys::uiDrawTextWeight as Weight; + pub use ui_sys::uiDrawTextItalic as Italic; + pub use ui_sys::uiDrawTextStretch as Stretch; + pub use ui_sys::uiDrawTextFontMetrics as FontMetrics; + + pub struct FontDescriptor { + family: CString, + pub size: f64, + pub weight: Weight, + pub italic: Italic, + pub stretch: Stretch, + } + + impl FontDescriptor { + #[inline] + pub fn new(family: &str, size: f64, weight: Weight, italic: Italic, stretch: Stretch) + -> FontDescriptor { + ffi_utils::ensure_initialized(); + FontDescriptor { + family: CString::new(family.as_bytes().to_vec()).unwrap(), + size: size, + weight: weight, + italic: italic, + stretch: stretch, + } + } + + /// FIXME(pcwalton): Should this return an Option? + #[inline] + pub fn load_closest_font(&self) -> Font { + ffi_utils::ensure_initialized(); + unsafe { + let font_descriptor = uiDrawTextFontDescriptor { + Family: self.family.as_ptr(), + Size: self.size, + Weight: self.weight, + Italic: self.italic, + Stretch: self.stretch, + }; + Font { + ui_draw_text_font: ui_sys::uiDrawLoadClosestFont(&font_descriptor), + } + } + } + + #[inline] + pub fn family(&self) -> &str { + self.family.to_str().unwrap() + } + } + + pub struct Font { + ui_draw_text_font: *mut uiDrawTextFont, + } + + impl Drop for Font { + #[inline] + fn drop(&mut self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawFreeTextFont(self.ui_draw_text_font) + } + } + } + + impl Font { + #[inline] + pub unsafe fn from_ui_draw_text_font(ui_draw_text_font: *mut uiDrawTextFont) -> Font { + Font { + ui_draw_text_font: ui_draw_text_font, + } + } + + #[inline] + pub fn handle(&self) -> usize { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawTextFontHandle(self.ui_draw_text_font) + } + } + + #[inline] + pub fn describe(&self) -> FontDescriptor { + ffi_utils::ensure_initialized(); + unsafe { + let mut ui_draw_text_font_descriptor = mem::uninitialized(); + ui_sys::uiDrawTextFontDescribe(self.ui_draw_text_font, + &mut ui_draw_text_font_descriptor); + let family = CStr::from_ptr(ui_draw_text_font_descriptor.Family).to_bytes() + .to_vec(); + let font_descriptor = FontDescriptor { + family: CString::new(family).unwrap(), + size: ui_draw_text_font_descriptor.Size, + weight: ui_draw_text_font_descriptor.Weight, + italic: ui_draw_text_font_descriptor.Italic, + stretch: ui_draw_text_font_descriptor.Stretch, + }; + ui_sys::uiFreeText(ui_draw_text_font_descriptor.Family as *mut c_char); + font_descriptor + } + } + + #[inline] + pub fn metrics(&self) -> FontMetrics { + ffi_utils::ensure_initialized(); + unsafe { + let mut metrics = mem::uninitialized(); + ui_sys::uiDrawTextFontGetMetrics(self.ui_draw_text_font, &mut metrics); + metrics + } + } + } + + pub struct Layout { + ui_draw_text_layout: *mut uiDrawTextLayout, + } + + impl Drop for Layout { + #[inline] + fn drop(&mut self) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawFreeTextLayout(self.ui_draw_text_layout) + } + } + } + + impl Layout { + #[inline] + pub fn new(text: &str, default_font: &Font, width: f64) -> Layout { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); + Layout { + ui_draw_text_layout: + ui_sys::uiDrawNewTextLayout(c_string.as_ptr(), + default_font.ui_draw_text_font, + width), + } + } + } + + #[inline] + pub fn as_ui_draw_text_layout(&self) -> *mut uiDrawTextLayout { + self.ui_draw_text_layout + } + + #[inline] + pub fn set_width(&self, width: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawTextLayoutSetWidth(self.ui_draw_text_layout, width) + } + } + + #[inline] + pub fn extents(&self) -> (f64, f64) { + ffi_utils::ensure_initialized(); + unsafe { + let mut extents = (0.0, 0.0); + ui_sys::uiDrawTextLayoutExtents(self.ui_draw_text_layout, + &mut extents.0, + &mut extents.1); + extents + } + } + + #[inline] + pub fn set_color(&self, start_char: i64, end_char: i64, r: f64, g: f64, b: f64, a: f64) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiDrawTextLayoutSetColor(self.ui_draw_text_layout, + start_char, + end_char, + r, + g, + b, + a) + } + } + } +} + diff --git a/tests/fixtures/libui-rs/src/ffi_utils.rs b/tests/fixtures/libui-rs/src/ffi_utils.rs new file mode 100644 index 000000000..866483db3 --- /dev/null +++ b/tests/fixtures/libui-rs/src/ffi_utils.rs @@ -0,0 +1,74 @@ +//! Useful utility functions for calling the `libui` C bindings. + +use libc::{c_char, c_void}; +use std::ffi::CStr; +use std::mem; +use std::ops::Deref; +use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering}; +use ui_sys; + +static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + +#[inline] +pub unsafe fn set_initialized() { + assert!(!INITIALIZED.swap(true, Ordering::SeqCst)); +} + +#[inline] +pub unsafe fn unset_initialized() { + INITIALIZED.store(false, Ordering::SeqCst); +} + +#[inline] +pub fn ensure_initialized() { + assert!(INITIALIZED.load(Ordering::SeqCst)); +} + +pub struct Text { + ui_text: *mut c_char, +} + +impl Drop for Text { + fn drop(&mut self) { + unsafe { + ui_sys::uiFreeText(self.ui_text) + } + } +} + +impl Deref for Text { + type Target = str; + fn deref(&self) -> &str { + unsafe { + CStr::from_ptr(self.ui_text).to_str().unwrap_or("") + } + } +} + +impl Text { + #[inline] + pub unsafe fn new(text: *mut c_char) -> Text { + debug_assert!(!text.is_null()); + Text { + ui_text: text, + } + } + + #[inline] + pub unsafe fn optional(text: *mut c_char) -> Option { + if text.is_null() { + None + } else { + Some(Text { + ui_text: text, + }) + } + } +} + +pub extern "C" fn void_void_callback(data: *mut c_void) { + unsafe { + mem::transmute::<*mut c_void, Box>>(data)() + } +} + diff --git a/tests/fixtures/libui-rs/src/lib.rs b/tests/fixtures/libui-rs/src/lib.rs new file mode 100644 index 000000000..57b46b0e5 --- /dev/null +++ b/tests/fixtures/libui-rs/src/lib.rs @@ -0,0 +1,28 @@ +//! Rust bindings to `libui`. +//! +//! Main C source repository: https://github.com/andlabs/libui +//! +//! Copyright © 2016 Mozilla Foundation + +#[macro_use] +extern crate bitflags; +extern crate libc; +extern crate ui_sys; + +pub use controls::{Area, AreaDrawParams, AreaHandler, BoxControl, Button, Checkbox, ColorButton}; +pub use controls::{Combobox, Control, DateTimePicker, Entry, FontButton, Group, Label}; +pub use controls::{MultilineEntry, ProgressBar, RadioButtons, Separator, Slider, Spinbox, Tab}; +pub use ffi_utils::Text; +pub use menus::{Menu, MenuItem}; +pub use ui::{InitError, InitOptions, init, main, msg_box, msg_box_error, on_should_quit}; +pub use ui::{open_file, queue_main, quit, save_file, uninit}; +pub use windows::Window; + +#[macro_use] +mod controls; +pub mod draw; +pub mod ffi_utils; +mod menus; +mod ui; +mod windows; + diff --git a/tests/fixtures/libui-rs/src/menus.rs b/tests/fixtures/libui-rs/src/menus.rs new file mode 100644 index 000000000..1255b691f --- /dev/null +++ b/tests/fixtures/libui-rs/src/menus.rs @@ -0,0 +1,144 @@ +//! Functions and types related to menus. + +use libc::{c_int, c_void}; +use std::ffi::CString; +use std::mem; +use ui_sys::{self, uiMenu, uiMenuItem, uiWindow}; +use windows::Window; + +// NB: If there ever becomes a way to destroy menus and/or menu items, we'll need to reference +// count these for memory safety. +#[derive(Clone)] +pub struct MenuItem { + ui_menu_item: *mut uiMenuItem, +} + +impl MenuItem { + #[inline] + pub fn enable(&self) { + unsafe { + ui_sys::uiMenuItemEnable(self.ui_menu_item) + } + } + + #[inline] + pub fn disable(&self) { + unsafe { + ui_sys::uiMenuItemDisable(self.ui_menu_item) + } + } + + #[inline] + pub fn on_clicked(&self, callback: Box) { + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiMenuItemOnClicked(self.ui_menu_item, + c_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(menu_item: *mut uiMenuItem, + window: *mut uiWindow, + data: *mut c_void) { + unsafe { + let menu_item = MenuItem { + ui_menu_item: menu_item, + }; + let window = Window::from_ui_window(window); + mem::transmute::<*mut c_void, + &mut Box>(data)(&menu_item, &window); + mem::forget(window); + } + } + } + + #[inline] + pub fn checked(&self) -> bool { + unsafe { + ui_sys::uiMenuItemChecked(self.ui_menu_item) != 0 + } + } + + #[inline] + pub fn set_checked(&self, checked: bool) { + unsafe { + ui_sys::uiMenuItemSetChecked(self.ui_menu_item, checked as c_int) + } + } +} + +// NB: If there ever becomes a way to destroy menus, we'll need to reference count these for memory +// safety. +#[derive(Clone)] +pub struct Menu { + ui_menu: *mut uiMenu, +} + +impl Menu { + #[inline] + pub fn append_item(&self, name: &str) -> MenuItem { + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + MenuItem { + ui_menu_item: ui_sys::uiMenuAppendItem(self.ui_menu, c_string.as_ptr()), + } + } + } + + #[inline] + pub fn append_check_item(&self, name: &str) -> MenuItem { + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + MenuItem { + ui_menu_item: ui_sys::uiMenuAppendCheckItem(self.ui_menu, c_string.as_ptr()), + } + } + } + + #[inline] + pub fn append_quit_item(&self) -> MenuItem { + unsafe { + MenuItem { + ui_menu_item: ui_sys::uiMenuAppendQuitItem(self.ui_menu), + } + } + } + + #[inline] + pub fn append_preferences_item(&self) -> MenuItem { + unsafe { + MenuItem { + ui_menu_item: ui_sys::uiMenuAppendPreferencesItem(self.ui_menu), + } + } + } + + #[inline] + pub fn append_about_item(&self) -> MenuItem { + unsafe { + MenuItem { + ui_menu_item: ui_sys::uiMenuAppendAboutItem(self.ui_menu), + } + } + } + + #[inline] + pub fn append_separator(&self) { + unsafe { + ui_sys::uiMenuAppendSeparator(self.ui_menu) + } + } + + #[inline] + pub fn new(name: &str) -> Menu { + unsafe { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + Menu { + ui_menu: ui_sys::uiNewMenu(c_string.as_ptr()), + } + } + } +} + diff --git a/tests/fixtures/libui-rs/src/ui.rs b/tests/fixtures/libui-rs/src/ui.rs new file mode 100644 index 000000000..ccdc4dd46 --- /dev/null +++ b/tests/fixtures/libui-rs/src/ui.rs @@ -0,0 +1,134 @@ +//! General functions. + +use ffi_utils::{self, Text}; +use libc::{c_char, c_void}; +use std::fmt::{self, Debug, Formatter}; +use std::ffi::{CStr, CString}; +use std::mem; +use std::ops::Deref; +use ui_sys::{self, uiInitOptions}; +use windows::Window; + +#[derive(Clone)] +pub struct InitOptions; + +#[inline] +pub fn init(_: InitOptions) -> Result<(),InitError> { + unsafe { + let mut init_options = uiInitOptions { + Size: mem::size_of::(), + }; + let err = ui_sys::uiInit(&mut init_options); + if err.is_null() { + ffi_utils::set_initialized(); + Ok(()) + } else { + Err(InitError { + ui_init_error: err, + }) + } + } +} + +#[inline] +pub fn uninit() { + unsafe { + ffi_utils::unset_initialized(); + Window::destroy_all_windows(); + ui_sys::uiUninit(); + } +} + +#[inline] +pub fn main() { + unsafe { + ui_sys::uiMain() + } +} + +#[inline] +pub fn quit() { + unsafe { + ui_sys::uiQuit() + } +} + +pub struct InitError { + ui_init_error: *const c_char, +} + +impl Drop for InitError { + fn drop(&mut self) { + unsafe { + ui_sys::uiFreeInitError(self.ui_init_error) + } + } +} + +impl Debug for InitError { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + (**self).fmt(f) + } +} + +impl Deref for InitError { + type Target = str; + fn deref(&self) -> &str { + unsafe { + CStr::from_ptr(self.ui_init_error).to_str().unwrap_or("") + } + } +} + +#[inline] +pub fn queue_main(callback: Box) { + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiQueueMain(ffi_utils::void_void_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } +} + +#[inline] +pub fn on_should_quit(callback: Box) { + unsafe { + let mut data: Box> = Box::new(callback); + ui_sys::uiOnShouldQuit(ffi_utils::void_void_callback, + &mut *data as *mut Box as *mut c_void); + mem::forget(data); + } +} + +#[inline] +pub fn open_file(parent: &Window) -> Option { + unsafe { + Text::optional(ui_sys::uiOpenFile(parent.as_ui_window())) + } +} + +#[inline] +pub fn save_file(parent: &Window) -> Option { + unsafe { + Text::optional(ui_sys::uiSaveFile(parent.as_ui_window())) + } +} + +#[inline] +pub fn msg_box(parent: &Window, title: &str, description: &str) { + unsafe { + let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); + let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); + ui_sys::uiMsgBox(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) + } +} + +#[inline] +pub fn msg_box_error(parent: &Window, title: &str, description: &str) { + unsafe { + let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); + let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); + ui_sys::uiMsgBoxError(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) + } +} + diff --git a/tests/fixtures/libui-rs/src/windows.rs b/tests/fixtures/libui-rs/src/windows.rs new file mode 100644 index 000000000..c43ff049b --- /dev/null +++ b/tests/fixtures/libui-rs/src/windows.rs @@ -0,0 +1,119 @@ +//! Functions and types related to windows. + +use controls::Control; +use ffi_utils::{self, Text}; +use libc::{c_int, c_void}; +use std::cell::RefCell; +use std::ffi::CString; +use std::mem; +use ui_sys::{self, uiControl, uiWindow}; + +thread_local! { + static WINDOWS: RefCell> = RefCell::new(Vec::new()) +} + +define_control!(Window, uiWindow, ui_window); + +impl Window { + #[inline] + pub fn as_ui_window(&self) -> *mut uiWindow { + self.ui_window + } + + #[inline] + pub fn title(&self) -> Text { + ffi_utils::ensure_initialized(); + unsafe { + Text::new(ui_sys::uiWindowTitle(self.ui_window)) + } + } + + #[inline] + pub fn set_title(&self, title: &str) { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); + ui_sys::uiWindowSetTitle(self.ui_window, c_string.as_ptr()) + } + } + + #[inline] + pub fn on_closing(&self, callback: Box bool>) { + ffi_utils::ensure_initialized(); + unsafe { + let mut data: Box bool>> = Box::new(callback); + ui_sys::uiWindowOnClosing(self.ui_window, + c_callback, + &mut *data as *mut Box bool> as + *mut c_void); + mem::forget(data); + } + + extern "C" fn c_callback(window: *mut uiWindow, data: *mut c_void) -> i32 { + unsafe { + let window = Window { + ui_window: window, + }; + mem::transmute::<*mut c_void, + Box bool>>>(data)(&window) as i32 + } + } + } + + #[inline] + pub fn set_child(&self, child: Control) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiWindowSetChild(self.ui_window, child.as_ui_control()) + } + } + + #[inline] + pub fn margined(&self) -> bool { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiWindowMargined(self.ui_window) != 0 + } + } + + #[inline] + pub fn set_margined(&self, margined: bool) { + ffi_utils::ensure_initialized(); + unsafe { + ui_sys::uiWindowSetMargined(self.ui_window, margined as c_int) + } + } + + #[inline] + pub fn new(title: &str, width: c_int, height: c_int, has_menubar: bool) -> Window { + ffi_utils::ensure_initialized(); + unsafe { + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); + let window = Window::from_ui_window(ui_sys::uiNewWindow(c_string.as_ptr(), + width, + height, + has_menubar as c_int)); + + WINDOWS.with(|windows| windows.borrow_mut().push(window.clone())); + + window + } + } + + #[inline] + pub unsafe fn from_ui_window(window: *mut uiWindow) -> Window { + Window { + ui_window: window, + } + } + + pub unsafe fn destroy_all_windows() { + WINDOWS.with(|windows| { + let mut windows = windows.borrow_mut(); + for window in windows.drain(..) { + window.destroy() + } + }) + } +} + diff --git a/tests/libui.rs b/tests/libui.rs new file mode 100644 index 000000000..6129df763 --- /dev/null +++ b/tests/libui.rs @@ -0,0 +1,3 @@ +#[test] +fn test() { +} From dec492a0524854c4a2d03b321565ea097521b597 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 16:36:24 +0200 Subject: [PATCH 013/298] DANGER! This will destroy your files! Add 'replace' option. The byte offset seems to be broken, though. --- src/main.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index eec8dc0b8..c99c1002a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ const USER_OPTIONS: &'static str = "What do you want to do? [r]eplace/[s]kip/[q] fn main() { if let Err(error) = try_main() { - writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); + writeln!(std::io::stderr(), "An error occured: {:#?}", error).unwrap(); std::process::exit(1); } } @@ -59,7 +59,20 @@ fn try_main() -> Result<(), ProgramError> { continue 'suggestions; } "r" => { - unimplemented!(); + let mut file = try!(File::open(&suggestion.file_name)); + let mut file_content = vec![]; + try!(file.read_to_end(&mut file_content)); + + let mut new_content = vec![]; + new_content.extend_from_slice(&file_content[..suggestion.byte_range.0]); + new_content.extend_from_slice(&suggestion.replacement.as_bytes()); + new_content.extend_from_slice(&file_content[suggestion.byte_range.1..]); + + let mut file = try!(File::create(&suggestion.file_name)); + + try!(file.set_len(new_content.len() as u64)); + try!(file.write_all(&new_content)); + println!("Replaced."); }, _ => { println!("{error}: I didn't get that. {user_options}", From f64dfe29898d9adfa8b57d9023d84fcf494a35bf Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 16:45:16 +0200 Subject: [PATCH 014/298] Add Apache 2.0 License --- LICENSE-APACHE | 202 +++++++++++++++++++++++++++++++++++++++++ LICENSE => LICENSE-MIT | 0 2 files changed, 202 insertions(+) create mode 100644 LICENSE-APACHE rename LICENSE => LICENSE-MIT (100%) diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/LICENSE b/LICENSE-MIT similarity index 100% rename from LICENSE rename to LICENSE-MIT From 91f3156cb5a078a94a07868828dd097e2ea87e43 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 16:49:55 +0200 Subject: [PATCH 015/298] Add Readme --- Cargo.toml | 2 ++ Readme.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 Readme.md diff --git a/Cargo.toml b/Cargo.toml index 0a90650e8..394ec1502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ authors = ["Pascal Hertleif "] name = "rustfix" version = "0.1.0" +readme = "README.md" +license = "Apache-2.0/MIT" [dependencies] colored = "1.2.0" diff --git a/Readme.md b/Readme.md new file mode 100644 index 000000000..79d534033 --- /dev/null +++ b/Readme.md @@ -0,0 +1,54 @@ +# rustfix + +**HIGHLY EXPERIMENTAL: CURRENTLY, IT REPLACES THE WRONG LINES!** + +The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by Clippy). + +## Current state + +This tool can + +- read a file of diagnostics (one JSON object per line) + +## Get the example running + +My current example output for diagnostics is based on libui-rs. You can find the example JSON in `tests/fixtures/libui-rs/clippy.json`. + +Run `rustfix`: + +```sh +$ cd tests/fixtures/libui-rs/ +$ cargo run -- clippy.json +``` + +### Generate the diagnostics JSON file yourself + +```sh +$ git clone https://github.com/pcwalton/libui-rs.git +# HEAD is at 13299d28f69f8009be8e08e453a9b0024f153a60 +$ cd libui-rs/ui/ +$ cargo clippy -- -Z unstable-options --error-format json &2> clippy.json +# Manually remove the first line ("Compiling....") +``` + +## Gotchas + +- rustc JSON output is unstable +- Not all suggestions can be applied trivially (e.g. clippy's "You should use `Default` instead of that `fn new()` you just wrote"-lint will replace your `new`-method with an `impl` block -- which is obvisouly invalid syntax.) +- This tool _will_ eat your laundry + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. From 9ce46a1943ae22142fa34d57b750dc08d3243e53 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 16:57:27 +0200 Subject: [PATCH 016/298] Remove JS Prototype --- src/main.js | 80 ----------------------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 src/main.js diff --git a/src/main.js b/src/main.js deleted file mode 100644 index 8c2a7bc0d..000000000 --- a/src/main.js +++ /dev/null @@ -1,80 +0,0 @@ -//! Read rustc JSON output and parse out the lints' suggestions to automatically -//! apply them. -//! -//! Just a prototype, the final thing should be in Rust - -const fs = require('fs'); - -/// Strips the indent of the first line form all other lines -function normalizeIndent(lines) { - if (!lines || !lines[0]) { return []; } - const matches = lines[0].match(/^(\s*)(.*)$/); - const leadingWhitespace = matches[1]; - - return lines - .map(line => line.replace(new RegExp("^" + leadingWhitespace), "")); -} - -/// Map a span to a suggestion. -function collectSpan(acc, message, span) { - if (!span.suggested_replacement) { return; } - acc.push({ - message: message, - file_name: span.file_name, - range: [ - [span.line_start, span.column_start], - [span.line_end, span.column_end], - ], - byte_range: [span.byte_start, span.byte_end], - text: normalizeIndent((span.text || []).map(x => x.text)), - replacement: span.suggested_replacement, - }); -} - -/// Collect suggestions from diagnostic messages, and their spans and children. -function collectSuggestions(acc, diagnostic, parent_message) { - const message = typeof parent_message === 'string' ? - parent_message : - diagnostic.message; - - (diagnostic.spans || []) - .forEach(span => collectSpan(acc, message, span)); - - (diagnostic.children || []) - .forEach(child => collectSuggestions(acc, child, message)); - - return acc; -} - -// Read some JSON file and parse its suggestions - -const args = process.argv.slice(2); - -if (!args[0]) { - console.log("Usage: node src/main.js json-file"); - process.exit(1); -} - -const file = fs.readFileSync(args[0]).toString('utf8'); -const lines = file.split('\n'); -const diagnostics = lines - .filter(line => line.trim().length > 0) - .map(line => JSON.parse(line)); -const suggestions = diagnostics - .reduce(collectSuggestions, []); - -suggestions.forEach(suggestion => { - console.log("___________________________________________"); - console.log(""); - console.log(suggestion.message); - console.log(""); - console.log("You might want to replace"); - console.log(""); - console.log(suggestion.text - .map(line => "- " + line).join("\n")); - console.log(""); - console.log("with"); - console.log(""); - console.log("+ " + suggestion.replacement); - console.log(""); -}); From 2212a2c387eeb9fa8e1c5b2ab5308448d2f143b8 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 17:01:20 +0200 Subject: [PATCH 017/298] Fix Clippy's Suggestions --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index c99c1002a..c291ada9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,7 +65,7 @@ fn try_main() -> Result<(), ProgramError> { let mut new_content = vec![]; new_content.extend_from_slice(&file_content[..suggestion.byte_range.0]); - new_content.extend_from_slice(&suggestion.replacement.as_bytes()); + new_content.extend_from_slice(suggestion.replacement.as_bytes()); new_content.extend_from_slice(&file_content[suggestion.byte_range.1..]); let mut file = try!(File::create(&suggestion.file_name)); @@ -121,7 +121,7 @@ fn read_file_to_string(file_name: &str) -> Result { } fn not_empty(s: &&str) -> bool { - s.trim().len() > 0 + !s.trim().is_empty() } fn split_at_lint_name(s: &str) -> String { From fb71f67ec6d9072e579b92782514880b15c8d8a4 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jul 2016 17:05:07 +0200 Subject: [PATCH 018/298] More Readme --- Readme.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 79d534033..09f9c448a 100644 --- a/Readme.md +++ b/Readme.md @@ -2,17 +2,21 @@ **HIGHLY EXPERIMENTAL: CURRENTLY, IT REPLACES THE WRONG LINES!** -The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by Clippy). +The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [Clippy](https://github.com/Manishearth/rust-clippy)). ## Current state This tool can - read a file of diagnostics (one JSON object per line) +- interactively step through the suggestions and ask the user what to do +- apply suggestions (currently overwrites the wrong lines!) + +![rustfix demo](http://i.imgur.com/E9YkK76.png) ## Get the example running -My current example output for diagnostics is based on libui-rs. You can find the example JSON in `tests/fixtures/libui-rs/clippy.json`. +My current example output for diagnostics is based on [libui-rs](https://github.com/pcwalton/libui-rs). You can find the example JSON in `tests/fixtures/libui-rs/clippy.json`. Run `rustfix`: From 695eec0151f898692626be73f7b37815c6458efd Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 8 Jul 2016 12:24:06 +0200 Subject: [PATCH 019/298] Refactor CLI UX a bit --- src/lib.rs | 10 +++--- src/main.rs | 95 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f5df264cd..2c0775446 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ extern crate serde_json; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; -#[derive(Debug)] +#[derive(Debug, Copy, Clone, Hash, PartialEq)] pub struct LinePosition(pub usize, pub usize); impl std::fmt::Display for LinePosition { @@ -15,7 +15,7 @@ impl std::fmt::Display for LinePosition { } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone, Hash, PartialEq)] pub struct LineRange(pub LinePosition, pub LinePosition); impl std::fmt::Display for LineRange { @@ -24,7 +24,7 @@ impl std::fmt::Display for LineRange { } } -#[derive(Debug)] +#[derive(Debug, Clone, Hash, PartialEq)] pub struct Suggestion { pub message: String, pub file_name: String, @@ -58,9 +58,9 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, parent_message: Option (try!(std::io::stdout().flush());) +} + fn try_main() -> Result<(), ProgramError> { let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); let file = try!(read_file_to_string(&file_name)); + let mut accepted_suggestions: Vec = vec![]; + 'diagnostics: for line in file.lines().filter(not_empty) { let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); 'suggestions: for suggestion in &rustfix::collect_suggestions(&deserialized, None) { @@ -34,48 +41,51 @@ fn try_main() -> Result<(), ProgramError> { {replacement}\n", info="Info".green().bold(), message=split_at_lint_name(&suggestion.message), - arrow="-->".blue().bold(), + arrow=" -->".blue().bold(), suggestion="Suggestion - Replace:".yellow().bold(), file=suggestion.file_name, range=suggestion.line_range, - text=indent(&reset_indent(&suggestion.text)), + text=indent(4, &reset_indent(&suggestion.text)), with="with:".yellow().bold(), - replacement=indent(&suggestion.replacement) + replacement=indent(4, &suggestion.replacement) ); 'userinput: loop { - println!("{prompt} {user_options}", - prompt="==>".green().bold(), user_options=USER_OPTIONS.green()); + print!("{arrow} {user_options}\n\ + {prompt} ", + arrow="==>".green().bold(), + prompt=" >".green().bold(), + user_options=USER_OPTIONS.green()); + flush!(); let mut input = String::new(); try!(std::io::stdin().read_line(&mut input)); match input.trim() { - "q" => { - println!("Thanks for playing."); - break 'diagnostics; - } "s" => { println!("Skipped."); continue 'suggestions; } "r" => { - let mut file = try!(File::open(&suggestion.file_name)); - let mut file_content = vec![]; - try!(file.read_to_end(&mut file_content)); - - let mut new_content = vec![]; - new_content.extend_from_slice(&file_content[..suggestion.byte_range.0]); - new_content.extend_from_slice(suggestion.replacement.as_bytes()); - new_content.extend_from_slice(&file_content[suggestion.byte_range.1..]); - - let mut file = try!(File::create(&suggestion.file_name)); - - try!(file.set_len(new_content.len() as u64)); - try!(file.write_all(&new_content)); - println!("Replaced."); + accepted_suggestions.push((*suggestion).clone()); + println!("Suggestion accepted. I'll remember that and apply it later."); + continue 'suggestions; }, + "q" => { + println!("Good work. Let me just apply these {} changes!", + accepted_suggestions.len()); + + try!(apply_suggestions(&accepted_suggestions)); + + println!("\nDone."); + println!("Thanks for playing!"); + break 'diagnostics; + } + "a" => { + println!("Let's get outta here!"); + break 'diagnostics; + } _ => { - println!("{error}: I didn't get that. {user_options}", + println!("{error}: I didn't quite get that. {user_options}", error="Error".red().bold(), user_options=USER_OPTIONS); continue 'userinput; } @@ -127,7 +137,7 @@ fn not_empty(s: &&str) -> bool { fn split_at_lint_name(s: &str) -> String { s.split(", #[") .collect::>() - .join("\n #[") + .join("\n #[") // Length of whitespace == length of "Info: " } fn reset_indent(s: &str) -> String { @@ -144,9 +154,38 @@ fn reset_indent(s: &str) -> String { .join("\n") } -fn indent(s: &str) -> String { +fn indent(size: u32, s: &str) -> String { + let whitespace: String = std::iter::repeat(' ').take(size as usize).collect(); + s.lines() - .map(|l| format!(" {}", l)) + .map(|l| format!("{}{}", whitespace, l)) .collect::>() .join("\n") } + +fn apply_suggestions(suggestions: &[rustfix::Suggestion]) -> Result<(), ProgramError> { + for suggestion in suggestions.iter().rev() { + // let file_content = read_file_to_string(&suggestion.file_name); + // file_content.lines().skip(suggestion.line_range.0.0) + // .take(suggestion.line_range.1.0) - suggestion.line_range.0.0; + + let mut file = try!(File::open(&suggestion.file_name)); + let mut file_content = vec![]; + try!(file.read_to_end(&mut file_content)); + + let mut new_content = vec![]; + new_content.extend_from_slice(&file_content[..suggestion.byte_range.0]); + new_content.extend_from_slice(suggestion.replacement.as_bytes()); + new_content.extend_from_slice(&file_content[suggestion.byte_range.1..]); + + let mut file = try!(File::create(&suggestion.file_name)); + + try!(file.set_len(new_content.len() as u64)); + try!(file.write_all(&new_content)); + + print!("."); + flush!(); + } + + Ok(()) +} From 2224a55fd8727b4d0b69828337a9f920f6ef60a6 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 14:20:50 +0200 Subject: [PATCH 020/298] Replace by Line Number --- src/lib.rs | 40 +++++++++----- src/main.rs | 155 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 123 insertions(+), 72 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2c0775446..68b29f027 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,20 +7,26 @@ pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; #[derive(Debug, Copy, Clone, Hash, PartialEq)] -pub struct LinePosition(pub usize, pub usize); +pub struct LinePosition { + pub line: usize, + pub column: usize, +} impl std::fmt::Display for LinePosition { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}:{}", self.0, self.1) + write!(f, "{}:{}", self.line, self.column) } } #[derive(Debug, Copy, Clone, Hash, PartialEq)] -pub struct LineRange(pub LinePosition, pub LinePosition); +pub struct LineRange { + pub start: LinePosition, + pub end: LinePosition, +} impl std::fmt::Display for LineRange { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}-{}", self.0, self.1) + write!(f, "{}-{}", self.start, self.end) } } @@ -29,7 +35,6 @@ pub struct Suggestion { pub message: String, pub file_name: String, pub line_range: LineRange, - pub byte_range: (usize, usize), pub text: String, pub replacement: String, } @@ -39,9 +44,16 @@ fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { Some(Suggestion { message: message.into(), file_name: span.file_name.clone(), - line_range: LineRange(LinePosition(span.line_start, span.column_start), - LinePosition(span.line_end, span.column_end)), - byte_range: (span.byte_start, span.byte_end), + line_range: LineRange { + start: LinePosition { + line: span.line_start, + column: span.column_start, + }, + end: LinePosition { + line: span.line_end, + column: span.column_end, + }, + }, text: span.text.iter().map(|ref x| x.text.clone()).collect::>().join("\n"), replacement: replacement, }) @@ -50,16 +62,18 @@ fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { } } -pub fn collect_suggestions(diagnostic: &Diagnostic, parent_message: Option) - -> Vec -{ +pub fn collect_suggestions(diagnostic: &Diagnostic, + parent_message: Option) + -> Vec { let message = parent_message.unwrap_or(diagnostic.message.clone()); let mut suggestions = vec![]; - suggestions.extend(diagnostic.spans.iter() + suggestions.extend(diagnostic.spans + .iter() .flat_map(|span| collect_span(&message, span))); - suggestions.extend(diagnostic.children.iter() + suggestions.extend(diagnostic.children + .iter() .flat_map(|children| collect_suggestions(children, Some(message.clone())))); suggestions diff --git a/src/main.rs b/src/main.rs index 6bee59686..edcced18f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,12 +10,20 @@ use std::io::{Read, Write}; use colored::Colorize; const USER_OPTIONS: &'static str = "What do you want to do? \ - [r]eplace/[s]kip/save and [q]uit/[a]bort (without saving)"; + [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; fn main() { - if let Err(error) = try_main() { - writeln!(std::io::stderr(), "An error occured: {:#?}", error).unwrap(); - std::process::exit(1); + let program = try_main(); + match program { + Ok(_) => std::process::exit(0), + Err(ProgramError::UserAbort) => { + writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap(); + std::process::exit(0); + } + Err(error) => { + writeln!(std::io::stderr(), "An error occured: {:#?}", error).unwrap(); + std::process::exit(1); + } } } @@ -32,29 +40,24 @@ fn try_main() -> Result<(), ProgramError> { 'diagnostics: for line in file.lines().filter(not_empty) { let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); 'suggestions: for suggestion in &rustfix::collect_suggestions(&deserialized, None) { - println!( - "\n{info}: {message}\n\ - {arrow} {file}:{range}\n\ - {suggestion}\n\n\ - {text}\n\n\ - {with}\n\n\ - {replacement}\n", - info="Info".green().bold(), - message=split_at_lint_name(&suggestion.message), - arrow=" -->".blue().bold(), - suggestion="Suggestion - Replace:".yellow().bold(), - file=suggestion.file_name, range=suggestion.line_range, - text=indent(4, &reset_indent(&suggestion.text)), - with="with:".yellow().bold(), - replacement=indent(4, &suggestion.replacement) - ); + println!("\n\n{info}: {message}\n{arrow} \ + {file}:{range}\n{suggestion}\n\n{text}\n\n{with}\n\n{replacement}\n", + info = "Info".green().bold(), + message = split_at_lint_name(&suggestion.message), + arrow = " -->".blue().bold(), + suggestion = "Suggestion - Replace:".yellow().bold(), + file = suggestion.file_name, + range = suggestion.line_range, + text = indent(4, &reset_indent(&suggestion.text)), + with = "with:".yellow().bold(), + replacement = indent(4, &suggestion.replacement)); 'userinput: loop { print!("{arrow} {user_options}\n\ {prompt} ", - arrow="==>".green().bold(), - prompt=" >".green().bold(), - user_options=USER_OPTIONS.green()); + arrow = "==>".green().bold(), + prompt = " >".green().bold(), + user_options = USER_OPTIONS.green()); flush!(); let mut input = String::new(); @@ -69,31 +72,42 @@ fn try_main() -> Result<(), ProgramError> { accepted_suggestions.push((*suggestion).clone()); println!("Suggestion accepted. I'll remember that and apply it later."); continue 'suggestions; - }, + } "q" => { - println!("Good work. Let me just apply these {} changes!", - accepted_suggestions.len()); - - try!(apply_suggestions(&accepted_suggestions)); - - println!("\nDone."); println!("Thanks for playing!"); break 'diagnostics; } "a" => { - println!("Let's get outta here!"); - break 'diagnostics; + return Err(ProgramError::UserAbort); } _ => { println!("{error}: I didn't quite get that. {user_options}", - error="Error".red().bold(), user_options=USER_OPTIONS); + error = "Error".red().bold(), + user_options = USER_OPTIONS); continue 'userinput; } } } } + } + if !accepted_suggestions.is_empty() { + println!("Good work. Let me just apply these {} changes!", + accepted_suggestions.len()); + + for suggestion in accepted_suggestions.iter().rev() { + try!(apply_suggestion(suggestion)); + + print!("."); + flush!(); + } + + println!("\nDone."); + } + + println!("See you around!"); + Ok(()) } @@ -101,6 +115,9 @@ quick_error! { /// All possible errors in programm lifecycle #[derive(Debug)] pub enum ProgramError { + UserAbort { + description("Let's get outta here!") + } /// Missing File NoFile { description("No input file given") @@ -136,14 +153,14 @@ fn not_empty(s: &&str) -> bool { fn split_at_lint_name(s: &str) -> String { s.split(", #[") - .collect::>() - .join("\n #[") // Length of whitespace == length of "Info: " + .collect::>() + .join("\n #[") // Length of whitespace == length of "Info: " } fn reset_indent(s: &str) -> String { - let leading_whitespace = - s.lines() - .nth(0).unwrap_or("") + let leading_whitespace = s.lines() + .nth(0) + .unwrap_or("") .chars() .take_while(|&c| char::is_whitespace(c)) .count(); @@ -158,34 +175,54 @@ fn indent(size: u32, s: &str) -> String { let whitespace: String = std::iter::repeat(' ').take(size as usize).collect(); s.lines() - .map(|l| format!("{}{}", whitespace, l)) - .collect::>() - .join("\n") + .map(|l| format!("{}{}", whitespace, l)) + .collect::>() + .join("\n") } -fn apply_suggestions(suggestions: &[rustfix::Suggestion]) -> Result<(), ProgramError> { - for suggestion in suggestions.iter().rev() { - // let file_content = read_file_to_string(&suggestion.file_name); - // file_content.lines().skip(suggestion.line_range.0.0) - // .take(suggestion.line_range.1.0) - suggestion.line_range.0.0; +/// Apply suggestion to a file +/// +/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the +/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant +/// to correspond to. So, for now, let's just replace lines! +/// +/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in +/// reverse order to not mess up the lines for replacements further down the road. +fn apply_suggestion(suggestion: &rustfix::Suggestion) -> Result<(), ProgramError> { + use std::cmp::max; + use std::iter::repeat; - let mut file = try!(File::open(&suggestion.file_name)); - let mut file_content = vec![]; - try!(file.read_to_end(&mut file_content)); + let file_content = try!(read_file_to_string(&suggestion.file_name)); + let mut new_content = String::new(); - let mut new_content = vec![]; - new_content.extend_from_slice(&file_content[..suggestion.byte_range.0]); - new_content.extend_from_slice(suggestion.replacement.as_bytes()); - new_content.extend_from_slice(&file_content[suggestion.byte_range.1..]); + // Add the lines before the section we want to replace + new_content.push_str(&file_content.lines() + .take(max(suggestion.line_range.start.line - 1, 0) as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); - let mut file = try!(File::create(&suggestion.file_name)); + // Indentation + new_content.push_str(&repeat(" ") + .take(suggestion.line_range.start.column - 1 as usize) + .collect::()); - try!(file.set_len(new_content.len() as u64)); - try!(file.write_all(&new_content)); + // TODO(killercup): Replace sections of lines only + new_content.push_str(suggestion.replacement.trim()); - print!("."); - flush!(); - } + // Add the lines after the section we want to replace + new_content.push_str("\n"); + new_content.push_str(&file_content.lines() + .skip(suggestion.line_range.end.line as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + let mut file = try!(File::create(&suggestion.file_name)); + let new_content = new_content.as_bytes(); + + try!(file.set_len(new_content.len() as u64)); + try!(file.write_all(&new_content)); Ok(()) } From ee128f315427c6ea2e0091b3b8fc66545246b51d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 15:27:56 +0200 Subject: [PATCH 021/298] Remember Trailing Semicolons --- src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index edcced18f..784b11435 100644 --- a/src/main.rs +++ b/src/main.rs @@ -200,9 +200,12 @@ fn apply_suggestion(suggestion: &rustfix::Suggestion) -> Result<(), ProgramError .take(max(suggestion.line_range.start.line - 1, 0) as usize) .collect::>() .join("\n")); - new_content.push_str("\n"); + + // Some suggestions seem to currently omit the trailing semicolon + let remember_a_semicolon = new_content.ends_with(';'); // Indentation + new_content.push_str("\n"); new_content.push_str(&repeat(" ") .take(suggestion.line_range.start.column - 1 as usize) .collect::()); @@ -210,6 +213,10 @@ fn apply_suggestion(suggestion: &rustfix::Suggestion) -> Result<(), ProgramError // TODO(killercup): Replace sections of lines only new_content.push_str(suggestion.replacement.trim()); + if remember_a_semicolon { + new_content.push_str(";"); + } + // Add the lines after the section we want to replace new_content.push_str("\n"); new_content.push_str(&file_content.lines() From 78a0edc674bfb234284bc711e542fd7b21202d33 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 15:28:02 +0200 Subject: [PATCH 022/298] Update Readme --- Readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 09f9c448a..81b4b43a2 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # rustfix -**HIGHLY EXPERIMENTAL: CURRENTLY, IT REPLACES THE WRONG LINES!** +> **HIGHLY EXPERIMENTAL – MIGHT EAT YOUR CODE** The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [Clippy](https://github.com/Manishearth/rust-clippy)). @@ -10,7 +10,7 @@ This tool can - read a file of diagnostics (one JSON object per line) - interactively step through the suggestions and ask the user what to do -- apply suggestions (currently overwrites the wrong lines!) +- apply suggestions (currently whole lines only) ![rustfix demo](http://i.imgur.com/E9YkK76.png) @@ -45,8 +45,8 @@ $ cargo clippy -- -Z unstable-options --error-format json &2> clippy.json Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. From e74e9b092cb53a24decb0b66f9e06515b164d7f3 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 17:33:06 +0200 Subject: [PATCH 023/298] Use Cargo to Get Suggestions for Great Justice --- Cargo.toml | 7 +- src/main.rs | 201 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 147 insertions(+), 61 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 394ec1502..c749a26c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,12 @@ [package] authors = ["Pascal Hertleif "] -name = "rustfix" -version = "0.1.0" -readme = "README.md" license = "Apache-2.0/MIT" +name = "rustfix" +readme = "README.md" +version = "0.1.0" [dependencies] +clap = "2.9.2" colored = "1.2.0" quick-error = "1.1.0" serde = "0.7.13" diff --git a/src/main.rs b/src/main.rs index 784b11435..de8414564 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,22 @@ +extern crate serde_json; #[macro_use] extern crate quick_error; -extern crate serde_json; +#[macro_use] +extern crate clap; extern crate colored; extern crate rustfix; use std::fs::File; use std::io::{Read, Write}; +use std::error::Error; +use std::process::Command; + use colored::Colorize; +use clap::{Arg, App}; + +use rustfix::Suggestion; +use rustfix::diagnostics::Diagnostic; const USER_OPTIONS: &'static str = "What do you want to do? \ [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; @@ -21,7 +30,11 @@ fn main() { std::process::exit(0); } Err(error) => { - writeln!(std::io::stderr(), "An error occured: {:#?}", error).unwrap(); + writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); + writeln!(std::io::stderr(), "{:?}", error).unwrap(); + if let Some(cause) = error.cause() { + writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap(); + } std::process::exit(1); } } @@ -32,64 +45,128 @@ macro_rules! flush { } fn try_main() -> Result<(), ProgramError> { - let file_name = try!(std::env::args().skip(1).next().ok_or(ProgramError::NoFile)); - let file = try!(read_file_to_string(&file_name)); + let matches = App::new("rustfix") + .about("Automatically apply suggestions made by rustc") + .version(crate_version!()) + .arg(Arg::with_name("clippy") + .long("clippy") + .help("Use `cargo clippy` for suggestions")) + .arg(Arg::with_name("from_file") + .long("from-file") + .value_name("FILE") + .takes_value(true) + .help("Read suggestions from file (each line is a JSON object)")) + .get_matches(); - let mut accepted_suggestions: Vec = vec![]; + // Get JSON output from rustc... + let json = if let Some(file_name) = matches.value_of("from_file") { + // either by reading a file the user saved (probably only for debugging rustfix itself)... + try!(json_from_file(&file_name)) + } else { + // or by spawning a subcommand that runs rustc. + let subcommand = if matches.is_present("clippy") { + "clippy" + } else { + "rustc" + }; + try!(json_from_subcommand(subcommand)) + }; - 'diagnostics: for line in file.lines().filter(not_empty) { - let deserialized: rustfix::diagnostics::Diagnostic = try!(serde_json::from_str(&line)); - 'suggestions: for suggestion in &rustfix::collect_suggestions(&deserialized, None) { - println!("\n\n{info}: {message}\n{arrow} \ - {file}:{range}\n{suggestion}\n\n{text}\n\n{with}\n\n{replacement}\n", - info = "Info".green().bold(), - message = split_at_lint_name(&suggestion.message), - arrow = " -->".blue().bold(), - suggestion = "Suggestion - Replace:".yellow().bold(), - file = suggestion.file_name, - range = suggestion.line_range, - text = indent(4, &reset_indent(&suggestion.text)), - with = "with:".yellow().bold(), - replacement = indent(4, &suggestion.replacement)); + let suggestions: Vec = json.lines() + .filter(not_empty) + .flat_map(|line| serde_json::from_str::(&line)) + .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None)) + .collect(); - 'userinput: loop { - print!("{arrow} {user_options}\n\ - {prompt} ", - arrow = "==>".green().bold(), - prompt = " >".green().bold(), - user_options = USER_OPTIONS.green()); + try!(handle_suggestions(&suggestions)); - flush!(); - let mut input = String::new(); - try!(std::io::stdin().read_line(&mut input)); + Ok(()) +} - match input.trim() { - "s" => { - println!("Skipped."); - continue 'suggestions; - } - "r" => { - accepted_suggestions.push((*suggestion).clone()); - println!("Suggestion accepted. I'll remember that and apply it later."); - continue 'suggestions; - } - "q" => { - println!("Thanks for playing!"); - break 'diagnostics; - } - "a" => { - return Err(ProgramError::UserAbort); - } - _ => { - println!("{error}: I didn't quite get that. {user_options}", - error = "Error".red().bold(), - user_options = USER_OPTIONS); - continue 'userinput; - } +fn json_from_file(file_name: &str) -> Result { + read_file_to_string(&file_name).map_err(From::from) +} + +fn json_from_subcommand(subcommand: &str) -> Result { + let output = try!(Command::new("cargo") + .args(&[subcommand, + "--quiet", + "--color", "never", + "--", + "-Z", "unstable-options", + "--error-format", "json"]) + .output()); + + let content = try!(String::from_utf8(output.stderr)); + + if !output.status.success() { + return Err(ProgramError::SubcommandError(format!("cargo {}", subcommand), content)); + } + + Ok(content) +} + +fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { + let mut accepted_suggestions: Vec<&Suggestion> = vec![]; + + if suggestions.is_empty() { + println!("I don't have any suggestions for you right now. Check back later!"); + return Ok(()); + } + + 'suggestions: for suggestion in suggestions { + println!("\n\n{info}: {message}\n\ + {arrow} {file}:{range}\n\ + {suggestion}\n\n\ + {text}\n\n\ + {with}\n\n\ + {replacement}\n", + info = "Info".green().bold(), + message = split_at_lint_name(&suggestion.message), + arrow = " -->".blue().bold(), + suggestion = "Suggestion - Replace:".yellow().bold(), + file = suggestion.file_name, + range = suggestion.line_range, + text = indent(4, &reset_indent(&suggestion.text)), + with = "with:".yellow().bold(), + replacement = indent(4, &suggestion.replacement)); + + 'userinput: loop { + print!("{arrow} {user_options}\n\ + {prompt} ", + arrow = "==>".green().bold(), + prompt = " >".green().bold(), + user_options = USER_OPTIONS.green()); + + flush!(); + let mut input = String::new(); + try!(std::io::stdin().read_line(&mut input)); + + match input.trim() { + "s" => { + println!("Skipped."); + continue 'suggestions; + } + "r" => { + accepted_suggestions.push(suggestion); + println!("Suggestion accepted. I'll remember that and apply it later."); + continue 'suggestions; + } + "q" => { + println!("Thanks for playing!"); + break 'suggestions; + } + "a" => { + return Err(ProgramError::UserAbort); + } + _ => { + println!("{error}: I didn't quite get that. {user_options}", + error = "Error".red().bold(), + user_options = USER_OPTIONS); + continue 'userinput; } } } - } if !accepted_suggestions.is_empty() { @@ -106,8 +183,6 @@ fn try_main() -> Result<(), ProgramError> { println!("\nDone."); } - println!("See you around!"); - Ok(()) } @@ -116,22 +191,32 @@ quick_error! { #[derive(Debug)] pub enum ProgramError { UserAbort { - description("Let's get outta here!") + display("Let's get outta here!") } /// Missing File NoFile { - description("No input file given") + display("No input file given") + } + SubcommandError(subcommand: String, output: String) { + display("Error executing subcommand `{}`", subcommand) + description(output) } /// Error while dealing with file or stdin/stdout Io(err: std::io::Error) { from() cause(err) + display("I/O error") description(err.description()) } + Utf8Error(err: std::string::FromUtf8Error) { + from() + display("Error reading input as UTF-8") + } /// Error with deserialization Serde(err: serde_json::Error) { from() cause(err) + display("Serde JSON error") description(err.description()) } } @@ -188,7 +273,7 @@ fn indent(size: u32, s: &str) -> String { /// /// This function is as stupid as possible. Make sure you call for the replacemnts in one file in /// reverse order to not mess up the lines for replacements further down the road. -fn apply_suggestion(suggestion: &rustfix::Suggestion) -> Result<(), ProgramError> { +fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { use std::cmp::max; use std::iter::repeat; @@ -202,7 +287,7 @@ fn apply_suggestion(suggestion: &rustfix::Suggestion) -> Result<(), ProgramError .join("\n")); // Some suggestions seem to currently omit the trailing semicolon - let remember_a_semicolon = new_content.ends_with(';'); + let remember_a_semicolon = suggestion.text.trim().ends_with(';'); // Indentation new_content.push_str("\n"); From 4b7e7cc980711236e7f8ef057084076c04951901 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 17:43:00 +0200 Subject: [PATCH 024/298] Update Readme to Include CLI Help --- Readme.md | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 81b4b43a2..cbf0652d0 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,9 @@ > **HIGHLY EXPERIMENTAL – MIGHT EAT YOUR CODE** -The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [Clippy](https://github.com/Manishearth/rust-clippy)). +The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [Clippy][clippy]). + +[clippy]: https://github.com/Manishearth/rust-clippy ## Current state @@ -14,6 +16,42 @@ This tool can ![rustfix demo](http://i.imgur.com/E9YkK76.png) +## Installation + +Assuming you have a recent Rust nightly and Cargo installed: + +```sh +$ cargo install --git https://github.com/killercup/rustfix.git +``` + +Make sure the binaries installed by Cargo are in your `$PATH`. + +## Usage + +In your project directory, just execute `rustfix`! + +You probably want to use `rustfix --clippy` to get all the suggestions from [Clippy][clippy] as well. Make sure you have `cargo clippy` installed (`cargo install clippy`). + +Please note that running `rustfix` multiple times in a project where no file was changed in the meantime will currently not generate any suggesions (as Cargo/Rust will skip the unchanged code and not compile it again). + +### CLI Options + +```plain +rustfix 0.1.0 +Automatically apply suggestions made by rustc + +USAGE: + rustfix [FLAGS] [OPTIONS] + +FLAGS: + --clippy Use `cargo clippy` for suggestions + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --from-file Read suggestions from file (each line is a JSON object) +``` + ## Get the example running My current example output for diagnostics is based on [libui-rs](https://github.com/pcwalton/libui-rs). You can find the example JSON in `tests/fixtures/libui-rs/clippy.json`. @@ -22,10 +60,10 @@ Run `rustfix`: ```sh $ cd tests/fixtures/libui-rs/ -$ cargo run -- clippy.json +$ cargo run -- --from-file clippy.json ``` -### Generate the diagnostics JSON file yourself +### Generate the example diagnostics JSON yourself ```sh $ git clone https://github.com/pcwalton/libui-rs.git From a249a967f2e9e800be45b090a3f5c9cbcdf5109f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 17:45:07 +0200 Subject: [PATCH 025/298] Omit Needless Borrows --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index de8414564..31a912d55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ fn try_main() -> Result<(), ProgramError> { let suggestions: Vec = json.lines() .filter(not_empty) - .flat_map(|line| serde_json::from_str::(&line)) + .flat_map(|line| serde_json::from_str::(line)) .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None)) .collect(); @@ -84,7 +84,7 @@ fn try_main() -> Result<(), ProgramError> { } fn json_from_file(file_name: &str) -> Result { - read_file_to_string(&file_name).map_err(From::from) + read_file_to_string(file_name).map_err(From::from) } fn json_from_subcommand(subcommand: &str) -> Result { From da7d9920f94a1c1318432ddc0181301da465d65d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 17:50:48 +0200 Subject: [PATCH 026/298] Add Comment to Remember Parsing Errors are Eaten --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index 31a912d55..3f298e901 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,9 @@ fn try_main() -> Result<(), ProgramError> { let suggestions: Vec = json.lines() .filter(not_empty) + // Convert JSON string (and eat parsing errors) .flat_map(|line| serde_json::from_str::(line)) + // One diagnostic line might have multiple suggestions .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None)) .collect(); From 8a496aa6cfc0027d7472f0b0016ea133a24e626f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 17:55:49 +0200 Subject: [PATCH 027/298] Mention Cargo-mode in Readme --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index cbf0652d0..dd622f882 100644 --- a/Readme.md +++ b/Readme.md @@ -10,6 +10,7 @@ The goal of this tool is to read and apply the suggestions made by rustc (and th This tool can +- parse rustc's diagnostics (it calls `cargo` for you and reads its output) - read a file of diagnostics (one JSON object per line) - interactively step through the suggestions and ask the user what to do - apply suggestions (currently whole lines only) From f13e843b5f75c6ac7649daf46e7a68a35415a042 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 18:15:53 +0200 Subject: [PATCH 028/298] Reduce Stupidity --- src/main.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3f298e901..465fc65f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -277,7 +277,6 @@ fn indent(size: u32, s: &str) -> String { /// reverse order to not mess up the lines for replacements further down the road. fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { use std::cmp::max; - use std::iter::repeat; let file_content = try!(read_file_to_string(&suggestion.file_name)); let mut new_content = String::new(); @@ -287,20 +286,13 @@ fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { .take(max(suggestion.line_range.start.line - 1, 0) as usize) .collect::>() .join("\n")); - - // Some suggestions seem to currently omit the trailing semicolon - let remember_a_semicolon = suggestion.text.trim().ends_with(';'); - - // Indentation new_content.push_str("\n"); - new_content.push_str(&repeat(" ") - .take(suggestion.line_range.start.column - 1 as usize) - .collect::()); // TODO(killercup): Replace sections of lines only - new_content.push_str(suggestion.replacement.trim()); + new_content.push_str(&indent((suggestion.line_range.start.column - 1) as u32, + suggestion.replacement.trim())); - if remember_a_semicolon { + if suggestion.text.trim().ends_with(';') && !suggestion.replacement.trim().ends_with(';') { new_content.push_str(";"); } From dd49d9f71e8a419490c70b9c55cc40d133004573 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 20:19:07 +0200 Subject: [PATCH 029/298] Fix Typos in Readme cf. #1 --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index dd622f882..4aad47fc0 100644 --- a/Readme.md +++ b/Readme.md @@ -33,7 +33,7 @@ In your project directory, just execute `rustfix`! You probably want to use `rustfix --clippy` to get all the suggestions from [Clippy][clippy] as well. Make sure you have `cargo clippy` installed (`cargo install clippy`). -Please note that running `rustfix` multiple times in a project where no file was changed in the meantime will currently not generate any suggesions (as Cargo/Rust will skip the unchanged code and not compile it again). +Please note that running `rustfix` multiple times in a project where no file was changed in the meantime will currently not generate any suggestions (as Cargo/Rust will skip the unchanged code and not compile it again). ### CLI Options @@ -77,7 +77,7 @@ $ cargo clippy -- -Z unstable-options --error-format json &2> clippy.json ## Gotchas - rustc JSON output is unstable -- Not all suggestions can be applied trivially (e.g. clippy's "You should use `Default` instead of that `fn new()` you just wrote"-lint will replace your `new`-method with an `impl` block -- which is obvisouly invalid syntax.) +- Not all suggestions can be applied trivially (e.g. clippy's "You should use `Default` instead of that `fn new()` you just wrote"-lint will replace your `new`-method with an `impl` block -- which is obviously invalid syntax.) - This tool _will_ eat your laundry ## License From b883480e794118908fd27108d05b85cfb751ab28 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 9 Jul 2016 20:30:04 +0200 Subject: [PATCH 030/298] First try at replacing partials lines Concerns #1 --- src/main.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 465fc65f3..fb8e6733b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -288,14 +288,30 @@ fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { .join("\n")); new_content.push_str("\n"); - // TODO(killercup): Replace sections of lines only - new_content.push_str(&indent((suggestion.line_range.start.column - 1) as u32, - suggestion.replacement.trim())); + // Parts of line before replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.line_range.start.line - 1) + .unwrap_or("") + .chars() + .take(suggestion.line_range.start.column - 1) + .collect::()); + // Insert new content! Finally! + new_content.push_str(&suggestion.replacement); + + // TODO(killercup): better handling of trailing semicolons if suggestion.text.trim().ends_with(';') && !suggestion.replacement.trim().ends_with(';') { new_content.push_str(";"); } + // Parts of line after replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.line_range.end.line - 1) + .unwrap_or("") + .chars() + .skip(suggestion.line_range.end.column) + .collect::()); + // Add the lines after the section we want to replace new_content.push_str("\n"); new_content.push_str(&file_content.lines() From 5f0234f2f5ae4f781ea79225b78ac54d3babc41a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 10 Jul 2016 00:48:52 +0200 Subject: [PATCH 031/298] Fix Column Offset --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index fb8e6733b..4867da77e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -309,7 +309,7 @@ fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { .nth(suggestion.line_range.end.line - 1) .unwrap_or("") .chars() - .skip(suggestion.line_range.end.column) + .skip(suggestion.line_range.end.column - 1) .collect::()); // Add the lines after the section we want to replace From 6937912bb89da024f6da89a35b2308f31af7663d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Mon, 11 Jul 2016 12:19:02 +0200 Subject: [PATCH 032/298] Let Clippy Worry about Semicolons --- src/main.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4867da77e..828aaaf2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -299,11 +299,6 @@ fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { // Insert new content! Finally! new_content.push_str(&suggestion.replacement); - // TODO(killercup): better handling of trailing semicolons - if suggestion.text.trim().ends_with(';') && !suggestion.replacement.trim().ends_with(';') { - new_content.push_str(";"); - } - // Parts of line after replacement new_content.push_str(&file_content.lines() .nth(suggestion.line_range.end.line - 1) From 4eebf8c2759203a8e25e14860662fc6bd9cc19dd Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Mon, 11 Jul 2016 18:25:01 +0200 Subject: [PATCH 033/298] Add TravisCI --- .travis.yml | 3 +++ Readme.md | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..efa26bc34 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: rust +rust: +- nightly diff --git a/Readme.md b/Readme.md index 4aad47fc0..a5498dffa 100644 --- a/Readme.md +++ b/Readme.md @@ -6,6 +6,8 @@ The goal of this tool is to read and apply the suggestions made by rustc (and th [clippy]: https://github.com/Manishearth/rust-clippy +[![Build Status](https://travis-ci.org/killercup/rustfix.svg?branch=master)](https://travis-ci.org/killercup/rustfix) + ## Current state This tool can From 49408a2a705de098030f6870c6316818d61039b7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 12 Jul 2016 15:58:26 +0530 Subject: [PATCH 034/298] fix clippy command redirection --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index a5498dffa..432482585 100644 --- a/Readme.md +++ b/Readme.md @@ -72,7 +72,7 @@ $ cargo run -- --from-file clippy.json $ git clone https://github.com/pcwalton/libui-rs.git # HEAD is at 13299d28f69f8009be8e08e453a9b0024f153a60 $ cd libui-rs/ui/ -$ cargo clippy -- -Z unstable-options --error-format json &2> clippy.json +$ cargo clippy -- -Z unstable-options --error-format json 2&> clippy.json # Manually remove the first line ("Compiling....") ``` From ac1f38baa19c8366346eea15f2f9268d081f4deb Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 27 Aug 2016 19:51:47 +0200 Subject: [PATCH 035/298] Upgrade serde to 0.8 --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c749a26c7..51885f73d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,6 @@ version = "0.1.0" clap = "2.9.2" colored = "1.2.0" quick-error = "1.1.0" -serde = "0.7.13" -serde_json = "0.7.4" -serde_macros = "0.7.13" +serde = "0.8" +serde_json = "0.8" +serde_macros = "0.8" From 5605d4f6c34d68c60a6f5ab8294078d0ef9f0419 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Sun, 18 Sep 2016 13:21:46 +0200 Subject: [PATCH 036/298] Did you mean to write: "clippy"? --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 432482585..8f58f9ca0 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ > **HIGHLY EXPERIMENTAL – MIGHT EAT YOUR CODE** -The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [Clippy][clippy]). +The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [clippy]). [clippy]: https://github.com/Manishearth/rust-clippy From bb3e5e70447452c709ce6646331a8a2e006e4bf6 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 18 Sep 2016 14:22:39 +0200 Subject: [PATCH 037/298] Fix a clippy suggestion --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 68b29f027..f4129fa4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { column: span.column_end, }, }, - text: span.text.iter().map(|ref x| x.text.clone()).collect::>().join("\n"), + text: span.text.iter().map(|x| x.text.clone()).collect::>().join("\n"), replacement: replacement, }) } else { From 27bbceee4e74b6bc8a503b32b30e8f37d1553fa9 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 18 Sep 2016 14:26:50 +0200 Subject: [PATCH 038/298] Set specific nightly version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efa26bc34..144c6aa45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: rust rust: -- nightly +- nightly-2016-09-09 From 66b9e3422fb0cc1e0236983513ec98a1a55b2e67 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Sun, 6 Nov 2016 07:26:44 -0800 Subject: [PATCH 039/298] replace serde_macros by serde_derive serde_macros is being deprecated in favor of serde_derive[0]. As a result, rustfix does not build on nighlty anymore[1]. This commit replaces serde_macros by serde_derive. [0] https://users.rust-lang.org/t/serde-transitioning-to-macros-1-1/7437/5 [1] https://github.com/serde-rs/serde/issues/606#issuecomment-258648508 --- Cargo.toml | 2 +- src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51885f73d..ab9bd740c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ colored = "1.2.0" quick-error = "1.1.0" serde = "0.8" serde_json = "0.8" -serde_macros = "0.8" +serde_derive = "0.8" diff --git a/src/lib.rs b/src/lib.rs index f4129fa4e..ba8732d01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ -#![feature(custom_derive, plugin)] -#![plugin(serde_macros)] - +#![feature(proc_macro)] +#[macro_use] +extern crate serde_derive; extern crate serde_json; pub mod diagnostics; From b7ca4413e3c77a45fd1269cb70949598aa0eb152 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Sun, 6 Nov 2016 17:00:59 -0800 Subject: [PATCH 040/298] travis: update to latest rust nightly --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 144c6aa45..efa26bc34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: rust rust: -- nightly-2016-09-09 +- nightly From 01284461c808d2569c6273688b1f4dd07b646f0e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 May 2017 17:36:40 +0200 Subject: [PATCH 041/298] Update to serde 1.0 --- Cargo.toml | 6 +++--- src/lib.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab9bd740c..ca4c76eb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,6 @@ version = "0.1.0" clap = "2.9.2" colored = "1.2.0" quick-error = "1.1.0" -serde = "0.8" -serde_json = "0.8" -serde_derive = "0.8" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" diff --git a/src/lib.rs b/src/lib.rs index ba8732d01..2a16ae1d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(proc_macro)] #[macro_use] extern crate serde_derive; extern crate serde_json; From 12cb9b07e24e4ee9f493fcb3ea7edd20165ec07d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 May 2017 18:33:39 +0200 Subject: [PATCH 042/298] Hilight the part of the text to be replaced in red --- src/lib.rs | 30 ++++++++++++++++++++++++++++-- src/main.rs | 20 ++++---------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a16ae1d7..616bbdb28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,12 +34,38 @@ pub struct Suggestion { pub message: String, pub file_name: String, pub line_range: LineRange, - pub text: String, + /// leading surrounding text, text to replace, trailing surrounding text + /// + /// This split is useful for higlighting the part that gets replaced + pub text: (String, String, String), pub replacement: String, } fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { if let Some(replacement) = span.suggested_replacement.clone() { + // unindent the snippet + let indent = span.text.iter().map(|line| { + let indent = line.text + .chars() + .take_while(|&c| char::is_whitespace(c)) + .count(); + std::cmp::min(indent, line.highlight_start) + }).min().expect("text to replace is empty"); + let start = span.text[0].highlight_start - 1; + let end = span.text[0].highlight_end - 1; + let lead = span.text[0].text[indent..start].to_string(); + let mut body = span.text[0].text[start..end].to_string(); + for line in span.text.iter().take(span.text.len() - 1).skip(1) { + body.push('\n'); + body.push_str(&line.text[indent..]); + } + let mut tail = String::new(); + let last = &span.text[span.text.len() - 1]; + if span.text.len() > 1 { + body.push('\n'); + body.push_str(&last.text[indent..last.highlight_end - 1]); + } + tail.push_str(&last.text[last.highlight_end - 1..]); Some(Suggestion { message: message.into(), file_name: span.file_name.clone(), @@ -53,7 +79,7 @@ fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { column: span.column_end, }, }, - text: span.text.iter().map(|x| x.text.clone()).collect::>().join("\n"), + text: (lead, body, tail), replacement: replacement, }) } else { diff --git a/src/main.rs b/src/main.rs index 828aaaf2d..8add5aeff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -120,7 +120,7 @@ fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { println!("\n\n{info}: {message}\n\ {arrow} {file}:{range}\n\ {suggestion}\n\n\ - {text}\n\n\ + {lead}{text}{tail}\n\n\ {with}\n\n\ {replacement}\n", info = "Info".green().bold(), @@ -129,7 +129,9 @@ fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { suggestion = "Suggestion - Replace:".yellow().bold(), file = suggestion.file_name, range = suggestion.line_range, - text = indent(4, &reset_indent(&suggestion.text)), + lead = indent(4, &suggestion.text.0), + text = suggestion.text.1.red(), + tail = suggestion.text.2, with = "with:".yellow().bold(), replacement = indent(4, &suggestion.replacement)); @@ -244,20 +246,6 @@ fn split_at_lint_name(s: &str) -> String { .join("\n #[") // Length of whitespace == length of "Info: " } -fn reset_indent(s: &str) -> String { - let leading_whitespace = s.lines() - .nth(0) - .unwrap_or("") - .chars() - .take_while(|&c| char::is_whitespace(c)) - .count(); - - s.lines() - .map(|line| String::from(&line[leading_whitespace..])) - .collect::>() - .join("\n") -} - fn indent(size: u32, s: &str) -> String { let whitespace: String = std::iter::repeat(' ').take(size as usize).collect(); From adf1c757f96d71f273d74bcea2d0563ceff7699b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 May 2017 18:34:07 +0200 Subject: [PATCH 043/298] Don't abort if cargo clippy or cargo rustc fails, they do with -Dwarnings --- src/main.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8add5aeff..82dd1f7b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,10 +101,6 @@ fn json_from_subcommand(subcommand: &str) -> Result { let content = try!(String::from_utf8(output.stderr)); - if !output.status.success() { - return Err(ProgramError::SubcommandError(format!("cargo {}", subcommand), content)); - } - Ok(content) } From 1a2e8be781ec04d605fcd786e30a60c0516b36b8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 14:16:18 +0200 Subject: [PATCH 044/298] Remove libui-rs --- tests/fixtures/libui-rs/clippy.json | 19 - tests/fixtures/libui-rs/src/controls.rs | 1259 ---------------------- tests/fixtures/libui-rs/src/draw.rs | 710 ------------ tests/fixtures/libui-rs/src/ffi_utils.rs | 74 -- tests/fixtures/libui-rs/src/lib.rs | 28 - tests/fixtures/libui-rs/src/menus.rs | 144 --- tests/fixtures/libui-rs/src/ui.rs | 134 --- tests/fixtures/libui-rs/src/windows.rs | 119 -- 8 files changed, 2487 deletions(-) delete mode 100644 tests/fixtures/libui-rs/clippy.json delete mode 100644 tests/fixtures/libui-rs/src/controls.rs delete mode 100644 tests/fixtures/libui-rs/src/draw.rs delete mode 100644 tests/fixtures/libui-rs/src/ffi_utils.rs delete mode 100644 tests/fixtures/libui-rs/src/lib.rs delete mode 100644 tests/fixtures/libui-rs/src/menus.rs delete mode 100644 tests/fixtures/libui-rs/src/ui.rs delete mode 100644 tests/fixtures/libui-rs/src/windows.rs diff --git a/tests/fixtures/libui-rs/clippy.json b/tests/fixtures/libui-rs/clippy.json deleted file mode 100644 index 3ddb19613..000000000 --- a/tests/fixtures/libui-rs/clippy.json +++ /dev/null @@ -1,19 +0,0 @@ -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Button)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":7710,"byte_end":7771,"line_start":245,"line_end":245,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&button)","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":7710,"byte_end":7771,"line_start":245,"line_end":245,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&button)","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Button)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Button)>)(&button)"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Entry)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":10752,"byte_end":10812,"line_start":350,"line_end":350,"column_start":17,"column_end":77,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&entry);","highlight_start":17,"highlight_end":77}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":10752,"byte_end":10812,"line_start":350,"line_end":350,"column_start":17,"column_end":77,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&entry);","highlight_start":17,"highlight_end":77}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Entry)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Entry)>)(&entry);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::Entry`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":11302,"byte_end":11456,"line_start":373,"line_end":378,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Entry {","highlight_start":5,"highlight_end":28},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Entry::from_ui_control(ui_sys::uiNewEntry())","highlight_start":1,"highlight_end":57},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":11302,"byte_end":11456,"line_start":373,"line_end":378,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Entry {","highlight_start":5,"highlight_end":28},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Entry::from_ui_control(ui_sys::uiNewEntry())","highlight_start":1,"highlight_end":57},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Entry { fn default() -> Self { controls::Entry::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Entry { fn default() -> Self { controls::Entry::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Checkbox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":12643,"byte_end":12706,"line_start":415,"line_end":415,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":12643,"byte_end":12706,"line_start":415,"line_end":415,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Checkbox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Checkbox)>)(&checkbox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::Tab`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":15808,"byte_end":15956,"line_start":526,"line_end":531,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Tab {","highlight_start":5,"highlight_end":26},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Tab::from_ui_control(ui_sys::uiNewTab())","highlight_start":1,"highlight_end":53},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":15808,"byte_end":15956,"line_start":526,"line_end":531,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Tab {","highlight_start":5,"highlight_end":26},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Tab::from_ui_control(ui_sys::uiNewTab())","highlight_start":1,"highlight_end":53},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Tab { fn default() -> Self { controls::Tab::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Tab { fn default() -> Self { controls::Tab::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Spinbox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":18423,"byte_end":18485,"line_start":621,"line_end":621,"column_start":17,"column_end":79,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox);","highlight_start":17,"highlight_end":79}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":18423,"byte_end":18485,"line_start":621,"line_end":621,"column_start":17,"column_end":79,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox);","highlight_start":17,"highlight_end":79}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Spinbox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Spinbox)>)(&spinbox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::ProgressBar`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":19068,"byte_end":19240,"line_start":648,"line_end":653,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ProgressBar {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ProgressBar::from_ui_control(ui_sys::uiNewProgressBar())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":19068,"byte_end":19240,"line_start":648,"line_end":653,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ProgressBar {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ProgressBar::from_ui_control(ui_sys::uiNewProgressBar())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::ProgressBar { fn default() -> Self { controls::ProgressBar::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::ProgressBar { fn default() -> Self { controls::ProgressBar::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Slider)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":20291,"byte_end":20352,"line_start":689,"line_end":689,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&slider);","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":20291,"byte_end":20352,"line_start":689,"line_end":689,"column_start":17,"column_end":78,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&slider);","highlight_start":17,"highlight_end":78}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Slider)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Slider)>)(&slider);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::Combobox)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":22291,"byte_end":22354,"line_start":758,"line_end":758,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&combobox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":22291,"byte_end":22354,"line_start":758,"line_end":758,"column_start":17,"column_end":80,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&combobox);","highlight_start":17,"highlight_end":80}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::Combobox)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::Combobox)>)(&combobox);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::Combobox`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":22455,"byte_end":22618,"line_start":765,"line_end":770,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Combobox {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Combobox::from_ui_control(ui_sys::uiNewCombobox())","highlight_start":1,"highlight_end":63},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":22455,"byte_end":22618,"line_start":765,"line_end":770,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> Combobox {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" Combobox::from_ui_control(ui_sys::uiNewCombobox())","highlight_start":1,"highlight_end":63},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::Combobox { fn default() -> Self { controls::Combobox::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::Combobox { fn default() -> Self { controls::Combobox::new() } }"}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::RadioButtons`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":23357,"byte_end":23532,"line_start":796,"line_end":801,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> RadioButtons {","highlight_start":5,"highlight_end":35},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons())","highlight_start":1,"highlight_end":71},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":23357,"byte_end":23532,"line_start":796,"line_end":801,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> RadioButtons {","highlight_start":5,"highlight_end":35},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons())","highlight_start":1,"highlight_end":71},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::RadioButtons { fn default() -> Self { controls::RadioButtons::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::RadioButtons { fn default() -> Self { controls::RadioButtons::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::MultilineEntry)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":25729,"byte_end":25831,"line_start":866,"line_end":867,"column_start":17,"column_end":73,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&multiline_entry);","highlight_start":1,"highlight_end":73}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":25729,"byte_end":25831,"line_start":866,"line_end":867,"column_start":17,"column_end":73,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&multiline_entry);","highlight_start":1,"highlight_end":73}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::MultilineEntry)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::MultilineEntry)>)(&multiline_entry);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::MultilineEntry`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":26379,"byte_end":26560,"line_start":890,"line_end":895,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> MultilineEntry {","highlight_start":5,"highlight_end":37},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry())","highlight_start":1,"highlight_end":75},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":26379,"byte_end":26560,"line_start":890,"line_end":895,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> MultilineEntry {","highlight_start":5,"highlight_end":37},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry())","highlight_start":1,"highlight_end":75},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::MultilineEntry { fn default() -> Self { controls::MultilineEntry::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::MultilineEntry { fn default() -> Self { controls::MultilineEntry::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::FontButton)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":36403,"byte_end":36468,"line_start":1182,"line_end":1182,"column_start":17,"column_end":82,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&font_button);","highlight_start":17,"highlight_end":82}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":36403,"byte_end":36468,"line_start":1182,"line_end":1182,"column_start":17,"column_end":82,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&font_button);","highlight_start":17,"highlight_end":82}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::FontButton)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::FontButton)>)(&font_button);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::FontButton`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":36575,"byte_end":36744,"line_start":1189,"line_end":1194,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> FontButton {","highlight_start":5,"highlight_end":33},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" FontButton::from_ui_control(ui_sys::uiNewFontButton())","highlight_start":1,"highlight_end":67},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":36575,"byte_end":36744,"line_start":1189,"line_end":1194,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> FontButton {","highlight_start":5,"highlight_end":33},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" FontButton::from_ui_control(ui_sys::uiNewFontButton())","highlight_start":1,"highlight_end":67},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::FontButton { fn default() -> Self { controls::FontButton::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::FontButton { fn default() -> Self { controls::FontButton::new() } }"}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r controls::ColorButton)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":38273,"byte_end":38339,"line_start":1237,"line_end":1237,"column_start":17,"column_end":83,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&color_button);","highlight_start":17,"highlight_end":83}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":38273,"byte_end":38339,"line_start":1237,"line_end":1237,"column_start":17,"column_end":83,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void, &mut Box>(data)(&color_button);","highlight_start":17,"highlight_end":83}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r controls::ColorButton)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r controls::ColorButton)>)(&color_button);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"you should consider adding a `Default` implementation for `controls::ColorButton`, #[warn(new_without_default)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/controls.rs","byte_start":38447,"byte_end":38619,"line_start":1244,"line_end":1249,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ColorButton {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ColorButton::from_ui_control(ui_sys::uiNewColorButton())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#new_without_default","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"try this","code":null,"level":"help","spans":[{"file_name":"src/controls.rs","byte_start":38447,"byte_end":38619,"line_start":1244,"line_end":1249,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn new() -> ColorButton {","highlight_start":5,"highlight_end":34},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ColorButton::from_ui_control(ui_sys::uiNewColorButton())","highlight_start":1,"highlight_end":69},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":"impl Default for controls::ColorButton { fn default() -> Self { controls::ColorButton::new() } }","expansion":null}],"children":[],"rendered":" impl Default for controls::ColorButton { fn default() -> Self { controls::ColorButton::new() } }"}],"rendered":null} -{"message":"item `draw::FontFamilies` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. Consider adding one, #[warn(len_without_is_empty)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/draw.rs","byte_start":53542,"byte_end":53720,"line_start":504,"line_end":509,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":" pub fn len(&self) -> u64 {","highlight_start":5,"highlight_end":31},{"text":" ffi_utils::ensure_initialized();","highlight_start":1,"highlight_end":41},{"text":" unsafe {","highlight_start":1,"highlight_end":17},{"text":" ui_sys::uiDrawFontFamiliesNumFamilies(self.ui_draw_font_families)","highlight_start":1,"highlight_end":78},{"text":" }","highlight_start":1,"highlight_end":10},{"text":" }","highlight_start":1,"highlight_end":6}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} -{"message":"transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>`), #[warn(transmute_ptr_to_ref)] on by default","code":null,"level":"warning","spans":[{"file_name":"src/menus.rs","byte_start":63327,"byte_end":63432,"line_start":50,"line_end":51,"column_start":17,"column_end":76,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&menu_item, &window);","highlight_start":1,"highlight_end":76}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try","code":null,"level":"help","spans":[{"file_name":"src/menus.rs","byte_start":63327,"byte_end":63432,"line_start":50,"line_end":51,"column_start":17,"column_end":76,"is_primary":true,"text":[{"text":" mem::transmute::<*mut c_void,","highlight_start":17,"highlight_end":46},{"text":" &mut Box>(data)(&menu_item, &window);","highlight_start":1,"highlight_end":76}],"label":null,"suggested_replacement":"&mut *(data as *mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>)","expansion":null}],"children":[],"rendered":" &mut *(data as *mut Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>)(&menu_item, &window);"},{"message":"for further information visit https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null} diff --git a/tests/fixtures/libui-rs/src/controls.rs b/tests/fixtures/libui-rs/src/controls.rs deleted file mode 100644 index 569927633..000000000 --- a/tests/fixtures/libui-rs/src/controls.rs +++ /dev/null @@ -1,1259 +0,0 @@ -//! Functions and types related to widgets. - -use draw; -use ffi_utils::{self, Text}; -use libc::{c_int, c_void}; -use std::ffi::CString; -use std::mem; -use std::ptr; -use ui_sys::{self, uiArea, uiAreaDrawParams, uiAreaHandler, uiAreaKeyEvent, uiAreaMouseEvent}; -use ui_sys::{uiBox, uiButton, uiCheckbox, uiColorButton, uiCombobox, uiControl, uiDateTimePicker}; -use ui_sys::{uiEntry, uiFontButton, uiGroup, uiLabel, uiMultilineEntry, uiProgressBar}; -use ui_sys::{uiRadioButtons, uiSeparator, uiSlider, uiSpinbox, uiTab}; - -pub use ui_sys::uiExtKey as ExtKey; - -// Defines a new control, creating a Rust wrapper, a `Deref` implementation, and a destructor. -// An example of use: -// -// define_control!(Slider, uiSlider, ui_slider) -#[macro_export] -macro_rules! define_control { - ($rust_type:ident, $ui_type:ident, $ui_field:ident) => { - pub struct $rust_type { - $ui_field: *mut $ui_type, - } - - impl ::std::ops::Deref for $rust_type { - type Target = ::controls::Control; - - #[inline] - fn deref(&self) -> &::controls::Control { - // FIXME(pcwalton): $10 says this is undefined behavior. How do I make it not so? - unsafe { - mem::transmute::<&$rust_type, &::controls::Control>(self) - } - } - } - - impl Drop for $rust_type { - #[inline] - fn drop(&mut self) { - // For now this does nothing, but in the future, when `libui` supports proper - // memory management, this will likely need to twiddle reference counts. - } - } - - impl Clone for $rust_type { - #[inline] - fn clone(&self) -> $rust_type { - $rust_type { - $ui_field: self.$ui_field, - } - } - } - - impl Into for $rust_type { - #[inline] - fn into(self) -> Control { - unsafe { - let control = Control::from_ui_control(self.$ui_field as *mut uiControl); - mem::forget(self); - control - } - } - } - - impl $rust_type { - #[inline] - pub unsafe fn from_ui_control($ui_field: *mut $ui_type) -> $rust_type { - $rust_type { - $ui_field: $ui_field - } - } - } - } -} - -pub struct Control { - ui_control: *mut uiControl, -} - -impl Drop for Control { - #[inline] - fn drop(&mut self) { - // For now this does nothing, but in the future, when `libui` supports proper memory - // management, this will likely need to twiddle reference counts. - } -} - -impl Clone for Control { - #[inline] - fn clone(&self) -> Control { - Control { - ui_control: self.ui_control, - } - } -} - -impl Control { - /// Creates a new `Control` object from an existing `uiControl`. - #[inline] - pub unsafe fn from_ui_control(ui_control: *mut uiControl) -> Control { - Control { - ui_control: ui_control, - } - } - - #[inline] - pub fn as_ui_control(&self) -> *mut uiControl { - self.ui_control - } - - /// Destroys a control. Any use of the control after this is use-after-free; therefore, this - /// is marked unsafe. - #[inline] - pub unsafe fn destroy(&self) { - // Don't check for initialization here since this can be run during deinitialization. - ui_sys::uiControlDestroy(self.ui_control) - } - - #[inline] - pub fn handle(&self) -> usize { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlHandle(self.ui_control) - } - } - - #[inline] - pub fn parent(&self) -> Option { - ffi_utils::ensure_initialized(); - unsafe { - let ui_control = ui_sys::uiControlParent(self.ui_control); - if ui_control.is_null() { - None - } else { - Some(Control::from_ui_control(ui_control)) - } - } - } - - #[inline] - pub unsafe fn set_parent(&self, parent: Option<&Control>) { - ffi_utils::ensure_initialized(); - ui_sys::uiControlSetParent(self.ui_control, - match parent { - None => ptr::null_mut(), - Some(parent) => parent.ui_control, - }) - } - - #[inline] - pub fn toplevel(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlToplevel(self.ui_control) != 0 - } - } - - #[inline] - pub fn visible(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlVisible(self.ui_control) != 0 - } - } - - #[inline] - pub fn show(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlShow(self.ui_control) - } - } - - #[inline] - pub fn hide(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlHide(self.ui_control) - } - } - - #[inline] - pub fn enabled(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlEnabled(self.ui_control) != 0 - } - } - - #[inline] - pub fn enable(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlEnable(self.ui_control) - } - } - - #[inline] - pub fn disable(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiControlDisable(self.ui_control) - } - } -} - -define_control!(Button, uiButton, ui_button); - -impl Button { - #[inline] - pub fn text(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiButtonText(self.ui_button)) - } - } - - #[inline] - pub fn set_text(&self, text: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - ui_sys::uiButtonSetText(self.ui_button, c_string.as_ptr()) - } - } - - #[inline] - pub fn on_clicked(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiButtonOnClicked(self.ui_button, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(button: *mut uiButton, data: *mut c_void) { - unsafe { - let button = Button { - ui_button: button, - }; - mem::transmute::<*mut c_void, &mut Box>(data)(&button) - } - } - } - - #[inline] - pub fn new(text: &str) -> Button { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - Button::from_ui_control(ui_sys::uiNewButton(c_string.as_ptr())) - } - } -} - -define_control!(BoxControl, uiBox, ui_box); - -impl BoxControl { - #[inline] - pub fn append(&self, child: Control, stretchy: bool) { - ffi_utils::ensure_initialized(); - unsafe { - assert!(child.parent().is_none()); - ui_sys::uiBoxAppend(self.ui_box, child.ui_control, stretchy as c_int) - } - } - - /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it - /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a - /// separate list of children ourselves… - #[inline] - pub fn delete(&self, index: u64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiBoxDelete(self.ui_box, index) - } - } - - #[inline] - pub fn padded(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiBoxPadded(self.ui_box) != 0 - } - } - - #[inline] - pub fn set_padded(&self, padded: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiBoxSetPadded(self.ui_box, padded as c_int) - } - } - - #[inline] - pub fn new_horizontal() -> BoxControl { - ffi_utils::ensure_initialized(); - unsafe { - BoxControl::from_ui_control(ui_sys::uiNewHorizontalBox()) - } - } - - #[inline] - pub fn new_vertical() -> BoxControl { - ffi_utils::ensure_initialized(); - unsafe { - BoxControl::from_ui_control(ui_sys::uiNewVerticalBox()) - } - } -} - -define_control!(Entry, uiEntry, ui_entry); - -impl Entry { - #[inline] - pub fn text(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiEntryText(self.ui_entry)) - } - } - - #[inline] - pub fn set_text(&self, text: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - ui_sys::uiEntrySetText(self.ui_entry, c_string.as_ptr()) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiEntryOnChanged(self.ui_entry, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { - unsafe { - let entry = Entry::from_ui_control(entry); - mem::transmute::<*mut c_void, &mut Box>(data)(&entry); - mem::forget(entry); - } - } - } - - #[inline] - pub fn read_only(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiEntryReadOnly(self.ui_entry) != 0 - } - } - - #[inline] - pub fn set_read_only(&self, readonly: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiEntrySetReadOnly(self.ui_entry, readonly as c_int) - } - } - - #[inline] - pub fn new() -> Entry { - ffi_utils::ensure_initialized(); - unsafe { - Entry::from_ui_control(ui_sys::uiNewEntry()) - } - } -} - -define_control!(Checkbox, uiCheckbox, ui_checkbox); - -impl Checkbox { - #[inline] - pub fn text(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiCheckboxText(self.ui_checkbox)) - } - } - - #[inline] - pub fn set_text(&self, text: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - ui_sys::uiCheckboxSetText(self.ui_checkbox, c_string.as_ptr()) - } - } - - #[inline] - pub fn on_toggled(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiCheckboxOnToggled(self.ui_checkbox, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(checkbox: *mut uiCheckbox, data: *mut c_void) { - unsafe { - let checkbox = Checkbox::from_ui_control(checkbox); - mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); - mem::forget(checkbox) - } - } - } - - #[inline] - pub fn checked(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiCheckboxChecked(self.ui_checkbox) != 0 - } - } - - #[inline] - pub fn set_checked(&self, checked: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiCheckboxSetChecked(self.ui_checkbox, checked as c_int) - } - } - - #[inline] - pub fn new(text: &str) -> Checkbox { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - Checkbox::from_ui_control(ui_sys::uiNewCheckbox(c_string.as_ptr())) - } - } -} - -define_control!(Label, uiLabel, ui_label); - -impl Label { - #[inline] - pub fn text(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiLabelText(self.ui_label)) - } - } - - #[inline] - pub fn set_text(&self, text: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - ui_sys::uiLabelSetText(self.ui_label, c_string.as_ptr()) - } - } - - #[inline] - pub fn new(text: &str) -> Label { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - Label::from_ui_control(ui_sys::uiNewLabel(c_string.as_ptr())) - } - } -} - -define_control!(Tab, uiTab, ui_tab); - -impl Tab { - #[inline] - pub fn append(&self, name: &str, control: Control) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - ui_sys::uiTabAppend(self.ui_tab, c_string.as_ptr(), control.ui_control) - } - } - - #[inline] - pub fn insert_at(&self, name: &str, before: u64, control: Control) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - ui_sys::uiTabInsertAt(self.ui_tab, c_string.as_ptr(), before, control.ui_control) - } - } - - /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it - /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a - /// separate list of children ourselves… - #[inline] - pub fn delete(&self, index: u64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiTabDelete(self.ui_tab, index) - } - } - - #[inline] - pub fn margined(&self, page: u64) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiTabMargined(self.ui_tab, page) != 0 - } - } - - #[inline] - pub fn set_margined(&self, page: u64, margined: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiTabSetMargined(self.ui_tab, page, margined as c_int) - } - } - - #[inline] - pub fn new() -> Tab { - ffi_utils::ensure_initialized(); - unsafe { - Tab::from_ui_control(ui_sys::uiNewTab()) - } - } -} - -define_control!(Group, uiGroup, ui_group); - -impl Group { - #[inline] - pub fn title(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiGroupTitle(self.ui_group)) - } - } - - #[inline] - pub fn set_title(&self, title: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); - ui_sys::uiGroupSetTitle(self.ui_group, c_string.as_ptr()) - } - } - - #[inline] - pub fn set_child(&self, child: Control) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiGroupSetChild(self.ui_group, child.ui_control) - } - } - - #[inline] - pub fn margined(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiGroupMargined(self.ui_group) != 0 - } - } - - #[inline] - pub fn set_margined(&self, margined: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiGroupSetMargined(self.ui_group, margined as c_int) - } - } - - #[inline] - pub fn new(title: &str) -> Group { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); - Group::from_ui_control(ui_sys::uiNewGroup(c_string.as_ptr())) - } - } -} - -define_control!(Spinbox, uiSpinbox, ui_spinbox); - -impl Spinbox { - #[inline] - pub fn value(&self) -> i64 { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiSpinboxValue(self.ui_spinbox) - } - } - - #[inline] - pub fn set_value(&self, value: i64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiSpinboxSetValue(self.ui_spinbox, value) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiSpinboxOnChanged(self.ui_spinbox, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) { - unsafe { - let spinbox = Spinbox::from_ui_control(spinbox); - mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); - mem::forget(spinbox); - } - } - } - - #[inline] - pub fn new(min: i64, max: i64) -> Spinbox { - ffi_utils::ensure_initialized(); - unsafe { - Spinbox::from_ui_control(ui_sys::uiNewSpinbox(min, max)) - } - } -} - -define_control!(ProgressBar, uiProgressBar, ui_progress_bar); - -impl ProgressBar { - #[inline] - pub fn set_value(&self, n: i32) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiProgressBarSetValue(self.ui_progress_bar, n) - } - } - - #[inline] - pub fn new() -> ProgressBar { - ffi_utils::ensure_initialized(); - unsafe { - ProgressBar::from_ui_control(ui_sys::uiNewProgressBar()) - } - } -} - -define_control!(Slider, uiSlider, ui_slider); - -impl Slider { - #[inline] - pub fn value(&self) -> i64 { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiSliderValue(self.ui_slider) - } - } - - #[inline] - pub fn set_value(&self, value: i64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiSliderSetValue(self.ui_slider, value) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiSliderOnChanged(self.ui_slider, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) { - unsafe { - let slider = Slider::from_ui_control(slider); - mem::transmute::<*mut c_void, &mut Box>(data)(&slider); - mem::forget(slider); - } - } - } - - #[inline] - pub fn new(min: i64, max: i64) -> Slider { - ffi_utils::ensure_initialized(); - unsafe { - Slider::from_ui_control(ui_sys::uiNewSlider(min, max)) - } - } -} - -define_control!(Separator, uiSeparator, ui_separator); - -impl Separator { - #[inline] - pub fn new_horizontal() -> Separator { - ffi_utils::ensure_initialized(); - unsafe { - Separator::from_ui_control(ui_sys::uiNewHorizontalSeparator()) - } - } -} - -define_control!(Combobox, uiCombobox, ui_combobox); - -impl Combobox { - #[inline] - pub fn append(&self, name: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - ui_sys::uiComboboxAppend(self.ui_combobox, c_string.as_ptr()) - } - } - - #[inline] - pub fn selected(&self) -> i64 { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiComboboxSelected(self.ui_combobox) - } - } - - #[inline] - pub fn set_selected(&self, n: i64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiComboboxSetSelected(self.ui_combobox, n) - } - } - - #[inline] - pub fn on_selected(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiComboboxOnSelected(self.ui_combobox, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(combobox: *mut uiCombobox, data: *mut c_void) { - unsafe { - let combobox = Combobox::from_ui_control(combobox); - mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); - mem::forget(combobox); - } - } - } - - #[inline] - pub fn new() -> Combobox { - ffi_utils::ensure_initialized(); - unsafe { - Combobox::from_ui_control(ui_sys::uiNewCombobox()) - } - } - - #[inline] - pub fn new_editable() -> Combobox { - ffi_utils::ensure_initialized(); - unsafe { - Combobox::from_ui_control(ui_sys::uiNewEditableCombobox()) - } - } -} - -// FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable -// with just the `uiRadioButtons*` methods… -define_control!(RadioButtons, uiRadioButtons, ui_radio_buttons); - -impl RadioButtons { - #[inline] - pub fn append(&self, name: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - ui_sys::uiRadioButtonsAppend(self.ui_radio_buttons, c_string.as_ptr()) - } - } - - #[inline] - pub fn new() -> RadioButtons { - ffi_utils::ensure_initialized(); - unsafe { - RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons()) - } - } -} - -// FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable -// with just the `uiDatetimePicker*` methods… -define_control!(DateTimePicker, uiDateTimePicker, ui_date_time_picker); - -impl DateTimePicker { - pub fn new_date_time_picker() -> DateTimePicker { - ffi_utils::ensure_initialized(); - unsafe { - DateTimePicker::from_ui_control(ui_sys::uiNewDateTimePicker()) - } - } - - pub fn new_date_picker() -> DateTimePicker { - ffi_utils::ensure_initialized(); - unsafe { - DateTimePicker::from_ui_control(ui_sys::uiNewDatePicker()) - } - } - - pub fn new_time_picker() -> DateTimePicker { - ffi_utils::ensure_initialized(); - unsafe { - DateTimePicker::from_ui_control(ui_sys::uiNewTimePicker()) - } - } -} - -define_control!(MultilineEntry, uiMultilineEntry, ui_multiline_entry); - -impl MultilineEntry { - #[inline] - pub fn text(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiMultilineEntryText(self.ui_multiline_entry)) - } - } - - #[inline] - pub fn set_text(&self, text: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - ui_sys::uiMultilineEntrySetText(self.ui_multiline_entry, c_string.as_ptr()) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiMultilineEntryOnChanged(self.ui_multiline_entry, - c_callback, - &mut *data as *mut Box as - *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(multiline_entry: *mut uiMultilineEntry, data: *mut c_void) { - unsafe { - let multiline_entry = MultilineEntry::from_ui_control(multiline_entry); - mem::transmute::<*mut c_void, - &mut Box>(data)(&multiline_entry); - mem::forget(multiline_entry); - } - } - } - - #[inline] - pub fn read_only(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiMultilineEntryReadOnly(self.ui_multiline_entry) != 0 - } - } - - #[inline] - pub fn set_read_only(&self, readonly: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiMultilineEntrySetReadOnly(self.ui_multiline_entry, readonly as c_int) - } - } - - #[inline] - pub fn new() -> MultilineEntry { - ffi_utils::ensure_initialized(); - unsafe { - MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry()) - } - } -} - -pub trait AreaHandler { - fn draw(&mut self, _area: &Area, _area_draw_params: &AreaDrawParams) {} - fn mouse_event(&mut self, _area: &Area, _area_mouse_event: &AreaMouseEvent) {} - fn mouse_crossed(&mut self, _area: &Area, _left: bool) {} - fn drag_broken(&mut self, _area: &Area) {} - fn key_event(&mut self, _area: &Area, _area_key_event: &AreaKeyEvent) -> bool { - true - } -} - -#[repr(C)] -struct RustAreaHandler { - ui_area_handler: uiAreaHandler, - trait_object: Box, -} - -impl RustAreaHandler { - #[inline] - fn new(trait_object: Box) -> Box { - ffi_utils::ensure_initialized(); - return Box::new(RustAreaHandler { - ui_area_handler: uiAreaHandler { - Draw: draw, - MouseEvent: mouse_event, - MouseCrossed: mouse_crossed, - DragBroken: drag_broken, - KeyEvent: key_event, - }, - trait_object: trait_object, - }); - - extern "C" fn draw(ui_area_handler: *mut uiAreaHandler, - ui_area: *mut uiArea, - ui_area_draw_params: *mut uiAreaDrawParams) { - unsafe { - let area = Area::from_ui_area(ui_area); - let area_draw_params = - AreaDrawParams::from_ui_area_draw_params(&*ui_area_draw_params); - (*(ui_area_handler as *mut RustAreaHandler)).trait_object.draw(&area, - &area_draw_params); - mem::forget(area_draw_params); - mem::forget(area); - } - } - - extern "C" fn mouse_event(ui_area_handler: *mut uiAreaHandler, - ui_area: *mut uiArea, - ui_area_mouse_event: *mut uiAreaMouseEvent) { - unsafe { - let area = Area::from_ui_area(ui_area); - let area_mouse_event = - AreaMouseEvent::from_ui_area_mouse_event(&*ui_area_mouse_event); - (*(ui_area_handler as *mut RustAreaHandler)).trait_object - .mouse_event(&area, &area_mouse_event); - mem::forget(area_mouse_event); - mem::forget(area); - } - } - - extern "C" fn mouse_crossed(ui_area_handler: *mut uiAreaHandler, - ui_area: *mut uiArea, - left: c_int) { - unsafe { - let area = Area::from_ui_area(ui_area); - (*(ui_area_handler as *mut RustAreaHandler)).trait_object.mouse_crossed(&area, - left != 0); - mem::forget(area); - } - } - - extern "C" fn drag_broken(ui_area_handler: *mut uiAreaHandler, ui_area: *mut uiArea) { - unsafe { - let area = Area::from_ui_area(ui_area); - (*(ui_area_handler as *mut RustAreaHandler)).trait_object.drag_broken(&area); - mem::forget(area); - } - } - - extern "C" fn key_event(ui_area_handler: *mut uiAreaHandler, - ui_area: *mut uiArea, - ui_area_key_event: *mut uiAreaKeyEvent) - -> c_int { - unsafe { - let area = Area::from_ui_area(ui_area); - let area_key_event = AreaKeyEvent::from_ui_area_key_event(&*ui_area_key_event); - let result = - (*(ui_area_handler as *mut RustAreaHandler)).trait_object - .key_event(&area, &area_key_event); - mem::forget(area_key_event); - mem::forget(area); - result as c_int - } - } - } -} - -define_control!(Area, uiArea, ui_area); - -impl Area { - #[inline] - pub unsafe fn from_ui_area(ui_area: *mut uiArea) -> Area { - Area { - ui_area: ui_area, - } - } - - #[inline] - pub fn set_size(&self, width: i64, height: i64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiAreaSetSize(self.ui_area, width, height) - } - } - - #[inline] - pub fn queue_redraw_all(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiAreaQueueRedrawAll(self.ui_area) - } - } - - #[inline] - pub fn scroll_to(&self, x: f64, y: f64, width: f64, height: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiAreaScrollTo(self.ui_area, x, y, width, height) - } - } - - #[inline] - pub fn new(area_handler: Box) -> Area { - ffi_utils::ensure_initialized(); - unsafe { - let mut rust_area_handler = RustAreaHandler::new(area_handler); - let area = - Area::from_ui_control(ui_sys::uiNewArea(&mut *rust_area_handler as - *mut RustAreaHandler as - *mut uiAreaHandler)); - mem::forget(rust_area_handler); - area - } - } - - #[inline] - pub fn new_scrolling(area_handler: Box, width: i64, height: i64) -> Area { - ffi_utils::ensure_initialized(); - unsafe { - let mut rust_area_handler = RustAreaHandler::new(area_handler); - let area = - Area::from_ui_control(ui_sys::uiNewScrollingArea(&mut *rust_area_handler as - *mut RustAreaHandler as - *mut uiAreaHandler, - width, - height)); - mem::forget(rust_area_handler); - area - } - } -} - -pub struct AreaDrawParams { - pub context: draw::Context, - - pub area_width: f64, - pub area_height: f64, - - pub clip_x: f64, - pub clip_y: f64, - pub clip_width: f64, - pub clip_height: f64, -} - -impl AreaDrawParams { - #[inline] - unsafe fn from_ui_area_draw_params(ui_area_draw_params: &uiAreaDrawParams) -> AreaDrawParams { - ffi_utils::ensure_initialized(); - AreaDrawParams { - context: draw::Context::from_ui_draw_context(ui_area_draw_params.Context), - area_width: ui_area_draw_params.AreaWidth, - area_height: ui_area_draw_params.AreaHeight, - clip_x: ui_area_draw_params.ClipX, - clip_y: ui_area_draw_params.ClipY, - clip_width: ui_area_draw_params.ClipWidth, - clip_height: ui_area_draw_params.ClipHeight, - } - } -} - -bitflags! { - pub flags Modifiers: u8 { - const MODIFIER_CTRL = 1 << 0, - const MODIFIER_ALT = 1 << 1, - const MODIFIER_SHIFT = 1 << 2, - const MODIFIER_SUPER = 1 << 3, - } -} - -#[derive(Copy, Clone, Debug)] -pub struct AreaMouseEvent { - pub x: f64, - pub y: f64, - - pub area_width: f64, - pub area_height: f64, - - pub down: u64, - pub up: u64, - - pub count: u64, - - pub modifiers: Modifiers, - - pub held_1_to_64: u64, -} - -impl AreaMouseEvent { - #[inline] - pub fn from_ui_area_mouse_event(ui_area_mouse_event: &uiAreaMouseEvent) -> AreaMouseEvent { - ffi_utils::ensure_initialized(); - AreaMouseEvent { - x: ui_area_mouse_event.X, - y: ui_area_mouse_event.Y, - area_width: ui_area_mouse_event.AreaWidth, - area_height: ui_area_mouse_event.AreaHeight, - down: ui_area_mouse_event.Down, - up: ui_area_mouse_event.Up, - count: ui_area_mouse_event.Count, - modifiers: Modifiers::from_bits(ui_area_mouse_event.Modifiers as u8).unwrap(), - held_1_to_64: ui_area_mouse_event.Held1To64, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub struct AreaKeyEvent { - pub key: u8, - pub ext_key: ExtKey, - pub modifier: Modifiers, - pub modifiers: Modifiers, - pub up: bool, -} - -impl AreaKeyEvent { - #[inline] - pub fn from_ui_area_key_event(ui_area_key_event: &uiAreaKeyEvent) -> AreaKeyEvent { - ffi_utils::ensure_initialized(); - AreaKeyEvent { - key: ui_area_key_event.Key as u8, - ext_key: ui_area_key_event.ExtKey, - modifier: Modifiers::from_bits(ui_area_key_event.Modifier as u8).unwrap(), - modifiers: Modifiers::from_bits(ui_area_key_event.Modifiers as u8).unwrap(), - up: ui_area_key_event.Up != 0, - } - } -} - -define_control!(FontButton, uiFontButton, ui_font_button); - -impl FontButton { - /// Returns a new font. - #[inline] - pub fn font(&self) -> draw::text::Font { - ffi_utils::ensure_initialized(); - unsafe { - draw::text::Font::from_ui_draw_text_font(ui_sys::uiFontButtonFont(self.ui_font_button)) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiFontButtonOnChanged(self.ui_font_button, - c_callback, - &mut *data as *mut Box as - *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(ui_font_button: *mut uiFontButton, data: *mut c_void) { - unsafe { - let font_button = FontButton::from_ui_control(ui_font_button); - mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); - mem::forget(font_button); - } - } - } - - #[inline] - pub fn new() -> FontButton { - ffi_utils::ensure_initialized(); - unsafe { - FontButton::from_ui_control(ui_sys::uiNewFontButton()) - } - } -} - -define_control!(ColorButton, uiColorButton, ui_color_button); - -impl ColorButton { - #[inline] - pub fn color(&self) -> Color { - ffi_utils::ensure_initialized(); - unsafe { - let mut color: Color = mem::uninitialized(); - ui_sys::uiColorButtonColor(self.ui_color_button, - &mut color.r, - &mut color.g, - &mut color.b, - &mut color.a); - color - } - } - - #[inline] - pub fn set_color(&self, color: &Color) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiColorButtonSetColor(self.ui_color_button, color.r, color.g, color.b, color.a) - } - } - - #[inline] - pub fn on_changed(&self, callback: Box) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiColorButtonOnChanged(self.ui_color_button, - c_callback, - &mut *data as *mut Box as - *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(ui_color_button: *mut uiColorButton, data: *mut c_void) { - unsafe { - let color_button = ColorButton::from_ui_control(ui_color_button); - mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); - mem::forget(color_button) - } - } - } - - #[inline] - pub fn new() -> ColorButton { - ffi_utils::ensure_initialized(); - unsafe { - ColorButton::from_ui_control(ui_sys::uiNewColorButton()) - } - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Color { - r: f64, - g: f64, - b: f64, - a: f64, -} - diff --git a/tests/fixtures/libui-rs/src/draw.rs b/tests/fixtures/libui-rs/src/draw.rs deleted file mode 100644 index 61857a4c2..000000000 --- a/tests/fixtures/libui-rs/src/draw.rs +++ /dev/null @@ -1,710 +0,0 @@ -//! Functions and types related to 2D vector graphics. - -use ffi_utils::{self, Text}; -use libc::{c_double, c_int}; -use std::marker::PhantomData; -use std::mem; -use std::ops::Mul; -use std::ptr; -use ui_sys::{self, uiDrawBrush, uiDrawBrushType, uiDrawContext, uiDrawFontFamilies, uiDrawMatrix}; -use ui_sys::{uiDrawPath, uiDrawStrokeParams}; - -pub use ui_sys::uiDrawBrushGradientStop as BrushGradientStop; -pub use ui_sys::uiDrawLineCap as LineCap; -pub use ui_sys::uiDrawLineJoin as LineJoin; -pub use ui_sys::uiDrawDefaultMiterLimit as DEFAULT_MITER_LIMIT; -pub use ui_sys::uiDrawFillMode as FillMode; - -pub struct Context { - ui_draw_context: *mut uiDrawContext, -} - -impl Context { - #[inline] - pub unsafe fn from_ui_draw_context(ui_draw_context: *mut uiDrawContext) -> Context { - ffi_utils::ensure_initialized(); - Context { - ui_draw_context: ui_draw_context, - } - } - - #[inline] - pub fn stroke(&self, path: &Path, brush: &Brush, stroke_params: &StrokeParams) { - ffi_utils::ensure_initialized(); - unsafe { - let brush = brush.as_ui_draw_brush_ref(); - let stroke_params = stroke_params.as_ui_draw_stroke_params_ref(); - ui_sys::uiDrawStroke(self.ui_draw_context, - path.ui_draw_path, - &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush, - &stroke_params.ui_draw_stroke_params as *const uiDrawStrokeParams - as *mut uiDrawStrokeParams) - } - } - - #[inline] - pub fn fill(&self, path: &Path, brush: &Brush) { - ffi_utils::ensure_initialized(); - unsafe { - let brush = brush.as_ui_draw_brush_ref(); - ui_sys::uiDrawFill(self.ui_draw_context, - path.ui_draw_path, - &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush) - } - } - - #[inline] - pub fn transform(&self, matrix: &Matrix) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawTransform(self.ui_draw_context, - &matrix.ui_matrix as *const uiDrawMatrix as *mut uiDrawMatrix) - } - } - - #[inline] - pub fn save(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawSave(self.ui_draw_context) - } - } - - #[inline] - pub fn restore(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawRestore(self.ui_draw_context) - } - } - - #[inline] - pub fn draw_text(&self, x: f64, y: f64, layout: &text::Layout) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawText(self.ui_draw_context, x, y, layout.as_ui_draw_text_layout()) - } - } -} - -#[derive(Clone, Debug)] -pub enum Brush { - Solid(SolidBrush), - LinearGradient(LinearGradientBrush), - RadialGradient(RadialGradientBrush), - Image, -} - -#[derive(Clone, Debug)] -pub struct UiDrawBrushRef<'a> { - ui_draw_brush: uiDrawBrush, - phantom: PhantomData<&'a uiDrawBrush>, -} - -impl Brush { - pub fn as_ui_draw_brush_ref(&self) -> UiDrawBrushRef { - ffi_utils::ensure_initialized(); - match *self { - Brush::Solid(ref solid_brush) => { - UiDrawBrushRef { - ui_draw_brush: uiDrawBrush { - Type: uiDrawBrushType::Solid, - - R: solid_brush.r, - G: solid_brush.g, - B: solid_brush.b, - A: solid_brush.a, - - X0: 0.0, - Y0: 0.0, - X1: 0.0, - Y1: 0.0, - OuterRadius: 0.0, - Stops: ptr::null_mut(), - NumStops: 0, - }, - phantom: PhantomData, - } - } - Brush::LinearGradient(ref linear_gradient_brush) => { - UiDrawBrushRef { - ui_draw_brush: uiDrawBrush { - Type: uiDrawBrushType::LinearGradient, - - R: 0.0, - G: 0.0, - B: 0.0, - A: 0.0, - - X0: linear_gradient_brush.start_x, - Y0: linear_gradient_brush.start_y, - X1: linear_gradient_brush.end_x, - Y1: linear_gradient_brush.end_y, - OuterRadius: 0.0, - Stops: linear_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, - NumStops: linear_gradient_brush.stops.len(), - }, - phantom: PhantomData, - } - } - Brush::RadialGradient(ref radial_gradient_brush) => { - UiDrawBrushRef { - ui_draw_brush: uiDrawBrush { - Type: uiDrawBrushType::RadialGradient, - - R: 0.0, - G: 0.0, - B: 0.0, - A: 0.0, - - X0: radial_gradient_brush.start_x, - Y0: radial_gradient_brush.start_y, - X1: radial_gradient_brush.outer_circle_center_x, - Y1: radial_gradient_brush.outer_circle_center_y, - OuterRadius: radial_gradient_brush.outer_radius, - Stops: radial_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, - NumStops: radial_gradient_brush.stops.len(), - }, - phantom: PhantomData, - } - } - Brush::Image => { - // These don't work yet in `libui`, but just for completeness' sake… - UiDrawBrushRef { - ui_draw_brush: uiDrawBrush { - Type: uiDrawBrushType::Image, - - R: 0.0, - G: 0.0, - B: 0.0, - A: 0.0, - - X0: 0.0, - Y0: 0.0, - X1: 0.0, - Y1: 0.0, - OuterRadius: 0.0, - Stops: ptr::null_mut(), - NumStops: 0, - }, - phantom: PhantomData, - } - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct SolidBrush { - pub r: f64, - pub g: f64, - pub b: f64, - pub a: f64, -} - -#[derive(Clone, Debug)] -pub struct LinearGradientBrush { - pub start_x: f64, - pub start_y: f64, - pub end_x: f64, - pub end_y: f64, - pub stops: Vec, -} - -#[derive(Clone, Debug)] -pub struct RadialGradientBrush { - pub start_x: f64, - pub start_y: f64, - pub outer_circle_center_x: f64, - pub outer_circle_center_y: f64, - pub outer_radius: f64, - pub stops: Vec, -} - -#[derive(Clone, Debug)] -pub struct StrokeParams { - pub cap: LineCap, - pub join: LineJoin, - pub thickness: f64, - pub miter_limit: f64, - pub dashes: Vec, - pub dash_phase: f64, -} - -#[derive(Clone, Debug)] -pub struct UiDrawStrokeParamsRef<'a> { - ui_draw_stroke_params: uiDrawStrokeParams, - phantom: PhantomData<&'a uiDrawStrokeParams>, -} - -impl StrokeParams { - pub fn as_ui_draw_stroke_params_ref(&self) -> UiDrawStrokeParamsRef { - ffi_utils::ensure_initialized(); - UiDrawStrokeParamsRef { - ui_draw_stroke_params: uiDrawStrokeParams { - Cap: self.cap, - Join: self.join, - Thickness: self.thickness, - MiterLimit: self.miter_limit, - Dashes: self.dashes.as_ptr() as *mut c_double, - NumDashes: self.dashes.len(), - DashPhase: self.dash_phase, - }, - phantom: PhantomData, - } - } -} - -pub struct Path { - ui_draw_path: *mut uiDrawPath, -} - -impl Drop for Path { - #[inline] - fn drop(&mut self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawFreePath(self.ui_draw_path) - } - } -} - -impl Path { - #[inline] - pub fn new(fill_mode: FillMode) -> Path { - ffi_utils::ensure_initialized(); - unsafe { - Path { - ui_draw_path: ui_sys::uiDrawNewPath(fill_mode), - } - } - } - - #[inline] - pub fn new_figure(&self, x: f64, y: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathNewFigure(self.ui_draw_path, x, y) - } - } - - #[inline] - pub fn new_figure_with_arc(&self, - x_center: f64, - y_center: f64, - radius: f64, - start_angle: f64, - sweep: f64, - negative: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathNewFigureWithArc(self.ui_draw_path, - x_center, - y_center, - radius, - start_angle, - sweep, - negative as c_int) - } - } - - #[inline] - pub fn line_to(&self, x: f64, y: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathLineTo(self.ui_draw_path, x, y) - } - } - - #[inline] - pub fn arc_to(&self, - x_center: f64, - y_center: f64, - radius: f64, - start_angle: f64, - sweep: f64, - negative: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathArcTo(self.ui_draw_path, - x_center, - y_center, - radius, - start_angle, - sweep, - negative as c_int) - } - } - - #[inline] - pub fn bezier_to(&self, c1x: f64, c1y: f64, c2x: f64, c2y: f64, end_x: f64, end_y: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathBezierTo(self.ui_draw_path, c1x, c1y, c2x, c2y, end_x, end_y) - } - } - - #[inline] - pub fn close_figure(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathCloseFigure(self.ui_draw_path) - } - } - - #[inline] - pub fn add_rectangle(&self, x: f64, y: f64, width: f64, height: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathAddRectangle(self.ui_draw_path, x, y, width, height) - } - } - - #[inline] - pub fn end(&self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawPathEnd(self.ui_draw_path) - } - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Matrix { - pub ui_matrix: uiDrawMatrix, -} - -impl Matrix { - #[inline] - pub fn from_ui_matrix(ui_matrix: &uiDrawMatrix) -> Matrix { - Matrix { - ui_matrix: *ui_matrix, - } - } - - #[inline] - pub fn identity() -> Matrix { - unsafe { - let mut matrix = mem::uninitialized(); - ui_sys::uiDrawMatrixSetIdentity(&mut matrix); - Matrix::from_ui_matrix(&matrix) - } - } - - #[inline] - pub fn translate(&mut self, x: f64, y: f64) { - unsafe { - ui_sys::uiDrawMatrixTranslate(&mut self.ui_matrix, x, y) - } - } - - #[inline] - pub fn scale(&mut self, x_center: f64, y_center: f64, x: f64, y: f64) { - unsafe { - ui_sys::uiDrawMatrixScale(&mut self.ui_matrix, x_center, y_center, x, y) - } - } - - #[inline] - pub fn rotate(&mut self, x: f64, y: f64, angle: f64) { - unsafe { - ui_sys::uiDrawMatrixRotate(&mut self.ui_matrix, x, y, angle) - } - } - - #[inline] - pub fn skew(&mut self, x: f64, y: f64, xamount: f64, yamount: f64) { - unsafe { - ui_sys::uiDrawMatrixSkew(&mut self.ui_matrix, x, y, xamount, yamount) - } - } - - #[inline] - pub fn multiply(&mut self, src: &Matrix) { - unsafe { - ui_sys::uiDrawMatrixMultiply(&mut self.ui_matrix, - &src.ui_matrix as *const uiDrawMatrix - as *mut uiDrawMatrix) - } - } - - #[inline] - pub fn invertible(&self) -> bool { - unsafe { - ui_sys::uiDrawMatrixInvertible(&self.ui_matrix as *const uiDrawMatrix - as *mut uiDrawMatrix) != 0 - } - } - - #[inline] - pub fn invert(&mut self) -> bool { - unsafe { - ui_sys::uiDrawMatrixInvert(&mut self.ui_matrix) != 0 - } - } - - #[inline] - pub fn transform_point(&self, mut point: (f64, f64)) -> (f64, f64) { - unsafe { - ui_sys::uiDrawMatrixTransformPoint(&self.ui_matrix as *const uiDrawMatrix as - *mut uiDrawMatrix, - &mut point.0, - &mut point.1); - point - } - } - - #[inline] - pub fn transform_size(&self, mut size: (f64, f64)) -> (f64, f64) { - unsafe { - ui_sys::uiDrawMatrixTransformSize(&self.ui_matrix as *const uiDrawMatrix as - *mut uiDrawMatrix, - &mut size.0, - &mut size.1); - size - } - } -} - -impl Mul for Matrix { - type Output = Matrix; - - fn mul(mut self, other: Matrix) -> Matrix { - self.multiply(&other); - self - } -} - -pub struct FontFamilies { - ui_draw_font_families: *mut uiDrawFontFamilies, -} - -impl Drop for FontFamilies { - #[inline] - fn drop(&mut self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawFreeFontFamilies(self.ui_draw_font_families) - } - } -} - -impl FontFamilies { - #[inline] - pub fn list() -> FontFamilies { - ffi_utils::ensure_initialized(); - unsafe { - FontFamilies { - ui_draw_font_families: ui_sys::uiDrawListFontFamilies(), - } - } - } - - #[inline] - pub fn len(&self) -> u64 { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawFontFamiliesNumFamilies(self.ui_draw_font_families) - } - } - - #[inline] - pub fn family(&self, index: u64) -> Text { - ffi_utils::ensure_initialized(); - assert!(index < self.len()); - unsafe { - Text::new(ui_sys::uiDrawFontFamiliesFamily(self.ui_draw_font_families, index)) - } - } -} - -pub mod text { - use ffi_utils; - use libc::c_char; - use std::ffi::{CStr, CString}; - use std::mem; - use ui_sys::{self, uiDrawTextFont, uiDrawTextFontDescriptor, uiDrawTextLayout}; - - pub use ui_sys::uiDrawTextWeight as Weight; - pub use ui_sys::uiDrawTextItalic as Italic; - pub use ui_sys::uiDrawTextStretch as Stretch; - pub use ui_sys::uiDrawTextFontMetrics as FontMetrics; - - pub struct FontDescriptor { - family: CString, - pub size: f64, - pub weight: Weight, - pub italic: Italic, - pub stretch: Stretch, - } - - impl FontDescriptor { - #[inline] - pub fn new(family: &str, size: f64, weight: Weight, italic: Italic, stretch: Stretch) - -> FontDescriptor { - ffi_utils::ensure_initialized(); - FontDescriptor { - family: CString::new(family.as_bytes().to_vec()).unwrap(), - size: size, - weight: weight, - italic: italic, - stretch: stretch, - } - } - - /// FIXME(pcwalton): Should this return an Option? - #[inline] - pub fn load_closest_font(&self) -> Font { - ffi_utils::ensure_initialized(); - unsafe { - let font_descriptor = uiDrawTextFontDescriptor { - Family: self.family.as_ptr(), - Size: self.size, - Weight: self.weight, - Italic: self.italic, - Stretch: self.stretch, - }; - Font { - ui_draw_text_font: ui_sys::uiDrawLoadClosestFont(&font_descriptor), - } - } - } - - #[inline] - pub fn family(&self) -> &str { - self.family.to_str().unwrap() - } - } - - pub struct Font { - ui_draw_text_font: *mut uiDrawTextFont, - } - - impl Drop for Font { - #[inline] - fn drop(&mut self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawFreeTextFont(self.ui_draw_text_font) - } - } - } - - impl Font { - #[inline] - pub unsafe fn from_ui_draw_text_font(ui_draw_text_font: *mut uiDrawTextFont) -> Font { - Font { - ui_draw_text_font: ui_draw_text_font, - } - } - - #[inline] - pub fn handle(&self) -> usize { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawTextFontHandle(self.ui_draw_text_font) - } - } - - #[inline] - pub fn describe(&self) -> FontDescriptor { - ffi_utils::ensure_initialized(); - unsafe { - let mut ui_draw_text_font_descriptor = mem::uninitialized(); - ui_sys::uiDrawTextFontDescribe(self.ui_draw_text_font, - &mut ui_draw_text_font_descriptor); - let family = CStr::from_ptr(ui_draw_text_font_descriptor.Family).to_bytes() - .to_vec(); - let font_descriptor = FontDescriptor { - family: CString::new(family).unwrap(), - size: ui_draw_text_font_descriptor.Size, - weight: ui_draw_text_font_descriptor.Weight, - italic: ui_draw_text_font_descriptor.Italic, - stretch: ui_draw_text_font_descriptor.Stretch, - }; - ui_sys::uiFreeText(ui_draw_text_font_descriptor.Family as *mut c_char); - font_descriptor - } - } - - #[inline] - pub fn metrics(&self) -> FontMetrics { - ffi_utils::ensure_initialized(); - unsafe { - let mut metrics = mem::uninitialized(); - ui_sys::uiDrawTextFontGetMetrics(self.ui_draw_text_font, &mut metrics); - metrics - } - } - } - - pub struct Layout { - ui_draw_text_layout: *mut uiDrawTextLayout, - } - - impl Drop for Layout { - #[inline] - fn drop(&mut self) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawFreeTextLayout(self.ui_draw_text_layout) - } - } - } - - impl Layout { - #[inline] - pub fn new(text: &str, default_font: &Font, width: f64) -> Layout { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); - Layout { - ui_draw_text_layout: - ui_sys::uiDrawNewTextLayout(c_string.as_ptr(), - default_font.ui_draw_text_font, - width), - } - } - } - - #[inline] - pub fn as_ui_draw_text_layout(&self) -> *mut uiDrawTextLayout { - self.ui_draw_text_layout - } - - #[inline] - pub fn set_width(&self, width: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawTextLayoutSetWidth(self.ui_draw_text_layout, width) - } - } - - #[inline] - pub fn extents(&self) -> (f64, f64) { - ffi_utils::ensure_initialized(); - unsafe { - let mut extents = (0.0, 0.0); - ui_sys::uiDrawTextLayoutExtents(self.ui_draw_text_layout, - &mut extents.0, - &mut extents.1); - extents - } - } - - #[inline] - pub fn set_color(&self, start_char: i64, end_char: i64, r: f64, g: f64, b: f64, a: f64) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiDrawTextLayoutSetColor(self.ui_draw_text_layout, - start_char, - end_char, - r, - g, - b, - a) - } - } - } -} - diff --git a/tests/fixtures/libui-rs/src/ffi_utils.rs b/tests/fixtures/libui-rs/src/ffi_utils.rs deleted file mode 100644 index 866483db3..000000000 --- a/tests/fixtures/libui-rs/src/ffi_utils.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Useful utility functions for calling the `libui` C bindings. - -use libc::{c_char, c_void}; -use std::ffi::CStr; -use std::mem; -use std::ops::Deref; -use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering}; -use ui_sys; - -static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; - -#[inline] -pub unsafe fn set_initialized() { - assert!(!INITIALIZED.swap(true, Ordering::SeqCst)); -} - -#[inline] -pub unsafe fn unset_initialized() { - INITIALIZED.store(false, Ordering::SeqCst); -} - -#[inline] -pub fn ensure_initialized() { - assert!(INITIALIZED.load(Ordering::SeqCst)); -} - -pub struct Text { - ui_text: *mut c_char, -} - -impl Drop for Text { - fn drop(&mut self) { - unsafe { - ui_sys::uiFreeText(self.ui_text) - } - } -} - -impl Deref for Text { - type Target = str; - fn deref(&self) -> &str { - unsafe { - CStr::from_ptr(self.ui_text).to_str().unwrap_or("") - } - } -} - -impl Text { - #[inline] - pub unsafe fn new(text: *mut c_char) -> Text { - debug_assert!(!text.is_null()); - Text { - ui_text: text, - } - } - - #[inline] - pub unsafe fn optional(text: *mut c_char) -> Option { - if text.is_null() { - None - } else { - Some(Text { - ui_text: text, - }) - } - } -} - -pub extern "C" fn void_void_callback(data: *mut c_void) { - unsafe { - mem::transmute::<*mut c_void, Box>>(data)() - } -} - diff --git a/tests/fixtures/libui-rs/src/lib.rs b/tests/fixtures/libui-rs/src/lib.rs deleted file mode 100644 index 57b46b0e5..000000000 --- a/tests/fixtures/libui-rs/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Rust bindings to `libui`. -//! -//! Main C source repository: https://github.com/andlabs/libui -//! -//! Copyright © 2016 Mozilla Foundation - -#[macro_use] -extern crate bitflags; -extern crate libc; -extern crate ui_sys; - -pub use controls::{Area, AreaDrawParams, AreaHandler, BoxControl, Button, Checkbox, ColorButton}; -pub use controls::{Combobox, Control, DateTimePicker, Entry, FontButton, Group, Label}; -pub use controls::{MultilineEntry, ProgressBar, RadioButtons, Separator, Slider, Spinbox, Tab}; -pub use ffi_utils::Text; -pub use menus::{Menu, MenuItem}; -pub use ui::{InitError, InitOptions, init, main, msg_box, msg_box_error, on_should_quit}; -pub use ui::{open_file, queue_main, quit, save_file, uninit}; -pub use windows::Window; - -#[macro_use] -mod controls; -pub mod draw; -pub mod ffi_utils; -mod menus; -mod ui; -mod windows; - diff --git a/tests/fixtures/libui-rs/src/menus.rs b/tests/fixtures/libui-rs/src/menus.rs deleted file mode 100644 index 1255b691f..000000000 --- a/tests/fixtures/libui-rs/src/menus.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! Functions and types related to menus. - -use libc::{c_int, c_void}; -use std::ffi::CString; -use std::mem; -use ui_sys::{self, uiMenu, uiMenuItem, uiWindow}; -use windows::Window; - -// NB: If there ever becomes a way to destroy menus and/or menu items, we'll need to reference -// count these for memory safety. -#[derive(Clone)] -pub struct MenuItem { - ui_menu_item: *mut uiMenuItem, -} - -impl MenuItem { - #[inline] - pub fn enable(&self) { - unsafe { - ui_sys::uiMenuItemEnable(self.ui_menu_item) - } - } - - #[inline] - pub fn disable(&self) { - unsafe { - ui_sys::uiMenuItemDisable(self.ui_menu_item) - } - } - - #[inline] - pub fn on_clicked(&self, callback: Box) { - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiMenuItemOnClicked(self.ui_menu_item, - c_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(menu_item: *mut uiMenuItem, - window: *mut uiWindow, - data: *mut c_void) { - unsafe { - let menu_item = MenuItem { - ui_menu_item: menu_item, - }; - let window = Window::from_ui_window(window); - mem::transmute::<*mut c_void, - &mut Box>(data)(&menu_item, &window); - mem::forget(window); - } - } - } - - #[inline] - pub fn checked(&self) -> bool { - unsafe { - ui_sys::uiMenuItemChecked(self.ui_menu_item) != 0 - } - } - - #[inline] - pub fn set_checked(&self, checked: bool) { - unsafe { - ui_sys::uiMenuItemSetChecked(self.ui_menu_item, checked as c_int) - } - } -} - -// NB: If there ever becomes a way to destroy menus, we'll need to reference count these for memory -// safety. -#[derive(Clone)] -pub struct Menu { - ui_menu: *mut uiMenu, -} - -impl Menu { - #[inline] - pub fn append_item(&self, name: &str) -> MenuItem { - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - MenuItem { - ui_menu_item: ui_sys::uiMenuAppendItem(self.ui_menu, c_string.as_ptr()), - } - } - } - - #[inline] - pub fn append_check_item(&self, name: &str) -> MenuItem { - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - MenuItem { - ui_menu_item: ui_sys::uiMenuAppendCheckItem(self.ui_menu, c_string.as_ptr()), - } - } - } - - #[inline] - pub fn append_quit_item(&self) -> MenuItem { - unsafe { - MenuItem { - ui_menu_item: ui_sys::uiMenuAppendQuitItem(self.ui_menu), - } - } - } - - #[inline] - pub fn append_preferences_item(&self) -> MenuItem { - unsafe { - MenuItem { - ui_menu_item: ui_sys::uiMenuAppendPreferencesItem(self.ui_menu), - } - } - } - - #[inline] - pub fn append_about_item(&self) -> MenuItem { - unsafe { - MenuItem { - ui_menu_item: ui_sys::uiMenuAppendAboutItem(self.ui_menu), - } - } - } - - #[inline] - pub fn append_separator(&self) { - unsafe { - ui_sys::uiMenuAppendSeparator(self.ui_menu) - } - } - - #[inline] - pub fn new(name: &str) -> Menu { - unsafe { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - Menu { - ui_menu: ui_sys::uiNewMenu(c_string.as_ptr()), - } - } - } -} - diff --git a/tests/fixtures/libui-rs/src/ui.rs b/tests/fixtures/libui-rs/src/ui.rs deleted file mode 100644 index ccdc4dd46..000000000 --- a/tests/fixtures/libui-rs/src/ui.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! General functions. - -use ffi_utils::{self, Text}; -use libc::{c_char, c_void}; -use std::fmt::{self, Debug, Formatter}; -use std::ffi::{CStr, CString}; -use std::mem; -use std::ops::Deref; -use ui_sys::{self, uiInitOptions}; -use windows::Window; - -#[derive(Clone)] -pub struct InitOptions; - -#[inline] -pub fn init(_: InitOptions) -> Result<(),InitError> { - unsafe { - let mut init_options = uiInitOptions { - Size: mem::size_of::(), - }; - let err = ui_sys::uiInit(&mut init_options); - if err.is_null() { - ffi_utils::set_initialized(); - Ok(()) - } else { - Err(InitError { - ui_init_error: err, - }) - } - } -} - -#[inline] -pub fn uninit() { - unsafe { - ffi_utils::unset_initialized(); - Window::destroy_all_windows(); - ui_sys::uiUninit(); - } -} - -#[inline] -pub fn main() { - unsafe { - ui_sys::uiMain() - } -} - -#[inline] -pub fn quit() { - unsafe { - ui_sys::uiQuit() - } -} - -pub struct InitError { - ui_init_error: *const c_char, -} - -impl Drop for InitError { - fn drop(&mut self) { - unsafe { - ui_sys::uiFreeInitError(self.ui_init_error) - } - } -} - -impl Debug for InitError { - fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - (**self).fmt(f) - } -} - -impl Deref for InitError { - type Target = str; - fn deref(&self) -> &str { - unsafe { - CStr::from_ptr(self.ui_init_error).to_str().unwrap_or("") - } - } -} - -#[inline] -pub fn queue_main(callback: Box) { - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiQueueMain(ffi_utils::void_void_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } -} - -#[inline] -pub fn on_should_quit(callback: Box) { - unsafe { - let mut data: Box> = Box::new(callback); - ui_sys::uiOnShouldQuit(ffi_utils::void_void_callback, - &mut *data as *mut Box as *mut c_void); - mem::forget(data); - } -} - -#[inline] -pub fn open_file(parent: &Window) -> Option { - unsafe { - Text::optional(ui_sys::uiOpenFile(parent.as_ui_window())) - } -} - -#[inline] -pub fn save_file(parent: &Window) -> Option { - unsafe { - Text::optional(ui_sys::uiSaveFile(parent.as_ui_window())) - } -} - -#[inline] -pub fn msg_box(parent: &Window, title: &str, description: &str) { - unsafe { - let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); - let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); - ui_sys::uiMsgBox(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) - } -} - -#[inline] -pub fn msg_box_error(parent: &Window, title: &str, description: &str) { - unsafe { - let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); - let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); - ui_sys::uiMsgBoxError(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) - } -} - diff --git a/tests/fixtures/libui-rs/src/windows.rs b/tests/fixtures/libui-rs/src/windows.rs deleted file mode 100644 index c43ff049b..000000000 --- a/tests/fixtures/libui-rs/src/windows.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! Functions and types related to windows. - -use controls::Control; -use ffi_utils::{self, Text}; -use libc::{c_int, c_void}; -use std::cell::RefCell; -use std::ffi::CString; -use std::mem; -use ui_sys::{self, uiControl, uiWindow}; - -thread_local! { - static WINDOWS: RefCell> = RefCell::new(Vec::new()) -} - -define_control!(Window, uiWindow, ui_window); - -impl Window { - #[inline] - pub fn as_ui_window(&self) -> *mut uiWindow { - self.ui_window - } - - #[inline] - pub fn title(&self) -> Text { - ffi_utils::ensure_initialized(); - unsafe { - Text::new(ui_sys::uiWindowTitle(self.ui_window)) - } - } - - #[inline] - pub fn set_title(&self, title: &str) { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); - ui_sys::uiWindowSetTitle(self.ui_window, c_string.as_ptr()) - } - } - - #[inline] - pub fn on_closing(&self, callback: Box bool>) { - ffi_utils::ensure_initialized(); - unsafe { - let mut data: Box bool>> = Box::new(callback); - ui_sys::uiWindowOnClosing(self.ui_window, - c_callback, - &mut *data as *mut Box bool> as - *mut c_void); - mem::forget(data); - } - - extern "C" fn c_callback(window: *mut uiWindow, data: *mut c_void) -> i32 { - unsafe { - let window = Window { - ui_window: window, - }; - mem::transmute::<*mut c_void, - Box bool>>>(data)(&window) as i32 - } - } - } - - #[inline] - pub fn set_child(&self, child: Control) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiWindowSetChild(self.ui_window, child.as_ui_control()) - } - } - - #[inline] - pub fn margined(&self) -> bool { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiWindowMargined(self.ui_window) != 0 - } - } - - #[inline] - pub fn set_margined(&self, margined: bool) { - ffi_utils::ensure_initialized(); - unsafe { - ui_sys::uiWindowSetMargined(self.ui_window, margined as c_int) - } - } - - #[inline] - pub fn new(title: &str, width: c_int, height: c_int, has_menubar: bool) -> Window { - ffi_utils::ensure_initialized(); - unsafe { - let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); - let window = Window::from_ui_window(ui_sys::uiNewWindow(c_string.as_ptr(), - width, - height, - has_menubar as c_int)); - - WINDOWS.with(|windows| windows.borrow_mut().push(window.clone())); - - window - } - } - - #[inline] - pub unsafe fn from_ui_window(window: *mut uiWindow) -> Window { - Window { - ui_window: window, - } - } - - pub unsafe fn destroy_all_windows() { - WINDOWS.with(|windows| { - let mut windows = windows.borrow_mut(); - for window in windows.drain(..) { - window.destroy() - } - }) - } -} - From 759740e67aa09c151f34660101d64aeaa258269a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 15:47:02 +0200 Subject: [PATCH 045/298] Create tests for rustfix --- .gitmodules | 3 ++ .travis.yml | 2 + test.sh | 23 +++++++++ tests/fixtures/libui-rs | 1 + .../fixtures/libui-rs.tests/simple/diff.diff | 22 ++++++++ .../fixtures/libui-rs.tests/simple/input.txt | 3 ++ .../fixtures/libui-rs.tests/simple/output.txt | 51 +++++++++++++++++++ .../libui-rs.tests/skipping/diff.diff | 13 +++++ .../libui-rs.tests/skipping/input.txt | 3 ++ .../libui-rs.tests/skipping/output.txt | 51 +++++++++++++++++++ tests/libui.rs | 3 -- 11 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 .gitmodules create mode 100755 test.sh create mode 160000 tests/fixtures/libui-rs create mode 100644 tests/fixtures/libui-rs.tests/simple/diff.diff create mode 100644 tests/fixtures/libui-rs.tests/simple/input.txt create mode 100644 tests/fixtures/libui-rs.tests/simple/output.txt create mode 100644 tests/fixtures/libui-rs.tests/skipping/diff.diff create mode 100644 tests/fixtures/libui-rs.tests/skipping/input.txt create mode 100644 tests/fixtures/libui-rs.tests/skipping/output.txt delete mode 100644 tests/libui.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..99589b62d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/fixtures/libui-rs"] + path = tests/fixtures/libui-rs + url = https://github.com/pcwalton/libui-rs.git diff --git a/.travis.yml b/.travis.yml index efa26bc34..46dddf27c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: rust rust: - nightly + +after_success: sh test.sh diff --git a/test.sh b/test.sh new file mode 100755 index 000000000..6cfd4575f --- /dev/null +++ b/test.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +root_dir=$(pwd) + +cd tests/fixtures/libui-rs/ui +for d in $root_dir/tests/fixtures/libui-rs.tests/*/ +do + echo $d + git checkout . + cargo clean + cat $d/input.txt | cargo run --manifest-path=$root_dir/Cargo.toml -- --clippy > output.txt + if test "$1" == "apply" + then + git diff > $d/diff.diff + cp output.txt $d/output.txt + else + git diff > diff.diff + set -e + diff diff.diff $d/diff.diff + diff output.txt $d/output.txt + set +e + fi +done diff --git a/tests/fixtures/libui-rs b/tests/fixtures/libui-rs new file mode 160000 index 000000000..13299d28f --- /dev/null +++ b/tests/fixtures/libui-rs @@ -0,0 +1 @@ +Subproject commit 13299d28f69f8009be8e08e453a9b0024f153a60 diff --git a/tests/fixtures/libui-rs.tests/simple/diff.diff b/tests/fixtures/libui-rs.tests/simple/diff.diff new file mode 100644 index 000000000..a54e60ad8 --- /dev/null +++ b/tests/fixtures/libui-rs.tests/simple/diff.diff @@ -0,0 +1,22 @@ +diff --git a/ui/src/controls.rs b/ui/src/controls.rs +index 5699276..59e36b9 100644 +--- a/ui/src/controls.rs ++++ b/ui/src/controls.rs +@@ -242,7 +242,7 @@ impl Button { + let button = Button { + ui_button: button, + }; +- mem::transmute::<*mut c_void, &mut Box>(data)(&button) ++ &mut *(data as *mut Box)(&button) + } + } + } +@@ -347,7 +347,7 @@ impl Entry { + extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { + unsafe { + let entry = Entry::from_ui_control(entry); +- mem::transmute::<*mut c_void, &mut Box>(data)(&entry); ++ &mut *(data as *mut Box)(&entry); + mem::forget(entry); + } + } diff --git a/tests/fixtures/libui-rs.tests/simple/input.txt b/tests/fixtures/libui-rs.tests/simple/input.txt new file mode 100644 index 000000000..ced652ef7 --- /dev/null +++ b/tests/fixtures/libui-rs.tests/simple/input.txt @@ -0,0 +1,3 @@ +r +r +q diff --git a/tests/fixtures/libui-rs.tests/simple/output.txt b/tests/fixtures/libui-rs.tests/simple/output.txt new file mode 100644 index 000000000..e0eff993d --- /dev/null +++ b/tests/fixtures/libui-rs.tests/simple/output.txt @@ -0,0 +1,51 @@ + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) + --> src/controls.rs:245:17-245:78 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&button) + +with: + + &mut *(data as *mut Box) + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) + --> src/controls.rs:350:17-350:77 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&entry); + +with: + + &mut *(data as *mut Box) + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. + + +Info: you should consider adding a `Default` implementation for `controls::Entry` + --> src/controls.rs:373:5-373:5 +Suggestion - Replace: + +pub fn new() -> Entry { + +with: + + impl Default for controls::Entry { + fn default() -> Self { + Self::new() + } + } + + + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Thanks for playing! +Good work. Let me just apply these 2 changes! +.. +Done. diff --git a/tests/fixtures/libui-rs.tests/skipping/diff.diff b/tests/fixtures/libui-rs.tests/skipping/diff.diff new file mode 100644 index 000000000..c38003a3e --- /dev/null +++ b/tests/fixtures/libui-rs.tests/skipping/diff.diff @@ -0,0 +1,13 @@ +diff --git a/ui/src/controls.rs b/ui/src/controls.rs +index 5699276..56d1c1e 100644 +--- a/ui/src/controls.rs ++++ b/ui/src/controls.rs +@@ -242,7 +242,7 @@ impl Button { + let button = Button { + ui_button: button, + }; +- mem::transmute::<*mut c_void, &mut Box>(data)(&button) ++ &mut *(data as *mut Box)(&button) + } + } + } diff --git a/tests/fixtures/libui-rs.tests/skipping/input.txt b/tests/fixtures/libui-rs.tests/skipping/input.txt new file mode 100644 index 000000000..0bfd421ef --- /dev/null +++ b/tests/fixtures/libui-rs.tests/skipping/input.txt @@ -0,0 +1,3 @@ +r +s +q diff --git a/tests/fixtures/libui-rs.tests/skipping/output.txt b/tests/fixtures/libui-rs.tests/skipping/output.txt new file mode 100644 index 000000000..ad8a07fd7 --- /dev/null +++ b/tests/fixtures/libui-rs.tests/skipping/output.txt @@ -0,0 +1,51 @@ + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) + --> src/controls.rs:245:17-245:78 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&button) + +with: + + &mut *(data as *mut Box) + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) + --> src/controls.rs:350:17-350:77 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&entry); + +with: + + &mut *(data as *mut Box) + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Skipped. + + +Info: you should consider adding a `Default` implementation for `controls::Entry` + --> src/controls.rs:373:5-373:5 +Suggestion - Replace: + +pub fn new() -> Entry { + +with: + + impl Default for controls::Entry { + fn default() -> Self { + Self::new() + } + } + + + +==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Thanks for playing! +Good work. Let me just apply these 1 changes! +. +Done. diff --git a/tests/libui.rs b/tests/libui.rs deleted file mode 100644 index 6129df763..000000000 --- a/tests/libui.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[test] -fn test() { -} From 4624e8929199bb0afd6c4492d5b710bee2078eb6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 15:48:40 +0200 Subject: [PATCH 046/298] Limit public parts of diagnostic structs to actually used parts --- src/diagnostics.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 50a4551bf..5d880ffdd 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,23 +6,23 @@ pub struct Diagnostic { /// The primary error message. pub message: String, - pub code: Option, + code: Option, /// "error: internal compiler error", "error", "warning", "note", "help". - pub level: String, + level: String, pub spans: Vec, /// Associated diagnostic messages. pub children: Vec, /// The message as rustc would render it. Currently this is only /// `Some` for "suggestions", but eventually it will include all /// snippets. - pub rendered: Option, + rendered: Option, } #[derive(Serialize, Deserialize, Debug)] pub struct DiagnosticSpan { pub file_name: String, - pub byte_start: usize, - pub byte_end: usize, + byte_start: u32, + byte_end: u32, /// 1-based. pub line_start: usize, pub line_end: usize, @@ -31,19 +31,18 @@ pub struct DiagnosticSpan { pub column_end: usize, /// Is this a "primary" span -- meaning the point, or one of the points, /// where the error occurred? - pub is_primary: bool, + is_primary: bool, /// Source text from the start of line_start to the end of line_end. pub text: Vec, /// Label that should be placed at this location (if any) - pub label: Option, + label: Option, /// If we are suggesting a replacement, this will contain text /// that should be sliced in atop this span. You may prefer to /// load the fully rendered version from the parent `Diagnostic`, /// however. pub suggested_replacement: Option, /// Macro invocations that created the code at this span, if any. - #[serde(bound="")] - pub expansion: Option>, + expansion: Option>, } #[derive(Serialize, Deserialize, Debug)] @@ -52,27 +51,28 @@ pub struct DiagnosticSpanLine { /// 1-based, character offset in self.text. pub highlight_start: usize, + pub highlight_end: usize, } #[derive(Serialize, Deserialize, Debug)] -pub struct DiagnosticSpanMacroExpansion { +struct DiagnosticSpanMacroExpansion { /// span where macro was applied to generate this code; note that /// this may itself derive from a macro (if /// `span.expansion.is_some()`) - pub span: DiagnosticSpan, + span: DiagnosticSpan, /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") - pub macro_decl_name: String, + macro_decl_name: String, /// span where macro was defined (if known) - pub def_site_span: Option, + def_site_span: Option, } #[derive(Serialize, Deserialize, Debug)] -pub struct DiagnosticCode { +struct DiagnosticCode { /// The code itself. - pub code: String, + code: String, /// An explanation for the code. - pub explanation: Option, + explanation: Option, } From acb089c89a3d6c441f9afea23bb4dfb73c170720 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 15:49:00 +0200 Subject: [PATCH 047/298] No need to be able to serialize diagnostic structs --- src/diagnostics.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 5d880ffdd..c6af23340 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -2,7 +2,7 @@ //! //! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) -#[derive(Serialize, Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct Diagnostic { /// The primary error message. pub message: String, @@ -18,7 +18,7 @@ pub struct Diagnostic { rendered: Option, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct DiagnosticSpan { pub file_name: String, byte_start: u32, @@ -45,7 +45,7 @@ pub struct DiagnosticSpan { expansion: Option>, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct DiagnosticSpanLine { pub text: String, @@ -55,7 +55,7 @@ pub struct DiagnosticSpanLine { pub highlight_end: usize, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Deserialize, Debug)] struct DiagnosticSpanMacroExpansion { /// span where macro was applied to generate this code; note that /// this may itself derive from a macro (if @@ -69,7 +69,7 @@ struct DiagnosticSpanMacroExpansion { def_site_span: Option, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Deserialize, Debug)] struct DiagnosticCode { /// The code itself. code: String, From 4e2009485728c20d07900e0cad21b593b4c3f319 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 15:51:57 +0200 Subject: [PATCH 048/298] Use `cargo --message-format` instead of rustc-flags --- src/main.rs | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index 82dd1f7b2..3f84c83e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#[macro_use] +extern crate serde_derive; extern crate serde_json; #[macro_use] extern crate quick_error; @@ -51,33 +53,22 @@ fn try_main() -> Result<(), ProgramError> { .arg(Arg::with_name("clippy") .long("clippy") .help("Use `cargo clippy` for suggestions")) - .arg(Arg::with_name("from_file") - .long("from-file") - .value_name("FILE") - .takes_value(true) - .help("Read suggestions from file (each line is a JSON object)")) .get_matches(); // Get JSON output from rustc... - let json = if let Some(file_name) = matches.value_of("from_file") { - // either by reading a file the user saved (probably only for debugging rustfix itself)... - try!(json_from_file(&file_name)) - } else { - // or by spawning a subcommand that runs rustc. let subcommand = if matches.is_present("clippy") { "clippy" } else { "rustc" }; try!(json_from_subcommand(subcommand)) - }; let suggestions: Vec = json.lines() .filter(not_empty) // Convert JSON string (and eat parsing errors) - .flat_map(|line| serde_json::from_str::(line)) + .flat_map(|line| serde_json::from_str::(line)) // One diagnostic line might have multiple suggestions - .flat_map(|diagnostic| rustfix::collect_suggestions(&diagnostic, None)) + .flat_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, None)) .collect(); try!(handle_suggestions(&suggestions)); @@ -85,18 +76,14 @@ fn try_main() -> Result<(), ProgramError> { Ok(()) } -fn json_from_file(file_name: &str) -> Result { - read_file_to_string(file_name).map_err(From::from) +#[derive(Deserialize)] +struct CargoMessage { + message: Diagnostic, } fn json_from_subcommand(subcommand: &str) -> Result { let output = try!(Command::new("cargo") - .args(&[subcommand, - "--quiet", - "--color", "never", - "--", - "-Z", "unstable-options", - "--error-format", "json"]) + .args(&[subcommand, "--message-format", "json"]) .output()); let content = try!(String::from_utf8(output.stderr)); From 0dac525c847bb395ef90126fbea14a38a3cc5387 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 15:52:43 +0200 Subject: [PATCH 049/298] Always use `cargo clippy`, but don't enable the lints by default --- src/main.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3f84c83e0..dbd63408a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,13 +55,14 @@ fn try_main() -> Result<(), ProgramError> { .help("Use `cargo clippy` for suggestions")) .get_matches(); + let mut extra_args = Vec::new(); + + if !matches.is_present("clippy") { + extra_args.push("-Aclippy"); + } + // Get JSON output from rustc... - let subcommand = if matches.is_present("clippy") { - "clippy" - } else { - "rustc" - }; - try!(json_from_subcommand(subcommand)) + let json = get_json(&extra_args)?; let suggestions: Vec = json.lines() .filter(not_empty) @@ -81,14 +82,14 @@ struct CargoMessage { message: Diagnostic, } -fn json_from_subcommand(subcommand: &str) -> Result { +fn get_json(extra_args: &[&str]) -> Result { let output = try!(Command::new("cargo") - .args(&[subcommand, "--message-format", "json"]) + .args(&["clippy", "--message-format", "json"]) + .arg("--") + .args(extra_args) .output()); - let content = try!(String::from_utf8(output.stderr)); - - Ok(content) + Ok(String::from_utf8(output.stdout)?) } fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { From 4bcc09c2302f868c861d710284fa6689471c90cd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 16:03:53 +0200 Subject: [PATCH 050/298] Fix test script for travis --- test.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test.sh b/test.sh index 6cfd4575f..de98e575d 100755 --- a/test.sh +++ b/test.sh @@ -1,5 +1,7 @@ #!/bin/bash +cargo install clippy + root_dir=$(pwd) cd tests/fixtures/libui-rs/ui @@ -9,7 +11,7 @@ do git checkout . cargo clean cat $d/input.txt | cargo run --manifest-path=$root_dir/Cargo.toml -- --clippy > output.txt - if test "$1" == "apply" + if [ "$1" == "apply" ] then git diff > $d/diff.diff cp output.txt $d/output.txt From 9314e1112d00a2b5bcb6ddbe1d6cda9095d25b31 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 12 May 2017 17:37:38 +0200 Subject: [PATCH 051/298] Rewrote test script in Rust --- .gitmodules | 2 +- .travis.yml | 2 - test.sh | 25 --------- tests/{fixtures => crates}/libui-rs | 0 tests/fixtures.rs | 53 +++++++++++++++++++ .../libui-rs}/simple/diff.diff | 0 .../libui-rs}/simple/input.txt | 0 .../libui-rs}/simple/output.txt | 0 .../libui-rs}/skipping/diff.diff | 0 .../libui-rs}/skipping/input.txt | 0 .../libui-rs}/skipping/output.txt | 0 11 files changed, 54 insertions(+), 28 deletions(-) delete mode 100755 test.sh rename tests/{fixtures => crates}/libui-rs (100%) create mode 100644 tests/fixtures.rs rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/simple/diff.diff (100%) rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/simple/input.txt (100%) rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/simple/output.txt (100%) rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/skipping/diff.diff (100%) rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/skipping/input.txt (100%) rename tests/{fixtures/libui-rs.tests => tests/libui-rs}/skipping/output.txt (100%) diff --git a/.gitmodules b/.gitmodules index 99589b62d..1736dfb52 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tests/fixtures/libui-rs"] - path = tests/fixtures/libui-rs + path = tests/crates/libui-rs url = https://github.com/pcwalton/libui-rs.git diff --git a/.travis.yml b/.travis.yml index 46dddf27c..efa26bc34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ language: rust rust: - nightly - -after_success: sh test.sh diff --git a/test.sh b/test.sh deleted file mode 100755 index de98e575d..000000000 --- a/test.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -cargo install clippy - -root_dir=$(pwd) - -cd tests/fixtures/libui-rs/ui -for d in $root_dir/tests/fixtures/libui-rs.tests/*/ -do - echo $d - git checkout . - cargo clean - cat $d/input.txt | cargo run --manifest-path=$root_dir/Cargo.toml -- --clippy > output.txt - if [ "$1" == "apply" ] - then - git diff > $d/diff.diff - cp output.txt $d/output.txt - else - git diff > diff.diff - set -e - diff diff.diff $d/diff.diff - diff output.txt $d/output.txt - set +e - fi -done diff --git a/tests/fixtures/libui-rs b/tests/crates/libui-rs similarity index 100% rename from tests/fixtures/libui-rs rename to tests/crates/libui-rs diff --git a/tests/fixtures.rs b/tests/fixtures.rs new file mode 100644 index 000000000..f00d38ba8 --- /dev/null +++ b/tests/fixtures.rs @@ -0,0 +1,53 @@ +use std::process::{Command, Stdio}; +use std::fs::File; +use std::io::{Read, Write}; + +#[test] +fn fixtures() { + // ignore if this fails + let _ = Command::new("cargo").arg("install").arg("clippy").status().unwrap(); + let root_dir = std::env::current_dir().unwrap(); + println!("root: {:?}", root_dir); + for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { + let fixture = fixture.unwrap(); + let fixture_path = fixture.path(); + // FIXME: don't expect the crate to be in the `ui` subdir + std::env::set_current_dir(fixture_path.join("ui")).unwrap(); + for entry in std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap() { + let test = entry.unwrap().path(); + println!("{:?}", test); + assert!(Command::new("git").arg("checkout").arg(".").status().unwrap().success()); + assert!(Command::new("cargo").arg("clean").status().unwrap().success()); + let mut input = Vec::new(); + File::open(test.join("input.txt")).unwrap().read_to_end(&mut input).unwrap(); + let manifest = format!("{:?}", root_dir.join("Cargo.toml")); + let mut cmd = Command::new("cargo") + .arg("run") + .arg(format!("--manifest-path={}", &manifest[1..manifest.len() - 1])) + .arg("--") + .arg("--clippy") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + cmd.stdin.as_mut().unwrap().write(&input).unwrap(); + let output = cmd.wait_with_output().unwrap(); + File::create("output.txt").unwrap().write_all(&output.stdout).unwrap(); + if std::env::var("APPLY_RUSTFIX").is_ok() { + std::fs::copy("output.txt", test.join("output.txt")).unwrap(); + let diff = Command::new("git").arg("diff").output().unwrap(); + File::create(test.join("diff.diff")).unwrap().write_all(&diff.stdout).unwrap(); + } else { + let diff = Command::new("git").arg("diff").output().unwrap(); + File::create("diff.diff").unwrap().write_all(&diff.stdout).unwrap(); + if !Command::new("diff").arg("-q").arg("diff.diff").arg(test.join("diff.diff")).status().unwrap().success() { + panic!("Unexpected changes applied by rustfix"); + } + if !Command::new("diff").arg("-q").arg("output.txt").arg(test.join("output.txt")).status().unwrap().success() { + panic!("Unexpected output by rustfix"); + } + } + } + std::env::set_current_dir(&root_dir).unwrap(); + } +} diff --git a/tests/fixtures/libui-rs.tests/simple/diff.diff b/tests/tests/libui-rs/simple/diff.diff similarity index 100% rename from tests/fixtures/libui-rs.tests/simple/diff.diff rename to tests/tests/libui-rs/simple/diff.diff diff --git a/tests/fixtures/libui-rs.tests/simple/input.txt b/tests/tests/libui-rs/simple/input.txt similarity index 100% rename from tests/fixtures/libui-rs.tests/simple/input.txt rename to tests/tests/libui-rs/simple/input.txt diff --git a/tests/fixtures/libui-rs.tests/simple/output.txt b/tests/tests/libui-rs/simple/output.txt similarity index 100% rename from tests/fixtures/libui-rs.tests/simple/output.txt rename to tests/tests/libui-rs/simple/output.txt diff --git a/tests/fixtures/libui-rs.tests/skipping/diff.diff b/tests/tests/libui-rs/skipping/diff.diff similarity index 100% rename from tests/fixtures/libui-rs.tests/skipping/diff.diff rename to tests/tests/libui-rs/skipping/diff.diff diff --git a/tests/fixtures/libui-rs.tests/skipping/input.txt b/tests/tests/libui-rs/skipping/input.txt similarity index 100% rename from tests/fixtures/libui-rs.tests/skipping/input.txt rename to tests/tests/libui-rs/skipping/input.txt diff --git a/tests/fixtures/libui-rs.tests/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt similarity index 100% rename from tests/fixtures/libui-rs.tests/skipping/output.txt rename to tests/tests/libui-rs/skipping/output.txt From a3fa6c1d50eb09c64f552637f4feadf069c7c1eb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 May 2017 13:29:11 +0200 Subject: [PATCH 052/298] Rewrite the scripts in duct --- Cargo.toml | 3 +++ tests/fixtures.rs | 50 +++++++++++++++++++++-------------------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ca4c76eb1..d606b8c22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ quick-error = "1.1.0" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" + +[dev-dependencies] +duct = "0.8.2" diff --git a/tests/fixtures.rs b/tests/fixtures.rs index f00d38ba8..f6dced21d 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -1,53 +1,47 @@ -use std::process::{Command, Stdio}; -use std::fs::File; -use std::io::{Read, Write}; +#[macro_use] +extern crate duct; #[test] fn fixtures() { // ignore if this fails - let _ = Command::new("cargo").arg("install").arg("clippy").status().unwrap(); + let _ = cmd!("cargo", "install", "clippy").run(); let root_dir = std::env::current_dir().unwrap(); println!("root: {:?}", root_dir); for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { let fixture = fixture.unwrap(); let fixture_path = fixture.path(); // FIXME: don't expect the crate to be in the `ui` subdir - std::env::set_current_dir(fixture_path.join("ui")).unwrap(); + let dir = fixture_path.join("ui"); for entry in std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap() { let test = entry.unwrap().path(); println!("{:?}", test); - assert!(Command::new("git").arg("checkout").arg(".").status().unwrap().success()); - assert!(Command::new("cargo").arg("clean").status().unwrap().success()); - let mut input = Vec::new(); - File::open(test.join("input.txt")).unwrap().read_to_end(&mut input).unwrap(); + assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); + assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); let manifest = format!("{:?}", root_dir.join("Cargo.toml")); - let mut cmd = Command::new("cargo") - .arg("run") - .arg(format!("--manifest-path={}", &manifest[1..manifest.len() - 1])) - .arg("--") - .arg("--clippy") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() + cmd!("cargo", + "run", + format!("--manifest-path={}", &manifest[1..manifest.len() - 1]), + "--", + "--clippy" + ) + .dir(&dir) + .stdin(test.join("input.txt")) + .stdout(dir.join("output.txt")) + .run() .unwrap(); - cmd.stdin.as_mut().unwrap().write(&input).unwrap(); - let output = cmd.wait_with_output().unwrap(); - File::create("output.txt").unwrap().write_all(&output.stdout).unwrap(); + if std::env::var("APPLY_RUSTFIX").is_ok() { - std::fs::copy("output.txt", test.join("output.txt")).unwrap(); - let diff = Command::new("git").arg("diff").output().unwrap(); - File::create(test.join("diff.diff")).unwrap().write_all(&diff.stdout).unwrap(); + std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); + cmd!("git", "diff").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); } else { - let diff = Command::new("git").arg("diff").output().unwrap(); - File::create("diff.diff").unwrap().write_all(&diff.stdout).unwrap(); - if !Command::new("diff").arg("-q").arg("diff.diff").arg(test.join("diff.diff")).status().unwrap().success() { + cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); + if !cmd!("diff", "-q", dir.join("diff.diff"), test.join("diff.diff")).dir(&dir).unchecked().run().unwrap().status.success() { panic!("Unexpected changes applied by rustfix"); } - if !Command::new("diff").arg("-q").arg("output.txt").arg(test.join("output.txt")).status().unwrap().success() { + if !cmd!("diff", "-q", dir.join("output.txt"), test.join("output.txt")).dir(&dir).unchecked().run().unwrap().status.success() { panic!("Unexpected output by rustfix"); } } } - std::env::set_current_dir(&root_dir).unwrap(); } } From 05897f71a203e629b99d8e3bd3135c1bb8e3f969 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 May 2017 13:29:22 +0200 Subject: [PATCH 053/298] Print the test output in travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index efa26bc34..8e4a79d4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ language: rust rust: - nightly + +script: +- cargo build +- cargo test -- --nocapture From 26658ad2f18042722c561ec28a2cf3ee89aeb612 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Mon, 15 May 2017 14:07:43 +0200 Subject: [PATCH 054/298] Add more logging to fixture tests --- tests/fixtures.rs | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/tests/fixtures.rs b/tests/fixtures.rs index f6dced21d..9a7bfe5bd 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -4,26 +4,36 @@ extern crate duct; #[test] fn fixtures() { // ignore if this fails - let _ = cmd!("cargo", "install", "clippy").run(); + let _ = cmd!("cargo", "install", "clippy").stderr_capture().run(); let root_dir = std::env::current_dir().unwrap(); - println!("root: {:?}", root_dir); + + println!("looking for fixtures in directory: {:?}", root_dir); + for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { let fixture = fixture.unwrap(); let fixture_path = fixture.path(); + // FIXME: don't expect the crate to be in the `ui` subdir let dir = fixture_path.join("ui"); - for entry in std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap() { + let tests = std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap(); + + for entry in tests { let test = entry.unwrap().path(); - println!("{:?}", test); + + println!("---"); + println!("Running test: {:?}", test); + assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); + let manifest = format!("{:?}", root_dir.join("Cargo.toml")); - cmd!("cargo", - "run", + + println!("Checking {:?} with clippy", test); + + cmd!("cargo", "run", format!("--manifest-path={}", &manifest[1..manifest.len() - 1]), - "--", - "--clippy" - ) + "--quiet", + "--", "--clippy") .dir(&dir) .stdin(test.join("input.txt")) .stdout(dir.join("output.txt")) @@ -32,16 +42,22 @@ fn fixtures() { if std::env::var("APPLY_RUSTFIX").is_ok() { std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); + cmd!("git", "diff").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); } else { cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); + if !cmd!("diff", "-q", dir.join("diff.diff"), test.join("diff.diff")).dir(&dir).unchecked().run().unwrap().status.success() { panic!("Unexpected changes applied by rustfix"); } + if !cmd!("diff", "-q", dir.join("output.txt"), test.join("output.txt")).dir(&dir).unchecked().run().unwrap().status.success() { panic!("Unexpected output by rustfix"); } } + + println!("---"); + println!("Success!"); } } } From 350febf0def841bea08a2474487d6bc706ca9044 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Mon, 15 May 2017 14:21:42 +0200 Subject: [PATCH 055/298] Add some metadata [ci skip] --- Cargo.toml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d606b8c22..73d5b49fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,20 @@ [package] -authors = ["Pascal Hertleif "] +authors = [ + "Pascal Hertleif ", + "Oliver Schneider ", +] license = "Apache-2.0/MIT" name = "rustfix" +description = "Automatically apply the suggestions made by rustc" +repository = "https://github.com/killercup/rustfix" +documentation = "https://docs.rs/rustfix" readme = "README.md" version = "0.1.0" +exclude = [ + "etc/*", + "examples/*", + "tests/*", +] [dependencies] clap = "2.9.2" From 5e48ecb182a3344f651e390213aae6497a73c3fa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 May 2017 14:24:35 +0200 Subject: [PATCH 056/298] Add yolo mode to rustfix --- src/main.rs | 31 ++- tests/fixtures.rs | 13 +- tests/tests/libui-rs/yolo/diff.diff | 201 +++++++++++++++++++ tests/tests/libui-rs/yolo/input.txt | 0 tests/tests/libui-rs/yolo/output.txt | 287 +++++++++++++++++++++++++++ 5 files changed, 525 insertions(+), 7 deletions(-) create mode 100644 tests/tests/libui-rs/yolo/diff.diff create mode 100644 tests/tests/libui-rs/yolo/input.txt create mode 100644 tests/tests/libui-rs/yolo/output.txt diff --git a/src/main.rs b/src/main.rs index dbd63408a..f973ed55c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,9 @@ fn try_main() -> Result<(), ProgramError> { .arg(Arg::with_name("clippy") .long("clippy") .help("Use `cargo clippy` for suggestions")) + .arg(Arg::with_name("yolo") + .long("yolo") + .help("Automatically apply all unambiguous suggestions")) .get_matches(); let mut extra_args = Vec::new(); @@ -61,6 +64,12 @@ fn try_main() -> Result<(), ProgramError> { extra_args.push("-Aclippy"); } + let mode = if matches.is_present("yolo") { + AutofixMode::Yolo + } else { + AutofixMode::None + }; + // Get JSON output from rustc... let json = get_json(&extra_args)?; @@ -72,7 +81,7 @@ fn try_main() -> Result<(), ProgramError> { .flat_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, None)) .collect(); - try!(handle_suggestions(&suggestions)); + try!(handle_suggestions(&suggestions, mode)); Ok(()) } @@ -92,7 +101,19 @@ fn get_json(extra_args: &[&str]) -> Result { Ok(String::from_utf8(output.stdout)?) } -fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { +#[derive(PartialEq, Eq, Debug)] +enum AutofixMode { + /// Do not apply any fixes automatically + None, + // /// Only apply suggestions of a whitelist of lints + // Whitelist, + // /// Check the confidence flag supplied by rustc + // Confidence, + /// Automatically apply all unambiguous suggestions + Yolo, +} + +fn handle_suggestions(suggestions: &[Suggestion], mode: AutofixMode) -> Result<(), ProgramError> { let mut accepted_suggestions: Vec<&Suggestion> = vec![]; if suggestions.is_empty() { @@ -118,6 +139,12 @@ fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> { tail = suggestion.text.2, with = "with:".yellow().bold(), replacement = indent(4, &suggestion.replacement)); + + if mode == AutofixMode::Yolo { + accepted_suggestions.push(suggestion); + println!("automatically applying suggestion (--yolo)"); + continue 'suggestions; + } 'userinput: loop { print!("{arrow} {user_options}\n\ diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 9a7bfe5bd..c6e6f4414 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -19,6 +19,7 @@ fn fixtures() { for entry in tests { let test = entry.unwrap().path(); + let yolo = test.file_name().unwrap() == "yolo"; println!("---"); println!("Running test: {:?}", test); @@ -30,11 +31,13 @@ fn fixtures() { println!("Checking {:?} with clippy", test); - cmd!("cargo", "run", - format!("--manifest-path={}", &manifest[1..manifest.len() - 1]), - "--quiet", - "--", "--clippy") - .dir(&dir) + let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); + let cmd = if yolo { + cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy", "--yolo") + } else { + cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy") + }; + cmd.dir(&dir) .stdin(test.join("input.txt")) .stdout(dir.join("output.txt")) .run() diff --git a/tests/tests/libui-rs/yolo/diff.diff b/tests/tests/libui-rs/yolo/diff.diff new file mode 100644 index 000000000..7e1f51375 --- /dev/null +++ b/tests/tests/libui-rs/yolo/diff.diff @@ -0,0 +1,201 @@ +diff --git a/ui/src/controls.rs b/ui/src/controls.rs +index 5699276..e54973c 100644 +--- a/ui/src/controls.rs ++++ b/ui/src/controls.rs +@@ -242,7 +242,7 @@ impl Button { + let button = Button { + ui_button: button, + }; +- mem::transmute::<*mut c_void, &mut Box>(data)(&button) ++ &mut *(data as *mut Box)(&button) + } + } + } +@@ -347,7 +347,7 @@ impl Entry { + extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { + unsafe { + let entry = Entry::from_ui_control(entry); +- mem::transmute::<*mut c_void, &mut Box>(data)(&entry); ++ &mut *(data as *mut Box)(&entry); + mem::forget(entry); + } + } +@@ -370,6 +370,12 @@ impl Entry { + } + + #[inline] ++ impl Default for controls::Entry { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> Entry { + ffi_utils::ensure_initialized(); + unsafe { +@@ -412,7 +418,7 @@ impl Checkbox { + extern "C" fn c_callback(checkbox: *mut uiCheckbox, data: *mut c_void) { + unsafe { + let checkbox = Checkbox::from_ui_control(checkbox); +- mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); ++ &mut *(data as *mut Box)(&checkbox); + mem::forget(checkbox) + } + } +@@ -523,6 +529,12 @@ impl Tab { + } + + #[inline] ++ impl Default for controls::Tab { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> Tab { + ffi_utils::ensure_initialized(); + unsafe { +@@ -618,7 +630,7 @@ impl Spinbox { + extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) { + unsafe { + let spinbox = Spinbox::from_ui_control(spinbox); +- mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); ++ &mut *(data as *mut Box)(&spinbox); + mem::forget(spinbox); + } + } +@@ -645,6 +657,12 @@ impl ProgressBar { + } + + #[inline] ++ impl Default for controls::ProgressBar { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> ProgressBar { + ffi_utils::ensure_initialized(); + unsafe { +@@ -686,7 +704,7 @@ impl Slider { + extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) { + unsafe { + let slider = Slider::from_ui_control(slider); +- mem::transmute::<*mut c_void, &mut Box>(data)(&slider); ++ &mut *(data as *mut Box)(&slider); + mem::forget(slider); + } + } +@@ -755,13 +773,19 @@ impl Combobox { + extern "C" fn c_callback(combobox: *mut uiCombobox, data: *mut c_void) { + unsafe { + let combobox = Combobox::from_ui_control(combobox); +- mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); ++ &mut *(data as *mut Box)(&combobox); + mem::forget(combobox); + } + } + } + + #[inline] ++ impl Default for controls::Combobox { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> Combobox { + ffi_utils::ensure_initialized(); + unsafe { +@@ -793,6 +817,12 @@ impl RadioButtons { + } + + #[inline] ++ impl Default for controls::RadioButtons { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> RadioButtons { + ffi_utils::ensure_initialized(); + unsafe { +@@ -863,8 +893,7 @@ impl MultilineEntry { + extern "C" fn c_callback(multiline_entry: *mut uiMultilineEntry, data: *mut c_void) { + unsafe { + let multiline_entry = MultilineEntry::from_ui_control(multiline_entry); +- mem::transmute::<*mut c_void, +- &mut Box>(data)(&multiline_entry); ++ &mut *(data as *mut Box)(&multiline_entry); + mem::forget(multiline_entry); + } + } +@@ -887,6 +916,12 @@ impl MultilineEntry { + } + + #[inline] ++ impl Default for controls::MultilineEntry { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> MultilineEntry { + ffi_utils::ensure_initialized(); + unsafe { +@@ -1179,13 +1214,19 @@ impl FontButton { + extern "C" fn c_callback(ui_font_button: *mut uiFontButton, data: *mut c_void) { + unsafe { + let font_button = FontButton::from_ui_control(ui_font_button); +- mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); ++ &mut *(data as *mut Box)(&font_button); + mem::forget(font_button); + } + } + } + + #[inline] ++ impl Default for controls::FontButton { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> FontButton { + ffi_utils::ensure_initialized(); + unsafe { +@@ -1234,13 +1275,19 @@ impl ColorButton { + extern "C" fn c_callback(ui_color_button: *mut uiColorButton, data: *mut c_void) { + unsafe { + let color_button = ColorButton::from_ui_control(ui_color_button); +- mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); ++ &mut *(data as *mut Box)(&color_button); + mem::forget(color_button) + } + } + } + + #[inline] ++ impl Default for controls::ColorButton { ++ fn default() -> Self { ++ Self::new() ++ } ++ } ++ + pub fn new() -> ColorButton { + ffi_utils::ensure_initialized(); + unsafe { +diff --git a/ui/src/menus.rs b/ui/src/menus.rs +index 1255b69..9847ddc 100644 +--- a/ui/src/menus.rs ++++ b/ui/src/menus.rs +@@ -47,8 +47,7 @@ impl MenuItem { + ui_menu_item: menu_item, + }; + let window = Window::from_ui_window(window); +- mem::transmute::<*mut c_void, +- &mut Box>(data)(&menu_item, &window); ++ &mut *(data as *mut Box)(&menu_item, &window); + mem::forget(window); + } + } diff --git a/tests/tests/libui-rs/yolo/input.txt b/tests/tests/libui-rs/yolo/input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt new file mode 100644 index 000000000..1e11e223f --- /dev/null +++ b/tests/tests/libui-rs/yolo/output.txt @@ -0,0 +1,287 @@ + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) + --> src/controls.rs:245:17-245:78 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&button) + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) + --> src/controls.rs:350:17-350:77 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&entry); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::Entry` + --> src/controls.rs:373:5-373:5 +Suggestion - Replace: + +pub fn new() -> Entry { + +with: + + impl Default for controls::Entry { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Checkbox)>`) + --> src/controls.rs:415:17-415:80 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::Tab` + --> src/controls.rs:526:5-526:5 +Suggestion - Replace: + +pub fn new() -> Tab { + +with: + + impl Default for controls::Tab { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Spinbox)>`) + --> src/controls.rs:621:17-621:79 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::ProgressBar` + --> src/controls.rs:648:5-648:5 +Suggestion - Replace: + +pub fn new() -> ProgressBar { + +with: + + impl Default for controls::ProgressBar { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Slider)>`) + --> src/controls.rs:689:17-689:78 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&slider); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Combobox)>`) + --> src/controls.rs:758:17-758:80 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::Combobox` + --> src/controls.rs:765:5-765:5 +Suggestion - Replace: + +pub fn new() -> Combobox { + +with: + + impl Default for controls::Combobox { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::RadioButtons` + --> src/controls.rs:796:5-796:5 +Suggestion - Replace: + +pub fn new() -> RadioButtons { + +with: + + impl Default for controls::RadioButtons { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::MultilineEntry)>`) + --> src/controls.rs:866:17-867:73 +Suggestion - Replace: + + mem::transmute::<*mut c_void, + &mut Box>(data)(&multiline_entry); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::MultilineEntry` + --> src/controls.rs:890:5-890:5 +Suggestion - Replace: + +pub fn new() -> MultilineEntry { + +with: + + impl Default for controls::MultilineEntry { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::FontButton)>`) + --> src/controls.rs:1182:17-1182:82 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::FontButton` + --> src/controls.rs:1189:5-1189:5 +Suggestion - Replace: + +pub fn new() -> FontButton { + +with: + + impl Default for controls::FontButton { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::ColorButton)>`) + --> src/controls.rs:1237:17-1237:83 +Suggestion - Replace: + +mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) + + +Info: you should consider adding a `Default` implementation for `controls::ColorButton` + --> src/controls.rs:1244:5-1244:5 +Suggestion - Replace: + +pub fn new() -> ColorButton { + +with: + + impl Default for controls::ColorButton { + fn default() -> Self { + Self::new() + } + } + + + +automatically applying suggestion (--yolo) + + +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>`) + --> src/menus.rs:50:17-51:76 +Suggestion - Replace: + + mem::transmute::<*mut c_void, + &mut Box>(data)(&menu_item, &window); + +with: + + &mut *(data as *mut Box) + +automatically applying suggestion (--yolo) +Good work. Let me just apply these 18 changes! +.................. +Done. From f733f20173a83609c9ecba03100e2ecd32c0659d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 May 2017 14:33:57 +0200 Subject: [PATCH 057/298] Also build rustfix on stable on travis, but only run tests on nightly since they need clippy --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e4a79d4a..a9b3a72d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: rust rust: - nightly +- stable script: - cargo build -- cargo test -- --nocapture +- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi From 151c55ac3030b97d96d07abb201f341fbe865bfa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 May 2017 10:50:10 +0200 Subject: [PATCH 058/298] Remove a hack from the fixture tests --- tests/crates/libui-rs.sub-path | 1 + tests/fixtures.rs | 38 ++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 tests/crates/libui-rs.sub-path diff --git a/tests/crates/libui-rs.sub-path b/tests/crates/libui-rs.sub-path new file mode 100644 index 000000000..2c850c209 --- /dev/null +++ b/tests/crates/libui-rs.sub-path @@ -0,0 +1 @@ +ui diff --git a/tests/fixtures.rs b/tests/fixtures.rs index c6e6f4414..29a29bf99 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -11,10 +11,24 @@ fn fixtures() { for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { let fixture = fixture.unwrap(); + if !fixture.file_type().unwrap().is_dir() { + continue; + } let fixture_path = fixture.path(); - // FIXME: don't expect the crate to be in the `ui` subdir - let dir = fixture_path.join("ui"); + let file = std::fs::File::open(fixture_path.with_extension("sub-path")) + .and_then(|mut file| { + use std::io::Read; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) + }); + let dir = if let Ok(path) = file { + fixture_path.join(path.trim()) + } else { + fixture_path.clone() + }; + println!("Running tests for {:?}", dir); let tests = std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap(); for entry in tests { @@ -26,6 +40,8 @@ fn fixtures() { assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); + // we only want to rustfix the final project, not any dependencies + assert!(cmd!("cargo", "build").dir(&dir).run().unwrap().status.success()); let manifest = format!("{:?}", root_dir.join("Cargo.toml")); @@ -50,12 +66,22 @@ fn fixtures() { } else { cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); - if !cmd!("diff", "-q", dir.join("diff.diff"), test.join("diff.diff")).dir(&dir).unchecked().run().unwrap().status.success() { - panic!("Unexpected changes applied by rustfix"); + let diff = cmd!("diff", dir.join("diff.diff"), test.join("diff.diff")) + .dir(&dir) + .stdout_capture() + .unchecked() + .run().unwrap(); + if !diff.status.success() { + panic!("Unexpected changes by rustfix:\n{}", std::str::from_utf8(&diff.stdout).unwrap()); } - if !cmd!("diff", "-q", dir.join("output.txt"), test.join("output.txt")).dir(&dir).unchecked().run().unwrap().status.success() { - panic!("Unexpected output by rustfix"); + let output = cmd!("diff", dir.join("output.txt"), test.join("output.txt")) + .dir(&dir) + .stdout_capture() + .unchecked() + .run().unwrap(); + if !output.status.success() { + panic!("Unexpected output by rustfix:\n{}", std::str::from_utf8(&output.stdout).unwrap()); } } From ccfc4fb5d46071c006ab7419b58dc0363e305470 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 May 2017 11:08:05 +0200 Subject: [PATCH 059/298] Allow multiple sub-paths to be specified for each test fixture --- tests/fixtures.rs | 114 +++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 29a29bf99..773b7601d 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -1,13 +1,15 @@ #[macro_use] extern crate duct; +use std::io::{BufReader, BufRead}; + #[test] fn fixtures() { // ignore if this fails let _ = cmd!("cargo", "install", "clippy").stderr_capture().run(); let root_dir = std::env::current_dir().unwrap(); - println!("looking for fixtures in directory: {:?}", root_dir); + println!("looking for fixtures in directory: {:?}\n", root_dir); for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { let fixture = fixture.unwrap(); @@ -16,77 +18,73 @@ fn fixtures() { } let fixture_path = fixture.path(); - let file = std::fs::File::open(fixture_path.with_extension("sub-path")) - .and_then(|mut file| { - use std::io::Read; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - Ok(contents) - }); - let dir = if let Ok(path) = file { - fixture_path.join(path.trim()) + let files: Vec = std::fs::File::open(fixture_path.with_extension("sub-path")) + .and_then(|file| BufReader::new(file).lines().collect()).unwrap_or_default(); + let dirs = if files.is_empty() { + vec![fixture_path.clone()] } else { - fixture_path.clone() + files.into_iter().map(|file| fixture_path.join(file.trim())).collect() }; - println!("Running tests for {:?}", dir); - let tests = std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap(); + for dir in dirs { + println!("===================================================================="); + println!("Running tests for {:?}\n", dir); + let tests = std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap(); - for entry in tests { - let test = entry.unwrap().path(); - let yolo = test.file_name().unwrap() == "yolo"; + for entry in tests { + let test = entry.unwrap().path(); + let yolo = test.file_name().unwrap() == "yolo"; - println!("---"); - println!("Running test: {:?}", test); + println!("Running test: {}", test.file_name().unwrap().to_str().unwrap()); - assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); - assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); - // we only want to rustfix the final project, not any dependencies - assert!(cmd!("cargo", "build").dir(&dir).run().unwrap().status.success()); + assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); + assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); + // we only want to rustfix the final project, not any dependencies + assert!(cmd!("cargo", "build").dir(&dir).run().unwrap().status.success()); - let manifest = format!("{:?}", root_dir.join("Cargo.toml")); + let manifest = format!("{:?}", root_dir.join("Cargo.toml")); - println!("Checking {:?} with clippy", test); + println!("Running cargo clippy to obtain suggestions"); - let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); - let cmd = if yolo { - cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy", "--yolo") - } else { - cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy") - }; - cmd.dir(&dir) - .stdin(test.join("input.txt")) - .stdout(dir.join("output.txt")) - .run() - .unwrap(); + let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); + let cmd = if yolo { + cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy", "--yolo") + } else { + cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy") + }; + cmd.dir(&dir) + .stdin(test.join("input.txt")) + .stdout(dir.join("output.txt")) + .run() + .unwrap(); - if std::env::var("APPLY_RUSTFIX").is_ok() { - std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); + if std::env::var("APPLY_RUSTFIX").is_ok() { + std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); - cmd!("git", "diff").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); - } else { - cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); + cmd!("git", "diff").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); + } else { + cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); - let diff = cmd!("diff", dir.join("diff.diff"), test.join("diff.diff")) - .dir(&dir) - .stdout_capture() - .unchecked() - .run().unwrap(); - if !diff.status.success() { - panic!("Unexpected changes by rustfix:\n{}", std::str::from_utf8(&diff.stdout).unwrap()); + let diff = cmd!("diff", dir.join("diff.diff"), test.join("diff.diff")) + .dir(&dir) + .stdout_capture() + .unchecked() + .run().unwrap(); + if !diff.status.success() { + panic!("Unexpected changes by rustfix:\n{}", std::str::from_utf8(&diff.stdout).unwrap()); + } + + let output = cmd!("diff", dir.join("output.txt"), test.join("output.txt")) + .dir(&dir) + .stdout_capture() + .unchecked() + .run().unwrap(); + if !output.status.success() { + panic!("Unexpected output by rustfix:\n{}", std::str::from_utf8(&output.stdout).unwrap()); + } } - let output = cmd!("diff", dir.join("output.txt"), test.join("output.txt")) - .dir(&dir) - .stdout_capture() - .unchecked() - .run().unwrap(); - if !output.status.success() { - panic!("Unexpected output by rustfix:\n{}", std::str::from_utf8(&output.stdout).unwrap()); - } + println!("Success!\n"); } - - println!("---"); - println!("Success!"); } } } From 1261fb0433f9bdb58b970181ad5caec7fefcdf0c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 23 Oct 2017 15:42:27 +0200 Subject: [PATCH 060/298] Fix tests and instructions --- Readme.md | 9 ++------- tests/tests/libui-rs/yolo/output.txt | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Readme.md b/Readme.md index 8f58f9ca0..faf18237b 100644 --- a/Readme.md +++ b/Readme.md @@ -62,18 +62,13 @@ My current example output for diagnostics is based on [libui-rs](https://github. Run `rustfix`: ```sh -$ cd tests/fixtures/libui-rs/ -$ cargo run -- --from-file clippy.json +$ cargo test ``` ### Generate the example diagnostics JSON yourself ```sh -$ git clone https://github.com/pcwalton/libui-rs.git -# HEAD is at 13299d28f69f8009be8e08e453a9b0024f153a60 -$ cd libui-rs/ui/ -$ cargo clippy -- -Z unstable-options --error-format json 2&> clippy.json -# Manually remove the first line ("Compiling....") +$ APPLY_RUSTFIX=1 cargo test ``` ## Gotchas diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index 1e11e223f..1768b71ba 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -270,7 +270,7 @@ automatically applying suggestion (--yolo) automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'r windows::Window)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`)  --> src/menus.rs:50:17-51:76 Suggestion - Replace: From 09f665e4efd0528a558444abfbb9cef132fdac56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 23 Oct 2017 16:25:33 +0200 Subject: [PATCH 061/298] Add `cargo-fix` executable --- src/bin/cargo-fix.rs | 4 ++++ tests/fixtures.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 src/bin/cargo-fix.rs diff --git a/src/bin/cargo-fix.rs b/src/bin/cargo-fix.rs new file mode 100644 index 000000000..cb72250cf --- /dev/null +++ b/src/bin/cargo-fix.rs @@ -0,0 +1,4 @@ +// horrible hack to get cargo to not complain about both +// the `cargo-fix` and `rustfix` targets to point to the +// same source file +include!{"../main.rs"} diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 773b7601d..753a7c39c 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -47,9 +47,9 @@ fn fixtures() { let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); let cmd = if yolo { - cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy", "--yolo") + cmd!("cargo", "run", manifest, "--bin", "rustfix", "--quiet", "--", "--clippy", "--yolo") } else { - cmd!("cargo", "run", manifest, "--quiet", "--", "--clippy") + cmd!("cargo", "run", manifest, "--bin", "rustfix", "--quiet", "--", "--clippy") }; cmd.dir(&dir) .stdin(test.join("input.txt")) From e4a2312bb294be919dde40656aa6e9354d0c0f81 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 23 Oct 2017 17:06:40 +0200 Subject: [PATCH 062/298] (); > {} --- src/bin/cargo-fix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-fix.rs b/src/bin/cargo-fix.rs index cb72250cf..e8ecda891 100644 --- a/src/bin/cargo-fix.rs +++ b/src/bin/cargo-fix.rs @@ -1,4 +1,4 @@ // horrible hack to get cargo to not complain about both // the `cargo-fix` and `rustfix` targets to point to the // same source file -include!{"../main.rs"} +include!("../main.rs"); From 42c6ab57e6901284eb93b5bb02608b5991bdf910 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 11:06:18 +0200 Subject: [PATCH 063/298] Get rid of annoying doc warnings --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 73d5b49fa..e854e4637 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ exclude = [ [dependencies] clap = "2.9.2" colored = "1.2.0" -quick-error = "1.1.0" +quick-error = "1.2.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" From d509f5f82990d0cfb091fc00382f3a8b07edc6d8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 11:37:33 +0200 Subject: [PATCH 064/298] Allow choosing a specific replacement if multiple apply --- src/lib.rs | 138 +- src/main.rs | 108 +- tests/crates/use_test/Cargo.toml | 6 + tests/crates/use_test/output.txt | 1452 ++++++++++++++++++++++ tests/crates/use_test/src/lib.rs | 3 + tests/fixtures.rs | 7 +- tests/tests/libui-rs/simple/input.txt | 4 +- tests/tests/libui-rs/simple/output.txt | 20 +- tests/tests/libui-rs/skipping/input.txt | 2 +- tests/tests/libui-rs/skipping/output.txt | 20 +- tests/tests/libui-rs/yolo/output.txt | 88 +- tests/tests/use_test/first/diff.diff | 11 + tests/tests/use_test/first/input.txt | 1 + tests/tests/use_test/first/output.txt | 1452 ++++++++++++++++++++++ tests/tests/use_test/second/diff.diff | 11 + tests/tests/use_test/second/input.txt | 1 + tests/tests/use_test/second/output.txt | 1452 ++++++++++++++++++++++ 17 files changed, 4652 insertions(+), 124 deletions(-) create mode 100644 tests/crates/use_test/Cargo.toml create mode 100644 tests/crates/use_test/output.txt create mode 100644 tests/crates/use_test/src/lib.rs create mode 100644 tests/tests/use_test/first/diff.diff create mode 100644 tests/tests/use_test/first/input.txt create mode 100644 tests/tests/use_test/first/output.txt create mode 100644 tests/tests/use_test/second/diff.diff create mode 100644 tests/tests/use_test/second/input.txt create mode 100644 tests/tests/use_test/second/output.txt diff --git a/src/lib.rs b/src/lib.rs index 616bbdb28..772723b40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,74 +32,98 @@ impl std::fmt::Display for LineRange { #[derive(Debug, Clone, Hash, PartialEq)] pub struct Suggestion { pub message: String, + pub snippets: Vec, + pub replacements: Vec, +} + +#[derive(Debug, Clone, Hash, PartialEq)] +pub struct Snippet { + pub sub_message: Option, pub file_name: String, pub line_range: LineRange, /// leading surrounding text, text to replace, trailing surrounding text /// /// This split is useful for higlighting the part that gets replaced pub text: (String, String, String), +} + +#[derive(Debug, Clone, Hash, PartialEq)] +pub struct Replacement { + pub snippet: Snippet, pub replacement: String, } -fn collect_span(message: &str, span: &DiagnosticSpan) -> Option { - if let Some(replacement) = span.suggested_replacement.clone() { - // unindent the snippet - let indent = span.text.iter().map(|line| { - let indent = line.text - .chars() - .take_while(|&c| char::is_whitespace(c)) - .count(); - std::cmp::min(indent, line.highlight_start) - }).min().expect("text to replace is empty"); - let start = span.text[0].highlight_start - 1; - let end = span.text[0].highlight_end - 1; - let lead = span.text[0].text[indent..start].to_string(); - let mut body = span.text[0].text[start..end].to_string(); - for line in span.text.iter().take(span.text.len() - 1).skip(1) { - body.push('\n'); - body.push_str(&line.text[indent..]); - } - let mut tail = String::new(); - let last = &span.text[span.text.len() - 1]; - if span.text.len() > 1 { - body.push('\n'); - body.push_str(&last.text[indent..last.highlight_end - 1]); - } - tail.push_str(&last.text[last.highlight_end - 1..]); - Some(Suggestion { - message: message.into(), - file_name: span.file_name.clone(), - line_range: LineRange { - start: LinePosition { - line: span.line_start, - column: span.column_start, - }, - end: LinePosition { - line: span.line_end, - column: span.column_end, - }, +fn parse_snippet(message: Option, span: &DiagnosticSpan) -> Snippet { + // unindent the snippet + let indent = span.text.iter().map(|line| { + let indent = line.text + .chars() + .take_while(|&c| char::is_whitespace(c)) + .count(); + std::cmp::min(indent, line.highlight_start) + }).min().expect("text to replace is empty"); + let start = span.text[0].highlight_start - 1; + let end = span.text[0].highlight_end - 1; + let lead = span.text[0].text[indent..start].to_string(); + let mut body = span.text[0].text[start..end].to_string(); + for line in span.text.iter().take(span.text.len() - 1).skip(1) { + body.push('\n'); + body.push_str(&line.text[indent..]); + } + let mut tail = String::new(); + let last = &span.text[span.text.len() - 1]; + if span.text.len() > 1 { + body.push('\n'); + body.push_str(&last.text[indent..last.highlight_end - 1]); + } + tail.push_str(&last.text[last.highlight_end - 1..]); + Snippet { + sub_message: message, + file_name: span.file_name.clone(), + line_range: LineRange { + start: LinePosition { + line: span.line_start, + column: span.column_start, }, - text: (lead, body, tail), - replacement: replacement, - }) - } else { - None + end: LinePosition { + line: span.line_end, + column: span.column_end, + }, + }, + text: (lead, body, tail), } } -pub fn collect_suggestions(diagnostic: &Diagnostic, - parent_message: Option) - -> Vec { - let message = parent_message.unwrap_or(diagnostic.message.clone()); - let mut suggestions = vec![]; - - suggestions.extend(diagnostic.spans - .iter() - .flat_map(|span| collect_span(&message, span))); - - suggestions.extend(diagnostic.children - .iter() - .flat_map(|children| collect_suggestions(children, Some(message.clone())))); - - suggestions +fn collect_span(message: Option, span: &DiagnosticSpan) -> Option { + span.suggested_replacement.clone().map(|replacement| Replacement { + snippet: parse_snippet(message, span), + replacement, + }) +} + +pub fn collect_suggestions(diagnostic: &Diagnostic) -> Option { + let mut replacements = vec![]; + + let snippets = diagnostic.spans + .iter() + .map(|span| parse_snippet(None, span)) + .collect(); + + for child in &diagnostic.children { + for span in &child.spans { + if let Some(sugg) = collect_span(Some(child.message.clone()), span) { + replacements.push(sugg); + } + } + } + + if replacements.is_empty() { + None + } else { + Some(Suggestion { + message: diagnostic.message.clone(), + snippets, + replacements, + }) + } } diff --git a/src/main.rs b/src/main.rs index f973ed55c..fa71f335d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,11 +17,13 @@ use std::process::Command; use colored::Colorize; use clap::{Arg, App}; -use rustfix::Suggestion; +use std::str::FromStr; + +use rustfix::{Suggestion, Replacement}; use rustfix::diagnostics::Diagnostic; const USER_OPTIONS: &'static str = "What do you want to do? \ - [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; + [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)"; fn main() { let program = try_main(); @@ -59,7 +61,7 @@ fn try_main() -> Result<(), ProgramError> { .get_matches(); let mut extra_args = Vec::new(); - + if !matches.is_present("clippy") { extra_args.push("-Aclippy"); } @@ -78,10 +80,10 @@ fn try_main() -> Result<(), ProgramError> { // Convert JSON string (and eat parsing errors) .flat_map(|line| serde_json::from_str::(line)) // One diagnostic line might have multiple suggestions - .flat_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, None)) + .filter_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message)) .collect(); - try!(handle_suggestions(&suggestions, mode)); + try!(handle_suggestions(suggestions, mode)); Ok(()) } @@ -113,8 +115,11 @@ enum AutofixMode { Yolo, } -fn handle_suggestions(suggestions: &[Suggestion], mode: AutofixMode) -> Result<(), ProgramError> { - let mut accepted_suggestions: Vec<&Suggestion> = vec![]; +fn handle_suggestions( + suggestions: Vec, + mode: AutofixMode, +) -> Result<(), ProgramError> { + let mut accepted_suggestions: Vec = vec![]; if suggestions.is_empty() { println!("I don't have any suggestions for you right now. Check back later!"); @@ -122,26 +127,37 @@ fn handle_suggestions(suggestions: &[Suggestion], mode: AutofixMode) -> Result<( } 'suggestions: for suggestion in suggestions { - println!("\n\n{info}: {message}\n\ - {arrow} {file}:{range}\n\ - {suggestion}\n\n\ - {lead}{text}{tail}\n\n\ - {with}\n\n\ - {replacement}\n", + println!("\n\n{info}: {message}\n", info = "Info".green().bold(), - message = split_at_lint_name(&suggestion.message), - arrow = " -->".blue().bold(), - suggestion = "Suggestion - Replace:".yellow().bold(), - file = suggestion.file_name, - range = suggestion.line_range, - lead = indent(4, &suggestion.text.0), - text = suggestion.text.1.red(), - tail = suggestion.text.2, - with = "with:".yellow().bold(), - replacement = indent(4, &suggestion.replacement)); - - if mode == AutofixMode::Yolo { - accepted_suggestions.push(suggestion); + message = split_at_lint_name(&suggestion.message)); + for snippet in suggestion.snippets { + println!("{arrow} {file}:{range}\n", + arrow = " -->".blue().bold(), + file = snippet.file_name, + range = snippet.line_range); + } + + for (i, suggestion) in suggestion.replacements.iter().enumerate() { + let snippet = &suggestion.snippet; + println!("[{id}]: {msg}\n\ + {suggestion}\n\n\ + {lead}{text}{tail}\n\n\ + {with}\n\n\ + {replacement}\n", + id = i, + msg = snippet.sub_message.as_ref().map(|s| &**s).unwrap_or(""), + suggestion = "Suggestion - Replace:".yellow().bold(), + lead = indent(4, &snippet.text.0), + text = snippet.text.1.red(), + tail = snippet.text.2, + with = "with:".yellow().bold(), + replacement = indent(4, &suggestion.replacement)); + } + println!(); + + if mode == AutofixMode::Yolo && suggestion.replacements.len() == 1 { + let mut replacements = suggestion.replacements; + accepted_suggestions.push(replacements.remove(0)); println!("automatically applying suggestion (--yolo)"); continue 'suggestions; } @@ -162,11 +178,6 @@ fn handle_suggestions(suggestions: &[Suggestion], mode: AutofixMode) -> Result<( println!("Skipped."); continue 'suggestions; } - "r" => { - accepted_suggestions.push(suggestion); - println!("Suggestion accepted. I'll remember that and apply it later."); - continue 'suggestions; - } "q" => { println!("Thanks for playing!"); break 'suggestions; @@ -174,11 +185,18 @@ fn handle_suggestions(suggestions: &[Suggestion], mode: AutofixMode) -> Result<( "a" => { return Err(ProgramError::UserAbort); } - _ => { - println!("{error}: I didn't quite get that. {user_options}", - error = "Error".red().bold(), - user_options = USER_OPTIONS); - continue 'userinput; + s => { + if let Ok(i) = usize::from_str(s) { + let mut replacements = suggestion.replacements; + accepted_suggestions.push(replacements.remove(i)); + println!("Suggestion accepted. I'll remember that and apply it later."); + continue 'suggestions; + } else { + println!("{error}: I didn't quite get that. {user_options}", + error = "Error".red().bold(), + user_options = USER_OPTIONS); + continue 'userinput; + } } } } @@ -274,25 +292,25 @@ fn indent(size: u32, s: &str) -> String { /// /// This function is as stupid as possible. Make sure you call for the replacemnts in one file in /// reverse order to not mess up the lines for replacements further down the road. -fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { +fn apply_suggestion(suggestion: &Replacement) -> Result<(), ProgramError> { use std::cmp::max; - let file_content = try!(read_file_to_string(&suggestion.file_name)); + let file_content = try!(read_file_to_string(&suggestion.snippet.file_name)); let mut new_content = String::new(); // Add the lines before the section we want to replace new_content.push_str(&file_content.lines() - .take(max(suggestion.line_range.start.line - 1, 0) as usize) + .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) .collect::>() .join("\n")); new_content.push_str("\n"); // Parts of line before replacement new_content.push_str(&file_content.lines() - .nth(suggestion.line_range.start.line - 1) + .nth(suggestion.snippet.line_range.start.line - 1) .unwrap_or("") .chars() - .take(suggestion.line_range.start.column - 1) + .take(suggestion.snippet.line_range.start.column - 1) .collect::()); // Insert new content! Finally! @@ -300,21 +318,21 @@ fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> { // Parts of line after replacement new_content.push_str(&file_content.lines() - .nth(suggestion.line_range.end.line - 1) + .nth(suggestion.snippet.line_range.end.line - 1) .unwrap_or("") .chars() - .skip(suggestion.line_range.end.column - 1) + .skip(suggestion.snippet.line_range.end.column - 1) .collect::()); // Add the lines after the section we want to replace new_content.push_str("\n"); new_content.push_str(&file_content.lines() - .skip(suggestion.line_range.end.line as usize) + .skip(suggestion.snippet.line_range.end.line as usize) .collect::>() .join("\n")); new_content.push_str("\n"); - let mut file = try!(File::create(&suggestion.file_name)); + let mut file = try!(File::create(&suggestion.snippet.file_name)); let new_content = new_content.as_bytes(); try!(file.set_len(new_content.len() as u64)); diff --git a/tests/crates/use_test/Cargo.toml b/tests/crates/use_test/Cargo.toml new file mode 100644 index 000000000..b508f265d --- /dev/null +++ b/tests/crates/use_test/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "use_test" +version = "0.1.0" +authors = ["Oliver Schneider "] + +[dependencies] diff --git a/tests/crates/use_test/output.txt b/tests/crates/use_test/output.txt new file mode 100644 index 000000000..d32d44ece --- /dev/null +++ b/tests/crates/use_test/output.txt @@ -0,0 +1,1452 @@ + + +Info: cannot find type `Iter` in this scope + + --> src/lib.rs:2:12-2:16 + +[0]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[1]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[2]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[3]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[4]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[5]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[6]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[7]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[8]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[9]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[10]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[11]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[12]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[13]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[14]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[15]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[16]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[17]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[18]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[19]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[20]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[21]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[22]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[23]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[24]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[25]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[26]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[27]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[28]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[29]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[30]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[31]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[32]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[33]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[34]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[35]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[36]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[37]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[38]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[39]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[40]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[41]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[42]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[43]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[44]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[45]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[46]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[47]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[48]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[49]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[50]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[51]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[52]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[53]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[54]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[55]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[56]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[57]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[58]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[59]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[60]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[61]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[62]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[63]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[64]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[65]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[66]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[67]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[68]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[69]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[70]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[71]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[72]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[73]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[74]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[75]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[76]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[77]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[78]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[79]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[80]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[81]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[82]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[83]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[84]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[85]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[86]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[87]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[88]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[89]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[90]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[91]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[92]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[93]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[94]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[95]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[96]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[97]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[98]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[99]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[100]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[101]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[102]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[103]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[104]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[105]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[106]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[107]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[108]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[109]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[110]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[111]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[112]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[113]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[114]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[115]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[116]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[117]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[118]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[119]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[120]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[121]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[122]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[123]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[124]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[125]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[126]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[127]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[128]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[129]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[130]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[131]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[132]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[133]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[134]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[135]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[136]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[137]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[138]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[139]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[140]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[141]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[142]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[143]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. +Good work. Let me just apply these 1 changes! +. +Done. diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs new file mode 100644 index 000000000..647f90fd6 --- /dev/null +++ b/tests/crates/use_test/src/lib.rs @@ -0,0 +1,3 @@ +pub fn foo() { + let x: Iter; +} diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 753a7c39c..3f8f719c5 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -39,7 +39,8 @@ fn fixtures() { assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); // we only want to rustfix the final project, not any dependencies - assert!(cmd!("cargo", "build").dir(&dir).run().unwrap().status.success()); + // we don't care if the final build succeeds, since we're also testing error suggestions + let _ = cmd!("cargo", "build").dir(&dir).stderr_null().stdout_null().run(); let manifest = format!("{:?}", root_dir.join("Cargo.toml")); @@ -60,9 +61,9 @@ fn fixtures() { if std::env::var("APPLY_RUSTFIX").is_ok() { std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); - cmd!("git", "diff").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); + cmd!("git", "diff", ".").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); } else { - cmd!("git", "diff").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); + cmd!("git", "diff", ".").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); let diff = cmd!("diff", dir.join("diff.diff"), test.join("diff.diff")) .dir(&dir) diff --git a/tests/tests/libui-rs/simple/input.txt b/tests/tests/libui-rs/simple/input.txt index ced652ef7..a7edde121 100644 --- a/tests/tests/libui-rs/simple/input.txt +++ b/tests/tests/libui-rs/simple/input.txt @@ -1,3 +1,3 @@ -r -r +0 +0 q diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index e0eff993d..22820c803 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -1,7 +1,10 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +  --> src/controls.rs:245:17-245:78 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -10,12 +13,16 @@ &mut *(data as *mut Box) -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +  --> src/controls.rs:350:17-350:77 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -24,12 +31,16 @@ &mut *(data as *mut Box) -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-373:5 + + --> src/controls.rs:373:5-378:6 + +[0]: try this Suggestion - Replace: pub fn new() -> Entry { @@ -44,7 +55,8 @@ -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 2 changes! .. diff --git a/tests/tests/libui-rs/skipping/input.txt b/tests/tests/libui-rs/skipping/input.txt index 0bfd421ef..d999fa2ff 100644 --- a/tests/tests/libui-rs/skipping/input.txt +++ b/tests/tests/libui-rs/skipping/input.txt @@ -1,3 +1,3 @@ -r +0 s q diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index ad8a07fd7..209bf3cd2 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -1,7 +1,10 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +  --> src/controls.rs:245:17-245:78 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -10,12 +13,16 @@ &mut *(data as *mut Box) -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +  --> src/controls.rs:350:17-350:77 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -24,12 +31,16 @@ &mut *(data as *mut Box) -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Skipped. Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-373:5 + + --> src/controls.rs:373:5-378:6 + +[0]: try this Suggestion - Replace: pub fn new() -> Entry { @@ -44,7 +55,8 @@ -==> What do you want to do? [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 1 changes! . diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index 1768b71ba..c57486a5b 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -1,7 +1,10 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +  --> src/controls.rs:245:17-245:78 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -10,11 +13,15 @@ &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +  --> src/controls.rs:350:17-350:77 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -23,11 +30,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-373:5 + + --> src/controls.rs:373:5-378:6 + +[0]: try this Suggestion - Replace: pub fn new() -> Entry { @@ -42,11 +53,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Checkbox)>`) +  --> src/controls.rs:415:17-415:80 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); @@ -55,11 +70,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Tab` - --> src/controls.rs:526:5-526:5 + + --> src/controls.rs:526:5-531:6 + +[0]: try this Suggestion - Replace: pub fn new() -> Tab { @@ -74,11 +93,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Spinbox)>`) +  --> src/controls.rs:621:17-621:79 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); @@ -87,11 +110,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ProgressBar` - --> src/controls.rs:648:5-648:5 + + --> src/controls.rs:648:5-653:6 + +[0]: try this Suggestion - Replace: pub fn new() -> ProgressBar { @@ -106,11 +133,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Slider)>`) +  --> src/controls.rs:689:17-689:78 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&slider); @@ -119,11 +150,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Combobox)>`) +  --> src/controls.rs:758:17-758:80 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); @@ -132,11 +167,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Combobox` - --> src/controls.rs:765:5-765:5 + + --> src/controls.rs:765:5-770:6 + +[0]: try this Suggestion - Replace: pub fn new() -> Combobox { @@ -151,11 +190,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::RadioButtons` - --> src/controls.rs:796:5-796:5 + + --> src/controls.rs:796:5-801:6 + +[0]: try this Suggestion - Replace: pub fn new() -> RadioButtons { @@ -170,11 +213,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::MultilineEntry)>`) +  --> src/controls.rs:866:17-867:73 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, @@ -184,11 +231,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::MultilineEntry` - --> src/controls.rs:890:5-890:5 + + --> src/controls.rs:890:5-895:6 + +[0]: try this Suggestion - Replace: pub fn new() -> MultilineEntry { @@ -203,11 +254,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::FontButton)>`) +  --> src/controls.rs:1182:17-1182:82 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); @@ -216,11 +271,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::FontButton` - --> src/controls.rs:1189:5-1189:5 + + --> src/controls.rs:1189:5-1194:6 + +[0]: try this Suggestion - Replace: pub fn new() -> FontButton { @@ -235,11 +294,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::ColorButton)>`) +  --> src/controls.rs:1237:17-1237:83 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); @@ -248,11 +311,15 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ColorButton` - --> src/controls.rs:1244:5-1244:5 + + --> src/controls.rs:1244:5-1249:6 + +[0]: try this Suggestion - Replace: pub fn new() -> ColorButton { @@ -267,11 +334,15 @@ automatically applying suggestion (--yolo) + automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`) +  --> src/menus.rs:50:17-51:76 + +[0]: try Suggestion - Replace: mem::transmute::<*mut c_void, @@ -281,6 +352,7 @@ automatically applying suggestion (--yolo) &mut *(data as *mut Box) + automatically applying suggestion (--yolo) Good work. Let me just apply these 18 changes! .................. diff --git a/tests/tests/use_test/first/diff.diff b/tests/tests/use_test/first/diff.diff new file mode 100644 index 000000000..0374b940a --- /dev/null +++ b/tests/tests/use_test/first/diff.diff @@ -0,0 +1,11 @@ +diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs +index 647f90f..ee66c16 100644 +--- a/tests/crates/use_test/src/lib.rs ++++ b/tests/crates/use_test/src/lib.rs +@@ -1,3 +1,6 @@ ++ ++use std::collections::binary_heap::Iter; ++ + pub fn foo() { + let x: Iter; + } diff --git a/tests/tests/use_test/first/input.txt b/tests/tests/use_test/first/input.txt new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/tests/use_test/first/input.txt @@ -0,0 +1 @@ +0 diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt new file mode 100644 index 000000000..d32d44ece --- /dev/null +++ b/tests/tests/use_test/first/output.txt @@ -0,0 +1,1452 @@ + + +Info: cannot find type `Iter` in this scope + + --> src/lib.rs:2:12-2:16 + +[0]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[1]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[2]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[3]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[4]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[5]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[6]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[7]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[8]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[9]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[10]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[11]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[12]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[13]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[14]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[15]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[16]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[17]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[18]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[19]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[20]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[21]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[22]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[23]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[24]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[25]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[26]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[27]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[28]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[29]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[30]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[31]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[32]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[33]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[34]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[35]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[36]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[37]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[38]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[39]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[40]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[41]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[42]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[43]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[44]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[45]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[46]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[47]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[48]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[49]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[50]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[51]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[52]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[53]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[54]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[55]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[56]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[57]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[58]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[59]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[60]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[61]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[62]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[63]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[64]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[65]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[66]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[67]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[68]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[69]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[70]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[71]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[72]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[73]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[74]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[75]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[76]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[77]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[78]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[79]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[80]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[81]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[82]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[83]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[84]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[85]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[86]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[87]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[88]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[89]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[90]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[91]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[92]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[93]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[94]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[95]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[96]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[97]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[98]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[99]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[100]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[101]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[102]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[103]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[104]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[105]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[106]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[107]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[108]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[109]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[110]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[111]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[112]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[113]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[114]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[115]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[116]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[117]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[118]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[119]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[120]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[121]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[122]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[123]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[124]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[125]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[126]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[127]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[128]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[129]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[130]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[131]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[132]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[133]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[134]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[135]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[136]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[137]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[138]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[139]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[140]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[141]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[142]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[143]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. +Good work. Let me just apply these 1 changes! +. +Done. diff --git a/tests/tests/use_test/second/diff.diff b/tests/tests/use_test/second/diff.diff new file mode 100644 index 000000000..f88a4d135 --- /dev/null +++ b/tests/tests/use_test/second/diff.diff @@ -0,0 +1,11 @@ +diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs +index 647f90f..2353e22 100644 +--- a/tests/crates/use_test/src/lib.rs ++++ b/tests/crates/use_test/src/lib.rs +@@ -1,3 +1,6 @@ ++ ++use std::collections::btree_map::Iter; ++ + pub fn foo() { + let x: Iter; + } diff --git a/tests/tests/use_test/second/input.txt b/tests/tests/use_test/second/input.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/tests/use_test/second/input.txt @@ -0,0 +1 @@ +1 diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt new file mode 100644 index 000000000..d32d44ece --- /dev/null +++ b/tests/tests/use_test/second/output.txt @@ -0,0 +1,1452 @@ + + +Info: cannot find type `Iter` in this scope + + --> src/lib.rs:2:12-2:16 + +[0]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[1]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[2]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[3]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[4]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[5]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[6]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[7]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[8]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[9]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[10]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[11]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[12]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[13]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[14]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[15]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[16]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[17]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[18]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[19]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[20]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[21]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[22]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[23]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[24]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[25]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[26]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[27]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[28]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[29]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[30]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[31]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[32]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[33]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[34]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[35]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[36]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[37]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[38]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[39]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[40]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[41]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[42]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[43]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[44]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[45]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[46]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[47]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[48]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[49]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[50]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[51]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[52]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[53]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[54]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[55]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[56]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[57]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[58]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[59]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[60]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[61]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[62]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[63]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[64]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[65]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[66]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[67]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[68]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[69]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[70]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[71]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[72]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[73]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[74]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[75]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[76]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[77]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[78]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[79]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[80]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[81]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[82]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[83]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[84]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[85]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[86]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[87]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[88]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[89]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[90]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[91]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[92]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[93]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[94]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[95]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[96]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[97]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[98]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[99]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[100]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[101]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[102]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[103]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[104]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[105]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[106]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[107]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[108]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[109]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[110]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[111]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[112]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[113]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[114]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[115]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[116]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[117]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[118]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[119]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[120]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[121]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[122]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[123]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[124]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[125]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[126]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[127]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[128]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[129]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[130]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[131]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + +[132]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[133]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[134]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[135]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[136]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[137]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[138]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[139]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[140]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[141]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[142]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[143]: possible candidates are found in other modules, you can import them into scope +Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) + > Suggestion accepted. I'll remember that and apply it later. +Good work. Let me just apply these 1 changes! +. +Done. From 3babdb4db60b3471ed13db3e1c4ec8027cc9bbac Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 11:38:39 +0200 Subject: [PATCH 065/298] Clean up the workspace after the tests --- tests/fixtures.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 3f8f719c5..2373994d9 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -84,6 +84,8 @@ fn fixtures() { } } + assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); + println!("Success!\n"); } } From 94b93739e02faa4e81690db3dee024e828277f47 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 12:28:29 +0200 Subject: [PATCH 066/298] Remove a file that was accidentally commited --- .gitignore | 1 + tests/crates/use_test/output.txt | 1452 ------------------------------ 2 files changed, 1 insertion(+), 1452 deletions(-) delete mode 100644 tests/crates/use_test/output.txt diff --git a/.gitignore b/.gitignore index a9d37c560..c45ad780d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target Cargo.lock +tests/crates/**/output.txt diff --git a/tests/crates/use_test/output.txt b/tests/crates/use_test/output.txt deleted file mode 100644 index d32d44ece..000000000 --- a/tests/crates/use_test/output.txt +++ /dev/null @@ -1,1452 +0,0 @@ - - -Info: cannot find type `Iter` in this scope - - --> src/lib.rs:2:12-2:16 - -[0]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[1]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[2]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[3]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[4]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[5]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[6]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[7]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[8]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[9]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[10]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[11]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[12]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[13]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[14]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[15]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[16]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[17]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[18]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[19]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[20]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[21]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[22]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[23]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[24]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[25]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[26]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[27]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[28]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[29]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[30]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[31]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[32]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[33]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[34]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[35]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[36]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[37]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[38]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[39]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[40]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[41]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[42]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[43]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[44]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[45]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[46]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[47]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[48]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[49]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[50]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[51]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[52]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[53]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[54]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[55]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[56]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[57]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[58]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[59]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[60]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[61]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[62]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[63]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[64]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[65]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[66]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[67]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[68]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[69]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[70]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[71]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[72]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[73]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[74]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[75]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[76]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[77]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[78]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[79]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[80]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[81]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[82]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[83]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[84]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[85]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[86]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[87]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[88]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[89]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[90]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[91]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[92]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[93]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[94]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[95]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[96]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[97]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[98]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[99]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[100]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[101]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[102]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[103]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[104]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[105]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[106]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[107]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[108]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[109]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[110]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[111]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[112]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[113]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[114]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[115]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[116]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[117]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[118]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[119]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[120]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[121]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[122]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[123]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[124]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[125]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[126]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[127]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[128]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[129]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[130]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[131]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - -[132]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[133]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[134]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[135]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[136]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[137]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[138]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[139]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[140]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[141]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[142]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[143]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. -Good work. Let me just apply these 1 changes! -. -Done. From 8c6c891990f52c9820f00fe22bba707e1990cefc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 12:28:50 +0200 Subject: [PATCH 067/298] Remove some empty lines from the output --- src/main.rs | 4 +-- tests/tests/libui-rs/simple/output.txt | 6 ---- tests/tests/libui-rs/skipping/output.txt | 6 ---- tests/tests/libui-rs/yolo/output.txt | 36 ------------------------ tests/tests/use_test/first/output.txt | 2 -- tests/tests/use_test/second/output.txt | 2 -- 6 files changed, 2 insertions(+), 54 deletions(-) diff --git a/src/main.rs b/src/main.rs index fa71f335d..fc27329c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -127,11 +127,11 @@ fn handle_suggestions( } 'suggestions: for suggestion in suggestions { - println!("\n\n{info}: {message}\n", + print!("\n\n{info}: {message}\n", info = "Info".green().bold(), message = split_at_lint_name(&suggestion.message)); for snippet in suggestion.snippets { - println!("{arrow} {file}:{range}\n", + print!("{arrow} {file}:{range}\n", arrow = " -->".blue().bold(), file = snippet.file_name, range = snippet.line_range); diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index 22820c803..0a4560fd2 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -1,9 +1,7 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) -  --> src/controls.rs:245:17-245:78 - [0]: try Suggestion - Replace: @@ -19,9 +17,7 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) -  --> src/controls.rs:350:17-350:77 - [0]: try Suggestion - Replace: @@ -37,9 +33,7 @@ Info: you should consider adding a `Default` implementation for `controls::Entry` -  --> src/controls.rs:373:5-378:6 - [0]: try this Suggestion - Replace: diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index 209bf3cd2..aee099ee7 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -1,9 +1,7 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) -  --> src/controls.rs:245:17-245:78 - [0]: try Suggestion - Replace: @@ -19,9 +17,7 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) -  --> src/controls.rs:350:17-350:77 - [0]: try Suggestion - Replace: @@ -37,9 +33,7 @@ Info: you should consider adding a `Default` implementation for `controls::Entry` -  --> src/controls.rs:373:5-378:6 - [0]: try this Suggestion - Replace: diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index c57486a5b..aa2d3c3ef 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -1,9 +1,7 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) -  --> src/controls.rs:245:17-245:78 - [0]: try Suggestion - Replace: @@ -18,9 +16,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) -  --> src/controls.rs:350:17-350:77 - [0]: try Suggestion - Replace: @@ -35,9 +31,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Entry` -  --> src/controls.rs:373:5-378:6 - [0]: try this Suggestion - Replace: @@ -58,9 +52,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Checkbox)>`) -  --> src/controls.rs:415:17-415:80 - [0]: try Suggestion - Replace: @@ -75,9 +67,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Tab` -  --> src/controls.rs:526:5-531:6 - [0]: try this Suggestion - Replace: @@ -98,9 +88,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Spinbox)>`) -  --> src/controls.rs:621:17-621:79 - [0]: try Suggestion - Replace: @@ -115,9 +103,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ProgressBar` -  --> src/controls.rs:648:5-653:6 - [0]: try this Suggestion - Replace: @@ -138,9 +124,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Slider)>`) -  --> src/controls.rs:689:17-689:78 - [0]: try Suggestion - Replace: @@ -155,9 +139,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Combobox)>`) -  --> src/controls.rs:758:17-758:80 - [0]: try Suggestion - Replace: @@ -172,9 +154,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Combobox` -  --> src/controls.rs:765:5-770:6 - [0]: try this Suggestion - Replace: @@ -195,9 +175,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::RadioButtons` -  --> src/controls.rs:796:5-801:6 - [0]: try this Suggestion - Replace: @@ -218,9 +196,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::MultilineEntry)>`) -  --> src/controls.rs:866:17-867:73 - [0]: try Suggestion - Replace: @@ -236,9 +212,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::MultilineEntry` -  --> src/controls.rs:890:5-895:6 - [0]: try this Suggestion - Replace: @@ -259,9 +233,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::FontButton)>`) -  --> src/controls.rs:1182:17-1182:82 - [0]: try Suggestion - Replace: @@ -276,9 +248,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::FontButton` -  --> src/controls.rs:1189:5-1194:6 - [0]: try this Suggestion - Replace: @@ -299,9 +269,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::ColorButton)>`) -  --> src/controls.rs:1237:17-1237:83 - [0]: try Suggestion - Replace: @@ -316,9 +284,7 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ColorButton` -  --> src/controls.rs:1244:5-1249:6 - [0]: try this Suggestion - Replace: @@ -339,9 +305,7 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`) -  --> src/menus.rs:50:17-51:76 - [0]: try Suggestion - Replace: diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt index d32d44ece..32d28c8a8 100644 --- a/tests/tests/use_test/first/output.txt +++ b/tests/tests/use_test/first/output.txt @@ -1,9 +1,7 @@ Info: cannot find type `Iter` in this scope -  --> src/lib.rs:2:12-2:16 - [0]: possible candidates are found in other modules, you can import them into scope Suggestion - Replace: diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt index d32d44ece..32d28c8a8 100644 --- a/tests/tests/use_test/second/output.txt +++ b/tests/tests/use_test/second/output.txt @@ -1,9 +1,7 @@ Info: cannot find type `Iter` in this scope -  --> src/lib.rs:2:12-2:16 - [0]: possible candidates are found in other modules, you can import them into scope Suggestion - Replace: From 343ae2fd634c4dd8bb43ee89011529735fd87619 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 12:55:28 +0200 Subject: [PATCH 068/298] Don't repeat the error message for every suggestion --- src/lib.rs | 43 ++- src/main.rs | 55 +-- tests/tests/libui-rs/simple/output.txt | 15 +- tests/tests/libui-rs/skipping/output.txt | 15 +- tests/tests/libui-rs/yolo/output.txt | 90 +++-- tests/tests/use_test/first/output.txt | 456 +++++++++-------------- tests/tests/use_test/second/output.txt | 456 +++++++++-------------- 7 files changed, 470 insertions(+), 660 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 772723b40..dc0caccab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,15 +30,21 @@ impl std::fmt::Display for LineRange { } #[derive(Debug, Clone, Hash, PartialEq)] +/// An error/warning and possible solutions for fixing it pub struct Suggestion { pub message: String, pub snippets: Vec, + pub solutions: Vec, +} + +#[derive(Debug, Clone, Hash, PartialEq)] +pub struct Solution { + pub message: String, pub replacements: Vec, } #[derive(Debug, Clone, Hash, PartialEq)] pub struct Snippet { - pub sub_message: Option, pub file_name: String, pub line_range: LineRange, /// leading surrounding text, text to replace, trailing surrounding text @@ -53,7 +59,7 @@ pub struct Replacement { pub replacement: String, } -fn parse_snippet(message: Option, span: &DiagnosticSpan) -> Snippet { +fn parse_snippet(span: &DiagnosticSpan) -> Snippet { // unindent the snippet let indent = span.text.iter().map(|line| { let indent = line.text @@ -78,7 +84,6 @@ fn parse_snippet(message: Option, span: &DiagnosticSpan) -> Snippet { } tail.push_str(&last.text[last.highlight_end - 1..]); Snippet { - sub_message: message, file_name: span.file_name.clone(), line_range: LineRange { start: LinePosition { @@ -94,36 +99,44 @@ fn parse_snippet(message: Option, span: &DiagnosticSpan) -> Snippet { } } -fn collect_span(message: Option, span: &DiagnosticSpan) -> Option { +fn collect_span(span: &DiagnosticSpan) -> Option { span.suggested_replacement.clone().map(|replacement| Replacement { - snippet: parse_snippet(message, span), + snippet: parse_snippet(span), replacement, }) } pub fn collect_suggestions(diagnostic: &Diagnostic) -> Option { - let mut replacements = vec![]; let snippets = diagnostic.spans .iter() - .map(|span| parse_snippet(None, span)) + .map(|span| parse_snippet(span)) .collect(); - for child in &diagnostic.children { - for span in &child.spans { - if let Some(sugg) = collect_span(Some(child.message.clone()), span) { - replacements.push(sugg); - } + let solutions: Vec<_> = diagnostic.children + .iter() + .filter_map(|child| { + let replacements: Vec<_> = child.spans + .iter() + .filter_map(collect_span) + .collect(); + if replacements.is_empty() { + None + } else { + Some(Solution { + message: child.message.clone(), + replacements, + }) } - } + }).collect(); - if replacements.is_empty() { + if solutions.is_empty() { None } else { Some(Suggestion { message: diagnostic.message.clone(), snippets, - replacements, + solutions, }) } } diff --git a/src/main.rs b/src/main.rs index fc27329c7..33f1d3642 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,26 +137,30 @@ fn handle_suggestions( range = snippet.line_range); } - for (i, suggestion) in suggestion.replacements.iter().enumerate() { - let snippet = &suggestion.snippet; - println!("[{id}]: {msg}\n\ - {suggestion}\n\n\ - {lead}{text}{tail}\n\n\ - {with}\n\n\ - {replacement}\n", - id = i, - msg = snippet.sub_message.as_ref().map(|s| &**s).unwrap_or(""), - suggestion = "Suggestion - Replace:".yellow().bold(), - lead = indent(4, &snippet.text.0), - text = snippet.text.1.red(), - tail = snippet.text.2, - with = "with:".yellow().bold(), - replacement = indent(4, &suggestion.replacement)); + let mut i = 0; + for solution in suggestion.solutions.iter() { + println!("\n{}", solution.message); + for suggestion in solution.replacements.iter() { + let snippet = &suggestion.snippet; + println!("[{id}]: {suggestion}\n\n\ + {lead}{text}{tail}\n\n\ + {with}\n\n\ + {replacement}\n", + id = i, + suggestion = "Suggestion - Replace:".yellow().bold(), + lead = indent(4, &snippet.text.0), + text = snippet.text.1.red(), + tail = snippet.text.2, + with = "with:".yellow().bold(), + replacement = indent(4, &suggestion.replacement)); + i += 1; + } } println!(); - if mode == AutofixMode::Yolo && suggestion.replacements.len() == 1 { - let mut replacements = suggestion.replacements; + if mode == AutofixMode::Yolo && suggestion.solutions.len() == 1 && suggestion.solutions[0].replacements.len() == 1 { + let mut solutions = suggestion.solutions; + let mut replacements = solutions.remove(0).replacements; accepted_suggestions.push(replacements.remove(0)); println!("automatically applying suggestion (--yolo)"); continue 'suggestions; @@ -187,10 +191,19 @@ fn handle_suggestions( } s => { if let Ok(i) = usize::from_str(s) { - let mut replacements = suggestion.replacements; - accepted_suggestions.push(replacements.remove(i)); - println!("Suggestion accepted. I'll remember that and apply it later."); - continue 'suggestions; + let replacement = suggestion.solutions + .iter() + .flat_map(|sol| sol.replacements.iter()) + .nth(i); + if let Some(replacement) = replacement { + accepted_suggestions.push(replacement.clone()); + println!("Suggestion accepted. I'll remember that and apply it later."); + continue 'suggestions; + } else { + println!("{error}: {i} is not a valid suggestion index", + error = "Error".red().bold(), + i = i); + } } else { println!("{error}: I didn't quite get that. {user_options}", error = "Error".red().bold(), diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index 0a4560fd2..943534328 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -2,8 +2,9 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -18,8 +19,9 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -34,8 +36,9 @@ Info: you should consider adding a `Default` implementation for `controls::Entry`  --> src/controls.rs:373:5-378:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> Entry { diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index aee099ee7..dd62a1103 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -2,8 +2,9 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -18,8 +19,9 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -34,8 +36,9 @@ Info: you should consider adding a `Default` implementation for `controls::Entry`  --> src/controls.rs:373:5-378:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> Entry { diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index aa2d3c3ef..fac4dac40 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -2,8 +2,9 @@ Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -17,8 +18,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -32,8 +34,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Entry`  --> src/controls.rs:373:5-378:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> Entry { @@ -53,8 +56,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Checkbox)>`)  --> src/controls.rs:415:17-415:80 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); @@ -68,8 +72,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Tab`  --> src/controls.rs:526:5-531:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> Tab { @@ -89,8 +94,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Spinbox)>`)  --> src/controls.rs:621:17-621:79 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); @@ -104,8 +110,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ProgressBar`  --> src/controls.rs:648:5-653:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> ProgressBar { @@ -125,8 +132,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Slider)>`)  --> src/controls.rs:689:17-689:78 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&slider); @@ -140,8 +148,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Combobox)>`)  --> src/controls.rs:758:17-758:80 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); @@ -155,8 +164,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::Combobox`  --> src/controls.rs:765:5-770:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> Combobox { @@ -176,8 +186,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::RadioButtons`  --> src/controls.rs:796:5-801:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> RadioButtons { @@ -197,8 +208,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::MultilineEntry)>`)  --> src/controls.rs:866:17-867:73 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&multiline_entry); @@ -213,8 +225,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::MultilineEntry`  --> src/controls.rs:890:5-895:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> MultilineEntry { @@ -234,8 +247,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::FontButton)>`)  --> src/controls.rs:1182:17-1182:82 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); @@ -249,8 +263,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::FontButton`  --> src/controls.rs:1189:5-1194:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> FontButton { @@ -270,8 +285,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::ColorButton)>`)  --> src/controls.rs:1237:17-1237:83 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); @@ -285,8 +301,9 @@ automatically applying suggestion (--yolo) Info: you should consider adding a `Default` implementation for `controls::ColorButton`  --> src/controls.rs:1244:5-1249:6 -[0]: try this -Suggestion - Replace: + +try this +[0]: Suggestion - Replace: pub fn new() -> ColorButton { @@ -306,8 +323,9 @@ automatically applying suggestion (--yolo) Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`)  --> src/menus.rs:50:17-51:76 -[0]: try -Suggestion - Replace: + +try +[0]: Suggestion - Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&menu_item, &window); diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt index 32d28c8a8..3ec1610b7 100644 --- a/tests/tests/use_test/first/output.txt +++ b/tests/tests/use_test/first/output.txt @@ -2,8 +2,9 @@ Info: cannot find type `Iter` in this scope  --> src/lib.rs:2:12-2:16 -[0]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[0]: Suggestion - Replace: pub fn foo() { @@ -12,8 +13,7 @@ use std::collections::binary_heap::Iter; -[1]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[1]: Suggestion - Replace: pub fn foo() { @@ -22,8 +22,7 @@ use std::collections::btree_map::Iter; -[2]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[2]: Suggestion - Replace: pub fn foo() { @@ -32,8 +31,7 @@ use std::collections::btree_set::Iter; -[3]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[3]: Suggestion - Replace: pub fn foo() { @@ -42,8 +40,7 @@ use std::collections::hash_map::Iter; -[4]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[4]: Suggestion - Replace: pub fn foo() { @@ -52,8 +49,7 @@ use std::collections::hash_set::Iter; -[5]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[5]: Suggestion - Replace: pub fn foo() { @@ -62,8 +58,7 @@ use std::collections::linked_list::Iter; -[6]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[6]: Suggestion - Replace: pub fn foo() { @@ -72,8 +67,7 @@ use std::collections::vec_deque::Iter; -[7]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[7]: Suggestion - Replace: pub fn foo() { @@ -82,8 +76,7 @@ use std::option::Iter; -[8]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[8]: Suggestion - Replace: pub fn foo() { @@ -92,8 +85,7 @@ use std::path::Iter; -[9]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[9]: Suggestion - Replace: pub fn foo() { @@ -102,8 +94,7 @@ use std::result::Iter; -[10]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[10]: Suggestion - Replace: pub fn foo() { @@ -112,8 +103,7 @@ use std::slice::Iter; -[11]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[11]: Suggestion - Replace: pub fn foo() { @@ -122,8 +112,9 @@ use std::sync::mpsc::Iter; -[12]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[12]: Suggestion - Replace: pub fn foo() { @@ -132,8 +123,7 @@ use std::collections::binary_heap::Iter; -[13]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[13]: Suggestion - Replace: pub fn foo() { @@ -142,8 +132,7 @@ use std::collections::btree_map::Iter; -[14]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[14]: Suggestion - Replace: pub fn foo() { @@ -152,8 +141,7 @@ use std::collections::btree_set::Iter; -[15]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[15]: Suggestion - Replace: pub fn foo() { @@ -162,8 +150,7 @@ use std::collections::hash_map::Iter; -[16]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[16]: Suggestion - Replace: pub fn foo() { @@ -172,8 +159,7 @@ use std::collections::hash_set::Iter; -[17]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[17]: Suggestion - Replace: pub fn foo() { @@ -182,8 +168,7 @@ use std::collections::linked_list::Iter; -[18]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[18]: Suggestion - Replace: pub fn foo() { @@ -192,8 +177,7 @@ use std::collections::vec_deque::Iter; -[19]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[19]: Suggestion - Replace: pub fn foo() { @@ -202,8 +186,7 @@ use std::option::Iter; -[20]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[20]: Suggestion - Replace: pub fn foo() { @@ -212,8 +195,7 @@ use std::path::Iter; -[21]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[21]: Suggestion - Replace: pub fn foo() { @@ -222,8 +204,7 @@ use std::result::Iter; -[22]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[22]: Suggestion - Replace: pub fn foo() { @@ -232,8 +213,7 @@ use std::slice::Iter; -[23]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[23]: Suggestion - Replace: pub fn foo() { @@ -242,8 +222,9 @@ use std::sync::mpsc::Iter; -[24]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[24]: Suggestion - Replace: pub fn foo() { @@ -252,8 +233,7 @@ use std::collections::binary_heap::Iter; -[25]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[25]: Suggestion - Replace: pub fn foo() { @@ -262,8 +242,7 @@ use std::collections::btree_map::Iter; -[26]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[26]: Suggestion - Replace: pub fn foo() { @@ -272,8 +251,7 @@ use std::collections::btree_set::Iter; -[27]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[27]: Suggestion - Replace: pub fn foo() { @@ -282,8 +260,7 @@ use std::collections::hash_map::Iter; -[28]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[28]: Suggestion - Replace: pub fn foo() { @@ -292,8 +269,7 @@ use std::collections::hash_set::Iter; -[29]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[29]: Suggestion - Replace: pub fn foo() { @@ -302,8 +278,7 @@ use std::collections::linked_list::Iter; -[30]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[30]: Suggestion - Replace: pub fn foo() { @@ -312,8 +287,7 @@ use std::collections::vec_deque::Iter; -[31]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[31]: Suggestion - Replace: pub fn foo() { @@ -322,8 +296,7 @@ use std::option::Iter; -[32]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[32]: Suggestion - Replace: pub fn foo() { @@ -332,8 +305,7 @@ use std::path::Iter; -[33]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[33]: Suggestion - Replace: pub fn foo() { @@ -342,8 +314,7 @@ use std::result::Iter; -[34]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[34]: Suggestion - Replace: pub fn foo() { @@ -352,8 +323,7 @@ use std::slice::Iter; -[35]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[35]: Suggestion - Replace: pub fn foo() { @@ -362,8 +332,9 @@ use std::sync::mpsc::Iter; -[36]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[36]: Suggestion - Replace: pub fn foo() { @@ -372,8 +343,7 @@ use std::collections::binary_heap::Iter; -[37]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[37]: Suggestion - Replace: pub fn foo() { @@ -382,8 +352,7 @@ use std::collections::btree_map::Iter; -[38]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[38]: Suggestion - Replace: pub fn foo() { @@ -392,8 +361,7 @@ use std::collections::btree_set::Iter; -[39]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[39]: Suggestion - Replace: pub fn foo() { @@ -402,8 +370,7 @@ use std::collections::hash_map::Iter; -[40]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[40]: Suggestion - Replace: pub fn foo() { @@ -412,8 +379,7 @@ use std::collections::hash_set::Iter; -[41]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[41]: Suggestion - Replace: pub fn foo() { @@ -422,8 +388,7 @@ use std::collections::linked_list::Iter; -[42]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[42]: Suggestion - Replace: pub fn foo() { @@ -432,8 +397,7 @@ use std::collections::vec_deque::Iter; -[43]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[43]: Suggestion - Replace: pub fn foo() { @@ -442,8 +406,7 @@ use std::option::Iter; -[44]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[44]: Suggestion - Replace: pub fn foo() { @@ -452,8 +415,7 @@ use std::path::Iter; -[45]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[45]: Suggestion - Replace: pub fn foo() { @@ -462,8 +424,7 @@ use std::result::Iter; -[46]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[46]: Suggestion - Replace: pub fn foo() { @@ -472,8 +433,7 @@ use std::slice::Iter; -[47]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[47]: Suggestion - Replace: pub fn foo() { @@ -482,8 +442,9 @@ use std::sync::mpsc::Iter; -[48]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[48]: Suggestion - Replace: pub fn foo() { @@ -492,8 +453,7 @@ use std::collections::binary_heap::Iter; -[49]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[49]: Suggestion - Replace: pub fn foo() { @@ -502,8 +462,7 @@ use std::collections::btree_map::Iter; -[50]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[50]: Suggestion - Replace: pub fn foo() { @@ -512,8 +471,7 @@ use std::collections::btree_set::Iter; -[51]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[51]: Suggestion - Replace: pub fn foo() { @@ -522,8 +480,7 @@ use std::collections::hash_map::Iter; -[52]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[52]: Suggestion - Replace: pub fn foo() { @@ -532,8 +489,7 @@ use std::collections::hash_set::Iter; -[53]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[53]: Suggestion - Replace: pub fn foo() { @@ -542,8 +498,7 @@ use std::collections::linked_list::Iter; -[54]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[54]: Suggestion - Replace: pub fn foo() { @@ -552,8 +507,7 @@ use std::collections::vec_deque::Iter; -[55]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[55]: Suggestion - Replace: pub fn foo() { @@ -562,8 +516,7 @@ use std::option::Iter; -[56]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[56]: Suggestion - Replace: pub fn foo() { @@ -572,8 +525,7 @@ use std::path::Iter; -[57]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[57]: Suggestion - Replace: pub fn foo() { @@ -582,8 +534,7 @@ use std::result::Iter; -[58]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[58]: Suggestion - Replace: pub fn foo() { @@ -592,8 +543,7 @@ use std::slice::Iter; -[59]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[59]: Suggestion - Replace: pub fn foo() { @@ -602,8 +552,9 @@ use std::sync::mpsc::Iter; -[60]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[60]: Suggestion - Replace: pub fn foo() { @@ -612,8 +563,7 @@ use std::collections::binary_heap::Iter; -[61]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[61]: Suggestion - Replace: pub fn foo() { @@ -622,8 +572,7 @@ use std::collections::btree_map::Iter; -[62]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[62]: Suggestion - Replace: pub fn foo() { @@ -632,8 +581,7 @@ use std::collections::btree_set::Iter; -[63]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[63]: Suggestion - Replace: pub fn foo() { @@ -642,8 +590,7 @@ use std::collections::hash_map::Iter; -[64]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[64]: Suggestion - Replace: pub fn foo() { @@ -652,8 +599,7 @@ use std::collections::hash_set::Iter; -[65]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[65]: Suggestion - Replace: pub fn foo() { @@ -662,8 +608,7 @@ use std::collections::linked_list::Iter; -[66]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[66]: Suggestion - Replace: pub fn foo() { @@ -672,8 +617,7 @@ use std::collections::vec_deque::Iter; -[67]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[67]: Suggestion - Replace: pub fn foo() { @@ -682,8 +626,7 @@ use std::option::Iter; -[68]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[68]: Suggestion - Replace: pub fn foo() { @@ -692,8 +635,7 @@ use std::path::Iter; -[69]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[69]: Suggestion - Replace: pub fn foo() { @@ -702,8 +644,7 @@ use std::result::Iter; -[70]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[70]: Suggestion - Replace: pub fn foo() { @@ -712,8 +653,7 @@ use std::slice::Iter; -[71]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[71]: Suggestion - Replace: pub fn foo() { @@ -722,8 +662,9 @@ use std::sync::mpsc::Iter; -[72]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[72]: Suggestion - Replace: pub fn foo() { @@ -732,8 +673,7 @@ use std::collections::binary_heap::Iter; -[73]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[73]: Suggestion - Replace: pub fn foo() { @@ -742,8 +682,7 @@ use std::collections::btree_map::Iter; -[74]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[74]: Suggestion - Replace: pub fn foo() { @@ -752,8 +691,7 @@ use std::collections::btree_set::Iter; -[75]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[75]: Suggestion - Replace: pub fn foo() { @@ -762,8 +700,7 @@ use std::collections::hash_map::Iter; -[76]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[76]: Suggestion - Replace: pub fn foo() { @@ -772,8 +709,7 @@ use std::collections::hash_set::Iter; -[77]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[77]: Suggestion - Replace: pub fn foo() { @@ -782,8 +718,7 @@ use std::collections::linked_list::Iter; -[78]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[78]: Suggestion - Replace: pub fn foo() { @@ -792,8 +727,7 @@ use std::collections::vec_deque::Iter; -[79]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[79]: Suggestion - Replace: pub fn foo() { @@ -802,8 +736,7 @@ use std::option::Iter; -[80]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[80]: Suggestion - Replace: pub fn foo() { @@ -812,8 +745,7 @@ use std::path::Iter; -[81]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[81]: Suggestion - Replace: pub fn foo() { @@ -822,8 +754,7 @@ use std::result::Iter; -[82]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[82]: Suggestion - Replace: pub fn foo() { @@ -832,8 +763,7 @@ use std::slice::Iter; -[83]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[83]: Suggestion - Replace: pub fn foo() { @@ -842,8 +772,9 @@ use std::sync::mpsc::Iter; -[84]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[84]: Suggestion - Replace: pub fn foo() { @@ -852,8 +783,7 @@ use std::collections::binary_heap::Iter; -[85]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[85]: Suggestion - Replace: pub fn foo() { @@ -862,8 +792,7 @@ use std::collections::btree_map::Iter; -[86]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[86]: Suggestion - Replace: pub fn foo() { @@ -872,8 +801,7 @@ use std::collections::btree_set::Iter; -[87]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[87]: Suggestion - Replace: pub fn foo() { @@ -882,8 +810,7 @@ use std::collections::hash_map::Iter; -[88]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[88]: Suggestion - Replace: pub fn foo() { @@ -892,8 +819,7 @@ use std::collections::hash_set::Iter; -[89]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[89]: Suggestion - Replace: pub fn foo() { @@ -902,8 +828,7 @@ use std::collections::linked_list::Iter; -[90]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[90]: Suggestion - Replace: pub fn foo() { @@ -912,8 +837,7 @@ use std::collections::vec_deque::Iter; -[91]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[91]: Suggestion - Replace: pub fn foo() { @@ -922,8 +846,7 @@ use std::option::Iter; -[92]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[92]: Suggestion - Replace: pub fn foo() { @@ -932,8 +855,7 @@ use std::path::Iter; -[93]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[93]: Suggestion - Replace: pub fn foo() { @@ -942,8 +864,7 @@ use std::result::Iter; -[94]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[94]: Suggestion - Replace: pub fn foo() { @@ -952,8 +873,7 @@ use std::slice::Iter; -[95]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[95]: Suggestion - Replace: pub fn foo() { @@ -962,8 +882,9 @@ use std::sync::mpsc::Iter; -[96]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[96]: Suggestion - Replace: pub fn foo() { @@ -972,8 +893,7 @@ use std::collections::binary_heap::Iter; -[97]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[97]: Suggestion - Replace: pub fn foo() { @@ -982,8 +902,7 @@ use std::collections::btree_map::Iter; -[98]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[98]: Suggestion - Replace: pub fn foo() { @@ -992,8 +911,7 @@ use std::collections::btree_set::Iter; -[99]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[99]: Suggestion - Replace: pub fn foo() { @@ -1002,8 +920,7 @@ use std::collections::hash_map::Iter; -[100]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[100]: Suggestion - Replace: pub fn foo() { @@ -1012,8 +929,7 @@ use std::collections::hash_set::Iter; -[101]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[101]: Suggestion - Replace: pub fn foo() { @@ -1022,8 +938,7 @@ use std::collections::linked_list::Iter; -[102]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[102]: Suggestion - Replace: pub fn foo() { @@ -1032,8 +947,7 @@ use std::collections::vec_deque::Iter; -[103]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[103]: Suggestion - Replace: pub fn foo() { @@ -1042,8 +956,7 @@ use std::option::Iter; -[104]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[104]: Suggestion - Replace: pub fn foo() { @@ -1052,8 +965,7 @@ use std::path::Iter; -[105]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[105]: Suggestion - Replace: pub fn foo() { @@ -1062,8 +974,7 @@ use std::result::Iter; -[106]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[106]: Suggestion - Replace: pub fn foo() { @@ -1072,8 +983,7 @@ use std::slice::Iter; -[107]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[107]: Suggestion - Replace: pub fn foo() { @@ -1082,8 +992,9 @@ use std::sync::mpsc::Iter; -[108]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[108]: Suggestion - Replace: pub fn foo() { @@ -1092,8 +1003,7 @@ use std::collections::binary_heap::Iter; -[109]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[109]: Suggestion - Replace: pub fn foo() { @@ -1102,8 +1012,7 @@ use std::collections::btree_map::Iter; -[110]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[110]: Suggestion - Replace: pub fn foo() { @@ -1112,8 +1021,7 @@ use std::collections::btree_set::Iter; -[111]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[111]: Suggestion - Replace: pub fn foo() { @@ -1122,8 +1030,7 @@ use std::collections::hash_map::Iter; -[112]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[112]: Suggestion - Replace: pub fn foo() { @@ -1132,8 +1039,7 @@ use std::collections::hash_set::Iter; -[113]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[113]: Suggestion - Replace: pub fn foo() { @@ -1142,8 +1048,7 @@ use std::collections::linked_list::Iter; -[114]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[114]: Suggestion - Replace: pub fn foo() { @@ -1152,8 +1057,7 @@ use std::collections::vec_deque::Iter; -[115]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[115]: Suggestion - Replace: pub fn foo() { @@ -1162,8 +1066,7 @@ use std::option::Iter; -[116]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[116]: Suggestion - Replace: pub fn foo() { @@ -1172,8 +1075,7 @@ use std::path::Iter; -[117]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[117]: Suggestion - Replace: pub fn foo() { @@ -1182,8 +1084,7 @@ use std::result::Iter; -[118]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[118]: Suggestion - Replace: pub fn foo() { @@ -1192,8 +1093,7 @@ use std::slice::Iter; -[119]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[119]: Suggestion - Replace: pub fn foo() { @@ -1202,8 +1102,9 @@ use std::sync::mpsc::Iter; -[120]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[120]: Suggestion - Replace: pub fn foo() { @@ -1212,8 +1113,7 @@ use std::collections::binary_heap::Iter; -[121]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[121]: Suggestion - Replace: pub fn foo() { @@ -1222,8 +1122,7 @@ use std::collections::btree_map::Iter; -[122]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[122]: Suggestion - Replace: pub fn foo() { @@ -1232,8 +1131,7 @@ use std::collections::btree_set::Iter; -[123]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[123]: Suggestion - Replace: pub fn foo() { @@ -1242,8 +1140,7 @@ use std::collections::hash_map::Iter; -[124]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[124]: Suggestion - Replace: pub fn foo() { @@ -1252,8 +1149,7 @@ use std::collections::hash_set::Iter; -[125]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[125]: Suggestion - Replace: pub fn foo() { @@ -1262,8 +1158,7 @@ use std::collections::linked_list::Iter; -[126]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[126]: Suggestion - Replace: pub fn foo() { @@ -1272,8 +1167,7 @@ use std::collections::vec_deque::Iter; -[127]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[127]: Suggestion - Replace: pub fn foo() { @@ -1282,8 +1176,7 @@ use std::option::Iter; -[128]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[128]: Suggestion - Replace: pub fn foo() { @@ -1292,8 +1185,7 @@ use std::path::Iter; -[129]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[129]: Suggestion - Replace: pub fn foo() { @@ -1302,8 +1194,7 @@ use std::result::Iter; -[130]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[130]: Suggestion - Replace: pub fn foo() { @@ -1312,8 +1203,7 @@ use std::slice::Iter; -[131]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[131]: Suggestion - Replace: pub fn foo() { @@ -1322,8 +1212,9 @@ use std::sync::mpsc::Iter; -[132]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[132]: Suggestion - Replace: pub fn foo() { @@ -1332,8 +1223,7 @@ use std::collections::binary_heap::Iter; -[133]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[133]: Suggestion - Replace: pub fn foo() { @@ -1342,8 +1232,7 @@ use std::collections::btree_map::Iter; -[134]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[134]: Suggestion - Replace: pub fn foo() { @@ -1352,8 +1241,7 @@ use std::collections::btree_set::Iter; -[135]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[135]: Suggestion - Replace: pub fn foo() { @@ -1362,8 +1250,7 @@ use std::collections::hash_map::Iter; -[136]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[136]: Suggestion - Replace: pub fn foo() { @@ -1372,8 +1259,7 @@ use std::collections::hash_set::Iter; -[137]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[137]: Suggestion - Replace: pub fn foo() { @@ -1382,8 +1268,7 @@ use std::collections::linked_list::Iter; -[138]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[138]: Suggestion - Replace: pub fn foo() { @@ -1392,8 +1277,7 @@ use std::collections::vec_deque::Iter; -[139]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[139]: Suggestion - Replace: pub fn foo() { @@ -1402,8 +1286,7 @@ use std::option::Iter; -[140]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[140]: Suggestion - Replace: pub fn foo() { @@ -1412,8 +1295,7 @@ use std::path::Iter; -[141]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[141]: Suggestion - Replace: pub fn foo() { @@ -1422,8 +1304,7 @@ use std::result::Iter; -[142]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[142]: Suggestion - Replace: pub fn foo() { @@ -1432,8 +1313,7 @@ use std::slice::Iter; -[143]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[143]: Suggestion - Replace: pub fn foo() { diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt index 32d28c8a8..3ec1610b7 100644 --- a/tests/tests/use_test/second/output.txt +++ b/tests/tests/use_test/second/output.txt @@ -2,8 +2,9 @@ Info: cannot find type `Iter` in this scope  --> src/lib.rs:2:12-2:16 -[0]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[0]: Suggestion - Replace: pub fn foo() { @@ -12,8 +13,7 @@ use std::collections::binary_heap::Iter; -[1]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[1]: Suggestion - Replace: pub fn foo() { @@ -22,8 +22,7 @@ use std::collections::btree_map::Iter; -[2]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[2]: Suggestion - Replace: pub fn foo() { @@ -32,8 +31,7 @@ use std::collections::btree_set::Iter; -[3]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[3]: Suggestion - Replace: pub fn foo() { @@ -42,8 +40,7 @@ use std::collections::hash_map::Iter; -[4]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[4]: Suggestion - Replace: pub fn foo() { @@ -52,8 +49,7 @@ use std::collections::hash_set::Iter; -[5]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[5]: Suggestion - Replace: pub fn foo() { @@ -62,8 +58,7 @@ use std::collections::linked_list::Iter; -[6]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[6]: Suggestion - Replace: pub fn foo() { @@ -72,8 +67,7 @@ use std::collections::vec_deque::Iter; -[7]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[7]: Suggestion - Replace: pub fn foo() { @@ -82,8 +76,7 @@ use std::option::Iter; -[8]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[8]: Suggestion - Replace: pub fn foo() { @@ -92,8 +85,7 @@ use std::path::Iter; -[9]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[9]: Suggestion - Replace: pub fn foo() { @@ -102,8 +94,7 @@ use std::result::Iter; -[10]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[10]: Suggestion - Replace: pub fn foo() { @@ -112,8 +103,7 @@ use std::slice::Iter; -[11]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[11]: Suggestion - Replace: pub fn foo() { @@ -122,8 +112,9 @@ use std::sync::mpsc::Iter; -[12]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[12]: Suggestion - Replace: pub fn foo() { @@ -132,8 +123,7 @@ use std::collections::binary_heap::Iter; -[13]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[13]: Suggestion - Replace: pub fn foo() { @@ -142,8 +132,7 @@ use std::collections::btree_map::Iter; -[14]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[14]: Suggestion - Replace: pub fn foo() { @@ -152,8 +141,7 @@ use std::collections::btree_set::Iter; -[15]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[15]: Suggestion - Replace: pub fn foo() { @@ -162,8 +150,7 @@ use std::collections::hash_map::Iter; -[16]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[16]: Suggestion - Replace: pub fn foo() { @@ -172,8 +159,7 @@ use std::collections::hash_set::Iter; -[17]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[17]: Suggestion - Replace: pub fn foo() { @@ -182,8 +168,7 @@ use std::collections::linked_list::Iter; -[18]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[18]: Suggestion - Replace: pub fn foo() { @@ -192,8 +177,7 @@ use std::collections::vec_deque::Iter; -[19]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[19]: Suggestion - Replace: pub fn foo() { @@ -202,8 +186,7 @@ use std::option::Iter; -[20]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[20]: Suggestion - Replace: pub fn foo() { @@ -212,8 +195,7 @@ use std::path::Iter; -[21]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[21]: Suggestion - Replace: pub fn foo() { @@ -222,8 +204,7 @@ use std::result::Iter; -[22]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[22]: Suggestion - Replace: pub fn foo() { @@ -232,8 +213,7 @@ use std::slice::Iter; -[23]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[23]: Suggestion - Replace: pub fn foo() { @@ -242,8 +222,9 @@ use std::sync::mpsc::Iter; -[24]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[24]: Suggestion - Replace: pub fn foo() { @@ -252,8 +233,7 @@ use std::collections::binary_heap::Iter; -[25]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[25]: Suggestion - Replace: pub fn foo() { @@ -262,8 +242,7 @@ use std::collections::btree_map::Iter; -[26]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[26]: Suggestion - Replace: pub fn foo() { @@ -272,8 +251,7 @@ use std::collections::btree_set::Iter; -[27]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[27]: Suggestion - Replace: pub fn foo() { @@ -282,8 +260,7 @@ use std::collections::hash_map::Iter; -[28]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[28]: Suggestion - Replace: pub fn foo() { @@ -292,8 +269,7 @@ use std::collections::hash_set::Iter; -[29]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[29]: Suggestion - Replace: pub fn foo() { @@ -302,8 +278,7 @@ use std::collections::linked_list::Iter; -[30]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[30]: Suggestion - Replace: pub fn foo() { @@ -312,8 +287,7 @@ use std::collections::vec_deque::Iter; -[31]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[31]: Suggestion - Replace: pub fn foo() { @@ -322,8 +296,7 @@ use std::option::Iter; -[32]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[32]: Suggestion - Replace: pub fn foo() { @@ -332,8 +305,7 @@ use std::path::Iter; -[33]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[33]: Suggestion - Replace: pub fn foo() { @@ -342,8 +314,7 @@ use std::result::Iter; -[34]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[34]: Suggestion - Replace: pub fn foo() { @@ -352,8 +323,7 @@ use std::slice::Iter; -[35]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[35]: Suggestion - Replace: pub fn foo() { @@ -362,8 +332,9 @@ use std::sync::mpsc::Iter; -[36]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[36]: Suggestion - Replace: pub fn foo() { @@ -372,8 +343,7 @@ use std::collections::binary_heap::Iter; -[37]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[37]: Suggestion - Replace: pub fn foo() { @@ -382,8 +352,7 @@ use std::collections::btree_map::Iter; -[38]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[38]: Suggestion - Replace: pub fn foo() { @@ -392,8 +361,7 @@ use std::collections::btree_set::Iter; -[39]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[39]: Suggestion - Replace: pub fn foo() { @@ -402,8 +370,7 @@ use std::collections::hash_map::Iter; -[40]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[40]: Suggestion - Replace: pub fn foo() { @@ -412,8 +379,7 @@ use std::collections::hash_set::Iter; -[41]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[41]: Suggestion - Replace: pub fn foo() { @@ -422,8 +388,7 @@ use std::collections::linked_list::Iter; -[42]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[42]: Suggestion - Replace: pub fn foo() { @@ -432,8 +397,7 @@ use std::collections::vec_deque::Iter; -[43]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[43]: Suggestion - Replace: pub fn foo() { @@ -442,8 +406,7 @@ use std::option::Iter; -[44]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[44]: Suggestion - Replace: pub fn foo() { @@ -452,8 +415,7 @@ use std::path::Iter; -[45]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[45]: Suggestion - Replace: pub fn foo() { @@ -462,8 +424,7 @@ use std::result::Iter; -[46]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[46]: Suggestion - Replace: pub fn foo() { @@ -472,8 +433,7 @@ use std::slice::Iter; -[47]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[47]: Suggestion - Replace: pub fn foo() { @@ -482,8 +442,9 @@ use std::sync::mpsc::Iter; -[48]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[48]: Suggestion - Replace: pub fn foo() { @@ -492,8 +453,7 @@ use std::collections::binary_heap::Iter; -[49]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[49]: Suggestion - Replace: pub fn foo() { @@ -502,8 +462,7 @@ use std::collections::btree_map::Iter; -[50]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[50]: Suggestion - Replace: pub fn foo() { @@ -512,8 +471,7 @@ use std::collections::btree_set::Iter; -[51]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[51]: Suggestion - Replace: pub fn foo() { @@ -522,8 +480,7 @@ use std::collections::hash_map::Iter; -[52]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[52]: Suggestion - Replace: pub fn foo() { @@ -532,8 +489,7 @@ use std::collections::hash_set::Iter; -[53]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[53]: Suggestion - Replace: pub fn foo() { @@ -542,8 +498,7 @@ use std::collections::linked_list::Iter; -[54]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[54]: Suggestion - Replace: pub fn foo() { @@ -552,8 +507,7 @@ use std::collections::vec_deque::Iter; -[55]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[55]: Suggestion - Replace: pub fn foo() { @@ -562,8 +516,7 @@ use std::option::Iter; -[56]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[56]: Suggestion - Replace: pub fn foo() { @@ -572,8 +525,7 @@ use std::path::Iter; -[57]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[57]: Suggestion - Replace: pub fn foo() { @@ -582,8 +534,7 @@ use std::result::Iter; -[58]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[58]: Suggestion - Replace: pub fn foo() { @@ -592,8 +543,7 @@ use std::slice::Iter; -[59]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[59]: Suggestion - Replace: pub fn foo() { @@ -602,8 +552,9 @@ use std::sync::mpsc::Iter; -[60]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[60]: Suggestion - Replace: pub fn foo() { @@ -612,8 +563,7 @@ use std::collections::binary_heap::Iter; -[61]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[61]: Suggestion - Replace: pub fn foo() { @@ -622,8 +572,7 @@ use std::collections::btree_map::Iter; -[62]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[62]: Suggestion - Replace: pub fn foo() { @@ -632,8 +581,7 @@ use std::collections::btree_set::Iter; -[63]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[63]: Suggestion - Replace: pub fn foo() { @@ -642,8 +590,7 @@ use std::collections::hash_map::Iter; -[64]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[64]: Suggestion - Replace: pub fn foo() { @@ -652,8 +599,7 @@ use std::collections::hash_set::Iter; -[65]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[65]: Suggestion - Replace: pub fn foo() { @@ -662,8 +608,7 @@ use std::collections::linked_list::Iter; -[66]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[66]: Suggestion - Replace: pub fn foo() { @@ -672,8 +617,7 @@ use std::collections::vec_deque::Iter; -[67]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[67]: Suggestion - Replace: pub fn foo() { @@ -682,8 +626,7 @@ use std::option::Iter; -[68]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[68]: Suggestion - Replace: pub fn foo() { @@ -692,8 +635,7 @@ use std::path::Iter; -[69]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[69]: Suggestion - Replace: pub fn foo() { @@ -702,8 +644,7 @@ use std::result::Iter; -[70]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[70]: Suggestion - Replace: pub fn foo() { @@ -712,8 +653,7 @@ use std::slice::Iter; -[71]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[71]: Suggestion - Replace: pub fn foo() { @@ -722,8 +662,9 @@ use std::sync::mpsc::Iter; -[72]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[72]: Suggestion - Replace: pub fn foo() { @@ -732,8 +673,7 @@ use std::collections::binary_heap::Iter; -[73]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[73]: Suggestion - Replace: pub fn foo() { @@ -742,8 +682,7 @@ use std::collections::btree_map::Iter; -[74]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[74]: Suggestion - Replace: pub fn foo() { @@ -752,8 +691,7 @@ use std::collections::btree_set::Iter; -[75]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[75]: Suggestion - Replace: pub fn foo() { @@ -762,8 +700,7 @@ use std::collections::hash_map::Iter; -[76]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[76]: Suggestion - Replace: pub fn foo() { @@ -772,8 +709,7 @@ use std::collections::hash_set::Iter; -[77]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[77]: Suggestion - Replace: pub fn foo() { @@ -782,8 +718,7 @@ use std::collections::linked_list::Iter; -[78]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[78]: Suggestion - Replace: pub fn foo() { @@ -792,8 +727,7 @@ use std::collections::vec_deque::Iter; -[79]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[79]: Suggestion - Replace: pub fn foo() { @@ -802,8 +736,7 @@ use std::option::Iter; -[80]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[80]: Suggestion - Replace: pub fn foo() { @@ -812,8 +745,7 @@ use std::path::Iter; -[81]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[81]: Suggestion - Replace: pub fn foo() { @@ -822,8 +754,7 @@ use std::result::Iter; -[82]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[82]: Suggestion - Replace: pub fn foo() { @@ -832,8 +763,7 @@ use std::slice::Iter; -[83]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[83]: Suggestion - Replace: pub fn foo() { @@ -842,8 +772,9 @@ use std::sync::mpsc::Iter; -[84]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[84]: Suggestion - Replace: pub fn foo() { @@ -852,8 +783,7 @@ use std::collections::binary_heap::Iter; -[85]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[85]: Suggestion - Replace: pub fn foo() { @@ -862,8 +792,7 @@ use std::collections::btree_map::Iter; -[86]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[86]: Suggestion - Replace: pub fn foo() { @@ -872,8 +801,7 @@ use std::collections::btree_set::Iter; -[87]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[87]: Suggestion - Replace: pub fn foo() { @@ -882,8 +810,7 @@ use std::collections::hash_map::Iter; -[88]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[88]: Suggestion - Replace: pub fn foo() { @@ -892,8 +819,7 @@ use std::collections::hash_set::Iter; -[89]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[89]: Suggestion - Replace: pub fn foo() { @@ -902,8 +828,7 @@ use std::collections::linked_list::Iter; -[90]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[90]: Suggestion - Replace: pub fn foo() { @@ -912,8 +837,7 @@ use std::collections::vec_deque::Iter; -[91]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[91]: Suggestion - Replace: pub fn foo() { @@ -922,8 +846,7 @@ use std::option::Iter; -[92]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[92]: Suggestion - Replace: pub fn foo() { @@ -932,8 +855,7 @@ use std::path::Iter; -[93]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[93]: Suggestion - Replace: pub fn foo() { @@ -942,8 +864,7 @@ use std::result::Iter; -[94]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[94]: Suggestion - Replace: pub fn foo() { @@ -952,8 +873,7 @@ use std::slice::Iter; -[95]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[95]: Suggestion - Replace: pub fn foo() { @@ -962,8 +882,9 @@ use std::sync::mpsc::Iter; -[96]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[96]: Suggestion - Replace: pub fn foo() { @@ -972,8 +893,7 @@ use std::collections::binary_heap::Iter; -[97]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[97]: Suggestion - Replace: pub fn foo() { @@ -982,8 +902,7 @@ use std::collections::btree_map::Iter; -[98]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[98]: Suggestion - Replace: pub fn foo() { @@ -992,8 +911,7 @@ use std::collections::btree_set::Iter; -[99]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[99]: Suggestion - Replace: pub fn foo() { @@ -1002,8 +920,7 @@ use std::collections::hash_map::Iter; -[100]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[100]: Suggestion - Replace: pub fn foo() { @@ -1012,8 +929,7 @@ use std::collections::hash_set::Iter; -[101]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[101]: Suggestion - Replace: pub fn foo() { @@ -1022,8 +938,7 @@ use std::collections::linked_list::Iter; -[102]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[102]: Suggestion - Replace: pub fn foo() { @@ -1032,8 +947,7 @@ use std::collections::vec_deque::Iter; -[103]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[103]: Suggestion - Replace: pub fn foo() { @@ -1042,8 +956,7 @@ use std::option::Iter; -[104]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[104]: Suggestion - Replace: pub fn foo() { @@ -1052,8 +965,7 @@ use std::path::Iter; -[105]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[105]: Suggestion - Replace: pub fn foo() { @@ -1062,8 +974,7 @@ use std::result::Iter; -[106]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[106]: Suggestion - Replace: pub fn foo() { @@ -1072,8 +983,7 @@ use std::slice::Iter; -[107]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[107]: Suggestion - Replace: pub fn foo() { @@ -1082,8 +992,9 @@ use std::sync::mpsc::Iter; -[108]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[108]: Suggestion - Replace: pub fn foo() { @@ -1092,8 +1003,7 @@ use std::collections::binary_heap::Iter; -[109]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[109]: Suggestion - Replace: pub fn foo() { @@ -1102,8 +1012,7 @@ use std::collections::btree_map::Iter; -[110]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[110]: Suggestion - Replace: pub fn foo() { @@ -1112,8 +1021,7 @@ use std::collections::btree_set::Iter; -[111]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[111]: Suggestion - Replace: pub fn foo() { @@ -1122,8 +1030,7 @@ use std::collections::hash_map::Iter; -[112]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[112]: Suggestion - Replace: pub fn foo() { @@ -1132,8 +1039,7 @@ use std::collections::hash_set::Iter; -[113]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[113]: Suggestion - Replace: pub fn foo() { @@ -1142,8 +1048,7 @@ use std::collections::linked_list::Iter; -[114]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[114]: Suggestion - Replace: pub fn foo() { @@ -1152,8 +1057,7 @@ use std::collections::vec_deque::Iter; -[115]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[115]: Suggestion - Replace: pub fn foo() { @@ -1162,8 +1066,7 @@ use std::option::Iter; -[116]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[116]: Suggestion - Replace: pub fn foo() { @@ -1172,8 +1075,7 @@ use std::path::Iter; -[117]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[117]: Suggestion - Replace: pub fn foo() { @@ -1182,8 +1084,7 @@ use std::result::Iter; -[118]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[118]: Suggestion - Replace: pub fn foo() { @@ -1192,8 +1093,7 @@ use std::slice::Iter; -[119]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[119]: Suggestion - Replace: pub fn foo() { @@ -1202,8 +1102,9 @@ use std::sync::mpsc::Iter; -[120]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[120]: Suggestion - Replace: pub fn foo() { @@ -1212,8 +1113,7 @@ use std::collections::binary_heap::Iter; -[121]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[121]: Suggestion - Replace: pub fn foo() { @@ -1222,8 +1122,7 @@ use std::collections::btree_map::Iter; -[122]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[122]: Suggestion - Replace: pub fn foo() { @@ -1232,8 +1131,7 @@ use std::collections::btree_set::Iter; -[123]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[123]: Suggestion - Replace: pub fn foo() { @@ -1242,8 +1140,7 @@ use std::collections::hash_map::Iter; -[124]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[124]: Suggestion - Replace: pub fn foo() { @@ -1252,8 +1149,7 @@ use std::collections::hash_set::Iter; -[125]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[125]: Suggestion - Replace: pub fn foo() { @@ -1262,8 +1158,7 @@ use std::collections::linked_list::Iter; -[126]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[126]: Suggestion - Replace: pub fn foo() { @@ -1272,8 +1167,7 @@ use std::collections::vec_deque::Iter; -[127]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[127]: Suggestion - Replace: pub fn foo() { @@ -1282,8 +1176,7 @@ use std::option::Iter; -[128]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[128]: Suggestion - Replace: pub fn foo() { @@ -1292,8 +1185,7 @@ use std::path::Iter; -[129]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[129]: Suggestion - Replace: pub fn foo() { @@ -1302,8 +1194,7 @@ use std::result::Iter; -[130]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[130]: Suggestion - Replace: pub fn foo() { @@ -1312,8 +1203,7 @@ use std::slice::Iter; -[131]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[131]: Suggestion - Replace: pub fn foo() { @@ -1322,8 +1212,9 @@ use std::sync::mpsc::Iter; -[132]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: + +possible candidates are found in other modules, you can import them into scope +[132]: Suggestion - Replace: pub fn foo() { @@ -1332,8 +1223,7 @@ use std::collections::binary_heap::Iter; -[133]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[133]: Suggestion - Replace: pub fn foo() { @@ -1342,8 +1232,7 @@ use std::collections::btree_map::Iter; -[134]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[134]: Suggestion - Replace: pub fn foo() { @@ -1352,8 +1241,7 @@ use std::collections::btree_set::Iter; -[135]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[135]: Suggestion - Replace: pub fn foo() { @@ -1362,8 +1250,7 @@ use std::collections::hash_map::Iter; -[136]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[136]: Suggestion - Replace: pub fn foo() { @@ -1372,8 +1259,7 @@ use std::collections::hash_set::Iter; -[137]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[137]: Suggestion - Replace: pub fn foo() { @@ -1382,8 +1268,7 @@ use std::collections::linked_list::Iter; -[138]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[138]: Suggestion - Replace: pub fn foo() { @@ -1392,8 +1277,7 @@ use std::collections::vec_deque::Iter; -[139]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[139]: Suggestion - Replace: pub fn foo() { @@ -1402,8 +1286,7 @@ use std::option::Iter; -[140]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[140]: Suggestion - Replace: pub fn foo() { @@ -1412,8 +1295,7 @@ use std::path::Iter; -[141]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[141]: Suggestion - Replace: pub fn foo() { @@ -1422,8 +1304,7 @@ use std::result::Iter; -[142]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[142]: Suggestion - Replace: pub fn foo() { @@ -1432,8 +1313,7 @@ use std::slice::Iter; -[143]: possible candidates are found in other modules, you can import them into scope -Suggestion - Replace: +[143]: Suggestion - Replace: pub fn foo() { From 1da2bcbcb35d659120957873c16131921a4ad493 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 24 Oct 2017 14:17:56 +0200 Subject: [PATCH 069/298] Allow pressing `r` when there's only one replacement --- src/main.rs | 13 +- tests/tests/libui-rs/simple/input.txt | 4 +- tests/tests/libui-rs/simple/output.txt | 6 +- tests/tests/libui-rs/skipping/input.txt | 2 +- tests/tests/libui-rs/skipping/output.txt | 6 +- tests/tests/use_test/first/output.txt | 2 +- tests/tests/use_test/replace_fail/diff.diff | 0 tests/tests/use_test/replace_fail/input.txt | 2 + tests/tests/use_test/replace_fail/output.txt | 1329 ++++++++++++++++++ tests/tests/use_test/second/output.txt | 2 +- 10 files changed, 1354 insertions(+), 12 deletions(-) create mode 100644 tests/tests/use_test/replace_fail/diff.diff create mode 100644 tests/tests/use_test/replace_fail/input.txt create mode 100644 tests/tests/use_test/replace_fail/output.txt diff --git a/src/main.rs b/src/main.rs index 33f1d3642..286b1bfb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ use rustfix::{Suggestion, Replacement}; use rustfix::diagnostics::Diagnostic; const USER_OPTIONS: &'static str = "What do you want to do? \ - [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving)"; + [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; fn main() { let program = try_main(); @@ -189,6 +189,17 @@ fn handle_suggestions( "a" => { return Err(ProgramError::UserAbort); } + "r" => { + if suggestion.solutions.len() == 1 && suggestion.solutions[0].replacements.len() == 1 { + let mut solutions = suggestion.solutions; + accepted_suggestions.push(solutions.remove(0).replacements.remove(0)); + println!("Suggestion accepted. I'll remember that and apply it later."); + continue 'suggestions; + } else { + println!("{error}: multiple suggestions apply, please pick a number", + error = "Error".red().bold()); + } + } s => { if let Ok(i) = usize::from_str(s) { let replacement = suggestion.solutions diff --git a/tests/tests/libui-rs/simple/input.txt b/tests/tests/libui-rs/simple/input.txt index a7edde121..ced652ef7 100644 --- a/tests/tests/libui-rs/simple/input.txt +++ b/tests/tests/libui-rs/simple/input.txt @@ -1,3 +1,3 @@ -0 -0 +r +r q diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index 943534328..e3ba217da 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -13,7 +13,7 @@ try &mut *(data as *mut Box) -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -30,7 +30,7 @@ try &mut *(data as *mut Box) -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -53,7 +53,7 @@ try this -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 2 changes! .. diff --git a/tests/tests/libui-rs/skipping/input.txt b/tests/tests/libui-rs/skipping/input.txt index d999fa2ff..0bfd421ef 100644 --- a/tests/tests/libui-rs/skipping/input.txt +++ b/tests/tests/libui-rs/skipping/input.txt @@ -1,3 +1,3 @@ -0 +r s q diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index dd62a1103..913213ba6 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -13,7 +13,7 @@ try &mut *(data as *mut Box) -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -30,7 +30,7 @@ try &mut *(data as *mut Box) -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Skipped. @@ -53,7 +53,7 @@ try this -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 1 changes! . diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt index 3ec1610b7..12da73809 100644 --- a/tests/tests/use_test/first/output.txt +++ b/tests/tests/use_test/first/output.txt @@ -1323,7 +1323,7 @@ possible candidates are found in other modules, you can import them into scope -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Good work. Let me just apply these 1 changes! . diff --git a/tests/tests/use_test/replace_fail/diff.diff b/tests/tests/use_test/replace_fail/diff.diff new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/use_test/replace_fail/input.txt b/tests/tests/use_test/replace_fail/input.txt new file mode 100644 index 000000000..fd05cbef8 --- /dev/null +++ b/tests/tests/use_test/replace_fail/input.txt @@ -0,0 +1,2 @@ +r +a diff --git a/tests/tests/use_test/replace_fail/output.txt b/tests/tests/use_test/replace_fail/output.txt new file mode 100644 index 000000000..f5f1cdb01 --- /dev/null +++ b/tests/tests/use_test/replace_fail/output.txt @@ -0,0 +1,1329 @@ + + +Info: cannot find type `Iter` in this scope + --> src/lib.rs:2:12-2:16 + +possible candidates are found in other modules, you can import them into scope +[0]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[1]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[2]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[3]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[4]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[5]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[6]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[7]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[8]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[9]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[10]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[11]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[12]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[13]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[14]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[15]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[16]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[17]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[18]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[19]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[20]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[21]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[22]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[23]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[24]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[25]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[26]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[27]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[28]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[29]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[30]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[31]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[32]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[33]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[34]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[35]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[36]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[37]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[38]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[39]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[40]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[41]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[42]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[43]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[44]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[45]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[46]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[47]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[48]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[49]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[50]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[51]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[52]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[53]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[54]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[55]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[56]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[57]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[58]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[59]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[60]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[61]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[62]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[63]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[64]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[65]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[66]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[67]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[68]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[69]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[70]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[71]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[72]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[73]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[74]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[75]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[76]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[77]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[78]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[79]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[80]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[81]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[82]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[83]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[84]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[85]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[86]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[87]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[88]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[89]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[90]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[91]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[92]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[93]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[94]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[95]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[96]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[97]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[98]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[99]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[100]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[101]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[102]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[103]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[104]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[105]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[106]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[107]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[108]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[109]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[110]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[111]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[112]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[113]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[114]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[115]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[116]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[117]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[118]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[119]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[120]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[121]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[122]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[123]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[124]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[125]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[126]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[127]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[128]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[129]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[130]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[131]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +possible candidates are found in other modules, you can import them into scope +[132]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::binary_heap::Iter; + + +[133]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_map::Iter; + + +[134]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::btree_set::Iter; + + +[135]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_map::Iter; + + +[136]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::hash_set::Iter; + + +[137]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::linked_list::Iter; + + +[138]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::collections::vec_deque::Iter; + + +[139]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::option::Iter; + + +[140]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::path::Iter; + + +[141]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::result::Iter; + + +[142]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::slice::Iter; + + +[143]: Suggestion - Replace: + +pub fn foo() { + +with: + + use std::sync::mpsc::Iter; + + + +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Error: multiple suggestions apply, please pick a number +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) + > Let's get outta here! diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt index 3ec1610b7..12da73809 100644 --- a/tests/tests/use_test/second/output.txt +++ b/tests/tests/use_test/second/output.txt @@ -1323,7 +1323,7 @@ possible candidates are found in other modules, you can import them into scope -==> What do you want to do? [0-9] replace | [s]kip | save and [q]uit | [a]bort (without saving) +==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Good work. Let me just apply these 1 changes! . From 3d6bfe4fff7a3fdfc96ca1fc2cdc17a65109ff18 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 09:10:17 +0100 Subject: [PATCH 070/298] Update output to latest rustc changes (no quadratic reports) --- tests/tests/use_test/first/output.txt | 1210 ------------------ tests/tests/use_test/replace_fail/output.txt | 1210 ------------------ tests/tests/use_test/second/output.txt | 1210 ------------------ 3 files changed, 3630 deletions(-) diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt index 12da73809..0fb5d12d4 100644 --- a/tests/tests/use_test/first/output.txt +++ b/tests/tests/use_test/first/output.txt @@ -113,1216 +113,6 @@ possible candidates are found in other modules, you can import them into scope -possible candidates are found in other modules, you can import them into scope -[12]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[13]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[14]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[15]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[16]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[17]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[18]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[19]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[20]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[21]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[22]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[23]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[24]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[25]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[26]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[27]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[28]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[29]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[30]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[31]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[32]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[33]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[34]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[35]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[36]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[37]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[38]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[39]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[40]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[41]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[42]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[43]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[44]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[45]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[46]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[47]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[48]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[49]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[50]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[51]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[52]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[53]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[54]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[55]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[56]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[57]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[58]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[59]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[60]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[61]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[62]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[63]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[64]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[65]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[66]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[67]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[68]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[69]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[70]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[71]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[72]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[73]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[74]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[75]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[76]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[77]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[78]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[79]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[80]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[81]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[82]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[83]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[84]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[85]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[86]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[87]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[88]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[89]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[90]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[91]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[92]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[93]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[94]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[95]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[96]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[97]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[98]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[99]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[100]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[101]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[102]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[103]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[104]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[105]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[106]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[107]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[108]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[109]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[110]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[111]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[112]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[113]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[114]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[115]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[116]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[117]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[118]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[119]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[120]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[121]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[122]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[123]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[124]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[125]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[126]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[127]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[128]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[129]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[130]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[131]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[132]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[133]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[134]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[135]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[136]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[137]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[138]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[139]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[140]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[141]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[142]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[143]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Good work. Let me just apply these 1 changes! diff --git a/tests/tests/use_test/replace_fail/output.txt b/tests/tests/use_test/replace_fail/output.txt index f5f1cdb01..c8743fc68 100644 --- a/tests/tests/use_test/replace_fail/output.txt +++ b/tests/tests/use_test/replace_fail/output.txt @@ -113,1216 +113,6 @@ possible candidates are found in other modules, you can import them into scope -possible candidates are found in other modules, you can import them into scope -[12]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[13]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[14]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[15]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[16]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[17]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[18]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[19]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[20]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[21]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[22]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[23]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[24]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[25]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[26]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[27]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[28]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[29]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[30]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[31]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[32]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[33]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[34]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[35]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[36]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[37]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[38]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[39]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[40]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[41]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[42]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[43]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[44]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[45]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[46]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[47]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[48]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[49]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[50]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[51]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[52]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[53]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[54]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[55]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[56]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[57]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[58]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[59]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[60]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[61]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[62]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[63]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[64]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[65]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[66]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[67]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[68]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[69]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[70]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[71]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[72]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[73]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[74]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[75]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[76]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[77]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[78]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[79]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[80]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[81]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[82]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[83]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[84]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[85]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[86]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[87]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[88]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[89]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[90]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[91]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[92]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[93]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[94]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[95]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[96]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[97]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[98]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[99]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[100]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[101]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[102]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[103]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[104]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[105]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[106]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[107]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[108]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[109]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[110]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[111]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[112]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[113]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[114]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[115]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[116]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[117]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[118]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[119]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[120]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[121]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[122]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[123]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[124]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[125]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[126]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[127]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[128]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[129]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[130]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[131]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[132]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[133]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[134]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[135]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[136]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[137]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[138]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[139]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[140]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[141]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[142]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[143]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Error: multiple suggestions apply, please pick a number ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt index 12da73809..0fb5d12d4 100644 --- a/tests/tests/use_test/second/output.txt +++ b/tests/tests/use_test/second/output.txt @@ -113,1216 +113,6 @@ possible candidates are found in other modules, you can import them into scope -possible candidates are found in other modules, you can import them into scope -[12]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[13]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[14]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[15]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[16]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[17]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[18]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[19]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[20]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[21]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[22]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[23]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[24]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[25]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[26]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[27]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[28]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[29]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[30]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[31]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[32]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[33]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[34]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[35]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[36]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[37]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[38]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[39]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[40]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[41]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[42]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[43]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[44]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[45]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[46]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[47]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[48]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[49]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[50]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[51]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[52]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[53]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[54]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[55]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[56]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[57]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[58]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[59]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[60]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[61]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[62]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[63]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[64]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[65]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[66]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[67]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[68]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[69]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[70]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[71]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[72]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[73]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[74]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[75]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[76]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[77]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[78]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[79]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[80]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[81]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[82]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[83]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[84]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[85]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[86]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[87]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[88]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[89]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[90]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[91]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[92]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[93]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[94]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[95]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[96]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[97]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[98]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[99]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[100]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[101]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[102]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[103]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[104]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[105]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[106]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[107]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[108]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[109]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[110]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[111]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[112]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[113]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[114]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[115]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[116]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[117]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[118]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[119]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[120]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[121]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[122]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[123]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[124]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[125]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[126]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[127]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[128]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[129]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[130]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[131]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - -possible candidates are found in other modules, you can import them into scope -[132]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[133]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[134]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[135]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[136]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[137]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[138]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[139]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[140]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[141]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[142]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[143]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. Good work. Let me just apply these 1 changes! From 710b45234551a98ac291f2454a995eefa94618ce Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 10:03:38 +0100 Subject: [PATCH 071/298] Add flag to only apply certain lints/errors' suggestions --- src/diagnostics.rs | 6 +++--- src/lib.rs | 15 ++++++++++++++- src/main.rs | 24 +++++++++++++++++++++++- tests/fixtures.rs | 24 +++++++++++++++++------- tests/tests/libui-rs/simple/args.txt | 1 + tests/tests/libui-rs/skipping/args.txt | 1 + tests/tests/libui-rs/yolo/args.txt | 1 + 7 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 tests/tests/libui-rs/simple/args.txt create mode 100644 tests/tests/libui-rs/skipping/args.txt create mode 100644 tests/tests/libui-rs/yolo/args.txt diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c6af23340..d0640b680 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,7 +6,7 @@ pub struct Diagnostic { /// The primary error message. pub message: String, - code: Option, + pub code: Option, /// "error: internal compiler error", "error", "warning", "note", "help". level: String, pub spans: Vec, @@ -70,9 +70,9 @@ struct DiagnosticSpanMacroExpansion { } #[derive(Deserialize, Debug)] -struct DiagnosticCode { +pub struct DiagnosticCode { /// The code itself. - code: String, + pub code: String, /// An explanation for the code. explanation: Option, } diff --git a/src/lib.rs b/src/lib.rs index dc0caccab..a984a4a82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ extern crate serde_derive; extern crate serde_json; +use std::collections::HashSet; + pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; @@ -106,7 +108,18 @@ fn collect_span(span: &DiagnosticSpan) -> Option { }) } -pub fn collect_suggestions(diagnostic: &Diagnostic) -> Option { +pub fn collect_suggestions(diagnostic: &Diagnostic, only: &Option>) -> Option { + if let Some(ref set) = *only { + if let Some(ref code) = diagnostic.code { + if !set.contains(&code.code) { + // This is not the code we are looking for + return None; + } + } else { + // No code, probably a weird builtin warning/error + return None; + } + } let snippets = diagnostic.spans .iter() diff --git a/src/main.rs b/src/main.rs index 286b1bfb4..5b2baf792 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use std::fs::File; use std::io::{Read, Write}; use std::error::Error; use std::process::Command; +use std::collections::HashSet; use colored::Colorize; use clap::{Arg, App}; @@ -48,6 +49,11 @@ macro_rules! flush { () => (try!(std::io::stdout().flush());) } +/// A list of `--only` aliases +const ALIAS: &[(&str, &[&str])] = &[ + ("use", &["E0412"]), +]; + fn try_main() -> Result<(), ProgramError> { let matches = App::new("rustfix") .about("Automatically apply suggestions made by rustc") @@ -58,6 +64,10 @@ fn try_main() -> Result<(), ProgramError> { .arg(Arg::with_name("yolo") .long("yolo") .help("Automatically apply all unambiguous suggestions")) + .arg(Arg::with_name("only") + .long("only") + .help("Only show errors or lints with the specific id(s) (comma separated)") + .use_delimiter(true)) .get_matches(); let mut extra_args = Vec::new(); @@ -72,6 +82,18 @@ fn try_main() -> Result<(), ProgramError> { AutofixMode::None }; + let mut only: Option> = matches.values_of("only").map(|values| values.map(|s| s.to_string()).collect()); + + if let Some(ref mut set) = only { + for alias in ALIAS { + if set.remove(alias.0) { + for alias in alias.1 { + set.insert(alias.to_string()); + } + } + } + } + // Get JSON output from rustc... let json = get_json(&extra_args)?; @@ -80,7 +102,7 @@ fn try_main() -> Result<(), ProgramError> { // Convert JSON string (and eat parsing errors) .flat_map(|line| serde_json::from_str::(line)) // One diagnostic line might have multiple suggestions - .filter_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message)) + .filter_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, &only)) .collect(); try!(handle_suggestions(suggestions, mode)); diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 2373994d9..2b6b8e659 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -1,7 +1,8 @@ #[macro_use] extern crate duct; -use std::io::{BufReader, BufRead}; +use std::io::{BufReader, BufRead, Read}; +use std::fs::File; #[test] fn fixtures() { @@ -32,7 +33,6 @@ fn fixtures() { for entry in tests { let test = entry.unwrap().path(); - let yolo = test.file_name().unwrap() == "yolo"; println!("Running test: {}", test.file_name().unwrap().to_str().unwrap()); @@ -47,11 +47,21 @@ fn fixtures() { println!("Running cargo clippy to obtain suggestions"); let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); - let cmd = if yolo { - cmd!("cargo", "run", manifest, "--bin", "rustfix", "--quiet", "--", "--clippy", "--yolo") - } else { - cmd!("cargo", "run", manifest, "--bin", "rustfix", "--quiet", "--", "--clippy") - }; + let mut args = vec![ + "run".to_owned(), + manifest, + "--bin".to_owned(), + "rustfix".to_owned(), + "--quiet".to_owned(), + "--".to_owned(), + "--clippy".to_owned(), + ]; + if let Ok(mut file) = File::open(test.join("args.txt")) { + let mut extra_args = String::new(); + file.read_to_string(&mut extra_args).unwrap(); + args.extend(extra_args.split_whitespace().map(|s| s.to_string())); + } + let cmd = duct::cmd("cargo", args); cmd.dir(&dir) .stdin(test.join("input.txt")) .stdout(dir.join("output.txt")) diff --git a/tests/tests/libui-rs/simple/args.txt b/tests/tests/libui-rs/simple/args.txt new file mode 100644 index 000000000..2e618abd4 --- /dev/null +++ b/tests/tests/libui-rs/simple/args.txt @@ -0,0 +1 @@ +--only transmute_ptr_to_ref,new_without_default diff --git a/tests/tests/libui-rs/skipping/args.txt b/tests/tests/libui-rs/skipping/args.txt new file mode 100644 index 000000000..2e618abd4 --- /dev/null +++ b/tests/tests/libui-rs/skipping/args.txt @@ -0,0 +1 @@ +--only transmute_ptr_to_ref,new_without_default diff --git a/tests/tests/libui-rs/yolo/args.txt b/tests/tests/libui-rs/yolo/args.txt new file mode 100644 index 000000000..cfa7251bc --- /dev/null +++ b/tests/tests/libui-rs/yolo/args.txt @@ -0,0 +1 @@ +--yolo --only transmute_ptr_to_ref,new_without_default From 2a3258f3c5c8aaa114094cb65a721ea20538d907 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 14:35:00 +0100 Subject: [PATCH 072/298] Address PR comments --- src/lib.rs | 6 +++--- src/main.rs | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a984a4a82..c4e4e3a79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,10 +108,10 @@ fn collect_span(span: &DiagnosticSpan) -> Option { }) } -pub fn collect_suggestions(diagnostic: &Diagnostic, only: &Option>) -> Option { - if let Some(ref set) = *only { +pub fn collect_suggestions(diagnostic: &Diagnostic, only: &HashSet) -> Option { + if !only.is_empty() { if let Some(ref code) = diagnostic.code { - if !set.contains(&code.code) { + if !only.contains(&code.code) { // This is not the code we are looking for return None; } diff --git a/src/main.rs b/src/main.rs index 5b2baf792..a5a2dcc1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ macro_rules! flush { } /// A list of `--only` aliases -const ALIAS: &[(&str, &[&str])] = &[ +const ALIASES: &[(&str, &[&str])] = &[ ("use", &["E0412"]), ]; @@ -82,14 +82,16 @@ fn try_main() -> Result<(), ProgramError> { AutofixMode::None }; - let mut only: Option> = matches.values_of("only").map(|values| values.map(|s| s.to_string()).collect()); + let mut only: HashSet = matches + .values_of("only") + .map_or(HashSet::new(), |values| { + values.map(ToString::to_string).collect() + }); - if let Some(ref mut set) = only { - for alias in ALIAS { - if set.remove(alias.0) { - for alias in alias.1 { - set.insert(alias.to_string()); - } + for alias in ALIASES { + if only.remove(alias.0) { + for alias in alias.1 { + only.insert(alias.to_string()); } } } From fd52be033b277811191186c01636b8421a6b66ec Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 11:19:02 +0100 Subject: [PATCH 073/298] Fold multiple suggestions into a list instead of repeating everything --- src/main.rs | 57 +++++++-- tests/tests/libui-rs/simple/output.txt | 15 +-- tests/tests/libui-rs/skipping/output.txt | 15 +-- tests/tests/libui-rs/yolo/output.txt | 102 +++++++--------- tests/tests/use_test/first/output.txt | 121 ++----------------- tests/tests/use_test/replace_fail/output.txt | 121 ++----------------- tests/tests/use_test/second/output.txt | 121 ++----------------- 7 files changed, 138 insertions(+), 414 deletions(-) diff --git a/src/main.rs b/src/main.rs index a5a2dcc1c..e45b451da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -139,6 +139,35 @@ enum AutofixMode { Yolo, } +fn prelude(suggestion: &Replacement) { + let snippet = &suggestion.snippet; + if snippet.text.1.is_empty() { + if suggestion.replacement.ends_with('\n') || suggestion.replacement.starts_with('\n') { + println!("{}", "Insert line:".yellow().bold()); + } else { + println!("{}", "At:".yellow().bold()); + println!( + "{lead}{text}{tail}", + lead = indent(4, &snippet.text.0), + text = "⍉".red(), + tail = snippet.text.2, + ); + println!("{}\n", indent(snippet.text.0.len() as u32, "^").red()); + println!("{}\n", "insert:".yellow().bold()); + } + } else { + println!("{}\n", "Replace:".yellow().bold()); + println!( + "{lead}{text}{tail}\n\n\ + {with}\n", + with = "with:".yellow().bold(), + lead = indent(4, &snippet.text.0), + text = snippet.text.1.red(), + tail = snippet.text.2, + ); + } +} + fn handle_suggestions( suggestions: Vec, mode: AutofixMode, @@ -164,19 +193,23 @@ fn handle_suggestions( let mut i = 0; for solution in suggestion.solutions.iter() { println!("\n{}", solution.message); + + // check whether we can squash all suggestions into a list + if solution.replacements.len() > 1 { + let first = solution.replacements[0].clone(); + if solution.replacements.iter().all(|s| first.snippet.file_name == s.snippet.file_name && first.snippet.line_range == s.snippet.line_range) { + prelude(&first); + for suggestion in solution.replacements.iter() { + println!("[{}]: {}", i, suggestion.replacement.trim()); + i += 1; + } + continue; + } + } for suggestion in solution.replacements.iter() { - let snippet = &suggestion.snippet; - println!("[{id}]: {suggestion}\n\n\ - {lead}{text}{tail}\n\n\ - {with}\n\n\ - {replacement}\n", - id = i, - suggestion = "Suggestion - Replace:".yellow().bold(), - lead = indent(4, &snippet.text.0), - text = snippet.text.1.red(), - tail = snippet.text.2, - with = "with:".yellow().bold(), - replacement = indent(4, &suggestion.replacement)); + print!("[{}]: ", i); + prelude(&suggestion); + println!("{}", indent(4, &suggestion.replacement)); i += 1; } } diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index e3ba217da..f7cf90438 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -4,7 +4,7 @@  --> src/controls.rs:245:17-245:78 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -12,7 +12,6 @@ try &mut *(data as *mut Box) - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -21,7 +20,7 @@ try  --> src/controls.rs:350:17-350:77 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -29,7 +28,6 @@ try &mut *(data as *mut Box) - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -38,11 +36,11 @@ try  --> src/controls.rs:373:5-378:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> Entry { +^ -pub fn new() -> Entry { - -with: +insert: impl Default for controls::Entry { fn default() -> Self { @@ -52,7 +50,6 @@ try this - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 2 changes! diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index 913213ba6..a79288084 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -4,7 +4,7 @@  --> src/controls.rs:245:17-245:78 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -12,7 +12,6 @@ try &mut *(data as *mut Box) - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. @@ -21,7 +20,7 @@ try  --> src/controls.rs:350:17-350:77 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -29,7 +28,6 @@ try &mut *(data as *mut Box) - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Skipped. @@ -38,11 +36,11 @@ try  --> src/controls.rs:373:5-378:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> Entry { +^ -pub fn new() -> Entry { - -with: +insert: impl Default for controls::Entry { fn default() -> Self { @@ -52,7 +50,6 @@ try this - ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Thanks for playing! Good work. Let me just apply these 1 changes! diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index fac4dac40..ff8521979 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -4,7 +4,7 @@  --> src/controls.rs:245:17-245:78 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&button) @@ -12,7 +12,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -20,7 +19,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:350:17-350:77 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&entry); @@ -28,7 +27,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -36,11 +34,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:373:5-378:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> Entry { +^ -pub fn new() -> Entry { - -with: +insert: impl Default for controls::Entry { fn default() -> Self { @@ -50,7 +48,6 @@ try this - automatically applying suggestion (--yolo) @@ -58,7 +55,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:415:17-415:80 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); @@ -66,7 +63,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -74,11 +70,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:526:5-531:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> Tab { +^ -pub fn new() -> Tab { - -with: +insert: impl Default for controls::Tab { fn default() -> Self { @@ -88,7 +84,6 @@ try this - automatically applying suggestion (--yolo) @@ -96,7 +91,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:621:17-621:79 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); @@ -104,7 +99,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -112,11 +106,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:648:5-653:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> ProgressBar { +^ -pub fn new() -> ProgressBar { - -with: +insert: impl Default for controls::ProgressBar { fn default() -> Self { @@ -126,7 +120,6 @@ try this - automatically applying suggestion (--yolo) @@ -134,7 +127,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:689:17-689:78 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&slider); @@ -142,7 +135,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -150,7 +142,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:758:17-758:80 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); @@ -158,7 +150,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -166,11 +157,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:765:5-770:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> Combobox { +^ -pub fn new() -> Combobox { - -with: +insert: impl Default for controls::Combobox { fn default() -> Self { @@ -180,7 +171,6 @@ try this - automatically applying suggestion (--yolo) @@ -188,11 +178,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:796:5-801:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> RadioButtons { +^ -pub fn new() -> RadioButtons { - -with: +insert: impl Default for controls::RadioButtons { fn default() -> Self { @@ -202,7 +192,6 @@ try this - automatically applying suggestion (--yolo) @@ -210,7 +199,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:866:17-867:73 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&multiline_entry); @@ -219,7 +208,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -227,11 +215,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:890:5-895:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> MultilineEntry { +^ -pub fn new() -> MultilineEntry { - -with: +insert: impl Default for controls::MultilineEntry { fn default() -> Self { @@ -241,7 +229,6 @@ try this - automatically applying suggestion (--yolo) @@ -249,7 +236,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:1182:17-1182:82 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); @@ -257,7 +244,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -265,11 +251,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:1189:5-1194:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> FontButton { +^ -pub fn new() -> FontButton { - -with: +insert: impl Default for controls::FontButton { fn default() -> Self { @@ -279,7 +265,6 @@ try this - automatically applying suggestion (--yolo) @@ -287,7 +272,7 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:1237:17-1237:83 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); @@ -295,7 +280,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) @@ -303,11 +287,11 @@ automatically applying suggestion (--yolo)  --> src/controls.rs:1244:5-1249:6 try this -[0]: Suggestion - Replace: +[0]: At: +⍉pub fn new() -> ColorButton { +^ -pub fn new() -> ColorButton { - -with: +insert: impl Default for controls::ColorButton { fn default() -> Self { @@ -317,7 +301,6 @@ try this - automatically applying suggestion (--yolo) @@ -325,7 +308,7 @@ automatically applying suggestion (--yolo)  --> src/menus.rs:50:17-51:76 try -[0]: Suggestion - Replace: +[0]: Replace: mem::transmute::<*mut c_void, &mut Box>(data)(&menu_item, &window); @@ -334,7 +317,6 @@ try &mut *(data as *mut Box) - automatically applying suggestion (--yolo) Good work. Let me just apply these 18 changes! .................. diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt index 0fb5d12d4..0a6510398 100644 --- a/tests/tests/use_test/first/output.txt +++ b/tests/tests/use_test/first/output.txt @@ -4,114 +4,19 @@  --> src/lib.rs:2:12-2:16 possible candidates are found in other modules, you can import them into scope -[0]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[1]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[2]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[3]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[4]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[5]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[6]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[7]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[8]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[9]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[10]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[11]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - +Insert line: +[0]: use std::collections::binary_heap::Iter; +[1]: use std::collections::btree_map::Iter; +[2]: use std::collections::btree_set::Iter; +[3]: use std::collections::hash_map::Iter; +[4]: use std::collections::hash_set::Iter; +[5]: use std::collections::linked_list::Iter; +[6]: use std::collections::vec_deque::Iter; +[7]: use std::option::Iter; +[8]: use std::path::Iter; +[9]: use std::result::Iter; +[10]: use std::slice::Iter; +[11]: use std::sync::mpsc::Iter; ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. diff --git a/tests/tests/use_test/replace_fail/output.txt b/tests/tests/use_test/replace_fail/output.txt index c8743fc68..4beed7939 100644 --- a/tests/tests/use_test/replace_fail/output.txt +++ b/tests/tests/use_test/replace_fail/output.txt @@ -4,114 +4,19 @@  --> src/lib.rs:2:12-2:16 possible candidates are found in other modules, you can import them into scope -[0]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[1]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[2]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[3]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[4]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[5]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[6]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[7]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[8]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[9]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[10]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[11]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - +Insert line: +[0]: use std::collections::binary_heap::Iter; +[1]: use std::collections::btree_map::Iter; +[2]: use std::collections::btree_set::Iter; +[3]: use std::collections::hash_map::Iter; +[4]: use std::collections::hash_set::Iter; +[5]: use std::collections::linked_list::Iter; +[6]: use std::collections::vec_deque::Iter; +[7]: use std::option::Iter; +[8]: use std::path::Iter; +[9]: use std::result::Iter; +[10]: use std::slice::Iter; +[11]: use std::sync::mpsc::Iter; ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Error: multiple suggestions apply, please pick a number diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt index 0fb5d12d4..0a6510398 100644 --- a/tests/tests/use_test/second/output.txt +++ b/tests/tests/use_test/second/output.txt @@ -4,114 +4,19 @@  --> src/lib.rs:2:12-2:16 possible candidates are found in other modules, you can import them into scope -[0]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::binary_heap::Iter; - - -[1]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_map::Iter; - - -[2]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::btree_set::Iter; - - -[3]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_map::Iter; - - -[4]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::hash_set::Iter; - - -[5]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::linked_list::Iter; - - -[6]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::collections::vec_deque::Iter; - - -[7]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::option::Iter; - - -[8]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::path::Iter; - - -[9]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::result::Iter; - - -[10]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::slice::Iter; - - -[11]: Suggestion - Replace: - -pub fn foo() { - -with: - - use std::sync::mpsc::Iter; - - +Insert line: +[0]: use std::collections::binary_heap::Iter; +[1]: use std::collections::btree_map::Iter; +[2]: use std::collections::btree_set::Iter; +[3]: use std::collections::hash_map::Iter; +[4]: use std::collections::hash_set::Iter; +[5]: use std::collections::linked_list::Iter; +[6]: use std::collections::vec_deque::Iter; +[7]: use std::option::Iter; +[8]: use std::path::Iter; +[9]: use std::result::Iter; +[10]: use std::slice::Iter; +[11]: use std::sync::mpsc::Iter; ==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)  > Suggestion accepted. I'll remember that and apply it later. From 748f1ee56b845b1986f96fddcfb19ab060bdfaf4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 19:06:31 +0100 Subject: [PATCH 074/298] Address PR comments --- src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index e45b451da..c191d3e42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -142,6 +142,7 @@ enum AutofixMode { fn prelude(suggestion: &Replacement) { let snippet = &suggestion.snippet; if snippet.text.1.is_empty() { + // Check whether this suggestion wants to be inserted before or after another line if suggestion.replacement.ends_with('\n') || suggestion.replacement.starts_with('\n') { println!("{}", "Insert line:".yellow().bold()); } else { @@ -197,7 +198,12 @@ fn handle_suggestions( // check whether we can squash all suggestions into a list if solution.replacements.len() > 1 { let first = solution.replacements[0].clone(); - if solution.replacements.iter().all(|s| first.snippet.file_name == s.snippet.file_name && first.snippet.line_range == s.snippet.line_range) { + let all_suggestions_replace_the_same_span = solution + .replacements + .iter() + .all(|s| first.snippet.file_name == s.snippet.file_name + && first.snippet.line_range == s.snippet.line_range); + if all_suggestions_replace_the_same_span { prelude(&first); for suggestion in solution.replacements.iter() { println!("[{}]: {}", i, suggestion.replacement.trim()); @@ -206,7 +212,7 @@ fn handle_suggestions( continue; } } - for suggestion in solution.replacements.iter() { + for suggestion in &solution.replacements { print!("[{}]: ", i); prelude(&suggestion); println!("{}", indent(4, &suggestion.replacement)); From e8f7dbe5bb4c487be0fb944810aeb525cbadc436 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Nov 2017 20:43:44 +0100 Subject: [PATCH 075/298] oblivionsly --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index c191d3e42..efa211a6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,7 +143,9 @@ fn prelude(suggestion: &Replacement) { let snippet = &suggestion.snippet; if snippet.text.1.is_empty() { // Check whether this suggestion wants to be inserted before or after another line - if suggestion.replacement.ends_with('\n') || suggestion.replacement.starts_with('\n') { + let wants_to_be_on_own_line = suggestion.replacement.ends_with('\n') + || suggestion.replacement.starts_with('\n'); + if wants_to_be_on_own_line { println!("{}", "Insert line:".yellow().bold()); } else { println!("{}", "At:".yellow().bold()); From a601912c31ec4c2aa7b16d3fe4df906b848319ca Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 10 Nov 2017 09:45:02 +0100 Subject: [PATCH 076/298] Update injection symbol --- src/main.rs | 2 +- tests/tests/libui-rs/simple/output.txt | 6 ++-- tests/tests/libui-rs/skipping/output.txt | 6 ++-- tests/tests/libui-rs/yolo/output.txt | 36 ++++++++++++------------ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/main.rs b/src/main.rs index efa211a6a..dcb45d96d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -152,7 +152,7 @@ fn prelude(suggestion: &Replacement) { println!( "{lead}{text}{tail}", lead = indent(4, &snippet.text.0), - text = "⍉".red(), + text = "v".red(), tail = snippet.text.2, ); println!("{}\n", indent(snippet.text.0.len() as u32, "^").red()); diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt index f7cf90438..23762b229 100644 --- a/tests/tests/libui-rs/simple/output.txt +++ b/tests/tests/libui-rs/simple/output.txt @@ -1,6 +1,6 @@ -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 try @@ -16,7 +16,7 @@ try  > Suggestion accepted. I'll remember that and apply it later. -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 try @@ -37,7 +37,7 @@ try try this [0]: At: -⍉pub fn new() -> Entry { +vpub fn new() -> Entry { ^ insert: diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt index a79288084..e7f1b1420 100644 --- a/tests/tests/libui-rs/skipping/output.txt +++ b/tests/tests/libui-rs/skipping/output.txt @@ -1,6 +1,6 @@ -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 try @@ -16,7 +16,7 @@ try  > Suggestion accepted. I'll remember that and apply it later. -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 try @@ -37,7 +37,7 @@ try try this [0]: At: -⍉pub fn new() -> Entry { +vpub fn new() -> Entry { ^ insert: diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt index ff8521979..fc479ff76 100644 --- a/tests/tests/libui-rs/yolo/output.txt +++ b/tests/tests/libui-rs/yolo/output.txt @@ -1,6 +1,6 @@ -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Button)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`)  --> src/controls.rs:245:17-245:78 try @@ -15,7 +15,7 @@ try automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Entry)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`)  --> src/controls.rs:350:17-350:77 try @@ -35,7 +35,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> Entry { +vpub fn new() -> Entry { ^ insert: @@ -51,7 +51,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Checkbox)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Checkbox)>`)  --> src/controls.rs:415:17-415:80 try @@ -71,7 +71,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> Tab { +vpub fn new() -> Tab { ^ insert: @@ -87,7 +87,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Spinbox)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Spinbox)>`)  --> src/controls.rs:621:17-621:79 try @@ -107,7 +107,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> ProgressBar { +vpub fn new() -> ProgressBar { ^ insert: @@ -123,7 +123,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Slider)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Slider)>`)  --> src/controls.rs:689:17-689:78 try @@ -138,7 +138,7 @@ try automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::Combobox)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Combobox)>`)  --> src/controls.rs:758:17-758:80 try @@ -158,7 +158,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> Combobox { +vpub fn new() -> Combobox { ^ insert: @@ -179,7 +179,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> RadioButtons { +vpub fn new() -> RadioButtons { ^ insert: @@ -195,7 +195,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::MultilineEntry)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::MultilineEntry)>`)  --> src/controls.rs:866:17-867:73 try @@ -216,7 +216,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> MultilineEntry { +vpub fn new() -> MultilineEntry { ^ insert: @@ -232,7 +232,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::FontButton)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::FontButton)>`)  --> src/controls.rs:1182:17-1182:82 try @@ -252,7 +252,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> FontButton { +vpub fn new() -> FontButton { ^ insert: @@ -268,7 +268,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r controls::ColorButton)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::ColorButton)>`)  --> src/controls.rs:1237:17-1237:83 try @@ -288,7 +288,7 @@ automatically applying suggestion (--yolo) try this [0]: At: -⍉pub fn new() -> ColorButton { +vpub fn new() -> ColorButton { ^ insert: @@ -304,7 +304,7 @@ try this automatically applying suggestion (--yolo) -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box std::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`) +Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`)  --> src/menus.rs:50:17-51:76 try From c649f6e3d93660d641dad434c181f79ced69015d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 20 Dec 2017 00:45:36 +0100 Subject: [PATCH 077/298] No crate tests no more (for now) --- .gitmodules | 3 - tests/crates/libui-rs | 1 - tests/crates/libui-rs.sub-path | 1 - tests/crates/use_test/Cargo.toml | 6 - tests/crates/use_test/src/lib.rs | 3 - tests/fixtures.rs | 103 ------ tests/tests/libui-rs/simple/args.txt | 1 - tests/tests/libui-rs/simple/diff.diff | 22 -- tests/tests/libui-rs/simple/input.txt | 3 - tests/tests/libui-rs/simple/output.txt | 57 ---- tests/tests/libui-rs/skipping/args.txt | 1 - tests/tests/libui-rs/skipping/diff.diff | 13 - tests/tests/libui-rs/skipping/input.txt | 3 - tests/tests/libui-rs/skipping/output.txt | 57 ---- tests/tests/libui-rs/yolo/args.txt | 1 - tests/tests/libui-rs/yolo/diff.diff | 201 ------------ tests/tests/libui-rs/yolo/input.txt | 0 tests/tests/libui-rs/yolo/output.txt | 323 ------------------- tests/tests/use_test/first/diff.diff | 11 - tests/tests/use_test/first/input.txt | 1 - tests/tests/use_test/first/output.txt | 25 -- tests/tests/use_test/replace_fail/diff.diff | 0 tests/tests/use_test/replace_fail/input.txt | 2 - tests/tests/use_test/replace_fail/output.txt | 24 -- tests/tests/use_test/second/diff.diff | 11 - tests/tests/use_test/second/input.txt | 1 - tests/tests/use_test/second/output.txt | 25 -- 27 files changed, 899 deletions(-) delete mode 160000 tests/crates/libui-rs delete mode 100644 tests/crates/libui-rs.sub-path delete mode 100644 tests/crates/use_test/Cargo.toml delete mode 100644 tests/crates/use_test/src/lib.rs delete mode 100644 tests/fixtures.rs delete mode 100644 tests/tests/libui-rs/simple/args.txt delete mode 100644 tests/tests/libui-rs/simple/diff.diff delete mode 100644 tests/tests/libui-rs/simple/input.txt delete mode 100644 tests/tests/libui-rs/simple/output.txt delete mode 100644 tests/tests/libui-rs/skipping/args.txt delete mode 100644 tests/tests/libui-rs/skipping/diff.diff delete mode 100644 tests/tests/libui-rs/skipping/input.txt delete mode 100644 tests/tests/libui-rs/skipping/output.txt delete mode 100644 tests/tests/libui-rs/yolo/args.txt delete mode 100644 tests/tests/libui-rs/yolo/diff.diff delete mode 100644 tests/tests/libui-rs/yolo/input.txt delete mode 100644 tests/tests/libui-rs/yolo/output.txt delete mode 100644 tests/tests/use_test/first/diff.diff delete mode 100644 tests/tests/use_test/first/input.txt delete mode 100644 tests/tests/use_test/first/output.txt delete mode 100644 tests/tests/use_test/replace_fail/diff.diff delete mode 100644 tests/tests/use_test/replace_fail/input.txt delete mode 100644 tests/tests/use_test/replace_fail/output.txt delete mode 100644 tests/tests/use_test/second/diff.diff delete mode 100644 tests/tests/use_test/second/input.txt delete mode 100644 tests/tests/use_test/second/output.txt diff --git a/.gitmodules b/.gitmodules index 1736dfb52..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "tests/fixtures/libui-rs"] - path = tests/crates/libui-rs - url = https://github.com/pcwalton/libui-rs.git diff --git a/tests/crates/libui-rs b/tests/crates/libui-rs deleted file mode 160000 index 13299d28f..000000000 --- a/tests/crates/libui-rs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 13299d28f69f8009be8e08e453a9b0024f153a60 diff --git a/tests/crates/libui-rs.sub-path b/tests/crates/libui-rs.sub-path deleted file mode 100644 index 2c850c209..000000000 --- a/tests/crates/libui-rs.sub-path +++ /dev/null @@ -1 +0,0 @@ -ui diff --git a/tests/crates/use_test/Cargo.toml b/tests/crates/use_test/Cargo.toml deleted file mode 100644 index b508f265d..000000000 --- a/tests/crates/use_test/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "use_test" -version = "0.1.0" -authors = ["Oliver Schneider "] - -[dependencies] diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs deleted file mode 100644 index 647f90fd6..000000000 --- a/tests/crates/use_test/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn foo() { - let x: Iter; -} diff --git a/tests/fixtures.rs b/tests/fixtures.rs deleted file mode 100644 index 2b6b8e659..000000000 --- a/tests/fixtures.rs +++ /dev/null @@ -1,103 +0,0 @@ -#[macro_use] -extern crate duct; - -use std::io::{BufReader, BufRead, Read}; -use std::fs::File; - -#[test] -fn fixtures() { - // ignore if this fails - let _ = cmd!("cargo", "install", "clippy").stderr_capture().run(); - let root_dir = std::env::current_dir().unwrap(); - - println!("looking for fixtures in directory: {:?}\n", root_dir); - - for fixture in std::fs::read_dir(root_dir.join("tests/crates")).unwrap() { - let fixture = fixture.unwrap(); - if !fixture.file_type().unwrap().is_dir() { - continue; - } - let fixture_path = fixture.path(); - - let files: Vec = std::fs::File::open(fixture_path.with_extension("sub-path")) - .and_then(|file| BufReader::new(file).lines().collect()).unwrap_or_default(); - let dirs = if files.is_empty() { - vec![fixture_path.clone()] - } else { - files.into_iter().map(|file| fixture_path.join(file.trim())).collect() - }; - for dir in dirs { - println!("===================================================================="); - println!("Running tests for {:?}\n", dir); - let tests = std::fs::read_dir(root_dir.join("tests/tests").join(fixture_path.file_name().unwrap())).unwrap(); - - for entry in tests { - let test = entry.unwrap().path(); - - println!("Running test: {}", test.file_name().unwrap().to_str().unwrap()); - - assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); - assert!(cmd!("cargo", "clean").dir(&dir).run().unwrap().status.success()); - // we only want to rustfix the final project, not any dependencies - // we don't care if the final build succeeds, since we're also testing error suggestions - let _ = cmd!("cargo", "build").dir(&dir).stderr_null().stdout_null().run(); - - let manifest = format!("{:?}", root_dir.join("Cargo.toml")); - - println!("Running cargo clippy to obtain suggestions"); - - let manifest = format!("--manifest-path={}", &manifest[1..manifest.len() - 1]); - let mut args = vec![ - "run".to_owned(), - manifest, - "--bin".to_owned(), - "rustfix".to_owned(), - "--quiet".to_owned(), - "--".to_owned(), - "--clippy".to_owned(), - ]; - if let Ok(mut file) = File::open(test.join("args.txt")) { - let mut extra_args = String::new(); - file.read_to_string(&mut extra_args).unwrap(); - args.extend(extra_args.split_whitespace().map(|s| s.to_string())); - } - let cmd = duct::cmd("cargo", args); - cmd.dir(&dir) - .stdin(test.join("input.txt")) - .stdout(dir.join("output.txt")) - .run() - .unwrap(); - - if std::env::var("APPLY_RUSTFIX").is_ok() { - std::fs::copy(dir.join("output.txt"), test.join("output.txt")).unwrap(); - - cmd!("git", "diff", ".").dir(&dir).stdout(test.join("diff.diff")).run().unwrap(); - } else { - cmd!("git", "diff", ".").dir(&dir).stdout(dir.join("diff.diff")).run().unwrap(); - - let diff = cmd!("diff", dir.join("diff.diff"), test.join("diff.diff")) - .dir(&dir) - .stdout_capture() - .unchecked() - .run().unwrap(); - if !diff.status.success() { - panic!("Unexpected changes by rustfix:\n{}", std::str::from_utf8(&diff.stdout).unwrap()); - } - - let output = cmd!("diff", dir.join("output.txt"), test.join("output.txt")) - .dir(&dir) - .stdout_capture() - .unchecked() - .run().unwrap(); - if !output.status.success() { - panic!("Unexpected output by rustfix:\n{}", std::str::from_utf8(&output.stdout).unwrap()); - } - } - - assert!(cmd!("git", "checkout", ".").dir(&dir).run().unwrap().status.success()); - - println!("Success!\n"); - } - } - } -} diff --git a/tests/tests/libui-rs/simple/args.txt b/tests/tests/libui-rs/simple/args.txt deleted file mode 100644 index 2e618abd4..000000000 --- a/tests/tests/libui-rs/simple/args.txt +++ /dev/null @@ -1 +0,0 @@ ---only transmute_ptr_to_ref,new_without_default diff --git a/tests/tests/libui-rs/simple/diff.diff b/tests/tests/libui-rs/simple/diff.diff deleted file mode 100644 index a54e60ad8..000000000 --- a/tests/tests/libui-rs/simple/diff.diff +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/ui/src/controls.rs b/ui/src/controls.rs -index 5699276..59e36b9 100644 ---- a/ui/src/controls.rs -+++ b/ui/src/controls.rs -@@ -242,7 +242,7 @@ impl Button { - let button = Button { - ui_button: button, - }; -- mem::transmute::<*mut c_void, &mut Box>(data)(&button) -+ &mut *(data as *mut Box)(&button) - } - } - } -@@ -347,7 +347,7 @@ impl Entry { - extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { - unsafe { - let entry = Entry::from_ui_control(entry); -- mem::transmute::<*mut c_void, &mut Box>(data)(&entry); -+ &mut *(data as *mut Box)(&entry); - mem::forget(entry); - } - } diff --git a/tests/tests/libui-rs/simple/input.txt b/tests/tests/libui-rs/simple/input.txt deleted file mode 100644 index ced652ef7..000000000 --- a/tests/tests/libui-rs/simple/input.txt +++ /dev/null @@ -1,3 +0,0 @@ -r -r -q diff --git a/tests/tests/libui-rs/simple/output.txt b/tests/tests/libui-rs/simple/output.txt deleted file mode 100644 index 23762b229..000000000 --- a/tests/tests/libui-rs/simple/output.txt +++ /dev/null @@ -1,57 +0,0 @@ - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`) - --> src/controls.rs:245:17-245:78 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&button) - -with: - - &mut *(data as *mut Box) - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`) - --> src/controls.rs:350:17-350:77 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&entry); - -with: - - &mut *(data as *mut Box) - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. - - -Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-378:6 - -try this -[0]: At: -vpub fn new() -> Entry { -^ - -insert: - - impl Default for controls::Entry { - fn default() -> Self { - Self::new() - } - } - - - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Thanks for playing! -Good work. Let me just apply these 2 changes! -.. -Done. diff --git a/tests/tests/libui-rs/skipping/args.txt b/tests/tests/libui-rs/skipping/args.txt deleted file mode 100644 index 2e618abd4..000000000 --- a/tests/tests/libui-rs/skipping/args.txt +++ /dev/null @@ -1 +0,0 @@ ---only transmute_ptr_to_ref,new_without_default diff --git a/tests/tests/libui-rs/skipping/diff.diff b/tests/tests/libui-rs/skipping/diff.diff deleted file mode 100644 index c38003a3e..000000000 --- a/tests/tests/libui-rs/skipping/diff.diff +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/ui/src/controls.rs b/ui/src/controls.rs -index 5699276..56d1c1e 100644 ---- a/ui/src/controls.rs -+++ b/ui/src/controls.rs -@@ -242,7 +242,7 @@ impl Button { - let button = Button { - ui_button: button, - }; -- mem::transmute::<*mut c_void, &mut Box>(data)(&button) -+ &mut *(data as *mut Box)(&button) - } - } - } diff --git a/tests/tests/libui-rs/skipping/input.txt b/tests/tests/libui-rs/skipping/input.txt deleted file mode 100644 index 0bfd421ef..000000000 --- a/tests/tests/libui-rs/skipping/input.txt +++ /dev/null @@ -1,3 +0,0 @@ -r -s -q diff --git a/tests/tests/libui-rs/skipping/output.txt b/tests/tests/libui-rs/skipping/output.txt deleted file mode 100644 index e7f1b1420..000000000 --- a/tests/tests/libui-rs/skipping/output.txt +++ /dev/null @@ -1,57 +0,0 @@ - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`) - --> src/controls.rs:245:17-245:78 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&button) - -with: - - &mut *(data as *mut Box) - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`) - --> src/controls.rs:350:17-350:77 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&entry); - -with: - - &mut *(data as *mut Box) - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Skipped. - - -Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-378:6 - -try this -[0]: At: -vpub fn new() -> Entry { -^ - -insert: - - impl Default for controls::Entry { - fn default() -> Self { - Self::new() - } - } - - - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Thanks for playing! -Good work. Let me just apply these 1 changes! -. -Done. diff --git a/tests/tests/libui-rs/yolo/args.txt b/tests/tests/libui-rs/yolo/args.txt deleted file mode 100644 index cfa7251bc..000000000 --- a/tests/tests/libui-rs/yolo/args.txt +++ /dev/null @@ -1 +0,0 @@ ---yolo --only transmute_ptr_to_ref,new_without_default diff --git a/tests/tests/libui-rs/yolo/diff.diff b/tests/tests/libui-rs/yolo/diff.diff deleted file mode 100644 index 7e1f51375..000000000 --- a/tests/tests/libui-rs/yolo/diff.diff +++ /dev/null @@ -1,201 +0,0 @@ -diff --git a/ui/src/controls.rs b/ui/src/controls.rs -index 5699276..e54973c 100644 ---- a/ui/src/controls.rs -+++ b/ui/src/controls.rs -@@ -242,7 +242,7 @@ impl Button { - let button = Button { - ui_button: button, - }; -- mem::transmute::<*mut c_void, &mut Box>(data)(&button) -+ &mut *(data as *mut Box)(&button) - } - } - } -@@ -347,7 +347,7 @@ impl Entry { - extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { - unsafe { - let entry = Entry::from_ui_control(entry); -- mem::transmute::<*mut c_void, &mut Box>(data)(&entry); -+ &mut *(data as *mut Box)(&entry); - mem::forget(entry); - } - } -@@ -370,6 +370,12 @@ impl Entry { - } - - #[inline] -+ impl Default for controls::Entry { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> Entry { - ffi_utils::ensure_initialized(); - unsafe { -@@ -412,7 +418,7 @@ impl Checkbox { - extern "C" fn c_callback(checkbox: *mut uiCheckbox, data: *mut c_void) { - unsafe { - let checkbox = Checkbox::from_ui_control(checkbox); -- mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); -+ &mut *(data as *mut Box)(&checkbox); - mem::forget(checkbox) - } - } -@@ -523,6 +529,12 @@ impl Tab { - } - - #[inline] -+ impl Default for controls::Tab { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> Tab { - ffi_utils::ensure_initialized(); - unsafe { -@@ -618,7 +630,7 @@ impl Spinbox { - extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) { - unsafe { - let spinbox = Spinbox::from_ui_control(spinbox); -- mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); -+ &mut *(data as *mut Box)(&spinbox); - mem::forget(spinbox); - } - } -@@ -645,6 +657,12 @@ impl ProgressBar { - } - - #[inline] -+ impl Default for controls::ProgressBar { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> ProgressBar { - ffi_utils::ensure_initialized(); - unsafe { -@@ -686,7 +704,7 @@ impl Slider { - extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) { - unsafe { - let slider = Slider::from_ui_control(slider); -- mem::transmute::<*mut c_void, &mut Box>(data)(&slider); -+ &mut *(data as *mut Box)(&slider); - mem::forget(slider); - } - } -@@ -755,13 +773,19 @@ impl Combobox { - extern "C" fn c_callback(combobox: *mut uiCombobox, data: *mut c_void) { - unsafe { - let combobox = Combobox::from_ui_control(combobox); -- mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); -+ &mut *(data as *mut Box)(&combobox); - mem::forget(combobox); - } - } - } - - #[inline] -+ impl Default for controls::Combobox { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> Combobox { - ffi_utils::ensure_initialized(); - unsafe { -@@ -793,6 +817,12 @@ impl RadioButtons { - } - - #[inline] -+ impl Default for controls::RadioButtons { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> RadioButtons { - ffi_utils::ensure_initialized(); - unsafe { -@@ -863,8 +893,7 @@ impl MultilineEntry { - extern "C" fn c_callback(multiline_entry: *mut uiMultilineEntry, data: *mut c_void) { - unsafe { - let multiline_entry = MultilineEntry::from_ui_control(multiline_entry); -- mem::transmute::<*mut c_void, -- &mut Box>(data)(&multiline_entry); -+ &mut *(data as *mut Box)(&multiline_entry); - mem::forget(multiline_entry); - } - } -@@ -887,6 +916,12 @@ impl MultilineEntry { - } - - #[inline] -+ impl Default for controls::MultilineEntry { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> MultilineEntry { - ffi_utils::ensure_initialized(); - unsafe { -@@ -1179,13 +1214,19 @@ impl FontButton { - extern "C" fn c_callback(ui_font_button: *mut uiFontButton, data: *mut c_void) { - unsafe { - let font_button = FontButton::from_ui_control(ui_font_button); -- mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); -+ &mut *(data as *mut Box)(&font_button); - mem::forget(font_button); - } - } - } - - #[inline] -+ impl Default for controls::FontButton { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> FontButton { - ffi_utils::ensure_initialized(); - unsafe { -@@ -1234,13 +1275,19 @@ impl ColorButton { - extern "C" fn c_callback(ui_color_button: *mut uiColorButton, data: *mut c_void) { - unsafe { - let color_button = ColorButton::from_ui_control(ui_color_button); -- mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); -+ &mut *(data as *mut Box)(&color_button); - mem::forget(color_button) - } - } - } - - #[inline] -+ impl Default for controls::ColorButton { -+ fn default() -> Self { -+ Self::new() -+ } -+ } -+ - pub fn new() -> ColorButton { - ffi_utils::ensure_initialized(); - unsafe { -diff --git a/ui/src/menus.rs b/ui/src/menus.rs -index 1255b69..9847ddc 100644 ---- a/ui/src/menus.rs -+++ b/ui/src/menus.rs -@@ -47,8 +47,7 @@ impl MenuItem { - ui_menu_item: menu_item, - }; - let window = Window::from_ui_window(window); -- mem::transmute::<*mut c_void, -- &mut Box>(data)(&menu_item, &window); -+ &mut *(data as *mut Box)(&menu_item, &window); - mem::forget(window); - } - } diff --git a/tests/tests/libui-rs/yolo/input.txt b/tests/tests/libui-rs/yolo/input.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/tests/libui-rs/yolo/output.txt b/tests/tests/libui-rs/yolo/output.txt deleted file mode 100644 index fc479ff76..000000000 --- a/tests/tests/libui-rs/yolo/output.txt +++ /dev/null @@ -1,323 +0,0 @@ - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Button)>`) - --> src/controls.rs:245:17-245:78 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&button) - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Entry)>`) - --> src/controls.rs:350:17-350:77 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&entry); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::Entry` - --> src/controls.rs:373:5-378:6 - -try this -[0]: At: -vpub fn new() -> Entry { -^ - -insert: - - impl Default for controls::Entry { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Checkbox)>`) - --> src/controls.rs:415:17-415:80 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::Tab` - --> src/controls.rs:526:5-531:6 - -try this -[0]: At: -vpub fn new() -> Tab { -^ - -insert: - - impl Default for controls::Tab { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Spinbox)>`) - --> src/controls.rs:621:17-621:79 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::ProgressBar` - --> src/controls.rs:648:5-653:6 - -try this -[0]: At: -vpub fn new() -> ProgressBar { -^ - -insert: - - impl Default for controls::ProgressBar { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Slider)>`) - --> src/controls.rs:689:17-689:78 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&slider); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::Combobox)>`) - --> src/controls.rs:758:17-758:80 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::Combobox` - --> src/controls.rs:765:5-770:6 - -try this -[0]: At: -vpub fn new() -> Combobox { -^ - -insert: - - impl Default for controls::Combobox { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::RadioButtons` - --> src/controls.rs:796:5-801:6 - -try this -[0]: At: -vpub fn new() -> RadioButtons { -^ - -insert: - - impl Default for controls::RadioButtons { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::MultilineEntry)>`) - --> src/controls.rs:866:17-867:73 - -try -[0]: Replace: - - mem::transmute::<*mut c_void, - &mut Box>(data)(&multiline_entry); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::MultilineEntry` - --> src/controls.rs:890:5-895:6 - -try this -[0]: At: -vpub fn new() -> MultilineEntry { -^ - -insert: - - impl Default for controls::MultilineEntry { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::FontButton)>`) - --> src/controls.rs:1182:17-1182:82 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::FontButton` - --> src/controls.rs:1189:5-1194:6 - -try this -[0]: At: -vpub fn new() -> FontButton { -^ - -insert: - - impl Default for controls::FontButton { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r controls::ColorButton)>`) - --> src/controls.rs:1237:17-1237:83 - -try -[0]: Replace: - -mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) - - -Info: you should consider adding a `Default` implementation for `controls::ColorButton` - --> src/controls.rs:1244:5-1249:6 - -try this -[0]: At: -vpub fn new() -> ColorButton { -^ - -insert: - - impl Default for controls::ColorButton { - fn default() -> Self { - Self::new() - } - } - - - -automatically applying suggestion (--yolo) - - -Info: transmute from a pointer type (`*mut libc::c_void`) to a reference type (`&mut std::boxed::Box bitflags::::ops::FnMut(&'r menus::MenuItem, &'s windows::Window)>`) - --> src/menus.rs:50:17-51:76 - -try -[0]: Replace: - - mem::transmute::<*mut c_void, - &mut Box>(data)(&menu_item, &window); - -with: - - &mut *(data as *mut Box) - -automatically applying suggestion (--yolo) -Good work. Let me just apply these 18 changes! -.................. -Done. diff --git a/tests/tests/use_test/first/diff.diff b/tests/tests/use_test/first/diff.diff deleted file mode 100644 index 0374b940a..000000000 --- a/tests/tests/use_test/first/diff.diff +++ /dev/null @@ -1,11 +0,0 @@ -diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs -index 647f90f..ee66c16 100644 ---- a/tests/crates/use_test/src/lib.rs -+++ b/tests/crates/use_test/src/lib.rs -@@ -1,3 +1,6 @@ -+ -+use std::collections::binary_heap::Iter; -+ - pub fn foo() { - let x: Iter; - } diff --git a/tests/tests/use_test/first/input.txt b/tests/tests/use_test/first/input.txt deleted file mode 100644 index 573541ac9..000000000 --- a/tests/tests/use_test/first/input.txt +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/tests/use_test/first/output.txt b/tests/tests/use_test/first/output.txt deleted file mode 100644 index 0a6510398..000000000 --- a/tests/tests/use_test/first/output.txt +++ /dev/null @@ -1,25 +0,0 @@ - - -Info: cannot find type `Iter` in this scope - --> src/lib.rs:2:12-2:16 - -possible candidates are found in other modules, you can import them into scope -Insert line: -[0]: use std::collections::binary_heap::Iter; -[1]: use std::collections::btree_map::Iter; -[2]: use std::collections::btree_set::Iter; -[3]: use std::collections::hash_map::Iter; -[4]: use std::collections::hash_set::Iter; -[5]: use std::collections::linked_list::Iter; -[6]: use std::collections::vec_deque::Iter; -[7]: use std::option::Iter; -[8]: use std::path::Iter; -[9]: use std::result::Iter; -[10]: use std::slice::Iter; -[11]: use std::sync::mpsc::Iter; - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. -Good work. Let me just apply these 1 changes! -. -Done. diff --git a/tests/tests/use_test/replace_fail/diff.diff b/tests/tests/use_test/replace_fail/diff.diff deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/tests/use_test/replace_fail/input.txt b/tests/tests/use_test/replace_fail/input.txt deleted file mode 100644 index fd05cbef8..000000000 --- a/tests/tests/use_test/replace_fail/input.txt +++ /dev/null @@ -1,2 +0,0 @@ -r -a diff --git a/tests/tests/use_test/replace_fail/output.txt b/tests/tests/use_test/replace_fail/output.txt deleted file mode 100644 index 4beed7939..000000000 --- a/tests/tests/use_test/replace_fail/output.txt +++ /dev/null @@ -1,24 +0,0 @@ - - -Info: cannot find type `Iter` in this scope - --> src/lib.rs:2:12-2:16 - -possible candidates are found in other modules, you can import them into scope -Insert line: -[0]: use std::collections::binary_heap::Iter; -[1]: use std::collections::btree_map::Iter; -[2]: use std::collections::btree_set::Iter; -[3]: use std::collections::hash_map::Iter; -[4]: use std::collections::hash_set::Iter; -[5]: use std::collections::linked_list::Iter; -[6]: use std::collections::vec_deque::Iter; -[7]: use std::option::Iter; -[8]: use std::path::Iter; -[9]: use std::result::Iter; -[10]: use std::slice::Iter; -[11]: use std::sync::mpsc::Iter; - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Error: multiple suggestions apply, please pick a number -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Let's get outta here! diff --git a/tests/tests/use_test/second/diff.diff b/tests/tests/use_test/second/diff.diff deleted file mode 100644 index f88a4d135..000000000 --- a/tests/tests/use_test/second/diff.diff +++ /dev/null @@ -1,11 +0,0 @@ -diff --git a/tests/crates/use_test/src/lib.rs b/tests/crates/use_test/src/lib.rs -index 647f90f..2353e22 100644 ---- a/tests/crates/use_test/src/lib.rs -+++ b/tests/crates/use_test/src/lib.rs -@@ -1,3 +1,6 @@ -+ -+use std::collections::btree_map::Iter; -+ - pub fn foo() { - let x: Iter; - } diff --git a/tests/tests/use_test/second/input.txt b/tests/tests/use_test/second/input.txt deleted file mode 100644 index d00491fd7..000000000 --- a/tests/tests/use_test/second/input.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/tests/tests/use_test/second/output.txt b/tests/tests/use_test/second/output.txt deleted file mode 100644 index 0a6510398..000000000 --- a/tests/tests/use_test/second/output.txt +++ /dev/null @@ -1,25 +0,0 @@ - - -Info: cannot find type `Iter` in this scope - --> src/lib.rs:2:12-2:16 - -possible candidates are found in other modules, you can import them into scope -Insert line: -[0]: use std::collections::binary_heap::Iter; -[1]: use std::collections::btree_map::Iter; -[2]: use std::collections::btree_set::Iter; -[3]: use std::collections::hash_map::Iter; -[4]: use std::collections::hash_set::Iter; -[5]: use std::collections::linked_list::Iter; -[6]: use std::collections::vec_deque::Iter; -[7]: use std::option::Iter; -[8]: use std::path::Iter; -[9]: use std::result::Iter; -[10]: use std::slice::Iter; -[11]: use std::sync::mpsc::Iter; - -==> What do you want to do? [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving) - > Suggestion accepted. I'll remember that and apply it later. -Good work. Let me just apply these 1 changes! -. -Done. From 926fc5d19707d0cf5e381350115b3d0b3ebeb5f6 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:04:53 +0100 Subject: [PATCH 078/298] Refactor tests to use explicit fixtures While this is just a quick draft, these tests use rustfix as a library and showcase how it might be used in clippy's test suite to check that suggestions can be applied. (It could e.g. work as an extension to compiletest.) --- Cargo.toml | 4 ++ build.rs | 38 +++++++++++ src/lib.rs | 14 ++++ tests/everything.rs | 125 ++++++++++++++++++++++++++++++++++ tests/fixtures/E0178.fixed.rs | 8 +++ tests/fixtures/E0178.json | 62 +++++++++++++++++ tests/fixtures/E0178.rs | 8 +++ 7 files changed, 259 insertions(+) create mode 100644 build.rs create mode 100644 tests/everything.rs create mode 100644 tests/fixtures/E0178.fixed.rs create mode 100644 tests/fixtures/E0178.json create mode 100644 tests/fixtures/E0178.rs diff --git a/Cargo.toml b/Cargo.toml index e854e4637..4b55c09b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,3 +26,7 @@ serde_derive = "1.0" [dev-dependencies] duct = "0.8.2" +env_logger = "0.5.0-rc.1" +log = "0.4.1" +pretty_assertions = "0.4.1" +tempdir = "0.3.5" diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..0f1033a7e --- /dev/null +++ b/build.rs @@ -0,0 +1,38 @@ +fn main() { + use std::env; + use std::error::Error; + use std::fs; + use std::io::Write; + use std::path::{Path, PathBuf}; + + fn get_fixture_files() -> Result, Box> { + Ok(fs::read_dir("./tests/fixtures")? + .into_iter() + .map(|e| e.unwrap().path()) + .filter(|p| p.is_file()) + .filter(|p| { + let x = p.to_string_lossy(); + x.ends_with(".rs") && !x.ends_with(".fixed.rs") + }) + .collect()) + } + + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("fixture_tests.rs"); + let mut f = fs::File::create(&dest_path).unwrap(); + + for file in &get_fixture_files().unwrap() { + write!(f, + r#" + #[test] + #[allow(non_snake_case)] + fn {name}() {{ + let _ = env_logger::try_init(); + test_rustfix_with_file("{filename}").unwrap(); + }} + "#, + name=file.file_stem().unwrap().to_str().unwrap(), + filename=file.to_str().unwrap(), + ).unwrap(); + } +} diff --git a/src/lib.rs b/src/lib.rs index c4e4e3a79..266e40c4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,16 @@ use std::collections::HashSet; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; +pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { + input.lines() + .filter(not_empty) + // Convert JSON string (and eat parsing errors) + .flat_map(|line| serde_json::from_str::(line)) + // One diagnostic line might have multiple suggestions + .filter_map(|cargo_msg| collect_suggestions(&cargo_msg, only)) + .collect() +} + #[derive(Debug, Copy, Clone, Hash, PartialEq)] pub struct LinePosition { pub line: usize, @@ -153,3 +163,7 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, only: &HashSet) -> O }) } } + +fn not_empty(s: &&str) -> bool { + !s.trim().is_empty() +} diff --git a/tests/everything.rs b/tests/everything.rs new file mode 100644 index 000000000..8a25b66b3 --- /dev/null +++ b/tests/everything.rs @@ -0,0 +1,125 @@ +#[macro_use] extern crate duct; +#[macro_use] extern crate pretty_assertions; +extern crate tempdir; +#[macro_use] extern crate log; +extern crate env_logger; +extern crate serde_json; +extern crate rustfix; + +use std::fs; +use std::error::Error; +use std::path::Path; +use std::collections::HashSet; +use tempdir::TempDir; + +use rustfix::Replacement; + +fn compile_and_get_json_errors(file: &Path) -> Result> { + let tmp = TempDir::new("rustfix-tests")?; + let better_call_clippy = cmd!( + "clippy-driver", "rustc", file, + "--error-format=json", "--emit=metadata", + "--out-dir", tmp.path() + ); + let res = better_call_clippy + .stdout_capture() + .stderr_capture() + .unchecked() + .run()?; + let stderr = String::from_utf8(res.stderr)?; + + use std::io::{Error, ErrorKind}; + match res.status.code() { + Some(1) => Ok(stderr), + _ => Err(Box::new(Error::new( + ErrorKind::Other, + format!("failed with status {:?}: {}", res.status.code(), stderr), + ))) + } +} + +fn read_file(path: &Path) -> Result> { + use std::io::Read; + + let mut buffer = String::new(); + let mut file = fs::File::open(path)?; + file.read_to_string(&mut buffer)?; + Ok(buffer) +} + +fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> Result> { + use std::cmp::max; + + let mut new_content = String::new(); + + // Add the lines before the section we want to replace + new_content.push_str(&file_content.lines() + .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + // Parts of line before replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.snippet.line_range.start.line - 1) + .unwrap_or("") + .chars() + .take(suggestion.snippet.line_range.start.column - 1) + .collect::()); + + // Insert new content! Finally! + new_content.push_str(&suggestion.replacement); + + // Parts of line after replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.snippet.line_range.end.line - 1) + .unwrap_or("") + .chars() + .skip(suggestion.snippet.line_range.end.column - 1) + .collect::()); + + // Add the lines after the section we want to replace + new_content.push_str("\n"); + new_content.push_str(&file_content.lines() + .skip(suggestion.snippet.line_range.end.line as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + Ok(new_content) +} + +fn test_rustfix_with_file>(file: P) -> Result<(), Box> { + let file: &Path = file.as_ref(); + debug!("{:?}", file); + let code = read_file(&file)?; + let errors = compile_and_get_json_errors(file)?; + let expected_json = read_file(&file.with_extension("json"))?; + + assert_eq!( + serde_json::from_str::(&errors)?, + serde_json::from_str::(&expected_json)?, + "got unexpected json from clippy" + ); + + let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); + let mut fixed = code.clone(); + + for sug in suggestions { + trace!("{:?}", sug); + for sol in sug.solutions { + trace!("{:?}", sol); + for r in sol.replacements { + info!("replaced."); + trace!("{:?}", r); + fixed = apply_suggestion(&mut fixed, &r)?; + } + } + } + + let expected_fixed = read_file(&file.with_extension("fixed.rs"))?; + assert_eq!(fixed.trim(), expected_fixed.trim(), "file doesn't look fixed"); + Ok(()) +} + +include!(concat!(env!("OUT_DIR"), "/fixture_tests.rs")); diff --git a/tests/fixtures/E0178.fixed.rs b/tests/fixtures/E0178.fixed.rs new file mode 100644 index 000000000..0b35261b8 --- /dev/null +++ b/tests/fixtures/E0178.fixed.rs @@ -0,0 +1,8 @@ +trait Foo {} + +struct Bar<'a> { + w: &'a (Foo + Copy), +} + +fn main() { +} diff --git a/tests/fixtures/E0178.json b/tests/fixtures/E0178.json new file mode 100644 index 000000000..3293e27bb --- /dev/null +++ b/tests/fixtures/E0178.json @@ -0,0 +1,62 @@ +{ + "message": "expected a path on the left-hand side of `+`, not `&'a Foo`", + "code": { + "code": "E0178", + "explanation": "\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/E0178.rs", + "byte_start": 38, + "byte_end": 52, + "line_start": 4, + "line_end": 4, + "column_start": 8, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " w: &'a Foo + Copy,", + "highlight_start": 8, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "try adding parentheses", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/E0178.rs", + "byte_start": 38, + "byte_end": 52, + "line_start": 4, + "line_end": 4, + "column_start": 8, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " w: &'a Foo + Copy,", + "highlight_start": 8, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": "&'a (Foo + Copy)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n" +} diff --git a/tests/fixtures/E0178.rs b/tests/fixtures/E0178.rs new file mode 100644 index 000000000..128520184 --- /dev/null +++ b/tests/fixtures/E0178.rs @@ -0,0 +1,8 @@ +trait Foo {} + +struct Bar<'a> { + w: &'a Foo + Copy, +} + +fn main() { +} From f1ce4fb0c5e669daf4e24ca516c918cacc22151f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:18:42 +0100 Subject: [PATCH 079/298] Ooops, rustc exits with 0 when lint is not error! --- tests/everything.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/everything.rs b/tests/everything.rs index 8a25b66b3..59cb54255 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -30,7 +30,7 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { use std::io::{Error, ErrorKind}; match res.status.code() { - Some(1) => Ok(stderr), + Some(0) | Some(1) => Ok(stderr), _ => Err(Box::new(Error::new( ErrorKind::Other, format!("failed with status {:?}: {}", res.status.code(), stderr), From 935352711b703fb7974d810b22a44a3de881ffec Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:19:22 +0100 Subject: [PATCH 080/298] Add record mode for quickly getting JSON output Just run it with `env RUSTFIX_TEST_RECORD_JSON=true cargo test` --- tests/everything.rs | 6 ++++++ tests/fixtures/.gitignore | 1 + 2 files changed, 7 insertions(+) create mode 100644 tests/fixtures/.gitignore diff --git a/tests/everything.rs b/tests/everything.rs index 59cb54255..2efe7b30d 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -96,6 +96,12 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let errors = compile_and_get_json_errors(file)?; let expected_json = read_file(&file.with_extension("json"))?; + if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { + use std::io::Write; + let mut recorded_json = fs::File::create(&file.with_extension("recorded.json"))?; + recorded_json.write_all(errors.as_bytes())?; + } + assert_eq!( serde_json::from_str::(&errors)?, serde_json::from_str::(&expected_json)?, diff --git a/tests/fixtures/.gitignore b/tests/fixtures/.gitignore new file mode 100644 index 000000000..fd7a31797 --- /dev/null +++ b/tests/fixtures/.gitignore @@ -0,0 +1 @@ +*.recorded.json From 2396ea53e6a6949653c4b9a25d0331846a5b93bd Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:20:02 +0100 Subject: [PATCH 081/298] Add test for needless_borrow lint One of my favorites! Isn't it great that clippy use get rind of one `&` per clippy run? --- tests/fixtures/needless_borrow.fixed.rs | 3 + tests/fixtures/needless_borrow.json | 78 +++++++++++++++++++++++++ tests/fixtures/needless_borrow.rs | 3 + 3 files changed, 84 insertions(+) create mode 100644 tests/fixtures/needless_borrow.fixed.rs create mode 100644 tests/fixtures/needless_borrow.json create mode 100644 tests/fixtures/needless_borrow.rs diff --git a/tests/fixtures/needless_borrow.fixed.rs b/tests/fixtures/needless_borrow.fixed.rs new file mode 100644 index 000000000..003c1bd04 --- /dev/null +++ b/tests/fixtures/needless_borrow.fixed.rs @@ -0,0 +1,3 @@ +fn main() { + let _x: &i32 = &&&&&5; +} diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json new file mode 100644 index 000000000..2421269bd --- /dev/null +++ b/tests/fixtures/needless_borrow.json @@ -0,0 +1,78 @@ +{ + "message": "this expression borrows a reference that is immediately dereferenced by the compiler", + "code": { + "code": "needless_borrow", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 31, + "byte_end": 38, + "line_start": 2, + "line_end": 2, + "column_start": 20, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _x: &i32 = &&&&&&5;", + "highlight_start": 20, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(needless_borrow)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow", + "code": null, + "level": "help", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "change this to", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 31, + "byte_end": 38, + "line_start": 2, + "line_end": 2, + "column_start": 20, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _x: &i32 = &&&&&&5;", + "highlight_start": 20, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": "&&&&&5", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow\n\n" +} diff --git a/tests/fixtures/needless_borrow.rs b/tests/fixtures/needless_borrow.rs new file mode 100644 index 000000000..079ae61a9 --- /dev/null +++ b/tests/fixtures/needless_borrow.rs @@ -0,0 +1,3 @@ +fn main() { + let _x: &i32 = &&&&&&5; +} From 7dc135241c673b339fd05f006cac8f886325c16d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:32:44 +0100 Subject: [PATCH 082/298] Yeah yeah, let's actually generate new tests --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 0f1033a7e..038238845 100644 --- a/build.rs +++ b/build.rs @@ -5,6 +5,8 @@ fn main() { use std::io::Write; use std::path::{Path, PathBuf}; + println!("rerun-if-changed=test/fixtures/"); + fn get_fixture_files() -> Result, Box> { Ok(fs::read_dir("./tests/fixtures")? .into_iter() From 2e2e26adcc1de04071772aa10c7d70d0c329beed Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:33:32 +0100 Subject: [PATCH 083/298] Don't be too clever There are tests with multiple JSON documents (one per line) --- tests/everything.rs | 4 +- tests/fixtures/E0178.json | 63 +---------------------- tests/fixtures/needless_borrow.json | 79 +---------------------------- 3 files changed, 4 insertions(+), 142 deletions(-) diff --git a/tests/everything.rs b/tests/everything.rs index 2efe7b30d..91e9b9dbd 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -103,8 +103,8 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } assert_eq!( - serde_json::from_str::(&errors)?, - serde_json::from_str::(&expected_json)?, + errors.trim(), + expected_json.trim(), "got unexpected json from clippy" ); diff --git a/tests/fixtures/E0178.json b/tests/fixtures/E0178.json index 3293e27bb..28f4c6e7a 100644 --- a/tests/fixtures/E0178.json +++ b/tests/fixtures/E0178.json @@ -1,62 +1 @@ -{ - "message": "expected a path on the left-hand side of `+`, not `&'a Foo`", - "code": { - "code": "E0178", - "explanation": "\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n" - }, - "level": "error", - "spans": [ - { - "file_name": "./tests/fixtures/E0178.rs", - "byte_start": 38, - "byte_end": 52, - "line_start": 4, - "line_end": 4, - "column_start": 8, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " w: &'a Foo + Copy,", - "highlight_start": 8, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "try adding parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/E0178.rs", - "byte_start": 38, - "byte_end": 52, - "line_start": 4, - "line_end": 4, - "column_start": 8, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " w: &'a Foo + Copy,", - "highlight_start": 8, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": "&'a (Foo + Copy)", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n" -} +{"message":"expected a path on the left-hand side of `+`, not `&'a Foo`","code":{"code":"E0178","explanation":"\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try adding parentheses","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":"&'a (Foo + Copy)","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n"} diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json index 2421269bd..385580016 100644 --- a/tests/fixtures/needless_borrow.json +++ b/tests/fixtures/needless_borrow.json @@ -1,78 +1 @@ -{ - "message": "this expression borrows a reference that is immediately dereferenced by the compiler", - "code": { - "code": "needless_borrow", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 31, - "byte_end": 38, - "line_start": 2, - "line_end": 2, - "column_start": 20, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _x: &i32 = &&&&&&5;", - "highlight_start": 20, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(needless_borrow)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow", - "code": null, - "level": "help", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "change this to", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 31, - "byte_end": 38, - "line_start": 2, - "line_end": 2, - "column_start": 20, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _x: &i32 = &&&&&&5;", - "highlight_start": 20, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": "&&&&&5", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow\n\n" -} +{"message":"this expression borrows a reference that is immediately dereferenced by the compiler","code":{"code":"needless_borrow","explanation":null},"level":"warning","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(needless_borrow)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"change this to","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":"&&&&&5","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow\n\n"} From 16a25ba120e7ae6f6aeff24308972880b8d0d315 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:34:02 +0100 Subject: [PATCH 084/298] Test some typeck suggestions --- tests/fixtures/str_lit_type_mismatch.fixed.rs | 16 ++++++++++++++++ tests/fixtures/str_lit_type_mismatch.json | 3 +++ tests/fixtures/str_lit_type_mismatch.rs | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/fixtures/str_lit_type_mismatch.fixed.rs create mode 100644 tests/fixtures/str_lit_type_mismatch.json create mode 100644 tests/fixtures/str_lit_type_mismatch.rs diff --git a/tests/fixtures/str_lit_type_mismatch.fixed.rs b/tests/fixtures/str_lit_type_mismatch.fixed.rs new file mode 100644 index 000000000..b1ee5c63e --- /dev/null +++ b/tests/fixtures/str_lit_type_mismatch.fixed.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +fn main() { + let x: &[u8] = b"foo"; //~ ERROR mismatched types + let y: &[u8; 4] = b"baaa"; //~ ERROR mismatched types + let z: &str = "foo"; //~ ERROR mismatched types +} diff --git a/tests/fixtures/str_lit_type_mismatch.json b/tests/fixtures/str_lit_type_mismatch.json new file mode 100644 index 000000000..34e46b40f --- /dev/null +++ b/tests/fixtures/str_lit_type_mismatch.json @@ -0,0 +1,3 @@ +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":"expected slice, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":null,"suggested_replacement":"b\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":"expected array of 4 elements, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8; 4]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":null,"suggested_replacement":"b\"baaa\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":"expected str, found array of 3 elements","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&str`\n found type `&'static [u8; 3]`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing the leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":null,"suggested_replacement":"\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n"} diff --git a/tests/fixtures/str_lit_type_mismatch.rs b/tests/fixtures/str_lit_type_mismatch.rs new file mode 100644 index 000000000..4a062f78a --- /dev/null +++ b/tests/fixtures/str_lit_type_mismatch.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +fn main() { + let x: &[u8] = "foo"; //~ ERROR mismatched types + let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types + let z: &str = b"foo"; //~ ERROR mismatched types +} From 6fab747108d1ddfcb08d2f6bc73a931d56cda9ff Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:36:08 +0100 Subject: [PATCH 085/298] How about we install clippy on CI? --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a9b3a72d3..2b92a8d23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ language: rust rust: - nightly - stable - +before_script: +- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo install clippy --force ; fi script: - cargo build - if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi From 4ca7457db69366f23da547a54aab7cf41927d342 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:47:12 +0100 Subject: [PATCH 086/298] Build scripts? Not actually that clever Apparently, it's hard to figure out if files were added/deleted to a directory in a build script. Oh well. --- build.rs | 40 ---------------------------------------- tests/everything.rs | 27 ++++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 43 deletions(-) delete mode 100644 build.rs diff --git a/build.rs b/build.rs deleted file mode 100644 index 038238845..000000000 --- a/build.rs +++ /dev/null @@ -1,40 +0,0 @@ -fn main() { - use std::env; - use std::error::Error; - use std::fs; - use std::io::Write; - use std::path::{Path, PathBuf}; - - println!("rerun-if-changed=test/fixtures/"); - - fn get_fixture_files() -> Result, Box> { - Ok(fs::read_dir("./tests/fixtures")? - .into_iter() - .map(|e| e.unwrap().path()) - .filter(|p| p.is_file()) - .filter(|p| { - let x = p.to_string_lossy(); - x.ends_with(".rs") && !x.ends_with(".fixed.rs") - }) - .collect()) - } - - let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("fixture_tests.rs"); - let mut f = fs::File::create(&dest_path).unwrap(); - - for file in &get_fixture_files().unwrap() { - write!(f, - r#" - #[test] - #[allow(non_snake_case)] - fn {name}() {{ - let _ = env_logger::try_init(); - test_rustfix_with_file("{filename}").unwrap(); - }} - "#, - name=file.file_stem().unwrap().to_str().unwrap(), - filename=file.to_str().unwrap(), - ).unwrap(); - } -} diff --git a/tests/everything.rs b/tests/everything.rs index 91e9b9dbd..cd3867e6f 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -8,7 +8,7 @@ extern crate rustfix; use std::fs; use std::error::Error; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::collections::HashSet; use tempdir::TempDir; @@ -94,7 +94,6 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { debug!("{:?}", file); let code = read_file(&file)?; let errors = compile_and_get_json_errors(file)?; - let expected_json = read_file(&file.with_extension("json"))?; if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { use std::io::Write; @@ -102,6 +101,8 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { recorded_json.write_all(errors.as_bytes())?; } + let expected_json = read_file(&file.with_extension("json"))?; + assert_eq!( errors.trim(), expected_json.trim(), @@ -128,4 +129,24 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { Ok(()) } -include!(concat!(env!("OUT_DIR"), "/fixture_tests.rs")); +fn get_fixture_files() -> Result, Box> { + Ok(fs::read_dir("./tests/fixtures")? + .into_iter() + .map(|e| e.unwrap().path()) + .filter(|p| p.is_file()) + .filter(|p| { + let x = p.to_string_lossy(); + x.ends_with(".rs") && !x.ends_with(".fixed.rs") + }) + .collect()) +} + +#[test] +fn fixtures() { + let _ = env_logger::try_init(); + + for file in &get_fixture_files().unwrap() { + test_rustfix_with_file(file).unwrap(); + info!("passed: {:?}", file); + } +} From 2ff9e3296a9929b04eff6ff5cc8f79af23f63a2c Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:47:27 +0100 Subject: [PATCH 087/298] Rename fixtures do original dash-case --- ...ype_mismatch.fixed.rs => str-lit-type-mismatch.fixed.rs} | 0 ...tr_lit_type_mismatch.json => str-lit-type-mismatch.json} | 6 +++--- .../{str_lit_type_mismatch.rs => str-lit-type-mismatch.rs} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/fixtures/{str_lit_type_mismatch.fixed.rs => str-lit-type-mismatch.fixed.rs} (100%) rename tests/fixtures/{str_lit_type_mismatch.json => str-lit-type-mismatch.json} (89%) rename tests/fixtures/{str_lit_type_mismatch.rs => str-lit-type-mismatch.rs} (100%) diff --git a/tests/fixtures/str_lit_type_mismatch.fixed.rs b/tests/fixtures/str-lit-type-mismatch.fixed.rs similarity index 100% rename from tests/fixtures/str_lit_type_mismatch.fixed.rs rename to tests/fixtures/str-lit-type-mismatch.fixed.rs diff --git a/tests/fixtures/str_lit_type_mismatch.json b/tests/fixtures/str-lit-type-mismatch.json similarity index 89% rename from tests/fixtures/str_lit_type_mismatch.json rename to tests/fixtures/str-lit-type-mismatch.json index 34e46b40f..4cd92098a 100644 --- a/tests/fixtures/str_lit_type_mismatch.json +++ b/tests/fixtures/str-lit-type-mismatch.json @@ -1,3 +1,3 @@ -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":"expected slice, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":null,"suggested_replacement":"b\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":"expected array of 4 elements, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8; 4]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":null,"suggested_replacement":"b\"baaa\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":"expected str, found array of 3 elements","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&str`\n found type `&'static [u8; 3]`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing the leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str_lit_type_mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":null,"suggested_replacement":"\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str_lit_type_mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":"expected slice, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":null,"suggested_replacement":"b\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":"expected array of 4 elements, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8; 4]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":null,"suggested_replacement":"b\"baaa\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":"expected str, found array of 3 elements","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&str`\n found type `&'static [u8; 3]`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing the leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":null,"suggested_replacement":"\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n"} diff --git a/tests/fixtures/str_lit_type_mismatch.rs b/tests/fixtures/str-lit-type-mismatch.rs similarity index 100% rename from tests/fixtures/str_lit_type_mismatch.rs rename to tests/fixtures/str-lit-type-mismatch.rs From 3c613323e4060e8978202d8876c52351a3729a76 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 3 Jan 2018 23:47:37 +0100 Subject: [PATCH 088/298] Add some more rustc test cases --- .../closure-immutable-outer-variable.fixed.rs | 20 +++++++++++++++++++ .../closure-immutable-outer-variable.json | 1 + .../closure-immutable-outer-variable.rs | 20 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/fixtures/closure-immutable-outer-variable.fixed.rs create mode 100644 tests/fixtures/closure-immutable-outer-variable.json create mode 100644 tests/fixtures/closure-immutable-outer-variable.rs diff --git a/tests/fixtures/closure-immutable-outer-variable.fixed.rs b/tests/fixtures/closure-immutable-outer-variable.fixed.rs new file mode 100644 index 000000000..80a5a45a3 --- /dev/null +++ b/tests/fixtures/closure-immutable-outer-variable.fixed.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Point at the captured immutable outer variable + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +} diff --git a/tests/fixtures/closure-immutable-outer-variable.json b/tests/fixtures/closure-immutable-outer-variable.json new file mode 100644 index 000000000..835217c9f --- /dev/null +++ b/tests/fixtures/closure-immutable-outer-variable.json @@ -0,0 +1 @@ +{"message":"cannot assign to captured outer variable in an `FnMut` closure","code":{"code":"E0594","explanation":null},"level":"error","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":615,"byte_end":624,"line_start":19,"line_end":19,"column_start":26,"column_end":35,"is_primary":true,"text":[{"text":" foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable","highlight_start":26,"highlight_end":35}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"consider making `y` mutable","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":580,"byte_end":581,"line_start":18,"line_end":18,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let y = true;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"mut y","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\n"} diff --git a/tests/fixtures/closure-immutable-outer-variable.rs b/tests/fixtures/closure-immutable-outer-variable.rs new file mode 100644 index 000000000..1d14afd6a --- /dev/null +++ b/tests/fixtures/closure-immutable-outer-variable.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Point at the captured immutable outer variable + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +} From 5e2fb77987458c930fa432a7d85df43d2d4a36cb Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 13:26:06 +0100 Subject: [PATCH 089/298] Rustfix rustfix --- src/lib.rs | 4 ++-- src/main.rs | 12 ++++++------ tests/everything.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 266e40c4e..e4d544785 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use std::collections::HashSet; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; -pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { +pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { input.lines() .filter(not_empty) // Convert JSON string (and eat parsing errors) @@ -118,7 +118,7 @@ fn collect_span(span: &DiagnosticSpan) -> Option { }) } -pub fn collect_suggestions(diagnostic: &Diagnostic, only: &HashSet) -> Option { +pub fn collect_suggestions(diagnostic: &Diagnostic, only: &HashSet) -> Option { if !only.is_empty() { if let Some(ref code) = diagnostic.code { if !only.contains(&code.code) { diff --git a/src/main.rs b/src/main.rs index dcb45d96d..5a53498af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ use std::str::FromStr; use rustfix::{Suggestion, Replacement}; use rustfix::diagnostics::Diagnostic; -const USER_OPTIONS: &'static str = "What do you want to do? \ +const USER_OPTIONS: &str = "What do you want to do? \ [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; fn main() { @@ -127,7 +127,7 @@ fn get_json(extra_args: &[&str]) -> Result { Ok(String::from_utf8(output.stdout)?) } -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Clone, Copy)] enum AutofixMode { /// Do not apply any fixes automatically None, @@ -194,7 +194,7 @@ fn handle_suggestions( } let mut i = 0; - for solution in suggestion.solutions.iter() { + for solution in &suggestion.solutions { println!("\n{}", solution.message); // check whether we can squash all suggestions into a list @@ -207,7 +207,7 @@ fn handle_suggestions( && first.snippet.line_range == s.snippet.line_range); if all_suggestions_replace_the_same_span { prelude(&first); - for suggestion in solution.replacements.iter() { + for suggestion in &solution.replacements { println!("[{}]: {}", i, suggestion.replacement.trim()); i += 1; } @@ -216,7 +216,7 @@ fn handle_suggestions( } for suggestion in &solution.replacements { print!("[{}]: ", i); - prelude(&suggestion); + prelude(suggestion); println!("{}", indent(4, &suggestion.replacement)); i += 1; } @@ -425,7 +425,7 @@ fn apply_suggestion(suggestion: &Replacement) -> Result<(), ProgramError> { let new_content = new_content.as_bytes(); try!(file.set_len(new_content.len() as u64)); - try!(file.write_all(&new_content)); + try!(file.write_all(new_content)); Ok(()) } diff --git a/tests/everything.rs b/tests/everything.rs index cd3867e6f..47b4a03f8 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -92,7 +92,7 @@ fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> Resu fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let file: &Path = file.as_ref(); debug!("{:?}", file); - let code = read_file(&file)?; + let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { From 9c1e240282447be1655601faf060e91d221c6dca Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 13:31:45 +0100 Subject: [PATCH 090/298] Enable Clippy's stability-by-obscurity feature (hide links to clippy docs which include version number) --- tests/everything.rs | 1 + tests/fixtures/needless_borrow.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/everything.rs b/tests/everything.rs index 47b4a03f8..9e5a33441 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -22,6 +22,7 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { "--out-dir", tmp.path() ); let res = better_call_clippy + .env("CLIPPY_DISABLE_DOCS_LINKS", "true") .stdout_capture() .stderr_capture() .unchecked() diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json index 385580016..af7fdbb48 100644 --- a/tests/fixtures/needless_borrow.json +++ b/tests/fixtures/needless_borrow.json @@ -1 +1 @@ -{"message":"this expression borrows a reference that is immediately dereferenced by the compiler","code":{"code":"needless_borrow","explanation":null},"level":"warning","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(needless_borrow)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"change this to","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":"&&&&&5","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow\n\n"} +{"message":"this expression borrows a reference that is immediately dereferenced by the compiler","code":{"code":"needless_borrow","explanation":null},"level":"warning","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(needless_borrow)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"change this to","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":"&&&&&5","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n\n"} From 3e251c2836cf5ee84616a20eee921431f7fa6107 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 14:24:37 +0100 Subject: [PATCH 091/298] Pretty print json --- src/lib.rs | 12 +- tests/everything.rs | 2 +- tests/fixtures/E0178.json | 63 +++++- .../closure-immutable-outer-variable.json | 63 +++++- tests/fixtures/needless_borrow.json | 71 +++++- tests/fixtures/str-lit-type-mismatch.json | 213 +++++++++++++++++- 6 files changed, 409 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e4d544785..e02c558d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,10 @@ pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { - input.lines() - .filter(not_empty) - // Convert JSON string (and eat parsing errors) - .flat_map(|line| serde_json::from_str::(line)) + serde_json::Deserializer::from_str(input) + .into_iter::() + // eat parsing errors + .flat_map(|line| line.ok()) // One diagnostic line might have multiple suggestions .filter_map(|cargo_msg| collect_suggestions(&cargo_msg, only)) .collect() @@ -163,7 +163,3 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, }) } } - -fn not_empty(s: &&str) -> bool { - !s.trim().is_empty() -} diff --git a/tests/everything.rs b/tests/everything.rs index 9e5a33441..9b5f6990d 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -18,7 +18,7 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; let better_call_clippy = cmd!( "clippy-driver", "rustc", file, - "--error-format=json", "--emit=metadata", + "--error-format=pretty-json", "-Zunstable-options", "--emit=metadata", "--out-dir", tmp.path() ); let res = better_call_clippy diff --git a/tests/fixtures/E0178.json b/tests/fixtures/E0178.json index 28f4c6e7a..75fd8a499 100644 --- a/tests/fixtures/E0178.json +++ b/tests/fixtures/E0178.json @@ -1 +1,62 @@ -{"message":"expected a path on the left-hand side of `+`, not `&'a Foo`","code":{"code":"E0178","explanation":"\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try adding parentheses","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":"&'a (Foo + Copy)","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n"} +{ + "message": "expected a path on the left-hand side of `+`, not `&'a Foo`", + "code": { + "code": "E0178", + "explanation": "\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/E0178.rs", + "byte_start": 38, + "byte_end": 52, + "line_start": 4, + "line_end": 4, + "column_start": 8, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " w: &'a Foo + Copy,", + "highlight_start": 8, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "try adding parentheses", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/E0178.rs", + "byte_start": 38, + "byte_end": 52, + "line_start": 4, + "line_end": 4, + "column_start": 8, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " w: &'a Foo + Copy,", + "highlight_start": 8, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": "&'a (Foo + Copy)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n" +} diff --git a/tests/fixtures/closure-immutable-outer-variable.json b/tests/fixtures/closure-immutable-outer-variable.json index 835217c9f..860db573a 100644 --- a/tests/fixtures/closure-immutable-outer-variable.json +++ b/tests/fixtures/closure-immutable-outer-variable.json @@ -1 +1,62 @@ -{"message":"cannot assign to captured outer variable in an `FnMut` closure","code":{"code":"E0594","explanation":null},"level":"error","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":615,"byte_end":624,"line_start":19,"line_end":19,"column_start":26,"column_end":35,"is_primary":true,"text":[{"text":" foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable","highlight_start":26,"highlight_end":35}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"consider making `y` mutable","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":580,"byte_end":581,"line_start":18,"line_end":18,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let y = true;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"mut y","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\n"} +{ + "message": "cannot assign to captured outer variable in an `FnMut` closure", + "code": { + "code": "E0594", + "explanation": null + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/closure-immutable-outer-variable.rs", + "byte_start": 615, + "byte_end": 624, + "line_start": 19, + "line_end": 19, + "column_start": 26, + "column_end": 35, + "is_primary": true, + "text": [ + { + "text": " foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable", + "highlight_start": 26, + "highlight_end": 35 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "consider making `y` mutable", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/closure-immutable-outer-variable.rs", + "byte_start": 580, + "byte_end": 581, + "line_start": 18, + "line_end": 18, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let y = true;", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": "mut y", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\n" +} diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json index af7fdbb48..60a32c533 100644 --- a/tests/fixtures/needless_borrow.json +++ b/tests/fixtures/needless_borrow.json @@ -1 +1,70 @@ -{"message":"this expression borrows a reference that is immediately dereferenced by the compiler","code":{"code":"needless_borrow","explanation":null},"level":"warning","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(needless_borrow)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"change this to","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":"&&&&&5","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n\n"} +{ + "message": "this expression borrows a reference that is immediately dereferenced by the compiler", + "code": { + "code": "needless_borrow", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 31, + "byte_end": 38, + "line_start": 2, + "line_end": 2, + "column_start": 20, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _x: &i32 = &&&&&&5;", + "highlight_start": 20, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(needless_borrow)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "change this to", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 31, + "byte_end": 38, + "line_start": 2, + "line_end": 2, + "column_start": 20, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _x: &i32 = &&&&&&5;", + "highlight_start": 20, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": "&&&&&5", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n\n" +} diff --git a/tests/fixtures/str-lit-type-mismatch.json b/tests/fixtures/str-lit-type-mismatch.json index 4cd92098a..ddd952983 100644 --- a/tests/fixtures/str-lit-type-mismatch.json +++ b/tests/fixtures/str-lit-type-mismatch.json @@ -1,3 +1,210 @@ -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":"expected slice, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":null,"suggested_replacement":"b\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":"expected array of 4 elements, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8; 4]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":null,"suggested_replacement":"b\"baaa\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":"expected str, found array of 3 elements","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&str`\n found type `&'static [u8; 3]`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing the leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":null,"suggested_replacement":"\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n"} +{ + "message": "mismatched types", + "code": { + "code": "E0308", + "explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 499, + "byte_end": 504, + "line_start": 13, + "line_end": 13, + "column_start": 20, + "column_end": 25, + "is_primary": true, + "text": [ + { + "text": " let x: &[u8] = \"foo\"; //~ ERROR mismatched types", + "highlight_start": 20, + "highlight_end": 25 + } + ], + "label": "expected slice, found str", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "expected type `&[u8]`\n found type `&'static str`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "consider adding a leading `b`", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 499, + "byte_end": 504, + "line_start": 13, + "line_end": 13, + "column_start": 20, + "column_end": 25, + "is_primary": true, + "text": [ + { + "text": " let x: &[u8] = \"foo\"; //~ ERROR mismatched types", + "highlight_start": 20, + "highlight_end": 25 + } + ], + "label": null, + "suggested_replacement": "b\"foo\"", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n" +} +{ + "message": "mismatched types", + "code": { + "code": "E0308", + "explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 555, + "byte_end": 561, + "line_start": 14, + "line_end": 14, + "column_start": 23, + "column_end": 29, + "is_primary": true, + "text": [ + { + "text": " let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types", + "highlight_start": 23, + "highlight_end": 29 + } + ], + "label": "expected array of 4 elements, found str", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "expected type `&[u8; 4]`\n found type `&'static str`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "consider adding a leading `b`", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 555, + "byte_end": 561, + "line_start": 14, + "line_end": 14, + "column_start": 23, + "column_end": 29, + "is_primary": true, + "text": [ + { + "text": " let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types", + "highlight_start": 23, + "highlight_end": 29 + } + ], + "label": null, + "suggested_replacement": "b\"baaa\"", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n" +} +{ + "message": "mismatched types", + "code": { + "code": "E0308", + "explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 608, + "byte_end": 614, + "line_start": 15, + "line_end": 15, + "column_start": 19, + "column_end": 25, + "is_primary": true, + "text": [ + { + "text": " let z: &str = b\"foo\"; //~ ERROR mismatched types", + "highlight_start": 19, + "highlight_end": 25 + } + ], + "label": "expected str, found array of 3 elements", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "expected type `&str`\n found type `&'static [u8; 3]`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "consider removing the leading `b`", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "byte_start": 608, + "byte_end": 614, + "line_start": 15, + "line_end": 15, + "column_start": 19, + "column_end": 25, + "is_primary": true, + "text": [ + { + "text": " let z: &str = b\"foo\"; //~ ERROR mismatched types", + "highlight_start": 19, + "highlight_end": 25 + } + ], + "label": null, + "suggested_replacement": "\"foo\"", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n" +} From 20485f1c779d05e1aa694239e092b35b57af39d4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 14:49:05 +0100 Subject: [PATCH 092/298] Compare the diagnostic structs instead of the json output --- tests/everything.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/everything.rs b/tests/everything.rs index 9b5f6990d..33f628142 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -95,6 +95,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { debug!("{:?}", file); let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; + let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { use std::io::Write; @@ -103,14 +104,13 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } let expected_json = read_file(&file.with_extension("json"))?; - + let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()); assert_eq!( - errors.trim(), - expected_json.trim(), - "got unexpected json from clippy" + expected_suggestions, + suggestions, + "got unexpected suggestions from clippy", ); - let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); let mut fixed = code.clone(); for sug in suggestions { From 42ccb94cff7448b747c7b3842350dc332d22d3bd Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 15:55:00 +0100 Subject: [PATCH 093/298] Nicer test output env RUST_LOG=everything=info cargo test -- --nocapture --- tests/everything.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/everything.rs b/tests/everything.rs index 33f628142..5429d3e1b 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -118,7 +118,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { for sol in sug.solutions { trace!("{:?}", sol); for r in sol.replacements { - info!("replaced."); + debug!("replaced."); trace!("{:?}", r); fixed = apply_suggestion(&mut fixed, &r)?; } From 27ec9926e2cd8de9b7c72595c4b8f6de33ca9586 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 15:55:18 +0100 Subject: [PATCH 094/298] Expand needless borrow test --- tests/fixtures/needless_borrow.fixed.rs | 6 +++ tests/fixtures/needless_borrow.json | 62 +++++++++++++++++++++++++ tests/fixtures/needless_borrow.rs | 6 +++ 3 files changed, 74 insertions(+) diff --git a/tests/fixtures/needless_borrow.fixed.rs b/tests/fixtures/needless_borrow.fixed.rs index 003c1bd04..546b6bb44 100644 --- a/tests/fixtures/needless_borrow.fixed.rs +++ b/tests/fixtures/needless_borrow.fixed.rs @@ -1,3 +1,9 @@ fn main() { let _x: &i32 = &&&&&5; + + struct Foo; + fn foo(_x: &Foo) { } + + let x = &Foo; + foo(x); } diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json index 60a32c533..0ef5ab3d7 100644 --- a/tests/fixtures/needless_borrow.json +++ b/tests/fixtures/needless_borrow.json @@ -68,3 +68,65 @@ ], "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n\n" } +{ + "message": "this expression borrows a reference that is immediately dereferenced by the compiler", + "code": { + "code": "needless_borrow", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 109, + "byte_end": 111, + "line_start": 8, + "line_end": 8, + "column_start": 9, + "column_end": 11, + "is_primary": true, + "text": [ + { + "text": " foo(&x);", + "highlight_start": 9, + "highlight_end": 11 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "change this to", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/needless_borrow.rs", + "byte_start": 109, + "byte_end": 111, + "line_start": 8, + "line_end": 8, + "column_start": 9, + "column_end": 11, + "is_primary": true, + "text": [ + { + "text": " foo(&x);", + "highlight_start": 9, + "highlight_end": 11 + } + ], + "label": null, + "suggested_replacement": "x", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:8:9\n |\n8 | foo(&x);\n | ^^ help: change this to: `x`\n\n" +} diff --git a/tests/fixtures/needless_borrow.rs b/tests/fixtures/needless_borrow.rs index 079ae61a9..b24668c8c 100644 --- a/tests/fixtures/needless_borrow.rs +++ b/tests/fixtures/needless_borrow.rs @@ -1,3 +1,9 @@ fn main() { let _x: &i32 = &&&&&&5; + + struct Foo; + fn foo(_x: &Foo) { } + + let x = &Foo; + foo(&x); } From cc3fc580d9399cf77cf1b994669b3c5380c63ca9 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 15:55:28 +0100 Subject: [PATCH 095/298] Add explicit inter loop test --- tests/fixtures/explicit_iter_loop.fixed.rs | 7 +++ tests/fixtures/explicit_iter_loop.json | 70 ++++++++++++++++++++++ tests/fixtures/explicit_iter_loop.rs | 7 +++ 3 files changed, 84 insertions(+) create mode 100644 tests/fixtures/explicit_iter_loop.fixed.rs create mode 100644 tests/fixtures/explicit_iter_loop.json create mode 100644 tests/fixtures/explicit_iter_loop.rs diff --git a/tests/fixtures/explicit_iter_loop.fixed.rs b/tests/fixtures/explicit_iter_loop.fixed.rs new file mode 100644 index 000000000..0ffeff17b --- /dev/null +++ b/tests/fixtures/explicit_iter_loop.fixed.rs @@ -0,0 +1,7 @@ +fn main() { + let xs = vec![1, 2, 3]; + + for x in &xs { + println!("{}", x) + } +} diff --git a/tests/fixtures/explicit_iter_loop.json b/tests/fixtures/explicit_iter_loop.json new file mode 100644 index 000000000..f256acbd0 --- /dev/null +++ b/tests/fixtures/explicit_iter_loop.json @@ -0,0 +1,70 @@ +{ + "message": "it is more idiomatic to loop over references to containers instead of using explicit iteration methods", + "code": { + "code": "explicit_iter_loop", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/explicit_iter_loop.rs", + "byte_start": 54, + "byte_end": 63, + "line_start": 4, + "line_end": 4, + "column_start": 14, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " for x in xs.iter() {", + "highlight_start": 14, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(explicit_iter_loop)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "to write this more concisely, try", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/explicit_iter_loop.rs", + "byte_start": 54, + "byte_end": 63, + "line_start": 4, + "line_end": 4, + "column_start": 14, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " for x in xs.iter() {", + "highlight_start": 14, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": "&xs", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: it is more idiomatic to loop over references to containers instead of using explicit iteration methods\n --> ./tests/fixtures/explicit_iter_loop.rs:4:14\n |\n4 | for x in xs.iter() {\n | ^^^^^^^^^ help: to write this more concisely, try: `&xs`\n |\n = note: #[warn(explicit_iter_loop)] on by default\n\n" + } diff --git a/tests/fixtures/explicit_iter_loop.rs b/tests/fixtures/explicit_iter_loop.rs new file mode 100644 index 000000000..2e9c84129 --- /dev/null +++ b/tests/fixtures/explicit_iter_loop.rs @@ -0,0 +1,7 @@ +fn main() { + let xs = vec![1, 2, 3]; + + for x in xs.iter() { + println!("{}", x) + } +} From d6ad579b08edc3d61de8ba4e93d78e554b6dd26d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 16:54:47 +0100 Subject: [PATCH 096/298] Actually tests that the 'fixed' files compile! --- tests/everything.rs | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/everything.rs b/tests/everything.rs index 5429d3e1b..9cf04690c 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -10,15 +10,17 @@ use std::fs; use std::error::Error; use std::path::{Path, PathBuf}; use std::collections::HashSet; +use std::process::Output; use tempdir::TempDir; use rustfix::Replacement; -fn compile_and_get_json_errors(file: &Path) -> Result> { +fn compile(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; let better_call_clippy = cmd!( "clippy-driver", "rustc", file, "--error-format=pretty-json", "-Zunstable-options", "--emit=metadata", + "--crate-name=rustfix_test", "--out-dir", tmp.path() ); let res = better_call_clippy @@ -27,6 +29,12 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { .stderr_capture() .unchecked() .run()?; + + Ok(res) +} + +fn compile_and_get_json_errors(file: &Path) -> Result> { + let res = compile(file)?; let stderr = String::from_utf8(res.stderr)?; use std::io::{Error, ErrorKind}; @@ -39,6 +47,25 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { } } +fn compiles_without_errors(file: &Path) -> Result<(), Box> { + let res = compile(file)?; + + use std::io::{Error, ErrorKind}; + match res.status.code() { + Some(0) => Ok(()), + _ => { + info!("file {:?} failed to compile:\n{}", file, String::from_utf8(res.stderr)?); + Err(Box::new(Error::new( + ErrorKind::Other, + format!( + "failed with status {:?} (`env RUST_LOG=everything=info` for more info)", + res.status.code(), + ), + ))) + } + } +} + fn read_file(path: &Path) -> Result> { use std::io::Read; @@ -92,6 +119,9 @@ fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> Resu fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let file: &Path = file.as_ref(); + let json_file = file.with_extension("json"); + let fixed_file = file.with_extension("fixed.rs"); + debug!("{:?}", file); let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; @@ -103,7 +133,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { recorded_json.write_all(errors.as_bytes())?; } - let expected_json = read_file(&file.with_extension("json"))?; + let expected_json = read_file(&json_file)?; let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()); assert_eq!( expected_suggestions, @@ -125,8 +155,11 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } } - let expected_fixed = read_file(&file.with_extension("fixed.rs"))?; + let expected_fixed = read_file(&fixed_file)?; assert_eq!(fixed.trim(), expected_fixed.trim(), "file doesn't look fixed"); + + compiles_without_errors(&fixed_file)?; + Ok(()) } From 626f4647b674af9e3903ca7ede8d383044c4f80a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 16:55:05 +0100 Subject: [PATCH 097/298] Tweak E0178 example to not trigger more warnings --- tests/fixtures/E0178.fixed.rs | 4 +++- tests/fixtures/E0178.json | 24 ++++++++++++------------ tests/fixtures/E0178.rs | 4 +++- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/fixtures/E0178.fixed.rs b/tests/fixtures/E0178.fixed.rs index 0b35261b8..e8f318813 100644 --- a/tests/fixtures/E0178.fixed.rs +++ b/tests/fixtures/E0178.fixed.rs @@ -1,7 +1,9 @@ +#![allow(dead_code)] + trait Foo {} struct Bar<'a> { - w: &'a (Foo + Copy), + w: &'a (Foo + Send), } fn main() { diff --git a/tests/fixtures/E0178.json b/tests/fixtures/E0178.json index 75fd8a499..ad75e8bf5 100644 --- a/tests/fixtures/E0178.json +++ b/tests/fixtures/E0178.json @@ -8,16 +8,16 @@ "spans": [ { "file_name": "./tests/fixtures/E0178.rs", - "byte_start": 38, - "byte_end": 52, - "line_start": 4, - "line_end": 4, + "byte_start": 60, + "byte_end": 74, + "line_start": 6, + "line_end": 6, "column_start": 8, "column_end": 22, "is_primary": true, "text": [ { - "text": " w: &'a Foo + Copy,", + "text": " w: &'a Foo + Send,", "highlight_start": 8, "highlight_end": 22 } @@ -35,22 +35,22 @@ "spans": [ { "file_name": "./tests/fixtures/E0178.rs", - "byte_start": 38, - "byte_end": 52, - "line_start": 4, - "line_end": 4, + "byte_start": 60, + "byte_end": 74, + "line_start": 6, + "line_end": 6, "column_start": 8, "column_end": 22, "is_primary": true, "text": [ { - "text": " w: &'a Foo + Copy,", + "text": " w: &'a Foo + Send,", "highlight_start": 8, "highlight_end": 22 } ], "label": null, - "suggested_replacement": "&'a (Foo + Copy)", + "suggested_replacement": "&'a (Foo + Send)", "expansion": null } ], @@ -58,5 +58,5 @@ "rendered": null } ], - "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n" + "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:6:8\n |\n6 | w: &'a Foo + Send,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Send)`\n\n" } diff --git a/tests/fixtures/E0178.rs b/tests/fixtures/E0178.rs index 128520184..c04e2a8cd 100644 --- a/tests/fixtures/E0178.rs +++ b/tests/fixtures/E0178.rs @@ -1,7 +1,9 @@ +#![allow(dead_code)] + trait Foo {} struct Bar<'a> { - w: &'a Foo + Copy, + w: &'a Foo + Send, } fn main() { From 088501f8310f86d3b0fc5411ab522ced461f08e8 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 16:56:30 +0100 Subject: [PATCH 098/298] Keep travis quiet [ci skip] lol ^ --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2b92a8d23..11e6012fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ before_script: script: - cargo build - if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi +notifications: + email: + on_success: never From 89e39308230e5374b55eb6f4b69029b1fcd3adce Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 17 Jan 2018 21:43:06 +0100 Subject: [PATCH 099/298] Add flag to record fixed rust files --- tests/everything.rs | 10 ++++++++-- tests/fixtures/.gitignore | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/everything.rs b/tests/everything.rs index 9cf04690c..744af305d 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -122,7 +122,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let json_file = file.with_extension("json"); let fixed_file = file.with_extension("fixed.rs"); - debug!("{:?}", file); + debug!("next up: {:?}", file); let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); @@ -155,6 +155,12 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } } + if std::env::var("RUSTFIX_TEST_RECORD_FIXED_RUST").is_ok() { + use std::io::Write; + let mut recorded_rust = fs::File::create(&file.with_extension("recorded.rs"))?; + recorded_rust.write_all(fixed.as_bytes())?; + } + let expected_fixed = read_file(&fixed_file)?; assert_eq!(fixed.trim(), expected_fixed.trim(), "file doesn't look fixed"); @@ -170,7 +176,7 @@ fn get_fixture_files() -> Result, Box> { .filter(|p| p.is_file()) .filter(|p| { let x = p.to_string_lossy(); - x.ends_with(".rs") && !x.ends_with(".fixed.rs") + x.ends_with(".rs") && !x.ends_with(".fixed.rs") && !x.ends_with(".recorded.rs") }) .collect()) } diff --git a/tests/fixtures/.gitignore b/tests/fixtures/.gitignore index fd7a31797..bfb599db1 100644 --- a/tests/fixtures/.gitignore +++ b/tests/fixtures/.gitignore @@ -1 +1,2 @@ *.recorded.json +*.recorded.rs From bba7f889395bb055dccc6e41ca69be9aa420203e Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 17 Jan 2018 21:43:26 +0100 Subject: [PATCH 100/298] Sometimes, rustc exits with status 101 This is fine. --- tests/everything.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/everything.rs b/tests/everything.rs index 744af305d..5ea403e73 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -39,7 +39,7 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { use std::io::{Error, ErrorKind}; match res.status.code() { - Some(0) | Some(1) => Ok(stderr), + Some(0) | Some(1) | Some(101) => Ok(stderr), _ => Err(Box::new(Error::new( ErrorKind::Other, format!("failed with status {:?}: {}", res.status.code(), stderr), From 0adacf872071b587245383dd929b4a4f1ee60965 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 17 Jan 2018 21:43:59 +0100 Subject: [PATCH 101/298] Fix overwriting suggestions when there are > 1 Forgot to copy this piece of clever algorithm from the CLI. --- tests/everything.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/everything.rs b/tests/everything.rs index 5ea403e73..f5cb19d0e 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -143,7 +143,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let mut fixed = code.clone(); - for sug in suggestions { + for sug in suggestions.into_iter().rev() { trace!("{:?}", sug); for sol in sug.solutions { trace!("{:?}", sol); From 9121d77d95bd779fd454e17811c0ca95a4dc1506 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 18 Jan 2018 09:53:55 +0100 Subject: [PATCH 102/298] Add test for redundant_closure_call lint --- .../fixtures/redundant_closure_call.fixed.rs | 7 + tests/fixtures/redundant_closure_call.json | 345 ++++++++++++++++++ tests/fixtures/redundant_closure_call.rs | 9 + 3 files changed, 361 insertions(+) create mode 100644 tests/fixtures/redundant_closure_call.fixed.rs create mode 100644 tests/fixtures/redundant_closure_call.json create mode 100644 tests/fixtures/redundant_closure_call.rs diff --git a/tests/fixtures/redundant_closure_call.fixed.rs b/tests/fixtures/redundant_closure_call.fixed.rs new file mode 100644 index 000000000..83b2de41b --- /dev/null +++ b/tests/fixtures/redundant_closure_call.fixed.rs @@ -0,0 +1,7 @@ +fn main() { + let a = 42; + + let b = 42; + + let c = "x"; +} diff --git a/tests/fixtures/redundant_closure_call.json b/tests/fixtures/redundant_closure_call.json new file mode 100644 index 000000000..2f48f639f --- /dev/null +++ b/tests/fixtures/redundant_closure_call.json @@ -0,0 +1,345 @@ +{ + "message": "Try not to call a closure in the expression where it is declared.", + "code": { + "code": "redundant_closure_call", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 24, + "byte_end": 33, + "line_start": 2, + "line_end": 2, + "column_start": 13, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " let a = (|| 42)();", + "highlight_start": 13, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(redundant_closure_call)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "Try doing something like: ", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 24, + "byte_end": 33, + "line_start": 2, + "line_end": 2, + "column_start": 13, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": " let a = (|| 42)();", + "highlight_start": 13, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": "42", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:2:13\n |\n2 | let a = (|| 42)();\n | ^^^^^^^^^ help: Try doing something like: : `42`\n |\n = note: #[warn(redundant_closure_call)] on by default\n\n" +} +{ + "message": "Try not to call a closure in the expression where it is declared.", + "code": { + "code": "redundant_closure_call", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 48, + "byte_end": 70, + "line_start": 4, + "line_end": 6, + "column_start": 13, + "column_end": 8, + "is_primary": true, + "text": [ + { + "text": " let b = (||", + "highlight_start": 13, + "highlight_end": 16 + }, + { + "text": " 42", + "highlight_start": 1, + "highlight_end": 11 + }, + { + "text": " )();", + "highlight_start": 1, + "highlight_end": 8 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "Try doing something like: ", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 48, + "byte_end": 70, + "line_start": 4, + "line_end": 6, + "column_start": 13, + "column_end": 8, + "is_primary": true, + "text": [ + { + "text": " let b = (||", + "highlight_start": 13, + "highlight_end": 16 + }, + { + "text": " 42", + "highlight_start": 1, + "highlight_end": 11 + }, + { + "text": " )();", + "highlight_start": 1, + "highlight_end": 8 + } + ], + "label": null, + "suggested_replacement": "42", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:4:13\n |\n4 | let b = (||\n | _____________^\n5 | | 42\n6 | | )();\n | |_______^ help: Try doing something like: : `42`\n\n" +} +{ + "message": "Try not to call a closure in the expression where it is declared.", + "code": { + "code": "redundant_closure_call", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 85, + "byte_end": 95, + "line_start": 8, + "line_end": 8, + "column_start": 13, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " let c = (|| \"x\")();", + "highlight_start": 13, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "Try doing something like: ", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 85, + "byte_end": 95, + "line_start": 8, + "line_end": 8, + "column_start": 13, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " let c = (|| \"x\")();", + "highlight_start": 13, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": "\"x\"", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:8:13\n |\n8 | let c = (|| \"x\")();\n | ^^^^^^^^^^ help: Try doing something like: : `\"x\"`\n\n" +} +{ + "message": "unused variable: `a`", + "code": { + "code": "unused_variables", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 20, + "byte_end": 21, + "line_start": 2, + "line_end": 2, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let a = (|| 42)();", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(unused_variables)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "to avoid this warning, consider using `_a` instead", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused variable: `a`\n --> ./tests/fixtures/redundant_closure_call.rs:2:9\n |\n2 | let a = (|| 42)();\n | ^\n |\n = note: #[warn(unused_variables)] on by default\n = note: to avoid this warning, consider using `_a` instead\n\n" +} +{ + "message": "unused variable: `b`", + "code": { + "code": "unused_variables", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 44, + "byte_end": 45, + "line_start": 4, + "line_end": 4, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let b = (||", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "to avoid this warning, consider using `_b` instead", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused variable: `b`\n --> ./tests/fixtures/redundant_closure_call.rs:4:9\n |\n4 | let b = (||\n | ^\n |\n = note: to avoid this warning, consider using `_b` instead\n\n" +} +{ + "message": "unused variable: `c`", + "code": { + "code": "unused_variables", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/redundant_closure_call.rs", + "byte_start": 81, + "byte_end": 82, + "line_start": 8, + "line_end": 8, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let c = (|| \"x\")();", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "to avoid this warning, consider using `_c` instead", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused variable: `c`\n --> ./tests/fixtures/redundant_closure_call.rs:8:9\n |\n8 | let c = (|| \"x\")();\n | ^\n |\n = note: to avoid this warning, consider using `_c` instead\n\n" +} diff --git a/tests/fixtures/redundant_closure_call.rs b/tests/fixtures/redundant_closure_call.rs new file mode 100644 index 000000000..fc0e740cb --- /dev/null +++ b/tests/fixtures/redundant_closure_call.rs @@ -0,0 +1,9 @@ +fn main() { + let a = (|| 42)(); + + let b = (|| + 42 + )(); + + let c = (|| "x")(); +} From 3d610f338d011b3c355d97d5b5c0fe2751ad2736 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 19 Jan 2018 13:34:14 +0100 Subject: [PATCH 103/298] Add test for fold_any --- .travis.yml | 2 +- tests/fixtures/fold-any.fixed.rs | 7 ++ tests/fixtures/fold-any.json | 204 +++++++++++++++++++++++++++++++ tests/fixtures/fold-any.rs | 8 ++ 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/fold-any.fixed.rs create mode 100644 tests/fixtures/fold-any.json create mode 100644 tests/fixtures/fold-any.rs diff --git a/.travis.yml b/.travis.yml index 11e6012fb..add90f50f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ rust: - nightly - stable before_script: -- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo install clippy --force ; fi +- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo install clippy --git https://github.com/rust-lang-nursery/rust-clippy.git --force; fi script: - cargo build - if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi diff --git a/tests/fixtures/fold-any.fixed.rs b/tests/fixtures/fold-any.fixed.rs new file mode 100644 index 000000000..7644508e0 --- /dev/null +++ b/tests/fixtures/fold-any.fixed.rs @@ -0,0 +1,7 @@ +fn main() { + let _ = (0..3).any(|x| x > 2); + + let _ = (0..3).any(|x| x > 2); + + let _ = (0..3).all(|x| x > 2); +} diff --git a/tests/fixtures/fold-any.json b/tests/fixtures/fold-any.json new file mode 100644 index 000000000..9a11d6230 --- /dev/null +++ b/tests/fixtures/fold-any.json @@ -0,0 +1,204 @@ +{ + "message": "this `.fold` can be written more succinctly using another method", + "code": { + "code": "unnecessary_fold", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 30, + "byte_end": 65, + "line_start": 2, + "line_end": 2, + "column_start": 19, + "column_end": 54, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3).fold(false, |acc, x| acc || x > 2);", + "highlight_start": 19, + "highlight_end": 54 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(unnecessary_fold)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "try", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 30, + "byte_end": 65, + "line_start": 2, + "line_end": 2, + "column_start": 19, + "column_end": 54, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3).fold(false, |acc, x| acc || x > 2);", + "highlight_start": 19, + "highlight_end": 54 + } + ], + "label": null, + "suggested_replacement": ".any(|x| x > 2)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:2:19\n |\n2 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`\n |\n = note: #[warn(unnecessary_fold)] on by default\n\n" +} +{ + "message": "this `.fold` can be written more succinctly using another method", + "code": { + "code": "unnecessary_fold", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 86, + "byte_end": 134, + "line_start": 4, + "line_end": 5, + "column_start": 19, + "column_end": 48, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3)", + "highlight_start": 19, + "highlight_end": 19 + }, + { + "text": " .fold(false, |acc, x| { acc || x > 2 });", + "highlight_start": 1, + "highlight_end": 48 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "try", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 86, + "byte_end": 134, + "line_start": 4, + "line_end": 5, + "column_start": 19, + "column_end": 48, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3)", + "highlight_start": 19, + "highlight_end": 19 + }, + { + "text": " .fold(false, |acc, x| { acc || x > 2 });", + "highlight_start": 1, + "highlight_end": 48 + } + ], + "label": null, + "suggested_replacement": ".any(|x| x > 2)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:4:19\n |\n4 | let _ = (0..3)\n | ___________________^\n5 | | .fold(false, |acc, x| { acc || x > 2 });\n | |_______________________________________________^ help: try: `.any(|x| x > 2)`\n\n" +} +{ + "message": "this `.fold` can be written more succinctly using another method", + "code": { + "code": "unnecessary_fold", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 155, + "byte_end": 189, + "line_start": 7, + "line_end": 7, + "column_start": 19, + "column_end": 53, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3).fold(true, |acc, x| acc && x > 2);", + "highlight_start": 19, + "highlight_end": 53 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "try", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/fold-any.rs", + "byte_start": 155, + "byte_end": 189, + "line_start": 7, + "line_end": 7, + "column_start": 19, + "column_end": 53, + "is_primary": true, + "text": [ + { + "text": " let _ = (0..3).fold(true, |acc, x| acc && x > 2);", + "highlight_start": 19, + "highlight_end": 53 + } + ], + "label": null, + "suggested_replacement": ".all(|x| x > 2)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:7:19\n |\n7 | let _ = (0..3).fold(true, |acc, x| acc && x > 2);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)`\n\n" +} diff --git a/tests/fixtures/fold-any.rs b/tests/fixtures/fold-any.rs new file mode 100644 index 000000000..acaae4f7d --- /dev/null +++ b/tests/fixtures/fold-any.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = (0..3).fold(false, |acc, x| acc || x > 2); + + let _ = (0..3) + .fold(false, |acc, x| { acc || x > 2 }); + + let _ = (0..3).fold(true, |acc, x| acc && x > 2); +} From 5ad590b568179c0bf32b31db54b0e908ce3e4349 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 19 Jan 2018 17:13:41 +0100 Subject: [PATCH 104/298] Add test for ambiguous `<` Inspired by https://twitter.com/b0rk/status/954366146505052160 --- tests/fixtures/lt-generic-comp.fixed.rs | 7 ++ tests/fixtures/lt-generic-comp.json | 87 +++++++++++++++++++++++++ tests/fixtures/lt-generic-comp.rs | 7 ++ 3 files changed, 101 insertions(+) create mode 100644 tests/fixtures/lt-generic-comp.fixed.rs create mode 100644 tests/fixtures/lt-generic-comp.json create mode 100644 tests/fixtures/lt-generic-comp.rs diff --git a/tests/fixtures/lt-generic-comp.fixed.rs b/tests/fixtures/lt-generic-comp.fixed.rs new file mode 100644 index 000000000..533c91734 --- /dev/null +++ b/tests/fixtures/lt-generic-comp.fixed.rs @@ -0,0 +1,7 @@ +fn main() { + let x = 5i64; + + if (x as u32) < 4 { + println!("yay"); + } +} diff --git a/tests/fixtures/lt-generic-comp.json b/tests/fixtures/lt-generic-comp.json new file mode 100644 index 000000000..4e8806054 --- /dev/null +++ b/tests/fixtures/lt-generic-comp.json @@ -0,0 +1,87 @@ +{ + "message": "`<` is interpreted as a start of generic arguments for `u32`, not a comparison", + "code": null, + "level": "error", + "spans": [ + { + "file_name": "./tests/fixtures/lt-generic-comp.rs", + "byte_start": 49, + "byte_end": 50, + "line_start": 4, + "line_end": 4, + "column_start": 19, + "column_end": 20, + "is_primary": false, + "text": [ + { + "text": " if x as u32 < 4 {", + "highlight_start": 19, + "highlight_end": 20 + } + ], + "label": "interpreted as generic arguments", + "suggested_replacement": null, + "expansion": null + }, + { + "file_name": "./tests/fixtures/lt-generic-comp.rs", + "byte_start": 47, + "byte_end": 48, + "line_start": 4, + "line_end": 4, + "column_start": 17, + "column_end": 18, + "is_primary": true, + "text": [ + { + "text": " if x as u32 < 4 {", + "highlight_start": 17, + "highlight_end": 18 + } + ], + "label": "not interpreted as comparison", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "try comparing the casted value", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/lt-generic-comp.rs", + "byte_start": 38, + "byte_end": 46, + "line_start": 4, + "line_end": 4, + "column_start": 8, + "column_end": 16, + "is_primary": true, + "text": [ + { + "text": " if x as u32 < 4 {", + "highlight_start": 8, + "highlight_end": 16 + } + ], + "label": null, + "suggested_replacement": "(x as u32)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison\n --> ./tests/fixtures/lt-generic-comp.rs:4:17\n |\n4 | if x as u32 < 4 {\n | -------- ^ - interpreted as generic arguments\n | | |\n | | not interpreted as comparison\n | help: try comparing the casted value: `(x as u32)`\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} diff --git a/tests/fixtures/lt-generic-comp.rs b/tests/fixtures/lt-generic-comp.rs new file mode 100644 index 000000000..c279b261f --- /dev/null +++ b/tests/fixtures/lt-generic-comp.rs @@ -0,0 +1,7 @@ +fn main() { + let x = 5i64; + + if x as u32 < 4 { + println!("yay"); + } +} From 7495251e3c3d61f2f8d11484228fff911af20231 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 20 Jan 2018 16:06:31 +0100 Subject: [PATCH 105/298] Don't loop{} on errors during suggestion parsing --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e02c558d6..e8302cd62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,8 @@ use diagnostics::{Diagnostic, DiagnosticSpan}; pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { serde_json::Deserializer::from_str(input) .into_iter::() - // eat parsing errors - .flat_map(|line| line.ok()) // One diagnostic line might have multiple suggestions - .filter_map(|cargo_msg| collect_suggestions(&cargo_msg, only)) + .filter_map(|cargo_msg| collect_suggestions(&cargo_msg.unwrap(), only)) .collect() } From c057d602c1d787cc274ec69b74a20be662d80c98 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 21 Jan 2018 13:12:48 +0100 Subject: [PATCH 106/298] Pass down errors instead of unwrapping them --- src/lib.rs | 14 +++++++++----- tests/everything.rs | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e8302cd62..fdae6b443 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,12 +7,16 @@ use std::collections::HashSet; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; -pub fn get_suggestions_from_json(input: &str, only: &HashSet) -> Vec { - serde_json::Deserializer::from_str(input) - .into_iter::() +pub fn get_suggestions_from_json( + input: &str, + only: &HashSet, +) -> serde_json::error::Result> { + let mut result = Vec::new(); + for cargo_msg in serde_json::Deserializer::from_str(input).into_iter::() { // One diagnostic line might have multiple suggestions - .filter_map(|cargo_msg| collect_suggestions(&cargo_msg.unwrap(), only)) - .collect() + result.extend(collect_suggestions(&cargo_msg?, only)); + } + Ok(result) } #[derive(Debug, Copy, Clone, Hash, PartialEq)] diff --git a/tests/everything.rs b/tests/everything.rs index f5cb19d0e..7cc50f7dc 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -125,7 +125,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { debug!("next up: {:?}", file); let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; - let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); + let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()).expect("could not load suggestions"); if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { use std::io::Write; @@ -134,7 +134,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } let expected_json = read_file(&json_file)?; - let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()); + let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()).expect("could not load expected suggesitons"); assert_eq!( expected_suggestions, suggestions, From 29f8a6b4beb2572baebd709e4d9a33b782c89f49 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 7 Mar 2018 10:03:35 -0800 Subject: [PATCH 107/298] Add -f --- src/main.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 5a53498af..4e7138d92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,11 @@ fn try_main() -> Result<(), ProgramError> { .long("only") .help("Only show errors or lints with the specific id(s) (comma separated)") .use_delimiter(true)) + .arg(Arg::with_name("file") + .long("file") + .short("f") + .takes_value(true) + .help("Load errors from the given JSON file")) .get_matches(); let mut extra_args = Vec::new(); @@ -97,7 +102,14 @@ fn try_main() -> Result<(), ProgramError> { } // Get JSON output from rustc... - let json = get_json(&extra_args)?; + let json = if let Some(file) = matches.value_of("file") { + let mut f = File::open(file)?; + let mut j = "".into(); + f.read_to_string(&mut j)?; + j + } else { + get_json(&extra_args)? + }; let suggestions: Vec = json.lines() .filter(not_empty) From f9e67dd15a6df3e70440c2af9d8970241893b91d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 7 Mar 2018 10:09:49 -0800 Subject: [PATCH 108/298] Don't require clippy --- src/main.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4e7138d92..d12aa53fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,7 +72,7 @@ fn try_main() -> Result<(), ProgramError> { .long("file") .short("f") .takes_value(true) - .help("Load errors from the given JSON file")) + .help("Load errors from the given JSON file (produced by `cargo build --message-format=json`)")) .get_matches(); let mut extra_args = Vec::new(); @@ -108,7 +108,7 @@ fn try_main() -> Result<(), ProgramError> { f.read_to_string(&mut j)?; j } else { - get_json(&extra_args)? + get_json(&extra_args, matches.is_present("clippy"))? }; let suggestions: Vec = json.lines() @@ -129,9 +129,14 @@ struct CargoMessage { message: Diagnostic, } -fn get_json(extra_args: &[&str]) -> Result { +fn get_json(extra_args: &[&str], clippy: bool) -> Result { + let build_cmd = if clippy { + "clippy" + } else { + "rustc" + }; let output = try!(Command::new("cargo") - .args(&["clippy", "--message-format", "json"]) + .args(&[build_cmd, "--message-format", "json"]) .arg("--") .args(extra_args) .output()); From dc88cc58b432ccec2eaac5b88ad901962486d37a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 8 Mar 2018 09:24:01 +0100 Subject: [PATCH 109/298] Update lt-generic-comp.json --- tests/fixtures/lt-generic-comp.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures/lt-generic-comp.json b/tests/fixtures/lt-generic-comp.json index 4e8806054..7faed93d2 100644 --- a/tests/fixtures/lt-generic-comp.json +++ b/tests/fixtures/lt-generic-comp.json @@ -46,7 +46,7 @@ ], "children": [ { - "message": "try comparing the casted value", + "message": "try comparing the cast value", "code": null, "level": "help", "spans": [ From aaf9d756ba8c832a160386de3072f8e9c07099b7 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 8 Mar 2018 14:00:28 +0100 Subject: [PATCH 110/298] Make bors happy --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index add90f50f..51719c8b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,14 @@ before_script: script: - cargo build - if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi +branches: + only: + # This is where pull requests from "bors r+" are built. + - staging + # This is where pull requests from "bors try" are built. + - trying + # Uncomment this to enable building pull requests. + - master notifications: email: on_success: never From f212450e0813a3dcf879a0dcdd45de7b6d19fc83 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 8 Mar 2018 14:01:02 +0100 Subject: [PATCH 111/298] Make bors *really* happy --- bors.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 bors.toml diff --git a/bors.toml b/bors.toml new file mode 100644 index 000000000..ca08e818b --- /dev/null +++ b/bors.toml @@ -0,0 +1,3 @@ +status = [ + "continuous-integration/travis-ci/push", +] From bc2efefd5badc6efb7e6b1adaf7dcfecdff016b0 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jan 2018 15:57:24 +0100 Subject: [PATCH 112/298] Add const static lifetime test This is broken right no because of the stray space after the `&` --- tests/fixtures/const_static_lifetime.fixed.rs | 3 + tests/fixtures/const_static_lifetime.json | 111 ++++++++++++++++++ tests/fixtures/const_static_lifetime.rs | 3 + 3 files changed, 117 insertions(+) create mode 100644 tests/fixtures/const_static_lifetime.fixed.rs create mode 100644 tests/fixtures/const_static_lifetime.json create mode 100644 tests/fixtures/const_static_lifetime.rs diff --git a/tests/fixtures/const_static_lifetime.fixed.rs b/tests/fixtures/const_static_lifetime.fixed.rs new file mode 100644 index 000000000..8548296dc --- /dev/null +++ b/tests/fixtures/const_static_lifetime.fixed.rs @@ -0,0 +1,3 @@ +const LOREM: & str = "ipsum"; + +fn main() {} diff --git a/tests/fixtures/const_static_lifetime.json b/tests/fixtures/const_static_lifetime.json new file mode 100644 index 000000000..4ab132d97 --- /dev/null +++ b/tests/fixtures/const_static_lifetime.json @@ -0,0 +1,111 @@ +{ + "message": "Constants have by default a `'static` lifetime", + "code": { + "code": "const_static_lifetime", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/const_static_lifetime.rs", + "byte_start": 14, + "byte_end": 21, + "line_start": 1, + "line_end": 1, + "column_start": 15, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": "const LOREM: &'static str = \"ipsum\";", + "highlight_start": 15, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(const_static_lifetime)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "consider removing `'static`", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/const_static_lifetime.rs", + "byte_start": 14, + "byte_end": 21, + "line_start": 1, + "line_end": 1, + "column_start": 15, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": "const LOREM: &'static str = \"ipsum\";", + "highlight_start": 15, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": "", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: Constants have by default a `'static` lifetime\n --> ./tests/fixtures/const_static_lifetime.rs:1:15\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | ^^^^^^^ help: consider removing `'static`\n |\n = note: #[warn(const_static_lifetime)] on by default\n\n" +} +{ + "message": "constant item is never used: `LOREM`", + "code": { + "code": "dead_code", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/const_static_lifetime.rs", + "byte_start": 0, + "byte_end": 36, + "line_start": 1, + "line_end": 1, + "column_start": 1, + "column_end": 37, + "is_primary": true, + "text": [ + { + "text": "const LOREM: &'static str = \"ipsum\";", + "highlight_start": 1, + "highlight_end": 37 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(dead_code)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "warning: constant item is never used: `LOREM`\n --> ./tests/fixtures/const_static_lifetime.rs:1:1\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n |\n = note: #[warn(dead_code)] on by default\n\n" +} diff --git a/tests/fixtures/const_static_lifetime.rs b/tests/fixtures/const_static_lifetime.rs new file mode 100644 index 000000000..665af8af0 --- /dev/null +++ b/tests/fixtures/const_static_lifetime.rs @@ -0,0 +1,3 @@ +const LOREM: &'static str = "ipsum"; + +fn main() {} From 446451a5455aeb180c3e40d87eee532685703c33 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 8 Mar 2018 09:44:54 +0100 Subject: [PATCH 113/298] Update to latest clippy --- tests/fixtures/E0178.json | 10 +- .../closure-immutable-outer-variable.json | 10 +- tests/fixtures/const_static_lifetime.fixed.rs | 2 +- tests/fixtures/const_static_lifetime.json | 16 +- tests/fixtures/explicit_iter_loop.json | 136 ++++++------- tests/fixtures/lt-generic-comp.json | 4 +- .../fixtures/redundant_closure_call.fixed.rs | 1 + tests/fixtures/redundant_closure_call.json | 185 +++--------------- tests/fixtures/redundant_closure_call.rs | 1 + tests/fixtures/str-lit-type-mismatch.json | 14 +- 10 files changed, 137 insertions(+), 242 deletions(-) diff --git a/tests/fixtures/E0178.json b/tests/fixtures/E0178.json index ad75e8bf5..52ac88c2b 100644 --- a/tests/fixtures/E0178.json +++ b/tests/fixtures/E0178.json @@ -58,5 +58,13 @@ "rendered": null } ], - "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:6:8\n |\n6 | w: &'a Foo + Send,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Send)`\n\n" + "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:6:8\n |\n6 | w: &'a Foo + Send,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Send)`\n\nIf you want more information on this error, try using \"rustc --explain E0178\"\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" } diff --git a/tests/fixtures/closure-immutable-outer-variable.json b/tests/fixtures/closure-immutable-outer-variable.json index 860db573a..3ecfb413d 100644 --- a/tests/fixtures/closure-immutable-outer-variable.json +++ b/tests/fixtures/closure-immutable-outer-variable.json @@ -58,5 +58,13 @@ "rendered": null } ], - "rendered": "error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\n" + "rendered": "error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\nIf you want more information on this error, try using \"rustc --explain E0594\"\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" } diff --git a/tests/fixtures/const_static_lifetime.fixed.rs b/tests/fixtures/const_static_lifetime.fixed.rs index 8548296dc..1160de8a9 100644 --- a/tests/fixtures/const_static_lifetime.fixed.rs +++ b/tests/fixtures/const_static_lifetime.fixed.rs @@ -1,3 +1,3 @@ -const LOREM: & str = "ipsum"; +const LOREM: &str = "ipsum"; fn main() {} diff --git a/tests/fixtures/const_static_lifetime.json b/tests/fixtures/const_static_lifetime.json index 4ab132d97..6c284cd14 100644 --- a/tests/fixtures/const_static_lifetime.json +++ b/tests/fixtures/const_static_lifetime.json @@ -43,22 +43,22 @@ "spans": [ { "file_name": "./tests/fixtures/const_static_lifetime.rs", - "byte_start": 14, - "byte_end": 21, + "byte_start": 13, + "byte_end": 25, "line_start": 1, "line_end": 1, - "column_start": 15, - "column_end": 22, + "column_start": 14, + "column_end": 26, "is_primary": true, "text": [ { "text": "const LOREM: &'static str = \"ipsum\";", - "highlight_start": 15, - "highlight_end": 22 + "highlight_start": 14, + "highlight_end": 26 } ], "label": null, - "suggested_replacement": "", + "suggested_replacement": "&str", "expansion": null } ], @@ -66,7 +66,7 @@ "rendered": null } ], - "rendered": "warning: Constants have by default a `'static` lifetime\n --> ./tests/fixtures/const_static_lifetime.rs:1:15\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | ^^^^^^^ help: consider removing `'static`\n |\n = note: #[warn(const_static_lifetime)] on by default\n\n" + "rendered": "warning: Constants have by default a `'static` lifetime\n --> ./tests/fixtures/const_static_lifetime.rs:1:15\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | -^^^^^^^---- help: consider removing `'static`: `&str`\n |\n = note: #[warn(const_static_lifetime)] on by default\n\n" } { "message": "constant item is never used: `LOREM`", diff --git a/tests/fixtures/explicit_iter_loop.json b/tests/fixtures/explicit_iter_loop.json index f256acbd0..1e286dec3 100644 --- a/tests/fixtures/explicit_iter_loop.json +++ b/tests/fixtures/explicit_iter_loop.json @@ -1,70 +1,70 @@ { - "message": "it is more idiomatic to loop over references to containers instead of using explicit iteration methods", - "code": { - "code": "explicit_iter_loop", - "explanation": null + "message": "it is more idiomatic to loop over references to containers instead of using explicit iteration methods", + "code": { + "code": "explicit_iter_loop", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "./tests/fixtures/explicit_iter_loop.rs", + "byte_start": 54, + "byte_end": 63, + "line_start": 4, + "line_end": 4, + "column_start": 14, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " for x in xs.iter() {", + "highlight_start": 14, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(explicit_iter_loop)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/explicit_iter_loop.rs", - "byte_start": 54, - "byte_end": 63, - "line_start": 4, - "line_end": 4, - "column_start": 14, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " for x in xs.iter() {", - "highlight_start": 14, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(explicit_iter_loop)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "to write this more concisely, try", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/explicit_iter_loop.rs", - "byte_start": 54, - "byte_end": 63, - "line_start": 4, - "line_end": 4, - "column_start": 14, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " for x in xs.iter() {", - "highlight_start": 14, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": "&xs", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: it is more idiomatic to loop over references to containers instead of using explicit iteration methods\n --> ./tests/fixtures/explicit_iter_loop.rs:4:14\n |\n4 | for x in xs.iter() {\n | ^^^^^^^^^ help: to write this more concisely, try: `&xs`\n |\n = note: #[warn(explicit_iter_loop)] on by default\n\n" - } + { + "message": "to write this more concisely, try", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/fixtures/explicit_iter_loop.rs", + "byte_start": 54, + "byte_end": 63, + "line_start": 4, + "line_end": 4, + "column_start": 14, + "column_end": 23, + "is_primary": true, + "text": [ + { + "text": " for x in xs.iter() {", + "highlight_start": 14, + "highlight_end": 23 + } + ], + "label": null, + "suggested_replacement": "&xs", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: it is more idiomatic to loop over references to containers instead of using explicit iteration methods\n --> ./tests/fixtures/explicit_iter_loop.rs:4:14\n |\n4 | for x in xs.iter() {\n | ^^^^^^^^^ help: to write this more concisely, try: `&xs`\n |\n = note: #[warn(explicit_iter_loop)] on by default\n\n" +} diff --git a/tests/fixtures/lt-generic-comp.json b/tests/fixtures/lt-generic-comp.json index 4e8806054..4230585dd 100644 --- a/tests/fixtures/lt-generic-comp.json +++ b/tests/fixtures/lt-generic-comp.json @@ -46,7 +46,7 @@ ], "children": [ { - "message": "try comparing the casted value", + "message": "try comparing the cast value", "code": null, "level": "help", "spans": [ @@ -75,7 +75,7 @@ "rendered": null } ], - "rendered": "error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison\n --> ./tests/fixtures/lt-generic-comp.rs:4:17\n |\n4 | if x as u32 < 4 {\n | -------- ^ - interpreted as generic arguments\n | | |\n | | not interpreted as comparison\n | help: try comparing the casted value: `(x as u32)`\n\n" + "rendered": "error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison\n --> ./tests/fixtures/lt-generic-comp.rs:4:17\n |\n4 | if x as u32 < 4 {\n | -------- ^ - interpreted as generic arguments\n | | |\n | | not interpreted as comparison\n | help: try comparing the cast value: `(x as u32)`\n\n" } { "message": "aborting due to previous error", diff --git a/tests/fixtures/redundant_closure_call.fixed.rs b/tests/fixtures/redundant_closure_call.fixed.rs index 83b2de41b..00cc55f7c 100644 --- a/tests/fixtures/redundant_closure_call.fixed.rs +++ b/tests/fixtures/redundant_closure_call.fixed.rs @@ -1,3 +1,4 @@ +#[allow(unused_variables)] fn main() { let a = 42; diff --git a/tests/fixtures/redundant_closure_call.json b/tests/fixtures/redundant_closure_call.json index 2f48f639f..ecc603070 100644 --- a/tests/fixtures/redundant_closure_call.json +++ b/tests/fixtures/redundant_closure_call.json @@ -8,10 +8,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 24, - "byte_end": 33, - "line_start": 2, - "line_end": 2, + "byte_start": 51, + "byte_end": 60, + "line_start": 3, + "line_end": 3, "column_start": 13, "column_end": 22, "is_primary": true, @@ -43,10 +43,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 24, - "byte_end": 33, - "line_start": 2, - "line_end": 2, + "byte_start": 51, + "byte_end": 60, + "line_start": 3, + "line_end": 3, "column_start": 13, "column_end": 22, "is_primary": true, @@ -66,7 +66,7 @@ "rendered": null } ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:2:13\n |\n2 | let a = (|| 42)();\n | ^^^^^^^^^ help: Try doing something like: : `42`\n |\n = note: #[warn(redundant_closure_call)] on by default\n\n" + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:3:13\n |\n3 | let a = (|| 42)();\n | ^^^^^^^^^ help: Try doing something like: : `42`\n |\n = note: #[warn(redundant_closure_call)] on by default\n\n" } { "message": "Try not to call a closure in the expression where it is declared.", @@ -78,10 +78,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 48, - "byte_end": 70, - "line_start": 4, - "line_end": 6, + "byte_start": 75, + "byte_end": 97, + "line_start": 5, + "line_end": 7, "column_start": 13, "column_end": 8, "is_primary": true, @@ -115,10 +115,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 48, - "byte_end": 70, - "line_start": 4, - "line_end": 6, + "byte_start": 75, + "byte_end": 97, + "line_start": 5, + "line_end": 7, "column_start": 13, "column_end": 8, "is_primary": true, @@ -148,7 +148,7 @@ "rendered": null } ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:4:13\n |\n4 | let b = (||\n | _____________^\n5 | | 42\n6 | | )();\n | |_______^ help: Try doing something like: : `42`\n\n" + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:5:13\n |\n5 | let b = (||\n | _____________^\n6 | | 42\n7 | | )();\n | |_______^ help: Try doing something like: : `42`\n\n" } { "message": "Try not to call a closure in the expression where it is declared.", @@ -160,10 +160,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 85, - "byte_end": 95, - "line_start": 8, - "line_end": 8, + "byte_start": 112, + "byte_end": 122, + "line_start": 9, + "line_end": 9, "column_start": 13, "column_end": 23, "is_primary": true, @@ -187,10 +187,10 @@ "spans": [ { "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 85, - "byte_end": 95, - "line_start": 8, - "line_end": 8, + "byte_start": 112, + "byte_end": 122, + "line_start": 9, + "line_end": 9, "column_start": 13, "column_end": 23, "is_primary": true, @@ -210,136 +210,5 @@ "rendered": null } ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:8:13\n |\n8 | let c = (|| \"x\")();\n | ^^^^^^^^^^ help: Try doing something like: : `\"x\"`\n\n" -} -{ - "message": "unused variable: `a`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 20, - "byte_end": 21, - "line_start": 2, - "line_end": 2, - "column_start": 9, - "column_end": 10, - "is_primary": true, - "text": [ - { - "text": " let a = (|| 42)();", - "highlight_start": 9, - "highlight_end": 10 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unused_variables)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "to avoid this warning, consider using `_a` instead", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `a`\n --> ./tests/fixtures/redundant_closure_call.rs:2:9\n |\n2 | let a = (|| 42)();\n | ^\n |\n = note: #[warn(unused_variables)] on by default\n = note: to avoid this warning, consider using `_a` instead\n\n" -} -{ - "message": "unused variable: `b`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 44, - "byte_end": 45, - "line_start": 4, - "line_end": 4, - "column_start": 9, - "column_end": 10, - "is_primary": true, - "text": [ - { - "text": " let b = (||", - "highlight_start": 9, - "highlight_end": 10 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "to avoid this warning, consider using `_b` instead", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `b`\n --> ./tests/fixtures/redundant_closure_call.rs:4:9\n |\n4 | let b = (||\n | ^\n |\n = note: to avoid this warning, consider using `_b` instead\n\n" -} -{ - "message": "unused variable: `c`", - "code": { - "code": "unused_variables", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 81, - "byte_end": 82, - "line_start": 8, - "line_end": 8, - "column_start": 9, - "column_end": 10, - "is_primary": true, - "text": [ - { - "text": " let c = (|| \"x\")();", - "highlight_start": 9, - "highlight_end": 10 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "to avoid this warning, consider using `_c` instead", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused variable: `c`\n --> ./tests/fixtures/redundant_closure_call.rs:8:9\n |\n8 | let c = (|| \"x\")();\n | ^\n |\n = note: to avoid this warning, consider using `_c` instead\n\n" + "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:9:13\n |\n9 | let c = (|| \"x\")();\n | ^^^^^^^^^^ help: Try doing something like: : `\"x\"`\n\n" } diff --git a/tests/fixtures/redundant_closure_call.rs b/tests/fixtures/redundant_closure_call.rs index fc0e740cb..1ed42686f 100644 --- a/tests/fixtures/redundant_closure_call.rs +++ b/tests/fixtures/redundant_closure_call.rs @@ -1,3 +1,4 @@ +#[allow(unused_variables)] fn main() { let a = (|| 42)(); diff --git a/tests/fixtures/str-lit-type-mismatch.json b/tests/fixtures/str-lit-type-mismatch.json index ddd952983..0e3e7643c 100644 --- a/tests/fixtures/str-lit-type-mismatch.json +++ b/tests/fixtures/str-lit-type-mismatch.json @@ -66,7 +66,7 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" } { "message": "mismatched types", @@ -136,7 +136,7 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" } { "message": "mismatched types", @@ -206,5 +206,13 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" +} +{ + "message": "aborting due to 3 previous errors", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to 3 previous errors\n\n" } From f7433c35ee1fa71246ab7ba8c9f4e0a9c45fc372 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 14 Mar 2018 06:37:17 +0100 Subject: [PATCH 114/298] Update bors.toml --- bors.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bors.toml b/bors.toml index ca08e818b..611828927 100644 --- a/bors.toml +++ b/bors.toml @@ -1,3 +1,4 @@ status = [ "continuous-integration/travis-ci/push", ] +required_approvals = 1 From 087770924b936f26642d5f07a615f3221b1d5e63 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 15 Mar 2018 16:30:31 +0100 Subject: [PATCH 115/298] remove -f shorthand for --file --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index d12aa53fc..0c8e2b3fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,6 @@ fn try_main() -> Result<(), ProgramError> { .use_delimiter(true)) .arg(Arg::with_name("file") .long("file") - .short("f") .takes_value(true) .help("Load errors from the given JSON file (produced by `cargo build --message-format=json`)")) .get_matches(); From c6c156fa4e37b3c1b05579c66b7db636b8798d53 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 2 May 2018 00:07:31 +0200 Subject: [PATCH 116/298] remove test that currently doesn't work probably because we need to enable clippy lint groups (but I don't want to spend time on this right now) --- tests/fixtures/const_static_lifetime.fixed.rs | 3 - tests/fixtures/const_static_lifetime.json | 111 ------------------ tests/fixtures/const_static_lifetime.rs | 3 - 3 files changed, 117 deletions(-) delete mode 100644 tests/fixtures/const_static_lifetime.fixed.rs delete mode 100644 tests/fixtures/const_static_lifetime.json delete mode 100644 tests/fixtures/const_static_lifetime.rs diff --git a/tests/fixtures/const_static_lifetime.fixed.rs b/tests/fixtures/const_static_lifetime.fixed.rs deleted file mode 100644 index 1160de8a9..000000000 --- a/tests/fixtures/const_static_lifetime.fixed.rs +++ /dev/null @@ -1,3 +0,0 @@ -const LOREM: &str = "ipsum"; - -fn main() {} diff --git a/tests/fixtures/const_static_lifetime.json b/tests/fixtures/const_static_lifetime.json deleted file mode 100644 index 6c284cd14..000000000 --- a/tests/fixtures/const_static_lifetime.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "message": "Constants have by default a `'static` lifetime", - "code": { - "code": "const_static_lifetime", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/const_static_lifetime.rs", - "byte_start": 14, - "byte_end": 21, - "line_start": 1, - "line_end": 1, - "column_start": 15, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": "const LOREM: &'static str = \"ipsum\";", - "highlight_start": 15, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(const_static_lifetime)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "consider removing `'static`", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/const_static_lifetime.rs", - "byte_start": 13, - "byte_end": 25, - "line_start": 1, - "line_end": 1, - "column_start": 14, - "column_end": 26, - "is_primary": true, - "text": [ - { - "text": "const LOREM: &'static str = \"ipsum\";", - "highlight_start": 14, - "highlight_end": 26 - } - ], - "label": null, - "suggested_replacement": "&str", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: Constants have by default a `'static` lifetime\n --> ./tests/fixtures/const_static_lifetime.rs:1:15\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | -^^^^^^^---- help: consider removing `'static`: `&str`\n |\n = note: #[warn(const_static_lifetime)] on by default\n\n" -} -{ - "message": "constant item is never used: `LOREM`", - "code": { - "code": "dead_code", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/const_static_lifetime.rs", - "byte_start": 0, - "byte_end": 36, - "line_start": 1, - "line_end": 1, - "column_start": 1, - "column_end": 37, - "is_primary": true, - "text": [ - { - "text": "const LOREM: &'static str = \"ipsum\";", - "highlight_start": 1, - "highlight_end": 37 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(dead_code)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - } - ], - "rendered": "warning: constant item is never used: `LOREM`\n --> ./tests/fixtures/const_static_lifetime.rs:1:1\n |\n1 | const LOREM: &'static str = \"ipsum\";\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n |\n = note: #[warn(dead_code)] on by default\n\n" -} diff --git a/tests/fixtures/const_static_lifetime.rs b/tests/fixtures/const_static_lifetime.rs deleted file mode 100644 index 665af8af0..000000000 --- a/tests/fixtures/const_static_lifetime.rs +++ /dev/null @@ -1,3 +0,0 @@ -const LOREM: &'static str = "ipsum"; - -fn main() {} From 571b43a1a1777561ddd7a41b37512bf0e3452c1a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 2 May 2018 00:07:58 +0200 Subject: [PATCH 117/298] Move `apply_suggestion{s,}` to rustfix lib --- src/lib.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 40 ++----------------------------- tests/everything.rs | 58 ++------------------------------------------- 3 files changed, 61 insertions(+), 94 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fdae6b443..71d2947a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ extern crate serde_derive; extern crate serde_json; use std::collections::HashSet; +use std::error::Error; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; @@ -165,3 +166,59 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, }) } } + +pub fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> String { + use std::cmp::max; + + let mut new_content = String::new(); + + // Add the lines before the section we want to replace + new_content.push_str(&file_content.lines() + .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + // Parts of line before replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.snippet.line_range.start.line - 1) + .unwrap_or("") + .chars() + .take(suggestion.snippet.line_range.start.column - 1) + .collect::()); + + // Insert new content! Finally! + new_content.push_str(&suggestion.replacement); + + // Parts of line after replacement + new_content.push_str(&file_content.lines() + .nth(suggestion.snippet.line_range.end.line - 1) + .unwrap_or("") + .chars() + .skip(suggestion.snippet.line_range.end.column - 1) + .collect::()); + + // Add the lines after the section we want to replace + new_content.push_str("\n"); + new_content.push_str(&file_content.lines() + .skip(suggestion.snippet.line_range.end.line as usize) + .collect::>() + .join("\n")); + new_content.push_str("\n"); + + new_content +} + +pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> String { + let mut fixed = code.to_string(); + + for sug in suggestions.iter().rev() { + for sol in &sug.solutions { + for r in &sol.replacements { + fixed = apply_suggestion(&mut fixed, r); + } + } + } + + fixed +} diff --git a/src/main.rs b/src/main.rs index 0c8e2b3fb..8cce54190 100644 --- a/src/main.rs +++ b/src/main.rs @@ -398,44 +398,8 @@ fn indent(size: u32, s: &str) -> String { /// This function is as stupid as possible. Make sure you call for the replacemnts in one file in /// reverse order to not mess up the lines for replacements further down the road. fn apply_suggestion(suggestion: &Replacement) -> Result<(), ProgramError> { - use std::cmp::max; - - let file_content = try!(read_file_to_string(&suggestion.snippet.file_name)); - let mut new_content = String::new(); - - // Add the lines before the section we want to replace - new_content.push_str(&file_content.lines() - .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); - - // Parts of line before replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.start.line - 1) - .unwrap_or("") - .chars() - .take(suggestion.snippet.line_range.start.column - 1) - .collect::()); - - // Insert new content! Finally! - new_content.push_str(&suggestion.replacement); - - // Parts of line after replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.end.line - 1) - .unwrap_or("") - .chars() - .skip(suggestion.snippet.line_range.end.column - 1) - .collect::()); - - // Add the lines after the section we want to replace - new_content.push_str("\n"); - new_content.push_str(&file_content.lines() - .skip(suggestion.snippet.line_range.end.line as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); + let mut file_content = try!(read_file_to_string(&suggestion.snippet.file_name)); + let new_content = rustfix::apply_suggestion(&mut file_content, suggestion); let mut file = try!(File::create(&suggestion.snippet.file_name)); let new_content = new_content.as_bytes(); diff --git a/tests/everything.rs b/tests/everything.rs index 7cc50f7dc..029bf13ba 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -13,7 +13,7 @@ use std::collections::HashSet; use std::process::Output; use tempdir::TempDir; -use rustfix::Replacement; +use rustfix::{Replacement, apply_suggestions}; fn compile(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; @@ -75,48 +75,6 @@ fn read_file(path: &Path) -> Result> { Ok(buffer) } -fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> Result> { - use std::cmp::max; - - let mut new_content = String::new(); - - // Add the lines before the section we want to replace - new_content.push_str(&file_content.lines() - .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); - - // Parts of line before replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.start.line - 1) - .unwrap_or("") - .chars() - .take(suggestion.snippet.line_range.start.column - 1) - .collect::()); - - // Insert new content! Finally! - new_content.push_str(&suggestion.replacement); - - // Parts of line after replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.end.line - 1) - .unwrap_or("") - .chars() - .skip(suggestion.snippet.line_range.end.column - 1) - .collect::()); - - // Add the lines after the section we want to replace - new_content.push_str("\n"); - new_content.push_str(&file_content.lines() - .skip(suggestion.snippet.line_range.end.line as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); - - Ok(new_content) -} - fn test_rustfix_with_file>(file: P) -> Result<(), Box> { let file: &Path = file.as_ref(); let json_file = file.with_extension("json"); @@ -141,19 +99,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { "got unexpected suggestions from clippy", ); - let mut fixed = code.clone(); - - for sug in suggestions.into_iter().rev() { - trace!("{:?}", sug); - for sol in sug.solutions { - trace!("{:?}", sol); - for r in sol.replacements { - debug!("replaced."); - trace!("{:?}", r); - fixed = apply_suggestion(&mut fixed, &r)?; - } - } - } + let fixed = apply_suggestions(&code, &suggestions); if std::env::var("RUSTFIX_TEST_RECORD_FIXED_RUST").is_ok() { use std::io::Write; From a5123f0751e5186a0cb16f6fc1462793a5d83866 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 May 2018 15:38:47 -0700 Subject: [PATCH 118/298] Remove tests that require clippy Looks like they're failing on nightly and hopefully we'll get enough coverage in rust-lang/rust itself to cover these use cases. --- .travis.yml | 2 - tests/everything.rs | 2 +- tests/fixtures/explicit_iter_loop.fixed.rs | 7 - tests/fixtures/explicit_iter_loop.json | 70 ------ tests/fixtures/explicit_iter_loop.rs | 7 - tests/fixtures/fold-any.fixed.rs | 7 - tests/fixtures/fold-any.json | 204 ----------------- tests/fixtures/fold-any.rs | 8 - tests/fixtures/needless_borrow.fixed.rs | 9 - tests/fixtures/needless_borrow.json | 132 ----------- tests/fixtures/needless_borrow.rs | 9 - .../fixtures/redundant_closure_call.fixed.rs | 8 - tests/fixtures/redundant_closure_call.json | 214 ------------------ tests/fixtures/redundant_closure_call.rs | 10 - 14 files changed, 1 insertion(+), 688 deletions(-) delete mode 100644 tests/fixtures/explicit_iter_loop.fixed.rs delete mode 100644 tests/fixtures/explicit_iter_loop.json delete mode 100644 tests/fixtures/explicit_iter_loop.rs delete mode 100644 tests/fixtures/fold-any.fixed.rs delete mode 100644 tests/fixtures/fold-any.json delete mode 100644 tests/fixtures/fold-any.rs delete mode 100644 tests/fixtures/needless_borrow.fixed.rs delete mode 100644 tests/fixtures/needless_borrow.json delete mode 100644 tests/fixtures/needless_borrow.rs delete mode 100644 tests/fixtures/redundant_closure_call.fixed.rs delete mode 100644 tests/fixtures/redundant_closure_call.json delete mode 100644 tests/fixtures/redundant_closure_call.rs diff --git a/.travis.yml b/.travis.yml index 51719c8b6..519b9dda2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: rust rust: - nightly - stable -before_script: -- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo install clippy --git https://github.com/rust-lang-nursery/rust-clippy.git --force; fi script: - cargo build - if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi diff --git a/tests/everything.rs b/tests/everything.rs index 029bf13ba..7206db89b 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -18,7 +18,7 @@ use rustfix::{Replacement, apply_suggestions}; fn compile(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; let better_call_clippy = cmd!( - "clippy-driver", "rustc", file, + "rustc", file, "--error-format=pretty-json", "-Zunstable-options", "--emit=metadata", "--crate-name=rustfix_test", "--out-dir", tmp.path() diff --git a/tests/fixtures/explicit_iter_loop.fixed.rs b/tests/fixtures/explicit_iter_loop.fixed.rs deleted file mode 100644 index 0ffeff17b..000000000 --- a/tests/fixtures/explicit_iter_loop.fixed.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let xs = vec![1, 2, 3]; - - for x in &xs { - println!("{}", x) - } -} diff --git a/tests/fixtures/explicit_iter_loop.json b/tests/fixtures/explicit_iter_loop.json deleted file mode 100644 index 1e286dec3..000000000 --- a/tests/fixtures/explicit_iter_loop.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "message": "it is more idiomatic to loop over references to containers instead of using explicit iteration methods", - "code": { - "code": "explicit_iter_loop", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/explicit_iter_loop.rs", - "byte_start": 54, - "byte_end": 63, - "line_start": 4, - "line_end": 4, - "column_start": 14, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " for x in xs.iter() {", - "highlight_start": 14, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(explicit_iter_loop)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "to write this more concisely, try", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/explicit_iter_loop.rs", - "byte_start": 54, - "byte_end": 63, - "line_start": 4, - "line_end": 4, - "column_start": 14, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " for x in xs.iter() {", - "highlight_start": 14, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": "&xs", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: it is more idiomatic to loop over references to containers instead of using explicit iteration methods\n --> ./tests/fixtures/explicit_iter_loop.rs:4:14\n |\n4 | for x in xs.iter() {\n | ^^^^^^^^^ help: to write this more concisely, try: `&xs`\n |\n = note: #[warn(explicit_iter_loop)] on by default\n\n" -} diff --git a/tests/fixtures/explicit_iter_loop.rs b/tests/fixtures/explicit_iter_loop.rs deleted file mode 100644 index 2e9c84129..000000000 --- a/tests/fixtures/explicit_iter_loop.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let xs = vec![1, 2, 3]; - - for x in xs.iter() { - println!("{}", x) - } -} diff --git a/tests/fixtures/fold-any.fixed.rs b/tests/fixtures/fold-any.fixed.rs deleted file mode 100644 index 7644508e0..000000000 --- a/tests/fixtures/fold-any.fixed.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let _ = (0..3).any(|x| x > 2); - - let _ = (0..3).any(|x| x > 2); - - let _ = (0..3).all(|x| x > 2); -} diff --git a/tests/fixtures/fold-any.json b/tests/fixtures/fold-any.json deleted file mode 100644 index 9a11d6230..000000000 --- a/tests/fixtures/fold-any.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "message": "this `.fold` can be written more succinctly using another method", - "code": { - "code": "unnecessary_fold", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 30, - "byte_end": 65, - "line_start": 2, - "line_end": 2, - "column_start": 19, - "column_end": 54, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3).fold(false, |acc, x| acc || x > 2);", - "highlight_start": 19, - "highlight_end": 54 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unnecessary_fold)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "try", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 30, - "byte_end": 65, - "line_start": 2, - "line_end": 2, - "column_start": 19, - "column_end": 54, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3).fold(false, |acc, x| acc || x > 2);", - "highlight_start": 19, - "highlight_end": 54 - } - ], - "label": null, - "suggested_replacement": ".any(|x| x > 2)", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:2:19\n |\n2 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`\n |\n = note: #[warn(unnecessary_fold)] on by default\n\n" -} -{ - "message": "this `.fold` can be written more succinctly using another method", - "code": { - "code": "unnecessary_fold", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 86, - "byte_end": 134, - "line_start": 4, - "line_end": 5, - "column_start": 19, - "column_end": 48, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3)", - "highlight_start": 19, - "highlight_end": 19 - }, - { - "text": " .fold(false, |acc, x| { acc || x > 2 });", - "highlight_start": 1, - "highlight_end": 48 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "try", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 86, - "byte_end": 134, - "line_start": 4, - "line_end": 5, - "column_start": 19, - "column_end": 48, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3)", - "highlight_start": 19, - "highlight_end": 19 - }, - { - "text": " .fold(false, |acc, x| { acc || x > 2 });", - "highlight_start": 1, - "highlight_end": 48 - } - ], - "label": null, - "suggested_replacement": ".any(|x| x > 2)", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:4:19\n |\n4 | let _ = (0..3)\n | ___________________^\n5 | | .fold(false, |acc, x| { acc || x > 2 });\n | |_______________________________________________^ help: try: `.any(|x| x > 2)`\n\n" -} -{ - "message": "this `.fold` can be written more succinctly using another method", - "code": { - "code": "unnecessary_fold", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 155, - "byte_end": 189, - "line_start": 7, - "line_end": 7, - "column_start": 19, - "column_end": 53, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3).fold(true, |acc, x| acc && x > 2);", - "highlight_start": 19, - "highlight_end": 53 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "try", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/fold-any.rs", - "byte_start": 155, - "byte_end": 189, - "line_start": 7, - "line_end": 7, - "column_start": 19, - "column_end": 53, - "is_primary": true, - "text": [ - { - "text": " let _ = (0..3).fold(true, |acc, x| acc && x > 2);", - "highlight_start": 19, - "highlight_end": 53 - } - ], - "label": null, - "suggested_replacement": ".all(|x| x > 2)", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this `.fold` can be written more succinctly using another method\n --> ./tests/fixtures/fold-any.rs:7:19\n |\n7 | let _ = (0..3).fold(true, |acc, x| acc && x > 2);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)`\n\n" -} diff --git a/tests/fixtures/fold-any.rs b/tests/fixtures/fold-any.rs deleted file mode 100644 index acaae4f7d..000000000 --- a/tests/fixtures/fold-any.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let _ = (0..3).fold(false, |acc, x| acc || x > 2); - - let _ = (0..3) - .fold(false, |acc, x| { acc || x > 2 }); - - let _ = (0..3).fold(true, |acc, x| acc && x > 2); -} diff --git a/tests/fixtures/needless_borrow.fixed.rs b/tests/fixtures/needless_borrow.fixed.rs deleted file mode 100644 index 546b6bb44..000000000 --- a/tests/fixtures/needless_borrow.fixed.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let _x: &i32 = &&&&&5; - - struct Foo; - fn foo(_x: &Foo) { } - - let x = &Foo; - foo(x); -} diff --git a/tests/fixtures/needless_borrow.json b/tests/fixtures/needless_borrow.json deleted file mode 100644 index 0ef5ab3d7..000000000 --- a/tests/fixtures/needless_borrow.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "message": "this expression borrows a reference that is immediately dereferenced by the compiler", - "code": { - "code": "needless_borrow", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 31, - "byte_end": 38, - "line_start": 2, - "line_end": 2, - "column_start": 20, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _x: &i32 = &&&&&&5;", - "highlight_start": 20, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(needless_borrow)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "change this to", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 31, - "byte_end": 38, - "line_start": 2, - "line_end": 2, - "column_start": 20, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _x: &i32 = &&&&&&5;", - "highlight_start": 20, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": "&&&&&5", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n\n" -} -{ - "message": "this expression borrows a reference that is immediately dereferenced by the compiler", - "code": { - "code": "needless_borrow", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 109, - "byte_end": 111, - "line_start": 8, - "line_end": 8, - "column_start": 9, - "column_end": 11, - "is_primary": true, - "text": [ - { - "text": " foo(&x);", - "highlight_start": 9, - "highlight_end": 11 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "change this to", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/needless_borrow.rs", - "byte_start": 109, - "byte_end": 111, - "line_start": 8, - "line_end": 8, - "column_start": 9, - "column_end": 11, - "is_primary": true, - "text": [ - { - "text": " foo(&x);", - "highlight_start": 9, - "highlight_end": 11 - } - ], - "label": null, - "suggested_replacement": "x", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:8:9\n |\n8 | foo(&x);\n | ^^ help: change this to: `x`\n\n" -} diff --git a/tests/fixtures/needless_borrow.rs b/tests/fixtures/needless_borrow.rs deleted file mode 100644 index b24668c8c..000000000 --- a/tests/fixtures/needless_borrow.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let _x: &i32 = &&&&&&5; - - struct Foo; - fn foo(_x: &Foo) { } - - let x = &Foo; - foo(&x); -} diff --git a/tests/fixtures/redundant_closure_call.fixed.rs b/tests/fixtures/redundant_closure_call.fixed.rs deleted file mode 100644 index 00cc55f7c..000000000 --- a/tests/fixtures/redundant_closure_call.fixed.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[allow(unused_variables)] -fn main() { - let a = 42; - - let b = 42; - - let c = "x"; -} diff --git a/tests/fixtures/redundant_closure_call.json b/tests/fixtures/redundant_closure_call.json deleted file mode 100644 index ecc603070..000000000 --- a/tests/fixtures/redundant_closure_call.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "message": "Try not to call a closure in the expression where it is declared.", - "code": { - "code": "redundant_closure_call", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 51, - "byte_end": 60, - "line_start": 3, - "line_end": 3, - "column_start": 13, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " let a = (|| 42)();", - "highlight_start": 13, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(redundant_closure_call)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "Try doing something like: ", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 51, - "byte_end": 60, - "line_start": 3, - "line_end": 3, - "column_start": 13, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " let a = (|| 42)();", - "highlight_start": 13, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": "42", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:3:13\n |\n3 | let a = (|| 42)();\n | ^^^^^^^^^ help: Try doing something like: : `42`\n |\n = note: #[warn(redundant_closure_call)] on by default\n\n" -} -{ - "message": "Try not to call a closure in the expression where it is declared.", - "code": { - "code": "redundant_closure_call", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 75, - "byte_end": 97, - "line_start": 5, - "line_end": 7, - "column_start": 13, - "column_end": 8, - "is_primary": true, - "text": [ - { - "text": " let b = (||", - "highlight_start": 13, - "highlight_end": 16 - }, - { - "text": " 42", - "highlight_start": 1, - "highlight_end": 11 - }, - { - "text": " )();", - "highlight_start": 1, - "highlight_end": 8 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "Try doing something like: ", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 75, - "byte_end": 97, - "line_start": 5, - "line_end": 7, - "column_start": 13, - "column_end": 8, - "is_primary": true, - "text": [ - { - "text": " let b = (||", - "highlight_start": 13, - "highlight_end": 16 - }, - { - "text": " 42", - "highlight_start": 1, - "highlight_end": 11 - }, - { - "text": " )();", - "highlight_start": 1, - "highlight_end": 8 - } - ], - "label": null, - "suggested_replacement": "42", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:5:13\n |\n5 | let b = (||\n | _____________^\n6 | | 42\n7 | | )();\n | |_______^ help: Try doing something like: : `42`\n\n" -} -{ - "message": "Try not to call a closure in the expression where it is declared.", - "code": { - "code": "redundant_closure_call", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 112, - "byte_end": 122, - "line_start": 9, - "line_end": 9, - "column_start": 13, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " let c = (|| \"x\")();", - "highlight_start": 13, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "Try doing something like: ", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/fixtures/redundant_closure_call.rs", - "byte_start": 112, - "byte_end": 122, - "line_start": 9, - "line_end": 9, - "column_start": 13, - "column_end": 23, - "is_primary": true, - "text": [ - { - "text": " let c = (|| \"x\")();", - "highlight_start": 13, - "highlight_end": 23 - } - ], - "label": null, - "suggested_replacement": "\"x\"", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: Try not to call a closure in the expression where it is declared.\n --> ./tests/fixtures/redundant_closure_call.rs:9:13\n |\n9 | let c = (|| \"x\")();\n | ^^^^^^^^^^ help: Try doing something like: : `\"x\"`\n\n" -} diff --git a/tests/fixtures/redundant_closure_call.rs b/tests/fixtures/redundant_closure_call.rs deleted file mode 100644 index 1ed42686f..000000000 --- a/tests/fixtures/redundant_closure_call.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[allow(unused_variables)] -fn main() { - let a = (|| 42)(); - - let b = (|| - 42 - )(); - - let c = (|| "x")(); -} From 8313660985215389e9184ee60fd0e2575c96b56e Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 3 May 2018 14:41:18 +0200 Subject: [PATCH 119/298] Split rustfix into two crates - rustfix stays as the library crate - cargo-fix becomes the new binary crate --- Cargo.toml | 12 +++++++++--- cargo-fix/Cargo.toml | 13 +++++++++++++ {src => cargo-fix/src}/main.rs | 11 +++++++++-- src/bin/cargo-fix.rs | 4 ---- src/lib.rs | 1 - 5 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 cargo-fix/Cargo.toml rename {src => cargo-fix/src}/main.rs (97%) delete mode 100644 src/bin/cargo-fix.rs diff --git a/Cargo.toml b/Cargo.toml index 4b55c09b9..057c1945d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/killercup/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" -version = "0.1.0" +version = "0.2.0" exclude = [ "etc/*", "examples/*", @@ -17,8 +17,6 @@ exclude = [ ] [dependencies] -clap = "2.9.2" -colored = "1.2.0" quick-error = "1.2.1" serde = "1.0" serde_json = "1.0" @@ -30,3 +28,11 @@ env_logger = "0.5.0-rc.1" log = "0.4.1" pretty_assertions = "0.4.1" tempdir = "0.3.5" + +[workspace] +members = [ + "cargo-fix", +] + +[patch.crates-io] +rustfix = { path = "." } diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml new file mode 100644 index 000000000..c57fda1cc --- /dev/null +++ b/cargo-fix/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cargo-fix" +version = "0.2.0" +authors = ["Pascal Hertleif "] + +[dependencies] +clap = "2.9.2" +colored = "1.2.0" +quick-error = "1.2.1" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" +rustfix = "0.1.0" diff --git a/src/main.rs b/cargo-fix/src/main.rs similarity index 97% rename from src/main.rs rename to cargo-fix/src/main.rs index 8cce54190..97f870b45 100644 --- a/src/main.rs +++ b/cargo-fix/src/main.rs @@ -55,7 +55,14 @@ const ALIASES: &[(&str, &[&str])] = &[ ]; fn try_main() -> Result<(), ProgramError> { - let matches = App::new("rustfix") + // Quickfix to be usable as rustfix as well as cargo-fix + let args = if ::std::env::args_os().nth(1).map(|x| &x == "fix").unwrap_or(false) { + ::std::env::args_os().skip(1) + } else { + ::std::env::args_os().skip(0) + }; + + let matches = App::new("cargo-fix") .about("Automatically apply suggestions made by rustc") .version(crate_version!()) .arg(Arg::with_name("clippy") @@ -72,7 +79,7 @@ fn try_main() -> Result<(), ProgramError> { .long("file") .takes_value(true) .help("Load errors from the given JSON file (produced by `cargo build --message-format=json`)")) - .get_matches(); + .get_matches_from(args); let mut extra_args = Vec::new(); diff --git a/src/bin/cargo-fix.rs b/src/bin/cargo-fix.rs deleted file mode 100644 index e8ecda891..000000000 --- a/src/bin/cargo-fix.rs +++ /dev/null @@ -1,4 +0,0 @@ -// horrible hack to get cargo to not complain about both -// the `cargo-fix` and `rustfix` targets to point to the -// same source file -include!("../main.rs"); diff --git a/src/lib.rs b/src/lib.rs index 71d2947a5..4f2345944 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ extern crate serde_derive; extern crate serde_json; use std::collections::HashSet; -use std::error::Error; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; From 2e87f694e0301370419240b70e77228f064a87e9 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 3 May 2018 15:01:49 +0200 Subject: [PATCH 120/298] Symlink Readme and license files in cargo-fix --- cargo-fix/LICENSE-APACHE | 1 + cargo-fix/LICENSE-MIT | 1 + cargo-fix/Readme.md | 1 + 3 files changed, 3 insertions(+) create mode 120000 cargo-fix/LICENSE-APACHE create mode 120000 cargo-fix/LICENSE-MIT create mode 120000 cargo-fix/Readme.md diff --git a/cargo-fix/LICENSE-APACHE b/cargo-fix/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/cargo-fix/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/cargo-fix/LICENSE-MIT b/cargo-fix/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/cargo-fix/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/cargo-fix/Readme.md b/cargo-fix/Readme.md new file mode 120000 index 000000000..cf2c5c52c --- /dev/null +++ b/cargo-fix/Readme.md @@ -0,0 +1 @@ +../Readme.md \ No newline at end of file From 4e18b5759446594d0fe054994e4dfcb57f03a980 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 3 May 2018 15:03:04 +0200 Subject: [PATCH 121/298] Add more metadata to cargo-fix crate --- cargo-fix/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index c57fda1cc..fe483b9b2 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -2,6 +2,12 @@ name = "cargo-fix" version = "0.2.0" authors = ["Pascal Hertleif "] +license = "Apache-2.0/MIT" +name = "rustfix" +description = "Automatically apply the suggestions made by rustc" +repository = "https://github.com/killercup/rustfix" +documentation = "https://docs.rs/rustfix" +readme = "README.md" [dependencies] clap = "2.9.2" From 193ef4afaaa6fdd39792069bd47675c9418ba89a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 3 May 2018 15:03:39 +0200 Subject: [PATCH 122/298] Fix metadata in cargo-fix crate Oops --- cargo-fix/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index fe483b9b2..c500e72ae 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -3,7 +3,6 @@ name = "cargo-fix" version = "0.2.0" authors = ["Pascal Hertleif "] license = "Apache-2.0/MIT" -name = "rustfix" description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/killercup/rustfix" documentation = "https://docs.rs/rustfix" From 07cbb8ee3f5ee17af8d9b9813fe3d7dc6957055b Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 3 May 2018 15:04:38 +0200 Subject: [PATCH 123/298] cargo-fix requires brand new rustfix 0.2 --- cargo-fix/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index c500e72ae..69d1ccb67 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -15,4 +15,4 @@ quick-error = "1.2.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -rustfix = "0.1.0" +rustfix = "0.2.0" From 400ae0e65ff3c7025069b850d52b1ac8ba25d1f9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 May 2018 20:18:26 -0700 Subject: [PATCH 124/298] Rewrite the `cargo fix` command This commit starts rewritign the `cargo fix` command in line with the recent discussions around the edition. The main changes here are: * The interactivity of `cargo fix` is removed * Executing `cargo fix` is now a thin veneer over `cargo check` * Fixes are automatically applied when it looks very likely to succeed if we apply them. * Fixes are only applied to the local workspace rather than upstream crates as well. There's still a number of missing features to fill out marked with a few TODO here and there but the test suite is already looking relatively solid. I think we've got a long way to go here but this is hopefully a good start in the direction of where we want to go. --- Cargo.toml | 4 - cargo-fix/Cargo.toml | 19 +- cargo-fix/src/lock.rs | 163 +++++++++ cargo-fix/src/main.rs | 527 ++++++++-------------------- cargo-fix/tests/all/dependencies.rs | 100 ++++++ cargo-fix/tests/all/main.rs | 264 ++++++++++++++ cargo-fix/tests/all/smoke.rs | 89 +++++ cargo-fix/tests/all/subtargets.rs | 69 ++++ cargo-fix/tests/all/warnings.rs | 15 + 9 files changed, 860 insertions(+), 390 deletions(-) create mode 100644 cargo-fix/src/lock.rs create mode 100644 cargo-fix/tests/all/dependencies.rs create mode 100644 cargo-fix/tests/all/main.rs create mode 100644 cargo-fix/tests/all/smoke.rs create mode 100644 cargo-fix/tests/all/subtargets.rs create mode 100644 cargo-fix/tests/all/warnings.rs diff --git a/Cargo.toml b/Cargo.toml index 057c1945d..426bdbfcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ exclude = [ ] [dependencies] -quick-error = "1.2.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" @@ -33,6 +32,3 @@ tempdir = "0.3.5" members = [ "cargo-fix", ] - -[patch.crates-io] -rustfix = { path = "." } diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index 69d1ccb67..f60d765db 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -8,11 +8,16 @@ repository = "https://github.com/killercup/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" +[[bin]] +name = "cargo-fix" +test = false + [dependencies] -clap = "2.9.2" -colored = "1.2.0" -quick-error = "1.2.1" -serde = "1.0" -serde_json = "1.0" -serde_derive = "1.0" -rustfix = "0.2.0" +failure = "0.1" +rustfix = { path = "..", version = "0.2" } +serde_json = "1" +log = "0.4" + +[dev-dependencies] +difference = "2" +url = "1" diff --git a/cargo-fix/src/lock.rs b/cargo-fix/src/lock.rs new file mode 100644 index 000000000..81294e18b --- /dev/null +++ b/cargo-fix/src/lock.rs @@ -0,0 +1,163 @@ +//! An implementation of IPC locks, guaranteed to be released if a process dies +//! +//! This module implements a locking server/client where the main `cargo fix` +//! process will start up a server and then all the client processes will +//! connect to it. The main purpose of this file is to enusre that each crate +//! (aka file entry point) is only fixed by one process at a time, currently +//! concurrent fixes can't happen. +//! +//! The basic design here is to use a TCP server which is pretty portable across +//! platforms. For simplicity it just uses threads as well. Clients connect to +//! the main server, inform the server what its name is, and then wait for the +//! server to give it the lock (aka write a byte). + +use std::collections::HashMap; +use std::env; +use std::io::{BufReader, BufRead, Read, Write}; +use std::net::{TcpStream, SocketAddr, TcpListener}; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::{self, JoinHandle}; + +use failure::{Error, ResultExt}; + +pub struct Server { + listener: TcpListener, + threads: HashMap, + done: Arc, +} + +pub struct StartedServer { + done: Arc, + addr: SocketAddr, + thread: Option>, +} + +pub struct Client { + _socket: TcpStream, +} + +struct ServerClient { + thread: Option>, + lock: Arc)>>, +} + +impl Server { + pub fn new() -> Result { + let listener = TcpListener::bind("127.0.0.1:0") + .with_context(|_| "failed to bind TCP listener to manage locking")?; + env::set_var("__CARGO_FIX_SERVER", listener.local_addr()?.to_string()); + Ok(Server { + listener, + threads: HashMap::new(), + done: Arc::new(AtomicBool::new(false)), + }) + } + + pub fn start(self) -> Result { + let addr = self.listener.local_addr()?; + let done = self.done.clone(); + let thread = thread::spawn(|| { + self.run(); + }); + Ok(StartedServer { + addr, + thread: Some(thread), + done, + }) + } + + fn run(mut self) { + while let Ok((client, _)) = self.listener.accept() { + if self.done.load(Ordering::SeqCst) { + break + } + + // Learn the name of our connected client to figure out if it needs + // to wait for another process to release the lock. + let mut client = BufReader::new(client); + let mut name = String::new(); + if client.read_line(&mut name).is_err() { + continue + } + let client = client.into_inner(); + + // If this "named mutex" is already registered and the thread is + // still going, put it on the queue. Otherwise wait on the previous + // thread and we'll replace it just below. + if let Some(t) = self.threads.get_mut(&name) { + let mut state = t.lock.lock().unwrap(); + if state.0 { + state.1.push(client); + continue + } + drop(t.thread.take().unwrap().join()); + } + + let lock = Arc::new(Mutex::new((true, vec![client]))); + let lock2 = lock.clone(); + let thread = thread::spawn(move || { + loop { + let mut client = { + let mut state = lock2.lock().unwrap(); + if state.1.len() == 0 { + state.0 = false; + break + } else { + state.1.remove(0) + } + }; + // Inform this client that it now has the lock and wait for + // it to disconnect by waiting for EOF. + if client.write_all(&[1]).is_err() { + continue + } + let mut dst = Vec::new(); + drop(client.read_to_end(&mut dst)); + } + }); + + self.threads.insert(name, ServerClient { + thread: Some(thread), + lock, + }); + } + } +} + +impl Drop for Server { + fn drop(&mut self) { + for (_, mut client) in self.threads.drain() { + if let Some(thread) = client.thread.take() { + drop(thread.join()); + } + } + } +} + +impl Drop for StartedServer { + fn drop(&mut self) { + self.done.store(true, Ordering::SeqCst); + // Ignore errors here as this is largely best-effort + if TcpStream::connect(&self.addr).is_err() { + return + } + drop(self.thread.take().unwrap().join()); + } +} + +impl Client { + pub fn lock(name: &str) -> Result { + let addr = env::var("__CARGO_FIX_SERVER") + .map_err(|_| format_err!("locking strategy misconfigured"))?; + let mut client = TcpStream::connect(&addr) + .with_context(|_| "failed to connect to parent lock server")?; + client.write_all(name.as_bytes()) + .and_then(|_| client.write_all(b"\n")) + .with_context(|_| "failed to write to lock server")?; + let mut buf = [0]; + client.read_exact(&mut buf) + .with_context(|_| "failed to acquire lock")?; + Ok(Client { _socket: client }) + } +} diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 97f870b45..4719302bc 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -1,418 +1,187 @@ #[macro_use] -extern crate serde_derive; +extern crate failure; +extern crate rustfix; extern crate serde_json; #[macro_use] -extern crate quick_error; -#[macro_use] -extern crate clap; -extern crate colored; - -extern crate rustfix; +extern crate log; +use std::collections::{HashSet, HashMap}; +use std::env; use std::fs::File; use std::io::{Read, Write}; -use std::error::Error; -use std::process::Command; -use std::collections::HashSet; +use std::process::{self, Command, ExitStatus}; +use std::str; +use std::path::Path; -use colored::Colorize; -use clap::{Arg, App}; - -use std::str::FromStr; - -use rustfix::{Suggestion, Replacement}; use rustfix::diagnostics::Diagnostic; +use failure::{Error, ResultExt}; -const USER_OPTIONS: &str = "What do you want to do? \ - [0-9] | [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)"; +mod lock; fn main() { - let program = try_main(); - match program { - Ok(_) => std::process::exit(0), - Err(ProgramError::UserAbort) => { - writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap(); - std::process::exit(0); - } - Err(error) => { - writeln!(std::io::stderr(), "An error occured: {}", error).unwrap(); - writeln!(std::io::stderr(), "{:?}", error).unwrap(); - if let Some(cause) = error.cause() { - writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap(); - } - std::process::exit(1); - } - } -} - -macro_rules! flush { - () => (try!(std::io::stdout().flush());) -} - -/// A list of `--only` aliases -const ALIASES: &[(&str, &[&str])] = &[ - ("use", &["E0412"]), -]; - -fn try_main() -> Result<(), ProgramError> { - // Quickfix to be usable as rustfix as well as cargo-fix - let args = if ::std::env::args_os().nth(1).map(|x| &x == "fix").unwrap_or(false) { - ::std::env::args_os().skip(1) + let result = if env::var("__CARGO_FIX_NOW_RUSTC").is_ok() { + cargo_fix_rustc() } else { - ::std::env::args_os().skip(0) + cargo_fix() }; - - let matches = App::new("cargo-fix") - .about("Automatically apply suggestions made by rustc") - .version(crate_version!()) - .arg(Arg::with_name("clippy") - .long("clippy") - .help("Use `cargo clippy` for suggestions")) - .arg(Arg::with_name("yolo") - .long("yolo") - .help("Automatically apply all unambiguous suggestions")) - .arg(Arg::with_name("only") - .long("only") - .help("Only show errors or lints with the specific id(s) (comma separated)") - .use_delimiter(true)) - .arg(Arg::with_name("file") - .long("file") - .takes_value(true) - .help("Load errors from the given JSON file (produced by `cargo build --message-format=json`)")) - .get_matches_from(args); - - let mut extra_args = Vec::new(); - - if !matches.is_present("clippy") { - extra_args.push("-Aclippy"); - } - - let mode = if matches.is_present("yolo") { - AutofixMode::Yolo - } else { - AutofixMode::None + let err = match result { + Ok(()) => return, + Err(e) => e, }; + eprintln!("error: {}", err); + for cause in err.causes().skip(1) { + eprintln!("\tcaused by: {}", cause); + } + process::exit(102); +} - let mut only: HashSet = matches - .values_of("only") - .map_or(HashSet::new(), |values| { - values.map(ToString::to_string).collect() - }); +fn cargo_fix() -> Result<(), Error> { + // Spin up our lock server which our subprocesses will use to synchronize + // fixes. + let _lockserver = lock::Server::new()?.start()?; - for alias in ALIASES { - if only.remove(alias.0) { - for alias in alias.1 { - only.insert(alias.to_string()); - } + let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); + let mut cmd = Command::new(&cargo); + // TODO: shouldn't hardcode `check` here, we want to allow things like + // `cargo fix bench` or something like that + // + // TODO: somehow we need to force `check` to actually do something here, if + // `cargo check` was previously run it won't actually do anything again. + cmd.arg("check"); + cmd.args(env::args().skip(2)); // skip `cmd-fix fix` + + // Override the rustc compiler as ourselves. That way whenever rustc would + // run we run instead and have an opportunity to inject fixes. + let me = env::current_exe() + .with_context(|_| "failed to learn about path to current exe")?; + cmd.env("RUSTC", &me) + .env("__CARGO_FIX_NOW_RUSTC", "1"); + if let Some(rustc) = env::var_os("RUSTC") { + cmd.env("RUSTC_ORIGINAL", rustc); + } + + // An now execute all of Cargo! This'll fix everything along the way. + // + // TODO: we probably want to do something fancy here like collect results + // from the client processes and print out a summary of what happened. + let status = cmd.status() + .with_context(|e| { + format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e) + })?; + exit_with(status); +} + +fn cargo_fix_rustc() -> Result<(), Error> { + // Try to figure out what we're compiling by looking for a rust-like file + // that exists. + let filename = env::args() + .skip(1) + .filter(|s| s.ends_with(".rs")) + .filter(|s| Path::new(s).exists()) + .next(); + + let rustc = env::var_os("RUSTC_ORIGINAL").unwrap_or("rustc".into()); + + // Our goal is to fix only the crates that the end user is interested in. + // That's very likely to only mean the crates in the workspace the user is + // working on, not random crates.io crates. + // + // To that end we only actually try to fix things if it looks like we're + // compiling a Rust file and it *doesn't* have an absolute filename. That's + // not the best heuristic but matches what Cargo does today at least. + if let Some(path) = filename { + if !Path::new(&path).is_absolute() { + rustfix_crate(rustc.as_ref(), &path)?; } } - // Get JSON output from rustc... - let json = if let Some(file) = matches.value_of("file") { - let mut f = File::open(file)?; - let mut j = "".into(); - f.read_to_string(&mut j)?; - j - } else { - get_json(&extra_args, matches.is_present("clippy"))? - }; + // TODO: if we executed rustfix above and the previous rustc invocation was + // successful and this `status()` is not, then we should revert all fixes + // we applied, present a scary warning, and then move on. + let mut cmd = Command::new(&rustc); + cmd.args(env::args().skip(1)); + exit_with(cmd.status().with_context(|_| "failed to spawn rustc")?); - let suggestions: Vec = json.lines() - .filter(not_empty) - // Convert JSON string (and eat parsing errors) - .flat_map(|line| serde_json::from_str::(line)) - // One diagnostic line might have multiple suggestions - .filter_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, &only)) - .collect(); - - try!(handle_suggestions(suggestions, mode)); - - Ok(()) } -#[derive(Deserialize)] -struct CargoMessage { - message: Diagnostic, -} +fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { + // First up we want to make sure that each crate is only checked by one + // process at a time. If two invocations concurrently check a crate then + // it's likely to corrupt it. + // + // Currently we do this by assigning the name on our lock to the first + // argument that looks like a Rust file. + let _lock = lock::Client::lock(filename)?; -fn get_json(extra_args: &[&str], clippy: bool) -> Result { - let build_cmd = if clippy { - "clippy" - } else { - "rustc" - }; - let output = try!(Command::new("cargo") - .args(&[build_cmd, "--message-format", "json"]) - .arg("--") - .args(extra_args) - .output()); + let mut cmd = Command::new(&rustc); + cmd.args(env::args().skip(1)); + cmd.arg("--error-format=json"); + let context = format!("failed to execute `{}`", rustc.to_string_lossy()); + let output = cmd.output().context(context.clone())?; - Ok(String::from_utf8(output.stdout)?) -} + // Sift through the output of the compiler to look for JSON messages + // indicating fixes that we can apply. Note that we *do not* look at the + // exit status here, that's intentional! We want to apply fixes even if + // there are compiler errors. + let stderr = str::from_utf8(&output.stderr) + .map_err(|_| format_err!("failed to parse rustc stderr as utf-8"))?; + let only = HashSet::new(); + let suggestions = stderr.lines() + .filter(|x| !x.is_empty()) -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -enum AutofixMode { - /// Do not apply any fixes automatically - None, - // /// Only apply suggestions of a whitelist of lints - // Whitelist, - // /// Check the confidence flag supplied by rustc - // Confidence, - /// Automatically apply all unambiguous suggestions - Yolo, -} + // Parse each line of stderr ignoring errors as they may not all be json + .filter_map(|line| serde_json::from_str::(line).ok()) -fn prelude(suggestion: &Replacement) { - let snippet = &suggestion.snippet; - if snippet.text.1.is_empty() { - // Check whether this suggestion wants to be inserted before or after another line - let wants_to_be_on_own_line = suggestion.replacement.ends_with('\n') - || suggestion.replacement.starts_with('\n'); - if wants_to_be_on_own_line { - println!("{}", "Insert line:".yellow().bold()); - } else { - println!("{}", "At:".yellow().bold()); - println!( - "{lead}{text}{tail}", - lead = indent(4, &snippet.text.0), - text = "v".red(), - tail = snippet.text.2, - ); - println!("{}\n", indent(snippet.text.0.len() as u32, "^").red()); - println!("{}\n", "insert:".yellow().bold()); + // From each diagnostic try to extract suggestions from rustc + .filter_map(|diag| rustfix::collect_suggestions(&diag, &only)); + + // Collect suggestions by file so we can apply them one at a time later. + let mut file_map = HashMap::new(); + for suggestion in suggestions { + // Make sure we've got a file associated with this suggestion and all + // snippets point to the same location. Right now it's not clear what + // we would do with multiple locations. + let (file_name, range) = match suggestion.snippets.get(0) { + Some(s) => (s.file_name.clone(), s.line_range), + None => continue, + }; + if !suggestion.snippets.iter().all(|s| { + s.file_name == file_name && s.line_range == range + }) { + continue } - } else { - println!("{}\n", "Replace:".yellow().bold()); - println!( - "{lead}{text}{tail}\n\n\ - {with}\n", - with = "with:".yellow().bold(), - lead = indent(4, &snippet.text.0), - text = snippet.text.1.red(), - tail = snippet.text.2, - ); - } -} -fn handle_suggestions( - suggestions: Vec, - mode: AutofixMode, -) -> Result<(), ProgramError> { - let mut accepted_suggestions: Vec = vec![]; - - if suggestions.is_empty() { - println!("I don't have any suggestions for you right now. Check back later!"); - return Ok(()); + file_map.entry(file_name) + .or_insert_with(Vec::new) + .push(suggestion); } - 'suggestions: for suggestion in suggestions { - print!("\n\n{info}: {message}\n", - info = "Info".green().bold(), - message = split_at_lint_name(&suggestion.message)); - for snippet in suggestion.snippets { - print!("{arrow} {file}:{range}\n", - arrow = " -->".blue().bold(), - file = snippet.file_name, - range = snippet.line_range); + for (file, suggestions) in file_map { + // Attempt to read the source code for this file. If this fails then + // that'd be pretty surprising, so log a message and otherwise keep + // going. + let mut code = String::new(); + if let Err(e) = File::open(&file).and_then(|mut f| f.read_to_string(&mut code)) { + warn!("failed to read `{}`: {}", file, e); + continue } - - let mut i = 0; - for solution in &suggestion.solutions { - println!("\n{}", solution.message); - - // check whether we can squash all suggestions into a list - if solution.replacements.len() > 1 { - let first = solution.replacements[0].clone(); - let all_suggestions_replace_the_same_span = solution - .replacements - .iter() - .all(|s| first.snippet.file_name == s.snippet.file_name - && first.snippet.line_range == s.snippet.line_range); - if all_suggestions_replace_the_same_span { - prelude(&first); - for suggestion in &solution.replacements { - println!("[{}]: {}", i, suggestion.replacement.trim()); - i += 1; - } - continue; - } - } - for suggestion in &solution.replacements { - print!("[{}]: ", i); - prelude(suggestion); - println!("{}", indent(4, &suggestion.replacement)); - i += 1; - } - } - println!(); - - if mode == AutofixMode::Yolo && suggestion.solutions.len() == 1 && suggestion.solutions[0].replacements.len() == 1 { - let mut solutions = suggestion.solutions; - let mut replacements = solutions.remove(0).replacements; - accepted_suggestions.push(replacements.remove(0)); - println!("automatically applying suggestion (--yolo)"); - continue 'suggestions; - } - - 'userinput: loop { - print!("{arrow} {user_options}\n\ - {prompt} ", - arrow = "==>".green().bold(), - prompt = " >".green().bold(), - user_options = USER_OPTIONS.green()); - - flush!(); - let mut input = String::new(); - try!(std::io::stdin().read_line(&mut input)); - - match input.trim() { - "s" => { - println!("Skipped."); - continue 'suggestions; - } - "q" => { - println!("Thanks for playing!"); - break 'suggestions; - } - "a" => { - return Err(ProgramError::UserAbort); - } - "r" => { - if suggestion.solutions.len() == 1 && suggestion.solutions[0].replacements.len() == 1 { - let mut solutions = suggestion.solutions; - accepted_suggestions.push(solutions.remove(0).replacements.remove(0)); - println!("Suggestion accepted. I'll remember that and apply it later."); - continue 'suggestions; - } else { - println!("{error}: multiple suggestions apply, please pick a number", - error = "Error".red().bold()); - } - } - s => { - if let Ok(i) = usize::from_str(s) { - let replacement = suggestion.solutions - .iter() - .flat_map(|sol| sol.replacements.iter()) - .nth(i); - if let Some(replacement) = replacement { - accepted_suggestions.push(replacement.clone()); - println!("Suggestion accepted. I'll remember that and apply it later."); - continue 'suggestions; - } else { - println!("{error}: {i} is not a valid suggestion index", - error = "Error".red().bold(), - i = i); - } - } else { - println!("{error}: I didn't quite get that. {user_options}", - error = "Error".red().bold(), - user_options = USER_OPTIONS); - continue 'userinput; - } - } - } - } - } - - if !accepted_suggestions.is_empty() { - println!("Good work. Let me just apply these {} changes!", - accepted_suggestions.len()); - - for suggestion in accepted_suggestions.iter().rev() { - try!(apply_suggestion(suggestion)); - - print!("."); - flush!(); - } - - println!("\nDone."); + let new_code = rustfix::apply_suggestions(&code, &suggestions); + File::create(&file) + .and_then(|mut f| f.write_all(new_code.as_bytes())) + .with_context(|_| format!("failed to write file `{}`", file))?; } Ok(()) } -quick_error! { - /// All possible errors in programm lifecycle - #[derive(Debug)] - pub enum ProgramError { - UserAbort { - display("Let's get outta here!") - } - /// Missing File - NoFile { - display("No input file given") - } - SubcommandError(subcommand: String, output: String) { - display("Error executing subcommand `{}`", subcommand) - description(output) - } - /// Error while dealing with file or stdin/stdout - Io(err: std::io::Error) { - from() - cause(err) - display("I/O error") - description(err.description()) - } - Utf8Error(err: std::string::FromUtf8Error) { - from() - display("Error reading input as UTF-8") - } - /// Error with deserialization - Serde(err: serde_json::Error) { - from() - cause(err) - display("Serde JSON error") - description(err.description()) +fn exit_with(status: ExitStatus) -> ! { + #[cfg(unix)] + { + use std::os::unix::prelude::*; + if let Some(signal) = status.signal() { + eprintln!("child failed with signal `{}`", signal); + process::exit(2); } } -} - -// Helpers -// ------- - -fn read_file_to_string(file_name: &str) -> Result { - let mut file = try!(File::open(file_name)); - let mut buffer = String::new(); - try!(file.read_to_string(&mut buffer)); - Ok(buffer) -} - -fn not_empty(s: &&str) -> bool { - !s.trim().is_empty() -} - -fn split_at_lint_name(s: &str) -> String { - s.split(", #[") - .collect::>() - .join("\n #[") // Length of whitespace == length of "Info: " -} - -fn indent(size: u32, s: &str) -> String { - let whitespace: String = std::iter::repeat(' ').take(size as usize).collect(); - - s.lines() - .map(|l| format!("{}{}", whitespace, l)) - .collect::>() - .join("\n") -} - -/// Apply suggestion to a file -/// -/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the -/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant -/// to correspond to. So, for now, let's just replace lines! -/// -/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in -/// reverse order to not mess up the lines for replacements further down the road. -fn apply_suggestion(suggestion: &Replacement) -> Result<(), ProgramError> { - let mut file_content = try!(read_file_to_string(&suggestion.snippet.file_name)); - let new_content = rustfix::apply_suggestion(&mut file_content, suggestion); - - let mut file = try!(File::create(&suggestion.snippet.file_name)); - let new_content = new_content.as_bytes(); - - try!(file.set_len(new_content.len() as u64)); - try!(file.write_all(new_content)); - - Ok(()) + process::exit(status.code().unwrap_or(3)); } diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs new file mode 100644 index 000000000..af3e9d8c2 --- /dev/null +++ b/cargo-fix/tests/all/dependencies.rs @@ -0,0 +1,100 @@ +use super::project; + +#[test] +fn fix_path_deps() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = { path = 'bar' } + + [workspace] + "# + ) + .file("src/lib.rs", r#" + extern crate bar; + + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + add(1) + } + "#) + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + "# + ) + .file("bar/src/lib.rs", r#" + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + add(1) + } + "#) + .build(); + + let stderr = "\ +[CHECKING] bar v0.1.0 (CWD/bar) +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix") + .stdout("") + .stderr(stderr) + .run(); +} + +#[test] +fn do_not_fix_non_relevant_deps() { + let p = project() + .file( + "foo/Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = { path = '../bar' } + + [workspace] + "# + ) + .file("foo/src/lib.rs", "") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + "# + ) + .file("bar/src/lib.rs", r#" + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + add(1) + } + "#) + .build(); + + p.expect_cmd("cargo fix") + .cwd("foo") + .status(101) + .run(); +} diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs new file mode 100644 index 000000000..8547cdf8d --- /dev/null +++ b/cargo-fix/tests/all/main.rs @@ -0,0 +1,264 @@ +extern crate difference; +extern crate url; + +use std::env; +use std::fs; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::str; +use std::sync::atomic::*; +use std::time::Instant; + +use difference::{Changeset, Difference}; +use url::Url; + +static CNT: AtomicUsize = ATOMIC_USIZE_INIT; +thread_local!(static IDX: usize = CNT.fetch_add(1, Ordering::SeqCst)); + +struct ProjectBuilder { + files: Vec<(String, String)>, +} + +struct Project { + root: PathBuf, +} + +fn project() -> ProjectBuilder { + ProjectBuilder { + files: Vec::new(), + } +} + +fn root() -> PathBuf { + let idx = IDX.with(|x| *x); + + let mut me = env::current_exe().unwrap(); + me.pop(); // chop off exe name + me.pop(); // chop off `deps` + me.pop(); // chop off `debug` / `release` + me.push("generated-tests"); + me.push(&format!("test{}", idx)); + return me +} + +impl ProjectBuilder { + fn file(&mut self, name: &str, contents: &str) -> &mut ProjectBuilder { + self.files.push((name.to_string(), contents.to_string())); + self + } + + fn build(&mut self) -> Project { + if !self.files.iter().any(|f| f.0.ends_with("Cargo.toml")) { + let manifest = r#" + [package] + name = "foo" + version = "0.1.0" + + [workspace] + "#; + self.files.push(("Cargo.toml".to_string(), manifest.to_string())); + } + let root = root(); + drop(fs::remove_dir_all(&root)); + for &(ref file, ref contents) in self.files.iter() { + let dst = root.join(file); + fs::create_dir_all(dst.parent().unwrap()).unwrap(); + fs::File::create(&dst).unwrap().write_all(contents.as_ref()).unwrap(); + } + Project { root } + } +} + +impl Project { + fn expect_cmd<'a>(&'a self, cmd: &'a str) -> ExpectCmd<'a> { + ExpectCmd { + project: self, + cmd: cmd, + stdout: None, + stdout_contains: Vec::new(), + stderr: None, + stderr_contains: Vec::new(), + status: 0, + ran: false, + cwd: None, + } + } +} + +struct ExpectCmd<'a> { + ran: bool, + project: &'a Project, + cmd: &'a str, + stdout: Option, + stdout_contains: Vec, + stderr: Option, + stderr_contains: Vec, + status: i32, + cwd: Option, +} + +impl<'a> ExpectCmd<'a> { + fn status(&mut self, status: i32) -> &mut Self { + self.status = status; + self + } + + fn cwd>(&mut self, path: P) -> &mut Self { + self.cwd = Some(self.project.root.join(path)); + self + } + + fn stdout(&mut self, s: &str) -> &mut Self { + self.stdout = Some(s.to_string()); + self + } + + fn stderr(&mut self, s: &str) -> &mut Self { + self.stderr = Some(s.to_string()); + self + } + + fn stderr_contains(&mut self, s: &str) -> &mut Self { + self.stderr_contains.push(s.to_string()); + self + } + + fn run(&mut self) { + self.ran = true; + let mut parts = self.cmd.split_whitespace(); + let mut cmd = Command::new(parts.next().unwrap()); + cmd.args(parts); + match self.cwd { + Some(ref p) => { cmd.current_dir(p); } + None => { cmd.current_dir(&self.project.root); } + } + + let mut me = env::current_exe().unwrap(); + me.pop(); // chop off exe name + me.pop(); // chop off `deps` + + let mut new_path = Vec::new(); + new_path.push(me); + new_path.extend( + env::split_paths(&env::var_os("PATH").unwrap_or(Default::default())), + ); + cmd.env("PATH", env::join_paths(&new_path).unwrap()); + + println!("\n···················································"); + println!("running {:?}", cmd); + let start = Instant::now(); + let output = match cmd.output() { + Ok(output) => output, + Err(err) => panic!("failed to spawn: {}", err), + }; + let dur = start.elapsed(); + println!("dur: {}.{:03}ms", dur.as_secs(), dur.subsec_nanos() / 1_000_000); + println!("exit: {}", output.status); + if output.stdout.len() > 0 { + println!("stdout ---\n{}", String::from_utf8_lossy(&output.stdout)); + } + if output.stderr.len() > 0 { + println!("stderr ---\n{}", String::from_utf8_lossy(&output.stderr)); + } + println!("···················································"); + let code = match output.status.code() { + Some(code) => code, + None => panic!("super extra failure: {}", output.status), + }; + if code != self.status { + panic!("expected exit code `{}` got `{}`", self.status, code); + } + self.match_std(&output.stdout, &self.stdout, &self.stdout_contains); + self.match_std(&output.stderr, &self.stderr, &self.stderr_contains); + } + + fn match_std(&self, actual: &[u8], expected: &Option, contains: &[String]) { + let actual = match str::from_utf8(actual) { + Ok(s) => s, + Err(_) => panic!("std wasn't utf8"), + }; + let actual = self.clean(actual); + if let Some(ref expected) = *expected { + diff(&self.clean(expected), &actual); + } + for s in contains { + let s = self.clean(s); + if actual.contains(&s) { + continue + } + println!("\nfailed to find contents within output stream\n\ + expected to find\n {}\n\nwithin:\n\n{}\n\n", + s, + actual); + panic!("test failed"); + } + } + + fn clean(&self, s: &str) -> String { + let url = Url::from_file_path(&self.project.root).unwrap(); + let s = s.replace("[CHECKING]", " Checking") + .replace("[FINISHED]", " Finished") + .replace("[COMPILING]", " Compiling") + .replace(&url.to_string(), "CWD") + .replace(&self.project.root.display().to_string(), "CWD") + .replace("\\", "/"); + let lines = s.lines() + .map(|s| { + let i = match s.find("target(s) in") { + Some(i) => i, + None => return s.to_string(), + }; + if s.trim().starts_with("Finished") { + s[..i].to_string() + } else { + s.to_string() + } + }); + let mut ret = String::new(); + for (i, line) in lines.enumerate() { + if i != 0 { + ret.push_str("\n"); + } + ret.push_str(&line); + } + ret + } +} + +impl<'a> Drop for ExpectCmd<'a> { + fn drop(&mut self) { + if !self.ran { + panic!("forgot to run this command"); + } + } +} + +fn diff(expected: &str, actual: &str) { + let changeset = Changeset::new(expected.trim(), actual.trim(), "\n"); + + let mut different = false; + for diff in changeset.diffs { + let (prefix, diff) = match diff { + Difference::Same(_) => continue, + Difference::Add(add) => ("+", add), + Difference::Rem(rem) => ("-", rem), + }; + if !different { + println!("differences found (+ == actual, - == expected):\n"); + different = true; + } + for diff in diff.lines() { + println!("{} {}", prefix, diff); + } + } + if different { + println!(""); + panic!("found some differences"); + } +} + +mod dependencies; +mod smoke; +mod subtargets; +mod warnings; diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs new file mode 100644 index 000000000..c1c5ca290 --- /dev/null +++ b/cargo-fix/tests/all/smoke.rs @@ -0,0 +1,89 @@ +use super::project; + +#[test] +fn no_changes_necessary() { + let p = project() + .file("src/lib.rs", "") + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix") + .stdout("") + .stderr(stderr) + .run(); +} + +#[test] +fn fixes_missing_ampersand() { + let p = project() + .file("src/lib.rs", r#" + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + } + "#) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix") + .stdout("") + .stderr(stderr) + .run(); +} + +#[test] +fn fixes_two_missing_ampersands() { + let p = project() + .file("src/lib.rs", r#" + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + add(1) + } + "#) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix") + .stdout("") + .stderr(stderr) + .run(); +} + +#[test] +fn tricky_ampersand() { + let p = project() + .file("src/lib.rs", r#" + fn add(a: &u32) -> u32 { + a + 1 + } + + pub fn foo() -> u32 { + add(1) + add(1) + } + "#) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix") + .stdout("") + .stderr(stderr) + .run(); +} diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs new file mode 100644 index 000000000..4cd99fb3b --- /dev/null +++ b/cargo-fix/tests/all/subtargets.rs @@ -0,0 +1,69 @@ +use super::project; + +#[test] +fn fixes_missing_ampersand() { + let p = project() + .file("src/main.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + fn main() { add(1); } + "#) + .file("src/lib.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + pub fn foo() -> u32 { add(1) } + + #[test] + pub fn foo2() { add(1); } + "#) + .file("tests/a.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + #[test] + pub fn foo() { add(1); } + "#) + .file("examples/foo.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + fn main() { add(1); } + "#) + .file("build.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + fn main() { add(1); } + "#) + .build(); + + let stderr = "\ +[COMPILING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo fix --all-targets").stdout("").stderr(stderr).run(); + p.expect_cmd("cargo build").run(); + p.expect_cmd("cargo test").run(); +} + +#[test] +fn fix_features() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [features] + bar = [] + + [workspace] + "# + ) + .file("src/lib.rs", r#" + fn add(a: &u32) -> u32 { a + 1 } + + #[cfg(feature = "bar")] + pub fn foo() -> u32 { add(1) } + "#) + .build(); + + p.expect_cmd("cargo fix").run(); + p.expect_cmd("cargo build").run(); + p.expect_cmd("cargo fix --features bar").run(); + p.expect_cmd("cargo build --features bar").run(); +} diff --git a/cargo-fix/tests/all/warnings.rs b/cargo-fix/tests/all/warnings.rs new file mode 100644 index 000000000..46d521b83 --- /dev/null +++ b/cargo-fix/tests/all/warnings.rs @@ -0,0 +1,15 @@ +use super::project; + +#[test] +fn shows_warnings() { + let p = project() + .file("src/lib.rs", r#" + use std::default::Default; + + pub fn foo() { + } + "#) + .build(); + + p.expect_cmd("cargo fix").stderr_contains("warning: unused import").run(); +} From 7d83fdffeacf14e012b532fc9ab3c4b34c7abe18 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 10:14:53 +0200 Subject: [PATCH 125/298] Add todo comment for lint-filtering HashSet --- cargo-fix/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 4719302bc..fc18665a2 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -105,6 +105,11 @@ fn cargo_fix_rustc() -> Result<(), Error> { } fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { + // If not empty, filter by these lints + // + // TODO: Implement a way to specify this + let only = HashSet::new(); + // First up we want to make sure that each crate is only checked by one // process at a time. If two invocations concurrently check a crate then // it's likely to corrupt it. @@ -125,7 +130,6 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { // there are compiler errors. let stderr = str::from_utf8(&output.stderr) .map_err(|_| format_err!("failed to parse rustc stderr as utf-8"))?; - let only = HashSet::new(); let suggestions = stderr.lines() .filter(|x| !x.is_empty()) From 43cc63ef84bc138570d9a4e87150455ca640d45f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 10:15:09 +0200 Subject: [PATCH 126/298] Simplify some .context() calls --- cargo-fix/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index fc18665a2..832f7ca31 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -53,7 +53,7 @@ fn cargo_fix() -> Result<(), Error> { // Override the rustc compiler as ourselves. That way whenever rustc would // run we run instead and have an opportunity to inject fixes. let me = env::current_exe() - .with_context(|_| "failed to learn about path to current exe")?; + .context("failed to learn about path to current exe")?; cmd.env("RUSTC", &me) .env("__CARGO_FIX_NOW_RUSTC", "1"); if let Some(rustc) = env::var_os("RUSTC") { @@ -100,8 +100,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { // we applied, present a scary warning, and then move on. let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); - exit_with(cmd.status().with_context(|_| "failed to spawn rustc")?); - + exit_with(cmd.status().context("failed to spawn rustc")?); } fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { @@ -121,15 +120,16 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); cmd.arg("--error-format=json"); - let context = format!("failed to execute `{}`", rustc.to_string_lossy()); - let output = cmd.output().context(context.clone())?; + let output = cmd.output() + .with_context(|_| format!("failed to execute `{}`", rustc.display()))?; // Sift through the output of the compiler to look for JSON messages // indicating fixes that we can apply. Note that we *do not* look at the // exit status here, that's intentional! We want to apply fixes even if // there are compiler errors. let stderr = str::from_utf8(&output.stderr) - .map_err(|_| format_err!("failed to parse rustc stderr as utf-8"))?; + .context("failed to parse rustc stderr as utf-8")?; + let suggestions = stderr.lines() .filter(|x| !x.is_empty()) From 06ccb07e656d16c2223eee6745789e9827cca43d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 13:40:53 -0700 Subject: [PATCH 127/298] Add an `env_logger` dependency --- cargo-fix/Cargo.toml | 1 + cargo-fix/src/main.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index f60d765db..82e9b9848 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -17,6 +17,7 @@ failure = "0.1" rustfix = { path = "..", version = "0.2" } serde_json = "1" log = "0.4" +env_logger = { version = "0.5", default-features = false } [dev-dependencies] difference = "2" diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 832f7ca31..67bd39a4a 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -4,6 +4,7 @@ extern crate rustfix; extern crate serde_json; #[macro_use] extern crate log; +extern crate env_logger; use std::collections::{HashSet, HashMap}; use std::env; @@ -19,6 +20,7 @@ use failure::{Error, ResultExt}; mod lock; fn main() { + env_logger::init(); let result = if env::var("__CARGO_FIX_NOW_RUSTC").is_ok() { cargo_fix_rustc() } else { From 6cb9bb71236dcbb17b4349b9cbc52ff47205755d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 13:44:09 -0700 Subject: [PATCH 128/298] Add AppVeyor configuration --- .appveyor.yml | 15 +++++++++++++++ .travis.yml | 18 ++++-------------- Readme.md | 3 ++- tests/everything.rs | 2 ++ 4 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000..1a31de483 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,15 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + +install: + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --all diff --git a/.travis.yml b/.travis.yml index 519b9dda2..54f732602 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,8 @@ language: rust rust: -- nightly -- stable + - nightly script: -- cargo build -- if [ $TRAVIS_RUST_VERSION == nightly ]; then cargo test -- --nocapture ; fi -branches: - only: - # This is where pull requests from "bors r+" are built. - - staging - # This is where pull requests from "bors try" are built. - - trying - # Uncomment this to enable building pull requests. - - master + - cargo test --all notifications: - email: - on_success: never + email: + on_success: never diff --git a/Readme.md b/Readme.md index faf18237b..4443a64ec 100644 --- a/Readme.md +++ b/Readme.md @@ -6,7 +6,8 @@ The goal of this tool is to read and apply the suggestions made by rustc (and th [clippy]: https://github.com/Manishearth/rust-clippy -[![Build Status](https://travis-ci.org/killercup/rustfix.svg?branch=master)](https://travis-ci.org/killercup/rustfix) +[![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) +[![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) ## Current state diff --git a/tests/everything.rs b/tests/everything.rs index 7206db89b..5a3b5ab6a 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -1,3 +1,5 @@ +#![cfg(not(windows))] // TODO: should fix these tests on Windows + #[macro_use] extern crate duct; #[macro_use] extern crate pretty_assertions; extern crate tempdir; From 82fb067825d5329298658a97526e8b201f699e70 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 15:06:20 -0700 Subject: [PATCH 129/298] Print some log information about what's being fixed --- cargo-fix/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 67bd39a4a..1447036ad 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -149,11 +149,15 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { // we would do with multiple locations. let (file_name, range) = match suggestion.snippets.get(0) { Some(s) => (s.file_name.clone(), s.line_range), - None => continue, + None => { + trace!("rejecting as it has no snippets {:?}", suggestion); + continue + } }; if !suggestion.snippets.iter().all(|s| { s.file_name == file_name && s.line_range == range }) { + trace!("rejecting as it spans mutliple files {:?}", suggestion); continue } @@ -171,6 +175,8 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { warn!("failed to read `{}`: {}", file, e); continue } + debug!("applying {} fixes to {}", suggestions.len(), file); + let new_code = rustfix::apply_suggestions(&code, &suggestions); File::create(&file) .and_then(|mut f| f.write_all(new_code.as_bytes())) From f611bb1fcb4f0e90487dc5bd0bf29adc1f75c0b1 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 11:07:33 +0200 Subject: [PATCH 130/298] Switch to replace-rs --- Cargo.toml | 2 ++ cargo-fix/src/main.rs | 2 +- src/diagnostics.rs | 6 +++--- src/lib.rs | 21 +++++++++++++++++---- tests/everything.rs | 7 ++++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 426bdbfcb..fa1db718c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ exclude = [ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +replace-rs = { git = "https://github.com/killercup/replace-rs" } +failure = "0.1.1" [dev-dependencies] duct = "0.8.2" diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 1447036ad..23a93b305 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -177,7 +177,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { } debug!("applying {} fixes to {}", suggestions.len(), file); - let new_code = rustfix::apply_suggestions(&code, &suggestions); + let new_code = rustfix::apply_suggestions(&code, &suggestions)?; File::create(&file) .and_then(|mut f| f.write_all(new_code.as_bytes())) .with_context(|_| format!("failed to write file `{}`", file))?; diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d0640b680..a0fe9fe44 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,5 +1,5 @@ //! Rustc Diagnostic JSON Output -//! +//! //! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) #[derive(Deserialize, Debug)] @@ -21,8 +21,8 @@ pub struct Diagnostic { #[derive(Deserialize, Debug)] pub struct DiagnosticSpan { pub file_name: String, - byte_start: u32, - byte_end: u32, + pub byte_start: u32, + pub byte_end: u32, /// 1-based. pub line_start: usize, pub line_end: usize, diff --git a/src/lib.rs b/src/lib.rs index 4f2345944..9974e35a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,13 @@ #[macro_use] extern crate serde_derive; extern crate serde_json; +extern crate failure; +extern crate replace_rs as replace; use std::collections::HashSet; +use std::ops::Range; + +use failure::Error; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; @@ -61,6 +66,7 @@ pub struct Solution { pub struct Snippet { pub file_name: String, pub line_range: LineRange, + pub range: Range, /// leading surrounding text, text to replace, trailing surrounding text /// /// This split is useful for higlighting the part that gets replaced @@ -109,6 +115,7 @@ fn parse_snippet(span: &DiagnosticSpan) -> Snippet { column: span.column_end, }, }, + range: (span.byte_start as usize)..(span.byte_end as usize), text: (lead, body, tail), } } @@ -208,16 +215,22 @@ pub fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> new_content } -pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> String { - let mut fixed = code.to_string(); +pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result { + use replace::Data; + + let mut fixed = Data::new(code.as_bytes()); for sug in suggestions.iter().rev() { for sol in &sug.solutions { for r in &sol.replacements { - fixed = apply_suggestion(&mut fixed, r); + fixed.replace_range( + r.snippet.range.start, + r.snippet.range.end - 1, + r.replacement.as_bytes(), + )?; } } } - fixed + Ok(String::from_utf8(fixed.to_vec())?) } diff --git a/tests/everything.rs b/tests/everything.rs index 5a3b5ab6a..d0e362f02 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -15,7 +15,7 @@ use std::collections::HashSet; use std::process::Output; use tempdir::TempDir; -use rustfix::{Replacement, apply_suggestions}; +use rustfix::apply_suggestions; fn compile(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; @@ -23,6 +23,7 @@ fn compile(file: &Path) -> Result> { "rustc", file, "--error-format=pretty-json", "-Zunstable-options", "--emit=metadata", "--crate-name=rustfix_test", + "-Zsuggestion-applicability", "--out-dir", tmp.path() ); let res = better_call_clippy @@ -101,7 +102,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { "got unexpected suggestions from clippy", ); - let fixed = apply_suggestions(&code, &suggestions); + let fixed = apply_suggestions(&code, &suggestions)?; if std::env::var("RUSTFIX_TEST_RECORD_FIXED_RUST").is_ok() { use std::io::Write; @@ -110,7 +111,7 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } let expected_fixed = read_file(&fixed_file)?; - assert_eq!(fixed.trim(), expected_fixed.trim(), "file doesn't look fixed"); + assert_eq!(fixed.trim(), expected_fixed.trim(), "file {} doesn't look fixed", file.display()); compiles_without_errors(&fixed_file)?; From d150af81d18787a4387cac9dc41da79b557ff200 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:05:35 +0200 Subject: [PATCH 131/298] Make replace a rustfix module --- Cargo.toml | 1 + src/lib.rs | 6 +- src/replace.rs | 223 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/replace.rs diff --git a/Cargo.toml b/Cargo.toml index fa1db718c..6694b7201 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ env_logger = "0.5.0-rc.1" log = "0.4.1" pretty_assertions = "0.4.1" tempdir = "0.3.5" +proptest = "0.7.0" [workspace] members = [ diff --git a/src/lib.rs b/src/lib.rs index 9974e35a7..9894b0069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,11 @@ #[macro_use] extern crate serde_derive; extern crate serde_json; +#[macro_use] extern crate failure; -extern crate replace_rs as replace; +#[cfg(test)] +#[macro_use] +extern crate proptest; use std::collections::HashSet; use std::ops::Range; @@ -11,6 +14,7 @@ use failure::Error; pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; +mod replace; pub fn get_suggestions_from_json( input: &str, diff --git a/src/replace.rs b/src/replace.rs new file mode 100644 index 000000000..5f4773f25 --- /dev/null +++ b/src/replace.rs @@ -0,0 +1,223 @@ +//! A small module giving you a simple container that allows easy and cheap +//! replacement of parts of its content, with the ability to prevent changing +//! the same parts multiple times. + +use std::rc::Rc; +use failure::Error; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum State { + Initial, + Replaced(Rc<[u8]>), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Span { + /// Start of this span in parent data + start: usize, + /// up to end inculding + end: usize, + data: State, +} + +/// A container that allows easily replacing chunks of its data +#[derive(Debug, Clone, Default)] +pub struct Data { + original: Vec, + parts: Vec, +} + +impl Data { + /// Create a new data container from a slice of bytes + pub fn new(data: &[u8]) -> Self { + Data { + original: data.into(), + parts: vec![Span { + data: State::Initial, + start: 0, + end: data.len(), + }], + } + } + + /// Render this data as a vector of bytes + pub fn to_vec(&self) -> Vec { + self.parts.iter().fold(Vec::new(), |mut acc, d| { + match d.data { + State::Initial => acc.extend_from_slice(&self.original[d.start..d.end]), + State::Replaced(ref d) => acc.extend_from_slice(&d), + }; + acc + }) + } + + /// Replace a chunk of data with the given slice, erroring when this part + /// was already changed previously. + pub fn replace_range( + &mut self, + from: usize, + up_to_and_including: usize, + data: &[u8], + ) -> Result<(), Error> { + ensure!( + from <= up_to_and_including, + "Invalid range {}...{}, start is larger than end", + from, + up_to_and_including + ); + ensure!( + up_to_and_including <= self.original.len(), + "Invalid range {}...{} given, original data is only {} byte long", + from, + up_to_and_including, + self.original.len() + ); + + // Since we error out when replacing an already replaced chunk of data, + // we can take some shortcuts here. For example, there can be no + // overlapping replacements -- we _always_ split a chunk of 'initial' + // data into three[^empty] parts, and there can't ever be two 'initial' + // parts touching. + // + // [^empty]: Leading and trailing ones might be empty if we replace + // the whole chunk. As an optimization and without loss of generality we + // don't add empty parts. + let new_parts = { + let index_of_part_to_split = self.parts + .iter() + .position(|p| p.start <= from && p.end >= up_to_and_including) + .ok_or_else(|| { + format_err!( + "Could not find data slice that covers range {}..{}", + from, + up_to_and_including + ) + })?; + + let part_to_split = &self.parts[index_of_part_to_split]; + ensure!( + part_to_split.data == State::Initial, + "Cannot replace slice of data that was already replaced" + ); + + let mut new_parts = Vec::with_capacity(self.parts.len() + 2); + + // Previous parts + if let Some(ps) = self.parts.get(..index_of_part_to_split) { + new_parts.extend_from_slice(&ps); + } + + // Keep initial data on left side of part + if from > part_to_split.start { + new_parts.push(Span { + start: part_to_split.start, + end: from, + data: State::Initial, + }); + } + + // New part + new_parts.push(Span { + start: from, + end: up_to_and_including, + data: State::Replaced(data.into()), + }); + + // Keep initial data on right side of part + if up_to_and_including < part_to_split.end { + new_parts.push(Span { + start: up_to_and_including + 1, + end: part_to_split.end, + data: State::Initial, + }); + } + + // Following parts + if let Some(ps) = self.parts.get(index_of_part_to_split + 1..) { + new_parts.extend_from_slice(&ps); + } + + new_parts + }; + + self.parts = new_parts; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use proptest::prelude::*; + + fn str(i: &[u8]) -> &str { + ::std::str::from_utf8(i).unwrap() + } + + #[test] + fn replace_some_stuff() { + let mut d = Data::new(b"foo bar baz"); + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + } + + #[test] + fn replace_a_single_char() { + let mut d = Data::new(b"let y = true;"); + d.replace_range(4, 4, b"mut y").unwrap(); + assert_eq!("let mut y = true;", str(&d.to_vec())); + } + + #[test] + fn replace_multiple_lines() { + let mut d = Data::new(b"lorem\nipsum\ndolor"); + + d.replace_range(6, 10, b"lol").unwrap(); + assert_eq!("lorem\nlol\ndolor", str(&d.to_vec())); + + d.replace_range(12, 17, b"lol").unwrap(); + assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); + } + + #[test] + #[should_panic(expected = "Cannot replace slice of data that was already replaced")] + fn replace_overlapping_stuff_errs() { + let mut d = Data::new(b"foo bar baz"); + + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + + d.replace_range(4, 6, b"lol").unwrap(); + } + + #[test] + #[should_panic(expected = "original data is only 3 byte long")] + fn broken_replacements() { + let mut d = Data::new(b"foo"); + d.replace_range(4, 7, b"lol").unwrap(); + } + + proptest! { + #[test] + #[ignore] + fn new_to_vec_roundtrip(ref s in "\\PC*") { + assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice()); + } + + #[test] + #[ignore] + fn replace_random_chunks( + ref data in "\\PC*", + ref replacements in prop::collection::vec( + (any::<::std::ops::Range>(), any::>()), + 1..1337, + ) + ) { + let mut d = Data::new(data.as_bytes()); + for &(ref range, ref bytes) in replacements { + let _ = d.replace_range(range.start, range.end, bytes); + } + } + } +} From 8aef421d82c3f831db0339e2fa7dfe0b9875a38d Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:24:25 +0200 Subject: [PATCH 132/298] Add test for preserving line endings Closes #77 --- cargo-fix/tests/all/main.rs | 13 +++++++++++-- cargo-fix/tests/all/smoke.rs | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 8547cdf8d..f0933c185 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -2,8 +2,8 @@ extern crate difference; extern crate url; use std::env; -use std::fs; -use std::io::Write; +use std::fs::{self, File}; +use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::process::Command; use std::str; @@ -84,6 +84,15 @@ impl Project { cwd: None, } } + + fn read(&self, path: &str) -> String { + let mut ret = String::new(); + File::open(self.root.join(path)) + .unwrap() + .read_to_string(&mut ret) + .unwrap(); + return ret + } } struct ExpectCmd<'a> { diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index c1c5ca290..0bebd621b 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -87,3 +87,16 @@ fn tricky_ampersand() { .stderr(stderr) .run(); } + +#[test] +fn preserve_line_endings() { + let p = project() + .file("src/lib.rs", "\ + fn add(a: &u32) -> u32 { a + 1 }\r\n\ + pub fn foo() -> u32 { add(1) }\r\n\ + ") + .build(); + + p.expect_cmd("cargo fix").run(); + assert!(p.read("src/lib.rs").contains("\r\n")); +} From de7714dc117ff5dbaf422607a105824b41a67e87 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:40:05 +0200 Subject: [PATCH 133/298] Add multiple suggestions test --- cargo-fix/tests/all/smoke.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 0bebd621b..51cf8e070 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -100,3 +100,31 @@ fn preserve_line_endings() { p.expect_cmd("cargo fix").run(); assert!(p.read("src/lib.rs").contains("\r\n")); } + +#[test] +fn multiple_suggestions_for_the_same_thing() { + let p = project() + .file("src/lib.rs", "\ + fn main() { + let xs = vec![String::from(\"foo\")]; + // error: no diplay in scope, and there are two options + // (std::path::Display and std::fmt::Display) + let d: &Display = &xs; + println!(\"{}\", d); + } + ") + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +error: Cannot replace slice of data that was already replaced +error: Could not compile `foo`. + +To learn more, run the command again with --verbose. +"; + + p.expect_cmd("cargo fix") + .stderr(stderr) + .status(101) + .run(); +} From 893f29fb382a670be6e50b8f6b247dd25c988b66 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:40:15 +0200 Subject: [PATCH 134/298] Omit now-unused crate --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6694b7201..70a654650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ exclude = [ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -replace-rs = { git = "https://github.com/killercup/replace-rs" } failure = "0.1.1" [dev-dependencies] From 45395939e7d6b50726f25a1e5b3941232545bc7f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:40:24 +0200 Subject: [PATCH 135/298] Prevent underflow --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9894b0069..c412809c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,7 +229,7 @@ pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result Date: Fri, 4 May 2018 23:42:57 +0200 Subject: [PATCH 136/298] Delete obsolete code --- src/lib.rs | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c412809c8..c8a7e0852 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,48 +177,6 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, } } -pub fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> String { - use std::cmp::max; - - let mut new_content = String::new(); - - // Add the lines before the section we want to replace - new_content.push_str(&file_content.lines() - .take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); - - // Parts of line before replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.start.line - 1) - .unwrap_or("") - .chars() - .take(suggestion.snippet.line_range.start.column - 1) - .collect::()); - - // Insert new content! Finally! - new_content.push_str(&suggestion.replacement); - - // Parts of line after replacement - new_content.push_str(&file_content.lines() - .nth(suggestion.snippet.line_range.end.line - 1) - .unwrap_or("") - .chars() - .skip(suggestion.snippet.line_range.end.column - 1) - .collect::()); - - // Add the lines after the section we want to replace - new_content.push_str("\n"); - new_content.push_str(&file_content.lines() - .skip(suggestion.snippet.line_range.end.line as usize) - .collect::>() - .join("\n")); - new_content.push_str("\n"); - - new_content -} - pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result { use replace::Data; From f9b8801585b7583cdd4e0a9ec96d1a0ae4a1d81c Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 4 May 2018 23:43:32 +0200 Subject: [PATCH 137/298] Run ignored tests on CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 54f732602..297b02d77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ rust: - nightly script: - cargo test --all + - cargo test --all -- --ignored notifications: email: on_success: never From cab6296b2ad94b46a1c3f449934662f3317745ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 15:39:53 -0700 Subject: [PATCH 138/298] Fix tests if `cargo fix` is already installed Make sure that we always run the version that we're compiling locally --- cargo-fix/tests/all/dependencies.rs | 4 ++-- cargo-fix/tests/all/smoke.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index af3e9d8c2..e7b727c0d 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -51,7 +51,7 @@ fn fix_path_deps() { [CHECKING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stdout("") .stderr(stderr) .run(); @@ -93,7 +93,7 @@ fn do_not_fix_non_relevant_deps() { "#) .build(); - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .cwd("foo") .status(101) .run(); diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 51cf8e070..9478c4e19 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -10,7 +10,7 @@ fn no_changes_necessary() { [CHECKING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stdout("") .stderr(stderr) .run(); @@ -34,7 +34,7 @@ fn fixes_missing_ampersand() { [CHECKING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stdout("") .stderr(stderr) .run(); @@ -58,7 +58,7 @@ fn fixes_two_missing_ampersands() { [CHECKING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stdout("") .stderr(stderr) .run(); @@ -82,7 +82,7 @@ fn tricky_ampersand() { [CHECKING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stdout("") .stderr(stderr) .run(); @@ -97,7 +97,7 @@ fn preserve_line_endings() { ") .build(); - p.expect_cmd("cargo fix").run(); + p.expect_cmd("cargo-fix fix").run(); assert!(p.read("src/lib.rs").contains("\r\n")); } @@ -123,7 +123,7 @@ error: Could not compile `foo`. To learn more, run the command again with --verbose. "; - p.expect_cmd("cargo fix") + p.expect_cmd("cargo-fix fix") .stderr(stderr) .status(101) .run(); From b0e0cc01c16a7516d9ec59280558482846de5af0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 22:44:38 -0700 Subject: [PATCH 139/298] Switch tests to working-code-by-default Don't use a compilation error to test rustfix but instead use a lint. --- cargo-fix/tests/all/dependencies.rs | 24 +++++-------- cargo-fix/tests/all/smoke.rs | 56 ++++++----------------------- cargo-fix/tests/all/subtargets.rs | 21 ++++------- 3 files changed, 25 insertions(+), 76 deletions(-) diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index e7b727c0d..059dffa23 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -19,12 +19,9 @@ fn fix_path_deps() { .file("src/lib.rs", r#" extern crate bar; - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + add(1) + let mut x = 3; + x } "#) .file( @@ -36,12 +33,9 @@ fn fix_path_deps() { "# ) .file("bar/src/lib.rs", r#" - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + add(1) + let mut x = 3; + x } "#) .build(); @@ -83,18 +77,16 @@ fn do_not_fix_non_relevant_deps() { "# ) .file("bar/src/lib.rs", r#" - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + add(1) + let mut x = 3; + x } "#) .build(); p.expect_cmd("cargo-fix fix") .cwd("foo") - .status(101) + .status(0) .run(); + assert!(p.read("bar/src/lib.rs").contains("mut")); } diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 9478c4e19..10bfb0c11 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -17,15 +17,12 @@ fn no_changes_necessary() { } #[test] -fn fixes_missing_ampersand() { +fn fixes_extra_mut() { let p = project() .file("src/lib.rs", r#" - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + let mut x = 3; + x } "#) .build(); @@ -44,12 +41,10 @@ fn fixes_missing_ampersand() { fn fixes_two_missing_ampersands() { let p = project() .file("src/lib.rs", r#" - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + add(1) + let mut x = 3; + let mut y = 3; + x + y } "#) .build(); @@ -65,15 +60,12 @@ fn fixes_two_missing_ampersands() { } #[test] -fn tricky_ampersand() { +fn tricky() { let p = project() .file("src/lib.rs", r#" - fn add(a: &u32) -> u32 { - a + 1 - } - pub fn foo() -> u32 { - add(1) + add(1) + let mut x = 3; let mut y = 3; + x + y } "#) .build(); @@ -93,38 +85,10 @@ fn preserve_line_endings() { let p = project() .file("src/lib.rs", "\ fn add(a: &u32) -> u32 { a + 1 }\r\n\ - pub fn foo() -> u32 { add(1) }\r\n\ + pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ ") .build(); p.expect_cmd("cargo-fix fix").run(); assert!(p.read("src/lib.rs").contains("\r\n")); } - -#[test] -fn multiple_suggestions_for_the_same_thing() { - let p = project() - .file("src/lib.rs", "\ - fn main() { - let xs = vec![String::from(\"foo\")]; - // error: no diplay in scope, and there are two options - // (std::path::Display and std::fmt::Display) - let d: &Display = &xs; - println!(\"{}\", d); - } - ") - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -error: Cannot replace slice of data that was already replaced -error: Could not compile `foo`. - -To learn more, run the command again with --verbose. -"; - - p.expect_cmd("cargo-fix fix") - .stderr(stderr) - .status(101) - .run(); -} diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index 4cd99fb3b..d86c743d7 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -4,28 +4,23 @@ use super::project; fn fixes_missing_ampersand() { let p = project() .file("src/main.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } - fn main() { add(1); } + fn main() { let mut x = 3; drop(x); } "#) .file("src/lib.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } - pub fn foo() -> u32 { add(1) } + pub fn foo() { let mut x = 3; drop(x); } #[test] - pub fn foo2() { add(1); } + pub fn foo2() { let mut x = 3; drop(x); } "#) .file("tests/a.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } #[test] - pub fn foo() { add(1); } + pub fn foo() { let mut x = 3; drop(x); } "#) .file("examples/foo.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } - fn main() { add(1); } + fn main() { let mut x = 3; drop(x); } "#) .file("build.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } - fn main() { add(1); } + fn main() { let mut x = 3; drop(x); } "#) .build(); @@ -55,10 +50,8 @@ fn fix_features() { "# ) .file("src/lib.rs", r#" - fn add(a: &u32) -> u32 { a + 1 } - #[cfg(feature = "bar")] - pub fn foo() -> u32 { add(1) } + pub fn foo() -> u32 { let mut x = 3; x } "#) .build(); From eb73d3129e56d58ec79a96b9283ea2bee7b339e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 22:45:13 -0700 Subject: [PATCH 140/298] Don't fix broken code This commit causes rustfix to bail out of attempting to fix a crate if it encounters already broken code. We wouldn't want to make the situation worse by accidentally introducing more breakage! --- cargo-fix/src/main.rs | 13 ++++++++++--- cargo-fix/tests/all/broken_build.rs | 26 ++++++++++++++++++++++++++ cargo-fix/tests/all/main.rs | 1 + 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 cargo-fix/tests/all/broken_build.rs diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 23a93b305..64f80b270 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -125,10 +125,17 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { let output = cmd.output() .with_context(|_| format!("failed to execute `{}`", rustc.display()))?; + // If rustc didn't succeed for whatever reasons then we're very likely to be + // looking at otherwise broken code. Let's not make things accidentally + // worse by applying fixes where a bug could cause *more* broken code. + // Instead, punt upwards which will reexec rustc over the original code, + // displaying pretty versions of the diagnostics we just read out. + if !output.status.success() { + return Ok(()) + } + // Sift through the output of the compiler to look for JSON messages - // indicating fixes that we can apply. Note that we *do not* look at the - // exit status here, that's intentional! We want to apply fixes even if - // there are compiler errors. + // indicating fixes that we can apply. let stderr = str::from_utf8(&output.stderr) .context("failed to parse rustc stderr as utf-8")?; diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs new file mode 100644 index 000000000..1c69b3030 --- /dev/null +++ b/cargo-fix/tests/all/broken_build.rs @@ -0,0 +1,26 @@ +use super::project; + +#[test] +fn do_not_fix_broken_builds() { + let p = project() + .file( + "src/lib.rs", + r#" + pub fn foo() { + let mut x = 3; + drop(x); + } + + pub fn foo2() { + let _x: u32 = "a"; + } + "# + ) + .build(); + + p.expect_cmd("cargo-fix fix") + .status(101) + .run(); + assert!(p.read("src/lib.rs").contains("let mut x = 3;")); +} + diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index f0933c185..b26491d2d 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -267,6 +267,7 @@ fn diff(expected: &str, actual: &str) { } } +mod broken_build; mod dependencies; mod smoke; mod subtargets; From df643225e879bcc352fc811c5cc36c53d3921495 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 23:03:41 -0700 Subject: [PATCH 141/298] Auto undo changes tha accidentally break code While this shouldn't show up it's best if we don't break users' code. Back out all file changes if this happens and make sure that we never break code with the fixes that we applied. --- cargo-fix/src/main.rs | 44 ++++++++++++++--- cargo-fix/tests/all/broken_build.rs | 76 +++++++++++++++++++++++++++++ cargo-fix/tests/all/main.rs | 12 +++++ 3 files changed, 125 insertions(+), 7 deletions(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 64f80b270..859ca199a 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -91,21 +91,49 @@ fn cargo_fix_rustc() -> Result<(), Error> { // To that end we only actually try to fix things if it looks like we're // compiling a Rust file and it *doesn't* have an absolute filename. That's // not the best heuristic but matches what Cargo does today at least. + let mut files_to_restore = HashMap::new(); if let Some(path) = filename { if !Path::new(&path).is_absolute() { - rustfix_crate(rustc.as_ref(), &path)?; + files_to_restore = rustfix_crate(rustc.as_ref(), &path)?; } } - // TODO: if we executed rustfix above and the previous rustc invocation was - // successful and this `status()` is not, then we should revert all fixes - // we applied, present a scary warning, and then move on. + // Ok now we have our final goal of testing out the changes that we applied. + // If these changes went awry and actually started to cause the crate to + // *stop* compiling then we want to back them out and continue to print + // warnings to the user. + // + // If we didn't actually make any changes then we can immediately exec the + // new rustc, and otherwise we capture the output to hide it in the scenario + // that we have to back it all out. let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); + if files_to_restore.len() > 0 { + let output = cmd.output().context("failed to spawn rustc")?; + + // If we succeeded then we'll want to commit to the changes we made, if + // any. If stderr is empty then there's no need for the final exec at + // the end, we just bail out here. + if output.status.success() && output.stderr.len() == 0 { + return Ok(()) + } + + // Otherwise if our rustc just failed then that means that we broke the + // user's code with our changes. Back out everything and fall through + // below to recompile again. + if !output.status.success() { + for (k, v) in files_to_restore { + File::create(&k) + .and_then(|mut f| f.write_all(v.as_bytes())) + .with_context(|_| format!("failed to write file `{}`", k))?; + } + } + } + exit_with(cmd.status().context("failed to spawn rustc")?); } -fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { +fn rustfix_crate(rustc: &Path, filename: &str) -> Result, Error> { // If not empty, filter by these lints // // TODO: Implement a way to specify this @@ -131,7 +159,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { // Instead, punt upwards which will reexec rustc over the original code, // displaying pretty versions of the diagnostics we just read out. if !output.status.success() { - return Ok(()) + return Ok(HashMap::new()) } // Sift through the output of the compiler to look for JSON messages @@ -173,6 +201,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { .push(suggestion); } + let mut old_files = HashMap::new(); for (file, suggestions) in file_map { // Attempt to read the source code for this file. If this fails then // that'd be pretty surprising, so log a message and otherwise keep @@ -188,9 +217,10 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result<(), Error> { File::create(&file) .and_then(|mut f| f.write_all(new_code.as_bytes())) .with_context(|_| format!("failed to write file `{}`", file))?; + old_files.insert(file, code); } - Ok(()) + Ok(old_files) } fn exit_with(status: ExitStatus) -> ! { diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 1c69b3030..1cb3acc7e 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -24,3 +24,79 @@ fn do_not_fix_broken_builds() { assert!(p.read("src/lib.rs").contains("let mut x = 3;")); } +#[test] +fn broken_fixes_backed_out() { + let p = project() + .file( + "foo/Cargo.toml", + r#" + [package] + name = 'foo' + version = '0.1.0' + [workspace] + "# + ) + .file( + "foo/src/main.rs", + r#" + use std::env; + use std::process::{self, Command}; + use std::path::PathBuf; + use std::fs; + + fn main() { + if env::args().any(|x| x == "src/lib.rs") { + let path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let path = path.join("foo"); + if path.exists() { + panic!("failing the second compilation, oh no!"); + } else { + fs::File::create(&path).unwrap(); + } + } + + let status = Command::new("rustc") + .args(env::args().skip(1)) + .status() + .expect("failed to run rustc"); + process::exit(status.code().unwrap_or(2)); + } + "# + ) + .file( + "bar/Cargo.toml", + r#" + [package] + name = 'bar' + version = '0.1.0' + [workspace] + "# + ) + .file("bar/build.rs", "fn main() {}") + .file( + "bar/src/lib.rs", + r#" + pub fn foo() { + let mut x = 3; + drop(x); + } + "# + ) + .build(); + + // Build our rustc shim + p.expect_cmd("cargo build") + .cwd("foo") + .run(); + + // Attempt to fix code, but our shim will always fail the second compile + p.expect_cmd("cargo-fix fix") + .cwd("bar") + .env("RUSTC", p.root.join("foo/target/debug/foo")) + .stderr_contains("oh no") + .status(101) + .run(); + + // Make sure the fix which should have been applied was backed out + assert!(p.read("bar/src/lib.rs").contains("let mut x = 3;")); +} diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index b26491d2d..edfc7d7d8 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -9,6 +9,7 @@ use std::process::Command; use std::str; use std::sync::atomic::*; use std::time::Instant; +use std::ffi::{OsStr, OsString}; use difference::{Changeset, Difference}; use url::Url; @@ -75,6 +76,7 @@ impl Project { ExpectCmd { project: self, cmd: cmd, + env: Vec::new(), stdout: None, stdout_contains: Vec::new(), stderr: None, @@ -99,6 +101,7 @@ struct ExpectCmd<'a> { ran: bool, project: &'a Project, cmd: &'a str, + env: Vec<(OsString, OsString)>, stdout: Option, stdout_contains: Vec, stderr: Option, @@ -118,6 +121,11 @@ impl<'a> ExpectCmd<'a> { self } + fn env, V: AsRef>(&mut self, k: K, v: V) -> &mut Self { + self.env.push((k.as_ref().to_owned(), v.as_ref().to_owned())); + self + } + fn stdout(&mut self, s: &str) -> &mut Self { self.stdout = Some(s.to_string()); self @@ -143,6 +151,10 @@ impl<'a> ExpectCmd<'a> { None => { cmd.current_dir(&self.project.root); } } + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + let mut me = env::current_exe().unwrap(); me.pop(); // chop off exe name me.pop(); // chop off `deps` From 3c691a3f75e282873a63066bd9f0fc7adcd5f2a6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 23:06:42 -0700 Subject: [PATCH 142/298] Pass --cap-lints=warn to the first compile Override any `deny(warnings)` settings to try to fix as many issues as possible. --- cargo-fix/src/main.rs | 3 ++- cargo-fix/tests/all/smoke.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 859ca199a..a75be6379 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -149,7 +149,8 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); - cmd.arg("--error-format=json"); + cmd.arg("--error-format=json") + .arg("--cap-lints=warn"); let output = cmd.output() .with_context(|_| format!("failed to execute `{}`", rustc.display()))?; diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 10bfb0c11..40341baf7 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -92,3 +92,17 @@ fn preserve_line_endings() { p.expect_cmd("cargo-fix fix").run(); assert!(p.read("src/lib.rs").contains("\r\n")); } + +#[test] +fn fix_deny_warnings() { + let p = project() + .file("src/lib.rs", "\ + #![deny(warnings)] + fn add(a: &u32) -> u32 { a + 1 }\r\n\ + pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ + ") + .build(); + + p.expect_cmd("cargo-fix fix").run(); + assert!(p.read("src/lib.rs").contains("\r\n")); +} From 1f2e5b907ce50089cae2d59445f2ecdf45559723 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 4 May 2018 23:10:26 -0700 Subject: [PATCH 143/298] Unconditionally pass `--cap-lints=warn` This way we can fix fixable warnings with `#[deny(warnings)]` but any unfixed warnings still get printed later as warnings. --- cargo-fix/src/main.rs | 8 ++++++-- cargo-fix/tests/all/broken_build.rs | 7 +++++-- cargo-fix/tests/all/smoke.rs | 24 +++++++++++++++++++++--- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index a75be6379..2e8a8e985 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -108,6 +108,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { // that we have to back it all out. let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); + cmd.arg("--cap-lints=warn"); if files_to_restore.len() > 0 { let output = cmd.output().context("failed to spawn rustc")?; @@ -159,6 +160,9 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result // worse by applying fixes where a bug could cause *more* broken code. // Instead, punt upwards which will reexec rustc over the original code, // displaying pretty versions of the diagnostics we just read out. + // + // TODO: this should be configurable by the CLI to sometimes proceed to + // attempt to fix broken code. if !output.status.success() { return Ok(HashMap::new()) } @@ -178,7 +182,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result .filter_map(|diag| rustfix::collect_suggestions(&diag, &only)); // Collect suggestions by file so we can apply them one at a time later. - let mut file_map = HashMap::new(); + let mut file_map = HashMap::with_capacity(suggestions.len()); for suggestion in suggestions { // Make sure we've got a file associated with this suggestion and all // snippets point to the same location. Right now it's not clear what @@ -202,7 +206,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result .push(suggestion); } - let mut old_files = HashMap::new(); + let mut old_files = HashMap::with_capacity(file_map.len()); for (file, suggestions) in file_map { // Attempt to read the source code for this file. If this fails then // that'd be pretty surprising, so log a message and otherwise keep diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 1cb3acc7e..590071eec 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -41,11 +41,14 @@ fn broken_fixes_backed_out() { r#" use std::env; use std::process::{self, Command}; - use std::path::PathBuf; + use std::path::{Path, PathBuf}; use std::fs; fn main() { - if env::args().any(|x| x == "src/lib.rs") { + let is_lib_rs = env::args_os() + .map(PathBuf::from) + .any(|l| l == Path::new("src/lib.rs")); + if is_lib_rs { let path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let path = path.join("foo"); if path.exists() { diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 40341baf7..fae2e784c 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -98,11 +98,29 @@ fn fix_deny_warnings() { let p = project() .file("src/lib.rs", "\ #![deny(warnings)] - fn add(a: &u32) -> u32 { a + 1 }\r\n\ - pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ + pub fn foo() { let mut x = 3; drop(x); } ") .build(); p.expect_cmd("cargo-fix fix").run(); - assert!(p.read("src/lib.rs").contains("\r\n")); +} + +#[test] +fn fix_deny_warnings_but_not_others() { + let p = project() + .file("src/lib.rs", " + #![deny(warnings)] + + pub fn foo() -> u32 { + let mut x = 3; + x + } + + fn bar() {} + ") + .build(); + + p.expect_cmd("cargo-fix fix").run(); + assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); + assert!(p.read("src/lib.rs").contains("fn bar() {}")); } From 99b0f8b1eeed605ecbb3d620004b92b15000fde3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 09:17:17 -0700 Subject: [PATCH 144/298] Fix compile on master --- cargo-fix/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 2e8a8e985..c8f128e38 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -182,7 +182,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result .filter_map(|diag| rustfix::collect_suggestions(&diag, &only)); // Collect suggestions by file so we can apply them one at a time later. - let mut file_map = HashMap::with_capacity(suggestions.len()); + let mut file_map = HashMap::new(); for suggestion in suggestions { // Make sure we've got a file associated with this suggestion and all // snippets point to the same location. Right now it's not clear what From ab3334e2457ac5ac631fa378344d71fd3df550b9 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 5 May 2018 18:14:11 +0200 Subject: [PATCH 145/298] Update READMEs [ci skip] --- Readme.md | 76 +++++---------------------------------------- cargo-fix/Readme.md | 36 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 70 deletions(-) mode change 120000 => 100644 cargo-fix/Readme.md diff --git a/Readme.md b/Readme.md index 4443a64ec..f2ecf7d41 100644 --- a/Readme.md +++ b/Readme.md @@ -1,82 +1,20 @@ # rustfix -> **HIGHLY EXPERIMENTAL – MIGHT EAT YOUR CODE** - -The goal of this tool is to read and apply the suggestions made by rustc (and third-party lints, like those offered by [clippy]). - -[clippy]: https://github.com/Manishearth/rust-clippy +The goal of this tool is to read and apply the suggestions made by rustc. [![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) [![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) -## Current state +## Current status -This tool can +Currently, rustfix is split into to crates: -- parse rustc's diagnostics (it calls `cargo` for you and reads its output) -- read a file of diagnostics (one JSON object per line) -- interactively step through the suggestions and ask the user what to do -- apply suggestions (currently whole lines only) +- `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs +- and `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code. -![rustfix demo](http://i.imgur.com/E9YkK76.png) +The magic of rustfix is entirely dependent on the diagnostics implement in the Rust compiler (and external lints, like [clippy]). -## Installation - -Assuming you have a recent Rust nightly and Cargo installed: - -```sh -$ cargo install --git https://github.com/killercup/rustfix.git -``` - -Make sure the binaries installed by Cargo are in your `$PATH`. - -## Usage - -In your project directory, just execute `rustfix`! - -You probably want to use `rustfix --clippy` to get all the suggestions from [Clippy][clippy] as well. Make sure you have `cargo clippy` installed (`cargo install clippy`). - -Please note that running `rustfix` multiple times in a project where no file was changed in the meantime will currently not generate any suggestions (as Cargo/Rust will skip the unchanged code and not compile it again). - -### CLI Options - -```plain -rustfix 0.1.0 -Automatically apply suggestions made by rustc - -USAGE: - rustfix [FLAGS] [OPTIONS] - -FLAGS: - --clippy Use `cargo clippy` for suggestions - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - --from-file Read suggestions from file (each line is a JSON object) -``` - -## Get the example running - -My current example output for diagnostics is based on [libui-rs](https://github.com/pcwalton/libui-rs). You can find the example JSON in `tests/fixtures/libui-rs/clippy.json`. - -Run `rustfix`: - -```sh -$ cargo test -``` - -### Generate the example diagnostics JSON yourself - -```sh -$ APPLY_RUSTFIX=1 cargo test -``` - -## Gotchas - -- rustc JSON output is unstable -- Not all suggestions can be applied trivially (e.g. clippy's "You should use `Default` instead of that `fn new()` you just wrote"-lint will replace your `new`-method with an `impl` block -- which is obviously invalid syntax.) -- This tool _will_ eat your laundry +[clippy]: https://github.com/rust-lang-nursery/rust-clippy ## License diff --git a/cargo-fix/Readme.md b/cargo-fix/Readme.md deleted file mode 120000 index cf2c5c52c..000000000 --- a/cargo-fix/Readme.md +++ /dev/null @@ -1 +0,0 @@ -../Readme.md \ No newline at end of file diff --git a/cargo-fix/Readme.md b/cargo-fix/Readme.md new file mode 100644 index 000000000..d8dc3f463 --- /dev/null +++ b/cargo-fix/Readme.md @@ -0,0 +1,35 @@ +# cargo fix + +Run `cargo fix` and get better code. + +[![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) +[![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) + +## Installation + +Assuming you have a recent Rust toolchain installed and active, run `cargo install cargo-fix`. + +## Usage + +1. Navigate to a cargo project + 1. Make sure you use version control and have a clean working directory (so you can easily see the changes rustfix makes later on) + 2. Make sure your project compiles +2. Run `cargo fix` +3. ??? (wait for it to compile and fix your code) +4. PROFIT! + +## License + +Licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. From a86ce67cb9c062e59430c72b3c106a0fd394d94e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 10:31:03 -0700 Subject: [PATCH 146/298] Start giving `cargo fix` a dedicated CLI This commit pulls in `clap` to have a location to actually insert a CLI for `cargo fix` itself. This'll hopefully allow us to continue to configure cargo-fix's behavior while also allowing passing arguments down to Cargo. This starts out by adding a `--broken-code` option which can be used to specify that previously broken code should be fixed, despite it being originally broken. Closes #70 Closes #71 Closes #84 --- cargo-fix/Cargo.toml | 1 + cargo-fix/src/cli.rs | 71 +++++++++++++++++++++++++++++ cargo-fix/src/main.rs | 42 ++--------------- cargo-fix/tests/all/broken_build.rs | 19 ++++++++ cargo-fix/tests/all/subtargets.rs | 4 +- 5 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 cargo-fix/src/cli.rs diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index 82e9b9848..18572dcd0 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -18,6 +18,7 @@ rustfix = { path = "..", version = "0.2" } serde_json = "1" log = "0.4" env_logger = { version = "0.5", default-features = false } +clap = "2.31" [dev-dependencies] difference = "2" diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs new file mode 100644 index 000000000..37ec85933 --- /dev/null +++ b/cargo-fix/src/cli.rs @@ -0,0 +1,71 @@ +use std::env; +use std::process::Command; + +use failure::{Error, ResultExt}; +use clap::{Arg, App, SubCommand, AppSettings}; + +use lock::Server; +use super::exit_with; + +pub fn run() -> Result<(), Error> { + let matches = App::new("Cargo Fix") + .bin_name("cargo") + .subcommand( + SubCommand::with_name("fix") + .version(env!("CARGO_PKG_VERSION")) + .author("The Rust Project Developers") + .about("Automatically apply rustc's suggestions about fixing code") + .setting(AppSettings::TrailingVarArg) + .arg(Arg::with_name("args").multiple(true)) + .arg( + Arg::with_name("broken-code") + .long("broken-code") + .help("Fix code even if it already has compiler errors") + ) + ) + .get_matches(); + let matches = match matches.subcommand() { + ("fix", Some(matches)) => matches, + _ => bail!("unknown cli arguments passed"), + }; + + if matches.is_present("broken-code") { + env::set_var("__CARGO_FIX_BROKEN_CODE", "1"); + } + + // Spin up our lock server which our subprocesses will use to synchronize + // fixes. + let _lockserver = Server::new()?.start()?; + + let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); + let mut cmd = Command::new(&cargo); + // TODO: shouldn't hardcode `check` here, we want to allow things like + // `cargo fix bench` or something like that + // + // TODO: somehow we need to force `check` to actually do something here, if + // `cargo check` was previously run it won't actually do anything again. + cmd.arg("check"); + if let Some(args) = matches.values_of("args") { + cmd.args(args); + } + + // Override the rustc compiler as ourselves. That way whenever rustc would + // run we run instead and have an opportunity to inject fixes. + let me = env::current_exe() + .context("failed to learn about path to current exe")?; + cmd.env("RUSTC", &me) + .env("__CARGO_FIX_NOW_RUSTC", "1"); + if let Some(rustc) = env::var_os("RUSTC") { + cmd.env("RUSTC_ORIGINAL", rustc); + } + + // An now execute all of Cargo! This'll fix everything along the way. + // + // TODO: we probably want to do something fancy here like collect results + // from the client processes and print out a summary of what happened. + let status = cmd.status() + .with_context(|e| { + format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e) + })?; + exit_with(status); +} diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index c8f128e38..e9bd41cb2 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -1,3 +1,4 @@ +extern crate clap; #[macro_use] extern crate failure; extern crate rustfix; @@ -17,6 +18,7 @@ use std::path::Path; use rustfix::diagnostics::Diagnostic; use failure::{Error, ResultExt}; +mod cli; mod lock; fn main() { @@ -24,7 +26,7 @@ fn main() { let result = if env::var("__CARGO_FIX_NOW_RUSTC").is_ok() { cargo_fix_rustc() } else { - cargo_fix() + cli::run() }; let err = match result { Ok(()) => return, @@ -37,42 +39,6 @@ fn main() { process::exit(102); } -fn cargo_fix() -> Result<(), Error> { - // Spin up our lock server which our subprocesses will use to synchronize - // fixes. - let _lockserver = lock::Server::new()?.start()?; - - let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); - let mut cmd = Command::new(&cargo); - // TODO: shouldn't hardcode `check` here, we want to allow things like - // `cargo fix bench` or something like that - // - // TODO: somehow we need to force `check` to actually do something here, if - // `cargo check` was previously run it won't actually do anything again. - cmd.arg("check"); - cmd.args(env::args().skip(2)); // skip `cmd-fix fix` - - // Override the rustc compiler as ourselves. That way whenever rustc would - // run we run instead and have an opportunity to inject fixes. - let me = env::current_exe() - .context("failed to learn about path to current exe")?; - cmd.env("RUSTC", &me) - .env("__CARGO_FIX_NOW_RUSTC", "1"); - if let Some(rustc) = env::var_os("RUSTC") { - cmd.env("RUSTC_ORIGINAL", rustc); - } - - // An now execute all of Cargo! This'll fix everything along the way. - // - // TODO: we probably want to do something fancy here like collect results - // from the client processes and print out a summary of what happened. - let status = cmd.status() - .with_context(|e| { - format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e) - })?; - exit_with(status); -} - fn cargo_fix_rustc() -> Result<(), Error> { // Try to figure out what we're compiling by looking for a rust-like file // that exists. @@ -163,7 +129,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result // // TODO: this should be configurable by the CLI to sometimes proceed to // attempt to fix broken code. - if !output.status.success() { + if !output.status.success() && env::var_os("__CARGO_FIX_BROKEN_CODE").is_none() { return Ok(HashMap::new()) } diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 590071eec..92295e834 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -24,6 +24,25 @@ fn do_not_fix_broken_builds() { assert!(p.read("src/lib.rs").contains("let mut x = 3;")); } +#[test] +fn fix_broken_if_requested() { + let p = project() + .file( + "src/lib.rs", + r#" + fn foo(a: &u32) -> u32 { a + 1 } + pub fn bar() { + foo(1); + } + "# + ) + .build(); + + p.expect_cmd("cargo-fix fix --broken-code") + .status(0) + .run(); +} + #[test] fn broken_fixes_backed_out() { let p = project() diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index d86c743d7..e24729968 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -28,7 +28,7 @@ fn fixes_missing_ampersand() { [COMPILING] foo v0.1.0 (CWD) [FINISHED] dev [unoptimized + debuginfo] "; - p.expect_cmd("cargo fix --all-targets").stdout("").stderr(stderr).run(); + p.expect_cmd("cargo fix -- --all-targets").stdout("").stderr(stderr).run(); p.expect_cmd("cargo build").run(); p.expect_cmd("cargo test").run(); } @@ -57,6 +57,6 @@ fn fix_features() { p.expect_cmd("cargo fix").run(); p.expect_cmd("cargo build").run(); - p.expect_cmd("cargo fix --features bar").run(); + p.expect_cmd("cargo fix -- --features bar").run(); p.expect_cmd("cargo build --features bar").run(); } From 5785698ddb064c9549b2a12e9e70834c553dbdbf Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 5 May 2018 21:39:31 +0200 Subject: [PATCH 147/298] Add some more logging --- cargo-fix/src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index e9bd41cb2..7c65da49d 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -24,8 +24,10 @@ mod lock; fn main() { env_logger::init(); let result = if env::var("__CARGO_FIX_NOW_RUSTC").is_ok() { + debug!("invoking cargo-fix as rustc wrapper"); cargo_fix_rustc() } else { + debug!("invoking cargo-fix as cargo subcommand"); cli::run() }; let err = match result { @@ -48,6 +50,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { .filter(|s| Path::new(s).exists()) .next(); + trace!("cargo-fix as rustc got file {:?}", filename); let rustc = env::var_os("RUSTC_ORIGINAL").unwrap_or("rustc".into()); // Our goal is to fix only the crates that the end user is interested in. @@ -60,6 +63,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { let mut files_to_restore = HashMap::new(); if let Some(path) = filename { if !Path::new(&path).is_absolute() { + trace!("start rustfixing {:?}", path); files_to_restore = rustfix_crate(rustc.as_ref(), &path)?; } } @@ -130,6 +134,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result // TODO: this should be configurable by the CLI to sometimes proceed to // attempt to fix broken code. if !output.status.success() && env::var_os("__CARGO_FIX_BROKEN_CODE").is_none() { + debug!("rustfixing `{:?}` failed, rustc exited with {:?}", filename, output.status.code()); return Ok(HashMap::new()) } @@ -149,6 +154,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result // Collect suggestions by file so we can apply them one at a time later. let mut file_map = HashMap::new(); + let mut num_suggestion = 0; for suggestion in suggestions { // Make sure we've got a file associated with this suggestion and all // snippets point to the same location. Right now it's not clear what @@ -170,8 +176,11 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result file_map.entry(file_name) .or_insert_with(Vec::new) .push(suggestion); + num_suggestion += 1; } + debug!("collected {} suggestions for `{}`", num_suggestion, filename); + let mut old_files = HashMap::with_capacity(file_map.len()); for (file, suggestions) in file_map { // Attempt to read the source code for this file. If this fails then From 0923fbf98437fd1badaa61d8cf7e61831ab6b1d4 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 5 May 2018 21:39:54 +0200 Subject: [PATCH 148/298] Add cargo-like output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, running `cargo fix` ends up printing a bunch of "Checking …" lines from the internal `cargo check` calls. In the step where we apply suggestions, I've now added "Fixing …" lines -- one per file. The style is the same as cargo's (it's using the same crates and color detection). --- cargo-fix/Cargo.toml | 2 ++ cargo-fix/src/main.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index 18572dcd0..679f74dfd 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -19,6 +19,8 @@ serde_json = "1" log = "0.4" env_logger = { version = "0.5", default-features = false } clap = "2.31" +termcolor = "0.3.6" +atty = "0.2.10" [dev-dependencies] difference = "2" diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 7c65da49d..10e7ea615 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -6,6 +6,8 @@ extern crate serde_json; #[macro_use] extern crate log; extern crate env_logger; +extern crate atty; +extern crate termcolor; use std::collections::{HashSet, HashMap}; use std::env; @@ -191,7 +193,12 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result warn!("failed to read `{}`: {}", file, e); continue } - debug!("applying {} fixes to {}", suggestions.len(), file); + let num_suggestions = suggestions.len(); + debug!("applying {} fixes to {}", num_suggestions, file); + log_for_human("Fixing", &format!("{name} ({n} {fixes})", + name = file, n = num_suggestions, + fixes = if num_suggestions > 1 { "fixes" } else { "fix" }, + ))?; let new_code = rustfix::apply_suggestions(&code, &suggestions)?; File::create(&file) @@ -203,6 +210,30 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result Ok(old_files) } +fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> { + use std::io::Write; + use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + + // Adapted from cargo, cf. + let color_choice = if atty::is(atty::Stream::Stderr) { + ColorChoice::Auto + } else { + ColorChoice::Never + }; + let mut stream = StandardStream::stderr(color_choice); + stream.reset()?; + + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)))?; + // Justify to 12 chars just like cargo + write!(&mut stream, "{:>12}", kind)?; + stream.reset()?; + + write!(&mut stream, " {}\n", msg)?; + stream.flush()?; + + Ok(()) +} + fn exit_with(status: ExitStatus) -> ! { #[cfg(unix)] { From 075fcbafbd8a0266030f2d5870b88658ee2a4f50 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 5 May 2018 21:40:36 +0200 Subject: [PATCH 149/298] =?UTF-8?q?Update=20tests=20to=20include=20"Fixing?= =?UTF-8?q?=20=E2=80=A6"=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #72 --- cargo-fix/tests/all/dependencies.rs | 2 ++ cargo-fix/tests/all/main.rs | 6 ++++-- cargo-fix/tests/all/smoke.rs | 3 +++ cargo-fix/tests/all/subtargets.rs | 20 +++++++++++++++----- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index 059dffa23..6395e5dc3 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -42,7 +42,9 @@ fn fix_path_deps() { let stderr = "\ [CHECKING] bar v0.1.0 (CWD/bar) +[FIXING] bar/src/lib.rs (1 fix) [CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (1 fix) [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index edfc7d7d8..7583f48ca 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -218,9 +218,11 @@ impl<'a> ExpectCmd<'a> { fn clean(&self, s: &str) -> String { let url = Url::from_file_path(&self.project.root).unwrap(); - let s = s.replace("[CHECKING]", " Checking") - .replace("[FINISHED]", " Finished") + let s = s + .replace("[CHECKING]", " Checking") + .replace("[FINISHED]", " Finished") .replace("[COMPILING]", " Compiling") + .replace("[FIXING]", " Fixing") .replace(&url.to_string(), "CWD") .replace(&self.project.root.display().to_string(), "CWD") .replace("\\", "/"); diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index fae2e784c..6085d9ffb 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -29,6 +29,7 @@ fn fixes_extra_mut() { let stderr = "\ [CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (1 fix) [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") @@ -51,6 +52,7 @@ fn fixes_two_missing_ampersands() { let stderr = "\ [CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (2 fixes) [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") @@ -72,6 +74,7 @@ fn tricky() { let stderr = "\ [CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (2 fixes) [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index e24729968..8a15e652f 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -24,11 +24,21 @@ fn fixes_missing_ampersand() { "#) .build(); - let stderr = "\ -[COMPILING] foo v0.1.0 (CWD) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo fix -- --all-targets").stdout("").stderr(stderr).run(); + p.expect_cmd("cargo fix -- --all-targets") + .stdout("") + .stderr_contains("[COMPILING] foo v0.1.0 (CWD)") + .stderr_contains("[FIXING] build.rs (1 fix)") + // Don't assert number of fixes for this one, as we don't know if we're + // fixing it once or twice! We run this all concurrently, and if we + // compile (and fix) in `--test` mode first, we get two fixes. Otherwise + // we'll fix one non-test thing, and then fix another one later in + // test mode. + .stderr_contains("[FIXING] src/lib.rs") + .stderr_contains("[FIXING] src/main.rs (1 fix)") + .stderr_contains("[FIXING] examples/foo.rs (1 fix)") + .stderr_contains("[FIXING] tests/a.rs (1 fix)") + .stderr_contains("[FINISHED] dev [unoptimized + debuginfo]") + .run(); p.expect_cmd("cargo build").run(); p.expect_cmd("cargo test").run(); } From e2ae392cf974e8faec79d45d8971a6387aad2632 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 5 May 2018 22:37:57 +0200 Subject: [PATCH 150/298] Introduce a diagnostics server This should make all writing of custom diagnostic messages be done in a serial way, preventing mangled output. As you may notice, this is quite similar to the lock server, from which I've also copied a bunch of code. In theory, we could make this part of the lock server, but I didn't want to make it too complicated for now, as they serve different purposes right now. --- cargo-fix/Cargo.toml | 2 + cargo-fix/src/cli.rs | 51 ++++++++++++++++++++- cargo-fix/src/diagnostics.rs | 87 ++++++++++++++++++++++++++++++++++++ cargo-fix/src/main.rs | 33 +++----------- 4 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 cargo-fix/src/diagnostics.rs diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index 679f74dfd..c99469733 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -21,6 +21,8 @@ env_logger = { version = "0.5", default-features = false } clap = "2.31" termcolor = "0.3.6" atty = "0.2.10" +serde_derive = "1.0.45" +serde = "1.0.45" [dev-dependencies] difference = "2" diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 37ec85933..0d00aa928 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -3,8 +3,10 @@ use std::process::Command; use failure::{Error, ResultExt}; use clap::{Arg, App, SubCommand, AppSettings}; +use atty; -use lock::Server; +use lock; +use diagnostics; use super::exit_with; pub fn run() -> Result<(), Error> { @@ -35,7 +37,12 @@ pub fn run() -> Result<(), Error> { // Spin up our lock server which our subprocesses will use to synchronize // fixes. - let _lockserver = Server::new()?.start()?; + let _lockserver = lock::Server::new()?.start()?; + + // Spin up our diagnostics server which our subprocesses will use to send + // use their dignostics messages in an ordered way. + let _lockserver = diagnostics::Server::new()? + .start(|m| { let _ = log_message(&m); })?; let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); let mut cmd = Command::new(&cargo); @@ -69,3 +76,43 @@ pub fn run() -> Result<(), Error> { })?; exit_with(status); } + + +fn log_message(msg: &diagnostics::Message) -> Result<(), Error> { + use diagnostics::Message::*; + + match msg { + Fixing { file, fixes } => { + log_for_human("Fixing", &format!("{name} ({n} {fixes})", + name = file, n = fixes, + fixes = if *fixes > 1 { "fixes" } else { "fix" }, + ))?; + } + } + + Ok(()) +} + +fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> { + use std::io::Write; + use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + + // Adapted from cargo, cf. + let color_choice = if atty::is(atty::Stream::Stderr) { + ColorChoice::Auto + } else { + ColorChoice::Never + }; + let mut stream = StandardStream::stderr(color_choice); + stream.reset()?; + + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)))?; + // Justify to 12 chars just like cargo + write!(&mut stream, "{:>12}", kind)?; + stream.reset()?; + + write!(&mut stream, " {}\n", msg)?; + stream.flush()?; + + Ok(()) +} diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs new file mode 100644 index 000000000..0454c2dc0 --- /dev/null +++ b/cargo-fix/src/diagnostics.rs @@ -0,0 +1,87 @@ +//! A small TCP server to handle collection of diagnostics information in a +//! cross-platform way. + +use std::env; +use std::io::BufReader; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::thread::{self, JoinHandle}; + +use failure::{Error, ResultExt}; +use serde_json; + +static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; + +#[derive(Deserialize, Serialize)] +pub enum Message { + Fixing { file: String, fixes: usize }, +} + +impl Message { + pub fn fixing(file: &str, num: usize) -> Message { + Message::Fixing { + file: file.into(), + fixes: num, + } + } + + pub fn post(&self) -> Result<(), Error> { + let addr = env::var(DIAGNOSICS_SERVER_VAR).context("diagnostics collector misconfigured")?; + let mut client = + TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?; + + serde_json::to_writer(&mut client, &self) + .context("failed to write message to diagnostics target")?; + + Ok(()) + } +} + +pub struct Server { + listener: TcpListener, +} + +pub struct StartedServer { + _addr: SocketAddr, + thread: Option>, +} + +impl Server { + pub fn new() -> Result { + let listener = TcpListener::bind("127.0.0.1:0") + .with_context(|_| "failed to bind TCP listener to manage locking")?; + env::set_var(DIAGNOSICS_SERVER_VAR, listener.local_addr()?.to_string()); + + Ok(Server { listener }) + } + + pub fn start( + self, + on_message: F, + ) -> Result { + let _addr = self.listener.local_addr()?; + let thread = thread::spawn(move || { + self.run(on_message); + }); + + Ok(StartedServer { + _addr, + thread: Some(thread), + }) + } + + fn run(self, on_message: F) { + while let Ok((client, _)) = self.listener.accept() { + let mut client = BufReader::new(client); + match serde_json::from_reader(client) { + Ok(message) => on_message(message), + Err(e) => { warn!("invalid diagnostics message: {}", e); } + } + } + } +} + +impl Drop for StartedServer { + fn drop(&mut self) { + drop(self.thread.take().unwrap().join()); + } +} diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 10e7ea615..b37c76841 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -4,6 +4,8 @@ extern crate failure; extern crate rustfix; extern crate serde_json; #[macro_use] +extern crate serde_derive; +#[macro_use] extern crate log; extern crate env_logger; extern crate atty; @@ -22,6 +24,7 @@ use failure::{Error, ResultExt}; mod cli; mod lock; +mod diagnostics; fn main() { env_logger::init(); @@ -195,10 +198,8 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result } let num_suggestions = suggestions.len(); debug!("applying {} fixes to {}", num_suggestions, file); - log_for_human("Fixing", &format!("{name} ({n} {fixes})", - name = file, n = num_suggestions, - fixes = if num_suggestions > 1 { "fixes" } else { "fix" }, - ))?; + + diagnostics::Message::fixing(&file, num_suggestion).post()?; let new_code = rustfix::apply_suggestions(&code, &suggestions)?; File::create(&file) @@ -210,30 +211,6 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result Ok(old_files) } -fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> { - use std::io::Write; - use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - - // Adapted from cargo, cf. - let color_choice = if atty::is(atty::Stream::Stderr) { - ColorChoice::Auto - } else { - ColorChoice::Never - }; - let mut stream = StandardStream::stderr(color_choice); - stream.reset()?; - - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)))?; - // Justify to 12 chars just like cargo - write!(&mut stream, "{:>12}", kind)?; - stream.reset()?; - - write!(&mut stream, " {}\n", msg)?; - stream.flush()?; - - Ok(()) -} - fn exit_with(status: ExitStatus) -> ! { #[cfg(unix)] { From 5d201944d7aba8380082dcb9e0c340d92e92850f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 15:14:28 -0700 Subject: [PATCH 151/298] Run `cargo fmt` --- cargo-fix/src/cli.rs | 35 +++++------ cargo-fix/src/diagnostics.rs | 4 +- cargo-fix/src/lock.rs | 37 +++++++----- cargo-fix/src/main.rs | 52 +++++++++------- cargo-fix/tests/all/broken_build.rs | 24 +++----- cargo-fix/tests/all/dependencies.rs | 60 ++++++++++--------- cargo-fix/tests/all/main.rs | 78 +++++++++++++----------- cargo-fix/tests/all/smoke.rs | 92 +++++++++++++++++------------ cargo-fix/tests/all/subtargets.rs | 44 ++++++++++---- cargo-fix/tests/all/warnings.rs | 11 +++- src/lib.rs | 69 ++++++++++++---------- src/replace.rs | 12 ++-- tests/everything.rs | 47 ++++++++++----- 13 files changed, 328 insertions(+), 237 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 0d00aa928..9ef18f915 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -2,7 +2,7 @@ use std::env; use std::process::Command; use failure::{Error, ResultExt}; -use clap::{Arg, App, SubCommand, AppSettings}; +use clap::{App, AppSettings, Arg, SubCommand}; use atty; use lock; @@ -22,8 +22,8 @@ pub fn run() -> Result<(), Error> { .arg( Arg::with_name("broken-code") .long("broken-code") - .help("Fix code even if it already has compiler errors") - ) + .help("Fix code even if it already has compiler errors"), + ), ) .get_matches(); let matches = match matches.subcommand() { @@ -41,8 +41,9 @@ pub fn run() -> Result<(), Error> { // Spin up our diagnostics server which our subprocesses will use to send // use their dignostics messages in an ordered way. - let _lockserver = diagnostics::Server::new()? - .start(|m| { let _ = log_message(&m); })?; + let _lockserver = diagnostics::Server::new()?.start(|m| { + let _ = log_message(&m); + })?; let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); let mut cmd = Command::new(&cargo); @@ -58,10 +59,8 @@ pub fn run() -> Result<(), Error> { // Override the rustc compiler as ourselves. That way whenever rustc would // run we run instead and have an opportunity to inject fixes. - let me = env::current_exe() - .context("failed to learn about path to current exe")?; - cmd.env("RUSTC", &me) - .env("__CARGO_FIX_NOW_RUSTC", "1"); + let me = env::current_exe().context("failed to learn about path to current exe")?; + cmd.env("RUSTC", &me).env("__CARGO_FIX_NOW_RUSTC", "1"); if let Some(rustc) = env::var_os("RUSTC") { cmd.env("RUSTC_ORIGINAL", rustc); } @@ -71,22 +70,24 @@ pub fn run() -> Result<(), Error> { // TODO: we probably want to do something fancy here like collect results // from the client processes and print out a summary of what happened. let status = cmd.status() - .with_context(|e| { - format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e) - })?; + .with_context(|e| format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e))?; exit_with(status); } - fn log_message(msg: &diagnostics::Message) -> Result<(), Error> { use diagnostics::Message::*; match msg { Fixing { file, fixes } => { - log_for_human("Fixing", &format!("{name} ({n} {fixes})", - name = file, n = fixes, - fixes = if *fixes > 1 { "fixes" } else { "fix" }, - ))?; + log_for_human( + "Fixing", + &format!( + "{name} ({n} {fixes})", + name = file, + n = fixes, + fixes = if *fixes > 1 { "fixes" } else { "fix" }, + ), + )?; } } diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index 0454c2dc0..36a3d61f5 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -74,7 +74,9 @@ impl Server { let mut client = BufReader::new(client); match serde_json::from_reader(client) { Ok(message) => on_message(message), - Err(e) => { warn!("invalid diagnostics message: {}", e); } + Err(e) => { + warn!("invalid diagnostics message: {}", e); + } } } } diff --git a/cargo-fix/src/lock.rs b/cargo-fix/src/lock.rs index 81294e18b..673267658 100644 --- a/cargo-fix/src/lock.rs +++ b/cargo-fix/src/lock.rs @@ -13,8 +13,8 @@ use std::collections::HashMap; use std::env; -use std::io::{BufReader, BufRead, Read, Write}; -use std::net::{TcpStream, SocketAddr, TcpListener}; +use std::io::{BufRead, BufReader, Read, Write}; +use std::net::{SocketAddr, TcpListener, TcpStream}; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::{self, JoinHandle}; @@ -70,7 +70,7 @@ impl Server { fn run(mut self) { while let Ok((client, _)) = self.listener.accept() { if self.done.load(Ordering::SeqCst) { - break + break; } // Learn the name of our connected client to figure out if it needs @@ -78,7 +78,7 @@ impl Server { let mut client = BufReader::new(client); let mut name = String::new(); if client.read_line(&mut name).is_err() { - continue + continue; } let client = client.into_inner(); @@ -89,7 +89,7 @@ impl Server { let mut state = t.lock.lock().unwrap(); if state.0 { state.1.push(client); - continue + continue; } drop(t.thread.take().unwrap().join()); } @@ -102,7 +102,7 @@ impl Server { let mut state = lock2.lock().unwrap(); if state.1.len() == 0 { state.0 = false; - break + break; } else { state.1.remove(0) } @@ -110,17 +110,20 @@ impl Server { // Inform this client that it now has the lock and wait for // it to disconnect by waiting for EOF. if client.write_all(&[1]).is_err() { - continue + continue; } let mut dst = Vec::new(); drop(client.read_to_end(&mut dst)); } }); - self.threads.insert(name, ServerClient { - thread: Some(thread), - lock, - }); + self.threads.insert( + name, + ServerClient { + thread: Some(thread), + lock, + }, + ); } } } @@ -140,7 +143,7 @@ impl Drop for StartedServer { self.done.store(true, Ordering::SeqCst); // Ignore errors here as this is largely best-effort if TcpStream::connect(&self.addr).is_err() { - return + return; } drop(self.thread.take().unwrap().join()); } @@ -150,13 +153,15 @@ impl Client { pub fn lock(name: &str) -> Result { let addr = env::var("__CARGO_FIX_SERVER") .map_err(|_| format_err!("locking strategy misconfigured"))?; - let mut client = TcpStream::connect(&addr) - .with_context(|_| "failed to connect to parent lock server")?; - client.write_all(name.as_bytes()) + let mut client = + TcpStream::connect(&addr).with_context(|_| "failed to connect to parent lock server")?; + client + .write_all(name.as_bytes()) .and_then(|_| client.write_all(b"\n")) .with_context(|_| "failed to write to lock server")?; let mut buf = [0]; - client.read_exact(&mut buf) + client + .read_exact(&mut buf) .with_context(|_| "failed to acquire lock")?; Ok(Client { _socket: client }) } diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index b37c76841..80487608f 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -1,17 +1,17 @@ +extern crate atty; extern crate clap; +extern crate env_logger; #[macro_use] extern crate failure; -extern crate rustfix; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; #[macro_use] extern crate log; -extern crate env_logger; -extern crate atty; +extern crate rustfix; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; extern crate termcolor; -use std::collections::{HashSet, HashMap}; +use std::collections::{HashMap, HashSet}; use std::env; use std::fs::File; use std::io::{Read, Write}; @@ -91,7 +91,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { // any. If stderr is empty then there's no need for the final exec at // the end, we just bail out here. if output.status.success() && output.stderr.len() == 0 { - return Ok(()) + return Ok(()); } // Otherwise if our rustc just failed then that means that we broke the @@ -125,8 +125,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); - cmd.arg("--error-format=json") - .arg("--cap-lints=warn"); + cmd.arg("--error-format=json").arg("--cap-lints=warn"); let output = cmd.output() .with_context(|_| format!("failed to execute `{}`", rustc.display()))?; @@ -139,14 +138,17 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result // TODO: this should be configurable by the CLI to sometimes proceed to // attempt to fix broken code. if !output.status.success() && env::var_os("__CARGO_FIX_BROKEN_CODE").is_none() { - debug!("rustfixing `{:?}` failed, rustc exited with {:?}", filename, output.status.code()); - return Ok(HashMap::new()) + debug!( + "rustfixing `{:?}` failed, rustc exited with {:?}", + filename, + output.status.code() + ); + return Ok(HashMap::new()); } // Sift through the output of the compiler to look for JSON messages // indicating fixes that we can apply. - let stderr = str::from_utf8(&output.stderr) - .context("failed to parse rustc stderr as utf-8")?; + let stderr = str::from_utf8(&output.stderr).context("failed to parse rustc stderr as utf-8")?; let suggestions = stderr.lines() .filter(|x| !x.is_empty()) @@ -168,23 +170,29 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result Some(s) => (s.file_name.clone(), s.line_range), None => { trace!("rejecting as it has no snippets {:?}", suggestion); - continue + continue; } }; - if !suggestion.snippets.iter().all(|s| { - s.file_name == file_name && s.line_range == range - }) { + if !suggestion + .snippets + .iter() + .all(|s| s.file_name == file_name && s.line_range == range) + { trace!("rejecting as it spans mutliple files {:?}", suggestion); - continue + continue; } - file_map.entry(file_name) + file_map + .entry(file_name) .or_insert_with(Vec::new) .push(suggestion); num_suggestion += 1; } - debug!("collected {} suggestions for `{}`", num_suggestion, filename); + debug!( + "collected {} suggestions for `{}`", + num_suggestion, filename + ); let mut old_files = HashMap::with_capacity(file_map.len()); for (file, suggestions) in file_map { @@ -194,7 +202,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result let mut code = String::new(); if let Err(e) = File::open(&file).and_then(|mut f| f.read_to_string(&mut code)) { warn!("failed to read `{}`: {}", file, e); - continue + continue; } let num_suggestions = suggestions.len(); debug!("applying {} fixes to {}", num_suggestions, file); diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 92295e834..b15f9ff21 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -14,13 +14,11 @@ fn do_not_fix_broken_builds() { pub fn foo2() { let _x: u32 = "a"; } - "# + "#, ) .build(); - p.expect_cmd("cargo-fix fix") - .status(101) - .run(); + p.expect_cmd("cargo-fix fix").status(101).run(); assert!(p.read("src/lib.rs").contains("let mut x = 3;")); } @@ -34,13 +32,11 @@ fn fix_broken_if_requested() { pub fn bar() { foo(1); } - "# + "#, ) .build(); - p.expect_cmd("cargo-fix fix --broken-code") - .status(0) - .run(); + p.expect_cmd("cargo-fix fix --broken-code").status(0).run(); } #[test] @@ -53,7 +49,7 @@ fn broken_fixes_backed_out() { name = 'foo' version = '0.1.0' [workspace] - "# + "#, ) .file( "foo/src/main.rs", @@ -83,7 +79,7 @@ fn broken_fixes_backed_out() { .expect("failed to run rustc"); process::exit(status.code().unwrap_or(2)); } - "# + "#, ) .file( "bar/Cargo.toml", @@ -92,7 +88,7 @@ fn broken_fixes_backed_out() { name = 'bar' version = '0.1.0' [workspace] - "# + "#, ) .file("bar/build.rs", "fn main() {}") .file( @@ -102,14 +98,12 @@ fn broken_fixes_backed_out() { let mut x = 3; drop(x); } - "# + "#, ) .build(); // Build our rustc shim - p.expect_cmd("cargo build") - .cwd("foo") - .run(); + p.expect_cmd("cargo build").cwd("foo").run(); // Attempt to fix code, but our shim will always fail the second compile p.expect_cmd("cargo-fix fix") diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index 6395e5dc3..54c7ca480 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -14,30 +14,36 @@ fn fix_path_deps() { bar = { path = 'bar' } [workspace] - "# + "#, ) - .file("src/lib.rs", r#" - extern crate bar; + .file( + "src/lib.rs", + r#" + extern crate bar; - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#) + pub fn foo() -> u32 { + let mut x = 3; + x + } + "#, + ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" - "# + "#, + ) + .file( + "bar/src/lib.rs", + r#" + pub fn foo() -> u32 { + let mut x = 3; + x + } + "#, ) - .file("bar/src/lib.rs", r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#) .build(); let stderr = "\ @@ -67,7 +73,7 @@ fn do_not_fix_non_relevant_deps() { bar = { path = '../bar' } [workspace] - "# + "#, ) .file("foo/src/lib.rs", "") .file( @@ -76,19 +82,19 @@ fn do_not_fix_non_relevant_deps() { [package] name = "bar" version = "0.1.0" - "# + "#, + ) + .file( + "bar/src/lib.rs", + r#" + pub fn foo() -> u32 { + let mut x = 3; + x + } + "#, ) - .file("bar/src/lib.rs", r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#) .build(); - p.expect_cmd("cargo-fix fix") - .cwd("foo") - .status(0) - .run(); + p.expect_cmd("cargo-fix fix").cwd("foo").status(0).run(); assert!(p.read("bar/src/lib.rs").contains("mut")); } diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 7583f48ca..7f327c94b 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -26,9 +26,7 @@ struct Project { } fn project() -> ProjectBuilder { - ProjectBuilder { - files: Vec::new(), - } + ProjectBuilder { files: Vec::new() } } fn root() -> PathBuf { @@ -40,7 +38,7 @@ fn root() -> PathBuf { me.pop(); // chop off `debug` / `release` me.push("generated-tests"); me.push(&format!("test{}", idx)); - return me + return me; } impl ProjectBuilder { @@ -58,14 +56,18 @@ impl ProjectBuilder { [workspace] "#; - self.files.push(("Cargo.toml".to_string(), manifest.to_string())); + self.files + .push(("Cargo.toml".to_string(), manifest.to_string())); } let root = root(); drop(fs::remove_dir_all(&root)); for &(ref file, ref contents) in self.files.iter() { let dst = root.join(file); fs::create_dir_all(dst.parent().unwrap()).unwrap(); - fs::File::create(&dst).unwrap().write_all(contents.as_ref()).unwrap(); + fs::File::create(&dst) + .unwrap() + .write_all(contents.as_ref()) + .unwrap(); } Project { root } } @@ -93,7 +95,7 @@ impl Project { .unwrap() .read_to_string(&mut ret) .unwrap(); - return ret + return ret; } } @@ -122,7 +124,8 @@ impl<'a> ExpectCmd<'a> { } fn env, V: AsRef>(&mut self, k: K, v: V) -> &mut Self { - self.env.push((k.as_ref().to_owned(), v.as_ref().to_owned())); + self.env + .push((k.as_ref().to_owned(), v.as_ref().to_owned())); self } @@ -147,8 +150,12 @@ impl<'a> ExpectCmd<'a> { let mut cmd = Command::new(parts.next().unwrap()); cmd.args(parts); match self.cwd { - Some(ref p) => { cmd.current_dir(p); } - None => { cmd.current_dir(&self.project.root); } + Some(ref p) => { + cmd.current_dir(p); + } + None => { + cmd.current_dir(&self.project.root); + } } for &(ref k, ref v) in self.env.iter() { @@ -161,9 +168,7 @@ impl<'a> ExpectCmd<'a> { let mut new_path = Vec::new(); new_path.push(me); - new_path.extend( - env::split_paths(&env::var_os("PATH").unwrap_or(Default::default())), - ); + new_path.extend(env::split_paths(&env::var_os("PATH").unwrap_or(Default::default()))); cmd.env("PATH", env::join_paths(&new_path).unwrap()); println!("\n···················································"); @@ -174,7 +179,11 @@ impl<'a> ExpectCmd<'a> { Err(err) => panic!("failed to spawn: {}", err), }; let dur = start.elapsed(); - println!("dur: {}.{:03}ms", dur.as_secs(), dur.subsec_nanos() / 1_000_000); + println!( + "dur: {}.{:03}ms", + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); println!("exit: {}", output.status); if output.stdout.len() > 0 { println!("stdout ---\n{}", String::from_utf8_lossy(&output.stdout)); @@ -206,38 +215,37 @@ impl<'a> ExpectCmd<'a> { for s in contains { let s = self.clean(s); if actual.contains(&s) { - continue + continue; } - println!("\nfailed to find contents within output stream\n\ - expected to find\n {}\n\nwithin:\n\n{}\n\n", - s, - actual); + println!( + "\nfailed to find contents within output stream\n\ + expected to find\n {}\n\nwithin:\n\n{}\n\n", + s, actual + ); panic!("test failed"); } } fn clean(&self, s: &str) -> String { let url = Url::from_file_path(&self.project.root).unwrap(); - let s = s - .replace("[CHECKING]", " Checking") - .replace("[FINISHED]", " Finished") + let s = s.replace("[CHECKING]", " Checking") + .replace("[FINISHED]", " Finished") .replace("[COMPILING]", " Compiling") - .replace("[FIXING]", " Fixing") + .replace("[FIXING]", " Fixing") .replace(&url.to_string(), "CWD") .replace(&self.project.root.display().to_string(), "CWD") .replace("\\", "/"); - let lines = s.lines() - .map(|s| { - let i = match s.find("target(s) in") { - Some(i) => i, - None => return s.to_string(), - }; - if s.trim().starts_with("Finished") { - s[..i].to_string() - } else { - s.to_string() - } - }); + let lines = s.lines().map(|s| { + let i = match s.find("target(s) in") { + Some(i) => i, + None => return s.to_string(), + }; + if s.trim().starts_with("Finished") { + s[..i].to_string() + } else { + s.to_string() + } + }); let mut ret = String::new(); for (i, line) in lines.enumerate() { if i != 0 { diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 6085d9ffb..20ccd75a0 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -2,9 +2,7 @@ use super::project; #[test] fn no_changes_necessary() { - let p = project() - .file("src/lib.rs", "") - .build(); + let p = project().file("src/lib.rs", "").build(); let stderr = "\ [CHECKING] foo v0.1.0 (CWD) @@ -19,12 +17,15 @@ fn no_changes_necessary() { #[test] fn fixes_extra_mut() { let p = project() - .file("src/lib.rs", r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#) + .file( + "src/lib.rs", + r#" + pub fn foo() -> u32 { + let mut x = 3; + x + } + "#, + ) .build(); let stderr = "\ @@ -41,13 +42,16 @@ fn fixes_extra_mut() { #[test] fn fixes_two_missing_ampersands() { let p = project() - .file("src/lib.rs", r#" - pub fn foo() -> u32 { - let mut x = 3; - let mut y = 3; - x + y - } - "#) + .file( + "src/lib.rs", + r#" + pub fn foo() -> u32 { + let mut x = 3; + let mut y = 3; + x + y + } + "#, + ) .build(); let stderr = "\ @@ -64,12 +68,15 @@ fn fixes_two_missing_ampersands() { #[test] fn tricky() { let p = project() - .file("src/lib.rs", r#" - pub fn foo() -> u32 { - let mut x = 3; let mut y = 3; - x + y - } - "#) + .file( + "src/lib.rs", + r#" + pub fn foo() -> u32 { + let mut x = 3; let mut y = 3; + x + y + } + "#, + ) .build(); let stderr = "\ @@ -86,10 +93,13 @@ fn tricky() { #[test] fn preserve_line_endings() { let p = project() - .file("src/lib.rs", "\ - fn add(a: &u32) -> u32 { a + 1 }\r\n\ - pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ - ") + .file( + "src/lib.rs", + "\ + fn add(a: &u32) -> u32 { a + 1 }\r\n\ + pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ + ", + ) .build(); p.expect_cmd("cargo-fix fix").run(); @@ -99,10 +109,13 @@ fn preserve_line_endings() { #[test] fn fix_deny_warnings() { let p = project() - .file("src/lib.rs", "\ - #![deny(warnings)] - pub fn foo() { let mut x = 3; drop(x); } - ") + .file( + "src/lib.rs", + "\ + #![deny(warnings)] + pub fn foo() { let mut x = 3; drop(x); } + ", + ) .build(); p.expect_cmd("cargo-fix fix").run(); @@ -111,16 +124,19 @@ fn fix_deny_warnings() { #[test] fn fix_deny_warnings_but_not_others() { let p = project() - .file("src/lib.rs", " - #![deny(warnings)] + .file( + "src/lib.rs", + " + #![deny(warnings)] - pub fn foo() -> u32 { - let mut x = 3; - x - } + pub fn foo() -> u32 { + let mut x = 3; + x + } - fn bar() {} - ") + fn bar() {} + ", + ) .build(); p.expect_cmd("cargo-fix fix").run(); diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index 8a15e652f..e51bec7a3 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -3,25 +3,40 @@ use super::project; #[test] fn fixes_missing_ampersand() { let p = project() - .file("src/main.rs", r#" + .file( + "src/main.rs", + r#" fn main() { let mut x = 3; drop(x); } - "#) - .file("src/lib.rs", r#" + "#, + ) + .file( + "src/lib.rs", + r#" pub fn foo() { let mut x = 3; drop(x); } #[test] pub fn foo2() { let mut x = 3; drop(x); } - "#) - .file("tests/a.rs", r#" + "#, + ) + .file( + "tests/a.rs", + r#" #[test] pub fn foo() { let mut x = 3; drop(x); } - "#) - .file("examples/foo.rs", r#" + "#, + ) + .file( + "examples/foo.rs", + r#" fn main() { let mut x = 3; drop(x); } - "#) - .file("build.rs", r#" + "#, + ) + .file( + "build.rs", + r#" fn main() { let mut x = 3; drop(x); } - "#) + "#, + ) .build(); p.expect_cmd("cargo fix -- --all-targets") @@ -57,12 +72,15 @@ fn fix_features() { bar = [] [workspace] - "# + "#, ) - .file("src/lib.rs", r#" + .file( + "src/lib.rs", + r#" #[cfg(feature = "bar")] pub fn foo() -> u32 { let mut x = 3; x } - "#) + "#, + ) .build(); p.expect_cmd("cargo fix").run(); diff --git a/cargo-fix/tests/all/warnings.rs b/cargo-fix/tests/all/warnings.rs index 46d521b83..fa53ea881 100644 --- a/cargo-fix/tests/all/warnings.rs +++ b/cargo-fix/tests/all/warnings.rs @@ -3,13 +3,18 @@ use super::project; #[test] fn shows_warnings() { let p = project() - .file("src/lib.rs", r#" + .file( + "src/lib.rs", + r#" use std::default::Default; pub fn foo() { } - "#) + "#, + ) .build(); - p.expect_cmd("cargo fix").stderr_contains("warning: unused import").run(); + p.expect_cmd("cargo fix") + .stderr_contains("warning: unused import") + .run(); } diff --git a/src/lib.rs b/src/lib.rs index c8a7e0852..f14fbec7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ #[macro_use] -extern crate serde_derive; -extern crate serde_json; -#[macro_use] extern crate failure; #[cfg(test)] #[macro_use] extern crate proptest; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; use std::collections::HashSet; use std::ops::Range; @@ -85,13 +85,17 @@ pub struct Replacement { fn parse_snippet(span: &DiagnosticSpan) -> Snippet { // unindent the snippet - let indent = span.text.iter().map(|line| { - let indent = line.text - .chars() - .take_while(|&c| char::is_whitespace(c)) - .count(); - std::cmp::min(indent, line.highlight_start) - }).min().expect("text to replace is empty"); + let indent = span.text + .iter() + .map(|line| { + let indent = line.text + .chars() + .take_while(|&c| char::is_whitespace(c)) + .count(); + std::cmp::min(indent, line.highlight_start) + }) + .min() + .expect("text to replace is empty"); let start = span.text[0].highlight_start - 1; let end = span.text[0].highlight_end - 1; let lead = span.text[0].text[indent..start].to_string(); @@ -125,13 +129,18 @@ fn parse_snippet(span: &DiagnosticSpan) -> Snippet { } fn collect_span(span: &DiagnosticSpan) -> Option { - span.suggested_replacement.clone().map(|replacement| Replacement { - snippet: parse_snippet(span), - replacement, - }) + span.suggested_replacement + .clone() + .map(|replacement| Replacement { + snippet: parse_snippet(span), + replacement, + }) } -pub fn collect_suggestions(diagnostic: &Diagnostic, only: &HashSet) -> Option { +pub fn collect_suggestions( + diagnostic: &Diagnostic, + only: &HashSet, +) -> Option { if !only.is_empty() { if let Some(ref code) = diagnostic.code { if !only.contains(&code.code) { @@ -144,27 +153,27 @@ pub fn collect_suggestions(diagnostic: &Diagnostic, } } - let snippets = diagnostic.spans + let snippets = diagnostic + .spans .iter() .map(|span| parse_snippet(span)) .collect(); - let solutions: Vec<_> = diagnostic.children + let solutions: Vec<_> = diagnostic + .children .iter() .filter_map(|child| { - let replacements: Vec<_> = child.spans - .iter() - .filter_map(collect_span) - .collect(); - if replacements.is_empty() { - None - } else { - Some(Solution { - message: child.message.clone(), - replacements, - }) - } - }).collect(); + let replacements: Vec<_> = child.spans.iter().filter_map(collect_span).collect(); + if replacements.is_empty() { + None + } else { + Some(Solution { + message: child.message.clone(), + replacements, + }) + } + }) + .collect(); if solutions.is_empty() { None diff --git a/src/replace.rs b/src/replace.rs index 5f4773f25..fc0c8b789 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -32,11 +32,13 @@ impl Data { pub fn new(data: &[u8]) -> Self { Data { original: data.into(), - parts: vec![Span { - data: State::Initial, - start: 0, - end: data.len(), - }], + parts: vec![ + Span { + data: State::Initial, + start: 0, + end: data.len(), + }, + ], } } diff --git a/tests/everything.rs b/tests/everything.rs index d0e362f02..0d42e1a33 100644 --- a/tests/everything.rs +++ b/tests/everything.rs @@ -1,12 +1,15 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows -#[macro_use] extern crate duct; -#[macro_use] extern crate pretty_assertions; -extern crate tempdir; -#[macro_use] extern crate log; +#[macro_use] +extern crate duct; extern crate env_logger; -extern crate serde_json; +#[macro_use] +extern crate log; +#[macro_use] +extern crate pretty_assertions; extern crate rustfix; +extern crate serde_json; +extern crate tempdir; use std::fs; use std::error::Error; @@ -20,11 +23,15 @@ use rustfix::apply_suggestions; fn compile(file: &Path) -> Result> { let tmp = TempDir::new("rustfix-tests")?; let better_call_clippy = cmd!( - "rustc", file, - "--error-format=pretty-json", "-Zunstable-options", "--emit=metadata", + "rustc", + file, + "--error-format=pretty-json", + "-Zunstable-options", + "--emit=metadata", "--crate-name=rustfix_test", "-Zsuggestion-applicability", - "--out-dir", tmp.path() + "--out-dir", + tmp.path() ); let res = better_call_clippy .env("CLIPPY_DISABLE_DOCS_LINKS", "true") @@ -46,7 +53,7 @@ fn compile_and_get_json_errors(file: &Path) -> Result> { _ => Err(Box::new(Error::new( ErrorKind::Other, format!("failed with status {:?}: {}", res.status.code(), stderr), - ))) + ))), } } @@ -57,7 +64,11 @@ fn compiles_without_errors(file: &Path) -> Result<(), Box> { match res.status.code() { Some(0) => Ok(()), _ => { - info!("file {:?} failed to compile:\n{}", file, String::from_utf8(res.stderr)?); + info!( + "file {:?} failed to compile:\n{}", + file, + String::from_utf8(res.stderr)? + ); Err(Box::new(Error::new( ErrorKind::Other, format!( @@ -86,7 +97,8 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { debug!("next up: {:?}", file); let code = read_file(file)?; let errors = compile_and_get_json_errors(file)?; - let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()).expect("could not load suggestions"); + let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()) + .expect("could not load suggestions"); if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { use std::io::Write; @@ -95,10 +107,10 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } let expected_json = read_file(&json_file)?; - let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()).expect("could not load expected suggesitons"); + let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) + .expect("could not load expected suggesitons"); assert_eq!( - expected_suggestions, - suggestions, + expected_suggestions, suggestions, "got unexpected suggestions from clippy", ); @@ -111,7 +123,12 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { } let expected_fixed = read_file(&fixed_file)?; - assert_eq!(fixed.trim(), expected_fixed.trim(), "file {} doesn't look fixed", file.display()); + assert_eq!( + fixed.trim(), + expected_fixed.trim(), + "file {} doesn't look fixed", + file.display() + ); compiles_without_errors(&fixed_file)?; From a1ea6d75920ddfb1db0c7c086ef8167642202346 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 15:21:26 -0700 Subject: [PATCH 152/298] Fix a typo when reporting what's fixed --- cargo-fix/src/main.rs | 2 +- cargo-fix/tests/all/smoke.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 80487608f..dbc9d2482 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -207,7 +207,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result let num_suggestions = suggestions.len(); debug!("applying {} fixes to {}", num_suggestions, file); - diagnostics::Message::fixing(&file, num_suggestion).post()?; + diagnostics::Message::fixing(&file, num_suggestions).post()?; let new_code = rustfix::apply_suggestions(&code, &suggestions)?; File::create(&file) diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 20ccd75a0..d71379841 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -143,3 +143,36 @@ fn fix_deny_warnings_but_not_others() { assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); assert!(p.read("src/lib.rs").contains("fn bar() {}")); } + +#[test] +fn fix_two_files() { + let p = project() + .file( + "src/lib.rs", + " + pub mod bar; + + pub fn foo() -> u32 { + let mut x = 3; + x + } + ", + ) + .file( + "src/bar.rs", + " + pub fn foo() -> u32 { + let mut x = 3; + x + } + ", + ) + .build(); + + p.expect_cmd("cargo-fix fix") + .stderr_contains("[FIXING] src/bar.rs (1 fix)") + .stderr_contains("[FIXING] src/lib.rs (1 fix)") + .run(); + assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); + assert!(!p.read("src/bar.rs").contains("let mut x = 3;")); +} From 6fa957e8c8790f3c21bdb1b41272a234a9b9a0cd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 15:22:54 -0700 Subject: [PATCH 153/298] Switch "fixing" messages to Cyan This is hopefully a little easier to see in contrast to the normal green "Compiling", and it stood out a bit more for me locally --- cargo-fix/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 9ef18f915..fbbdfe603 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -107,7 +107,7 @@ fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> { let mut stream = StandardStream::stderr(color_choice); stream.reset()?; - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)))?; + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?; // Justify to 12 chars just like cargo write!(&mut stream, "{:>12}", kind)?; stream.reset()?; From b2ddfeb201899169dd5bde9d68d2eaf58fe4203a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 15:40:13 -0700 Subject: [PATCH 154/298] Don't print "Fixing" if fixes are reverted This commit alters the printing of `Fixing` to not happen if we end up reverting the fixes that we applied. Instead the message of `Fixing` is delayed until *after* we've run through the compiler and know that we've fixed the code. This also updates the `Message::post` method to block until the diagnostic has finished writing, which fixes a race that was coming up in the test suite. --- cargo-fix/src/diagnostics.rs | 14 ++++++++--- cargo-fix/src/main.rs | 38 +++++++++++++++++++++-------- cargo-fix/tests/all/broken_build.rs | 1 + cargo-fix/tests/all/main.rs | 32 +++++++++++++++++++++--- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index 36a3d61f5..39b3217ea 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -2,8 +2,8 @@ //! cross-platform way. use std::env; -use std::io::BufReader; -use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::io::{BufReader, Write, Read}; +use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; use std::thread::{self, JoinHandle}; use failure::{Error, ResultExt}; @@ -29,8 +29,16 @@ impl Message { let mut client = TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?; - serde_json::to_writer(&mut client, &self) + let s = serde_json::to_string(self) + .context("failed to serialize message")?; + client.write_all(s.as_bytes()) .context("failed to write message to diagnostics target")?; + client.shutdown(Shutdown::Write) + .context("failed to shutdown")?; + + let mut tmp = Vec::new(); + client.read_to_end(&mut tmp) + .context("failed to receive a disconnect")?; Ok(()) } diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 80487608f..a7acf4313 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -22,6 +22,8 @@ use std::path::Path; use rustfix::diagnostics::Diagnostic; use failure::{Error, ResultExt}; +use diagnostics::Message; + mod cli; mod lock; mod diagnostics; @@ -65,11 +67,11 @@ fn cargo_fix_rustc() -> Result<(), Error> { // To that end we only actually try to fix things if it looks like we're // compiling a Rust file and it *doesn't* have an absolute filename. That's // not the best heuristic but matches what Cargo does today at least. - let mut files_to_restore = HashMap::new(); + let mut fixes = FixedCrate::default(); if let Some(path) = filename { if !Path::new(&path).is_absolute() { trace!("start rustfixing {:?}", path); - files_to_restore = rustfix_crate(rustc.as_ref(), &path)?; + fixes = rustfix_crate(rustc.as_ref(), &path)?; } } @@ -84,9 +86,15 @@ fn cargo_fix_rustc() -> Result<(), Error> { let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); cmd.arg("--cap-lints=warn"); - if files_to_restore.len() > 0 { + if fixes.original_files.len() > 0 { let output = cmd.output().context("failed to spawn rustc")?; + if output.status.success() { + for message in fixes.messages.drain(..) { + message.post()?; + } + } + // If we succeeded then we'll want to commit to the changes we made, if // any. If stderr is empty then there's no need for the final exec at // the end, we just bail out here. @@ -98,7 +106,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { // user's code with our changes. Back out everything and fall through // below to recompile again. if !output.status.success() { - for (k, v) in files_to_restore { + for (k, v) in fixes.original_files { File::create(&k) .and_then(|mut f| f.write_all(v.as_bytes())) .with_context(|_| format!("failed to write file `{}`", k))?; @@ -109,7 +117,13 @@ fn cargo_fix_rustc() -> Result<(), Error> { exit_with(cmd.status().context("failed to spawn rustc")?); } -fn rustfix_crate(rustc: &Path, filename: &str) -> Result, Error> { +#[derive(Default)] +struct FixedCrate { + messages: Vec, + original_files: HashMap, +} + +fn rustfix_crate(rustc: &Path, filename: &str) -> Result { // If not empty, filter by these lints // // TODO: Implement a way to specify this @@ -143,7 +157,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result filename, output.status.code() ); - return Ok(HashMap::new()); + return Ok(Default::default()) } // Sift through the output of the compiler to look for JSON messages @@ -194,7 +208,8 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result num_suggestion, filename ); - let mut old_files = HashMap::with_capacity(file_map.len()); + let mut original_files = HashMap::with_capacity(file_map.len()); + let mut messages = Vec::new(); for (file, suggestions) in file_map { // Attempt to read the source code for this file. If this fails then // that'd be pretty surprising, so log a message and otherwise keep @@ -207,16 +222,19 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result let num_suggestions = suggestions.len(); debug!("applying {} fixes to {}", num_suggestions, file); - diagnostics::Message::fixing(&file, num_suggestion).post()?; + messages.push(Message::fixing(&file, num_suggestions)); let new_code = rustfix::apply_suggestions(&code, &suggestions)?; File::create(&file) .and_then(|mut f| f.write_all(new_code.as_bytes())) .with_context(|_| format!("failed to write file `{}`", file))?; - old_files.insert(file, code); + original_files.insert(file, code); } - Ok(old_files) + Ok(FixedCrate { + messages, + original_files, + }) } fn exit_with(status: ExitStatus) -> ! { diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index b15f9ff21..d8376de3b 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -110,6 +110,7 @@ fn broken_fixes_backed_out() { .cwd("bar") .env("RUSTC", p.root.join("foo/target/debug/foo")) .stderr_contains("oh no") + .stderr_not_contains("[FIXING]") .status(101) .run(); diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 7f327c94b..06028fbfd 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -83,6 +83,7 @@ impl Project { stdout_contains: Vec::new(), stderr: None, stderr_contains: Vec::new(), + stderr_not_contains: Vec::new(), status: 0, ran: false, cwd: None, @@ -108,6 +109,7 @@ struct ExpectCmd<'a> { stdout_contains: Vec, stderr: Option, stderr_contains: Vec, + stderr_not_contains: Vec, status: i32, cwd: Option, } @@ -144,6 +146,11 @@ impl<'a> ExpectCmd<'a> { self } + fn stderr_not_contains(&mut self, s: &str) -> &mut Self { + self.stderr_not_contains.push(s.to_string()); + self + } + fn run(&mut self) { self.ran = true; let mut parts = self.cmd.split_whitespace(); @@ -199,11 +206,22 @@ impl<'a> ExpectCmd<'a> { if code != self.status { panic!("expected exit code `{}` got `{}`", self.status, code); } - self.match_std(&output.stdout, &self.stdout, &self.stdout_contains); - self.match_std(&output.stderr, &self.stderr, &self.stderr_contains); + self.match_std(&output.stdout, &self.stdout, &self.stdout_contains, &[]); + self.match_std( + &output.stderr, + &self.stderr, + &self.stderr_contains, + &self.stderr_not_contains, + ); } - fn match_std(&self, actual: &[u8], expected: &Option, contains: &[String]) { + fn match_std( + &self, + actual: &[u8], + expected: &Option, + contains: &[String], + not_contains: &[String], + ) { let actual = match str::from_utf8(actual) { Ok(s) => s, Err(_) => panic!("std wasn't utf8"), @@ -224,6 +242,14 @@ impl<'a> ExpectCmd<'a> { ); panic!("test failed"); } + for s in not_contains { + let s = self.clean(s); + if !actual.contains(&s) { + continue; + } + println!("expected to not find `{}`", s); + panic!("test failed"); + } } fn clean(&self, s: &str) -> String { From 5de95a9ed8276a248b72bc15c7b82ecdfeea4eba Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 21:01:47 -0700 Subject: [PATCH 155/298] Fix compile on stable --- cargo-fix/src/cli.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index fbbdfe603..d76e10ce7 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -77,8 +77,8 @@ pub fn run() -> Result<(), Error> { fn log_message(msg: &diagnostics::Message) -> Result<(), Error> { use diagnostics::Message::*; - match msg { - Fixing { file, fixes } => { + match *msg { + Fixing { ref file, ref fixes } => { log_for_human( "Fixing", &format!( From 59b3617c0f06609930cca3a1e7f645f0ded71bbe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 5 May 2018 21:37:04 -0700 Subject: [PATCH 156/298] Warn users when fixes break code The rustfix tool detects it, so let's inform the user what just happened! Closes #88 --- cargo-fix/src/cli.rs | 78 ++++++++++++++++++++--------- cargo-fix/src/diagnostics.rs | 22 +++++--- cargo-fix/src/main.rs | 40 ++++++++++++++- cargo-fix/tests/all/broken_build.rs | 37 ++++++++++---- 4 files changed, 137 insertions(+), 40 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index d76e10ce7..41f9f195c 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -1,12 +1,13 @@ use std::env; use std::process::Command; +use std::io::Write; -use failure::{Error, ResultExt}; use clap::{App, AppSettings, Arg, SubCommand}; -use atty; +use failure::{Error, ResultExt}; +use termcolor::{Color, ColorSpec, StandardStream, WriteColor}; use lock; -use diagnostics; +use diagnostics::{Message, Server}; use super::exit_with; pub fn run() -> Result<(), Error> { @@ -41,8 +42,10 @@ pub fn run() -> Result<(), Error> { // Spin up our diagnostics server which our subprocesses will use to send // use their dignostics messages in an ordered way. - let _lockserver = diagnostics::Server::new()?.start(|m| { - let _ = log_message(&m); + let _lockserver = Server::new()?.start(|m, stream| { + if let Err(e) = log_message(&m, stream) { + warn!("failed to log message: {}", e); + } })?; let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); @@ -74,7 +77,7 @@ pub fn run() -> Result<(), Error> { exit_with(status); } -fn log_message(msg: &diagnostics::Message) -> Result<(), Error> { +fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> { use diagnostics::Message::*; match *msg { @@ -87,33 +90,60 @@ fn log_message(msg: &diagnostics::Message) -> Result<(), Error> { n = fixes, fixes = if *fixes > 1 { "fixes" } else { "fix" }, ), + stream, + )?; + } + FixFailed { ref files, ref krate } => { + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; + write!(stream, "warning")?; + stream.reset()?; + stream.set_color(ColorSpec::new().set_bold(true))?; + write!(stream, ": ")?; + if let Some(ref krate) = *krate { + write!( + stream, + "failed to automatically apply fixes suggested by rustc \ + to crate `{}`\n", + krate, + )?; + } else { + write!(stream, "failed to automatically apply fixes suggested by rustc\n")?; + } + if files.len() > 0 { + write!( + stream, + "\nafter fixes were automatically applied the compiler \ + reported errors within these files:\n\n" + )?; + for file in files { + write!(stream, " * {}\n", file)?; + } + write!(stream, "\n")?; + + } + write!( + stream, + "This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could gist the full output\n\ + of this command to https://github.com/rust-lang-nursery/rustfix/issues\n\ + we'd be very appreciative!\n\n\ + " )?; } } + stream.reset()?; + stream.flush()?; Ok(()) } -fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> { - use std::io::Write; - use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - - // Adapted from cargo, cf. - let color_choice = if atty::is(atty::Stream::Stderr) { - ColorChoice::Auto - } else { - ColorChoice::Never - }; - let mut stream = StandardStream::stderr(color_choice); - stream.reset()?; - +fn log_for_human(kind: &str, msg: &str, stream: &mut StandardStream) -> Result<(), Error> { stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?; // Justify to 12 chars just like cargo - write!(&mut stream, "{:>12}", kind)?; + write!(stream, "{:>12}", kind)?; stream.reset()?; - - write!(&mut stream, " {}\n", msg)?; - stream.flush()?; - + write!(stream, " {}\n", msg)?; Ok(()) } diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index 39b3217ea..3a9504980 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -6,14 +6,17 @@ use std::io::{BufReader, Write, Read}; use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; use std::thread::{self, JoinHandle}; +use atty; use failure::{Error, ResultExt}; use serde_json; +use termcolor::{ColorChoice, StandardStream}; static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; #[derive(Deserialize, Serialize)] pub enum Message { Fixing { file: String, fixes: usize }, + FixFailed { files: Vec, krate: Option }, } impl Message { @@ -62,10 +65,9 @@ impl Server { Ok(Server { listener }) } - pub fn start( - self, - on_message: F, - ) -> Result { + pub fn start(self, on_message: F) -> Result + where F: Fn(Message, &mut StandardStream) + Send + 'static, + { let _addr = self.listener.local_addr()?; let thread = thread::spawn(move || { self.run(on_message); @@ -77,11 +79,19 @@ impl Server { }) } - fn run(self, on_message: F) { + fn run(self, on_message: F) + where F: Fn(Message, &mut StandardStream) + { + let color_choice = if atty::is(atty::Stream::Stderr) { + ColorChoice::Auto + } else { + ColorChoice::Never + }; + let mut stream = StandardStream::stderr(color_choice); while let Ok((client, _)) = self.listener.accept() { let mut client = BufReader::new(client); match serde_json::from_reader(client) { - Ok(message) => on_message(message), + Ok(message) => on_message(message, &mut stream), Err(e) => { warn!("invalid diagnostics message: {}", e); } diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index a7acf4313..0a649c45d 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -11,7 +11,7 @@ extern crate serde_derive; extern crate serde_json; extern crate termcolor; -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, HashSet, BTreeSet}; use std::env; use std::fs::File; use std::io::{Read, Write}; @@ -86,6 +86,7 @@ fn cargo_fix_rustc() -> Result<(), Error> { let mut cmd = Command::new(&rustc); cmd.args(env::args().skip(1)); cmd.arg("--cap-lints=warn"); + cmd.arg("--error-format=json"); if fixes.original_files.len() > 0 { let output = cmd.output().context("failed to spawn rustc")?; @@ -111,9 +112,13 @@ fn cargo_fix_rustc() -> Result<(), Error> { .and_then(|mut f| f.write_all(v.as_bytes())) .with_context(|_| format!("failed to write file `{}`", k))?; } + log_failed_fix(&output.stderr)?; } } + let mut cmd = Command::new(&rustc); + cmd.args(env::args().skip(1)); + cmd.arg("--cap-lints=warn"); exit_with(cmd.status().context("failed to spawn rustc")?); } @@ -248,3 +253,36 @@ fn exit_with(status: ExitStatus) -> ! { } process::exit(status.code().unwrap_or(3)); } + +fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> { + let stderr = str::from_utf8(stderr) + .context("failed to parse rustc stderr as utf-8")?; + + let diagnostics = stderr.lines() + .filter(|x| !x.is_empty()) + .filter_map(|line| serde_json::from_str::(line).ok()); + let mut files = BTreeSet::new(); + for diagnostic in diagnostics { + for span in diagnostic.spans.into_iter() { + files.insert(span.file_name); + } + } + let mut krate = None; + let mut prev_dash_dash_krate_name = false; + for arg in env::args() { + if prev_dash_dash_krate_name { + krate = Some(arg.clone()); + } + + if arg == "--crate-name" { + prev_dash_dash_krate_name = true; + } else { + prev_dash_dash_krate_name = false; + } + } + + let files = files.into_iter().collect(); + Message::FixFailed { files, krate }.post()?; + + Ok(()) +} diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index d8376de3b..4583fc207 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -53,11 +53,12 @@ fn broken_fixes_backed_out() { ) .file( "foo/src/main.rs", - r#" + r##" use std::env; - use std::process::{self, Command}; - use std::path::{Path, PathBuf}; use std::fs; + use std::io::Write; + use std::path::{Path, PathBuf}; + use std::process::{self, Command}; fn main() { let is_lib_rs = env::args_os() @@ -67,7 +68,10 @@ fn broken_fixes_backed_out() { let path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let path = path.join("foo"); if path.exists() { - panic!("failing the second compilation, oh no!"); + fs::File::create("src/lib.rs") + .unwrap() + .write_all(b"not rust code") + .unwrap(); } else { fs::File::create(&path).unwrap(); } @@ -79,7 +83,7 @@ fn broken_fixes_backed_out() { .expect("failed to run rustc"); process::exit(status.code().unwrap_or(2)); } - "#, + "##, ) .file( "bar/Cargo.toml", @@ -109,11 +113,26 @@ fn broken_fixes_backed_out() { p.expect_cmd("cargo-fix fix") .cwd("bar") .env("RUSTC", p.root.join("foo/target/debug/foo")) - .stderr_contains("oh no") + .stderr_contains("not rust code") + .stderr_contains( + "\ + warning: failed to automatically apply fixes suggested by rustc \ + to crate `bar`\n\ + \n\ + after fixes were automatically applied the compiler reported \ + errors within these files:\n\ + \n \ + * src/lib.rs\n\ + \n\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could gist the full output\n\ + of this command to https://github.com/rust-lang-nursery/rustfix/issues\n\ + we'd be very appreciative!\ + " + ) .stderr_not_contains("[FIXING]") .status(101) .run(); - - // Make sure the fix which should have been applied was backed out - assert!(p.read("bar/src/lib.rs").contains("let mut x = 3;")); } From 8f4465899bed3bc8811d0017955bd19a0800d822 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 18:49:38 +0200 Subject: [PATCH 157/298] Adjust wording when asking for bug report This omits the reference to gist (which may confuse people not familiar with gist.github.com), and moves the link to our issue tracker to its own line, which makes copying easier (for those whose terminals don't have a "ctrl+click to open link" feature). --- cargo-fix/src/cli.rs | 20 ++++++++++---------- cargo-fix/tests/all/broken_build.rs | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 41f9f195c..2254279ea 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -10,6 +10,15 @@ use lock; use diagnostics::{Message, Server}; use super::exit_with; +static PLEASE_REPORT_THIS_BUG: &str = "\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ +"; + pub fn run() -> Result<(), Error> { let matches = App::new("Cargo Fix") .bin_name("cargo") @@ -121,16 +130,7 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> write!(stream, "\n")?; } - write!( - stream, - "This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could gist the full output\n\ - of this command to https://github.com/rust-lang-nursery/rustfix/issues\n\ - we'd be very appreciative!\n\n\ - " - )?; + stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; } } diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 4583fc207..ca8f09f09 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -127,9 +127,9 @@ fn broken_fixes_backed_out() { This likely indicates a bug in either rustc or rustfix itself,\n\ and we would appreciate a bug report! You're likely to see \n\ a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could gist the full output\n\ - of this command to https://github.com/rust-lang-nursery/rustfix/issues\n\ - we'd be very appreciative!\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ " ) .stderr_not_contains("[FIXING]") From e160ba5712692839876c58c4a6408d44d503f822 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 18:53:45 +0200 Subject: [PATCH 158/298] Add more debug logging to rustfix --- Cargo.toml | 1 + src/lib.rs | 2 ++ src/replace.rs | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 70a654650..964d006d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" failure = "0.1.1" +log = "0.4.1" [dev-dependencies] duct = "0.8.2" diff --git a/src/lib.rs b/src/lib.rs index f14fbec7b..d514a7615 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #[macro_use] +extern crate log; +#[macro_use] extern crate failure; #[cfg(test)] #[macro_use] diff --git a/src/replace.rs b/src/replace.rs index fc0c8b789..a95cf4719 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -89,8 +89,23 @@ impl Data { .iter() .position(|p| p.start <= from && p.end >= up_to_and_including) .ok_or_else(|| { + use log::Level::Debug; + if log_enabled!(Debug) { + let slices = self.parts + .iter() + .map(|p| (p.start, p.end, match p.data { + State::Initial => "initial", + State::Replaced(..) => "replaced", + })) + .collect::>(); + debug!("no single slice covering {}...{}, current slices: {:?}", + from, up_to_and_including, slices, + ); + } + format_err!( - "Could not find data slice that covers range {}..{}", + "Could not replace range {}...{} in file \ + -- maybe parts of it were already replaced?", from, up_to_and_including ) From 040686fe8d561d6efb9c86aec80abbddd1380bc6 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 18:56:03 +0200 Subject: [PATCH 159/298] Custom warning when rustfix replacing fails When rustfix fails to replace a chunk of code, we now display a similar warning than when we "fixed" the code so that it no longer compiles. Previously, when rustfix fails to apply suggestions to a file, we bailed out of the whole loop over all the files in the current target. Instead, we'll now log a nice error message. (I'm not sure if that is a good idea but we will revert non-compiling changes later on anyway.) --- cargo-fix/src/cli.rs | 10 +++++++++ cargo-fix/src/diagnostics.rs | 1 + cargo-fix/src/main.rs | 18 ++++++++++----- cargo-fix/tests/all/broken_lints.rs | 35 +++++++++++++++++++++++++++++ cargo-fix/tests/all/main.rs | 1 + 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 cargo-fix/tests/all/broken_lints.rs diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 2254279ea..b8dbbc7ed 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -102,6 +102,16 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> stream, )?; } + ReplaceFailed { ref file, ref message } => { + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; + write!(stream, "warning")?; + stream.reset()?; + stream.set_color(ColorSpec::new().set_bold(true))?; + write!(stream, ": error applying suggestions to `{}`\n", file)?; + stream.reset()?; + write!(stream, "The full error message was:\n\n> {}\n\n", message)?; + stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; + } FixFailed { ref files, ref krate } => { stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; write!(stream, "warning")?; diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index 3a9504980..b6ea61ce4 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -17,6 +17,7 @@ static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; pub enum Message { Fixing { file: String, fixes: usize }, FixFailed { files: Vec, krate: Option }, + ReplaceFailed { file: String, message: String }, } impl Message { diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 0a649c45d..c54bd3761 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -229,11 +229,19 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { messages.push(Message::fixing(&file, num_suggestions)); - let new_code = rustfix::apply_suggestions(&code, &suggestions)?; - File::create(&file) - .and_then(|mut f| f.write_all(new_code.as_bytes())) - .with_context(|_| format!("failed to write file `{}`", file))?; - original_files.insert(file, code); + match rustfix::apply_suggestions(&code, &suggestions) { + Err(e) => { + diagnostics::Message::ReplaceFailed { file: file, message: e.to_string() }.post()?; + // TODO: Add flag to decide if we want to continue or bail out + continue; + } + Ok(new_code) => { + File::create(&file) + .and_then(|mut f| f.write_all(new_code.as_bytes())) + .with_context(|_| format!("failed to write file `{}`", file))?; + original_files.insert(file, code); + } + } } Ok(FixedCrate { diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs new file mode 100644 index 000000000..046aeeed2 --- /dev/null +++ b/cargo-fix/tests/all/broken_lints.rs @@ -0,0 +1,35 @@ +//! Ensure we give good error message when rustfix failes to apply changes +//! +//! TODO: Add rustc shim that outputs wrong suggestions instead of depending on +//! actual rustc bugs! + +use super::project; + +#[test] +fn tell_user_about_broken_lints() { + let p = project() + .file( + "src/lib.rs", + r#" + pub fn foo() { + let mut i = 42; + } + "#, + ) + .build(); + + p.expect_cmd("cargo-fix fix") + .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") + .stderr_contains("The full error message was:") + .stderr_contains("> Could not replace range 56...60 in file -- maybe parts of it were already replaced?") + .stderr_contains("\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ + ") + .status(0) + .run(); +} diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 06028fbfd..62f03dab3 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -316,6 +316,7 @@ fn diff(expected: &str, actual: &str) { } mod broken_build; +mod broken_lints; mod dependencies; mod smoke; mod subtargets; From 3f3905ed0d308f0a3d9d8d67177644773bf58903 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 17:56:51 +0200 Subject: [PATCH 160/298] Refactor rustfix tests a bit To allow us to add more fixture tests modes soon. --- tests/{fixtures => everything}/.gitignore | 0 tests/{fixtures => everything}/E0178.fixed.rs | 0 tests/{fixtures => everything}/E0178.json | 6 +++--- tests/{fixtures => everything}/E0178.rs | 0 .../closure-immutable-outer-variable.fixed.rs | 0 .../closure-immutable-outer-variable.json | 6 +++--- .../closure-immutable-outer-variable.rs | 0 .../lt-generic-comp.fixed.rs | 0 .../lt-generic-comp.json | 8 +++---- .../lt-generic-comp.rs | 0 .../str-lit-type-mismatch.fixed.rs | 0 .../str-lit-type-mismatch.json | 18 ++++++++-------- .../str-lit-type-mismatch.rs | 0 tests/{everything.rs => parse_and_replace.rs} | 21 ++++++++++++------- 14 files changed, 32 insertions(+), 27 deletions(-) rename tests/{fixtures => everything}/.gitignore (100%) rename tests/{fixtures => everything}/E0178.fixed.rs (100%) rename tests/{fixtures => everything}/E0178.json (84%) rename tests/{fixtures => everything}/E0178.rs (100%) rename tests/{fixtures => everything}/closure-immutable-outer-variable.fixed.rs (100%) rename tests/{fixtures => everything}/closure-immutable-outer-variable.json (73%) rename tests/{fixtures => everything}/closure-immutable-outer-variable.rs (100%) rename tests/{fixtures => everything}/lt-generic-comp.fixed.rs (100%) rename tests/{fixtures => everything}/lt-generic-comp.json (79%) rename tests/{fixtures => everything}/lt-generic-comp.rs (100%) rename tests/{fixtures => everything}/str-lit-type-mismatch.fixed.rs (100%) rename tests/{fixtures => everything}/str-lit-type-mismatch.json (76%) rename tests/{fixtures => everything}/str-lit-type-mismatch.rs (100%) rename tests/{everything.rs => parse_and_replace.rs} (92%) diff --git a/tests/fixtures/.gitignore b/tests/everything/.gitignore similarity index 100% rename from tests/fixtures/.gitignore rename to tests/everything/.gitignore diff --git a/tests/fixtures/E0178.fixed.rs b/tests/everything/E0178.fixed.rs similarity index 100% rename from tests/fixtures/E0178.fixed.rs rename to tests/everything/E0178.fixed.rs diff --git a/tests/fixtures/E0178.json b/tests/everything/E0178.json similarity index 84% rename from tests/fixtures/E0178.json rename to tests/everything/E0178.json index 52ac88c2b..89f15b528 100644 --- a/tests/fixtures/E0178.json +++ b/tests/everything/E0178.json @@ -7,7 +7,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/E0178.rs", + "file_name": "./tests/everything/E0178.rs", "byte_start": 60, "byte_end": 74, "line_start": 6, @@ -34,7 +34,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/E0178.rs", + "file_name": "./tests/everything/E0178.rs", "byte_start": 60, "byte_end": 74, "line_start": 6, @@ -58,7 +58,7 @@ "rendered": null } ], - "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:6:8\n |\n6 | w: &'a Foo + Send,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Send)`\n\nIf you want more information on this error, try using \"rustc --explain E0178\"\n" + "rendered": "error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/everything/E0178.rs:6:8\n |\n6 | w: &'a Foo + Send,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Send)`\n\nIf you want more information on this error, try using \"rustc --explain E0178\"\n" } { "message": "aborting due to previous error", diff --git a/tests/fixtures/E0178.rs b/tests/everything/E0178.rs similarity index 100% rename from tests/fixtures/E0178.rs rename to tests/everything/E0178.rs diff --git a/tests/fixtures/closure-immutable-outer-variable.fixed.rs b/tests/everything/closure-immutable-outer-variable.fixed.rs similarity index 100% rename from tests/fixtures/closure-immutable-outer-variable.fixed.rs rename to tests/everything/closure-immutable-outer-variable.fixed.rs diff --git a/tests/fixtures/closure-immutable-outer-variable.json b/tests/everything/closure-immutable-outer-variable.json similarity index 73% rename from tests/fixtures/closure-immutable-outer-variable.json rename to tests/everything/closure-immutable-outer-variable.json index 3ecfb413d..f7afa491d 100644 --- a/tests/fixtures/closure-immutable-outer-variable.json +++ b/tests/everything/closure-immutable-outer-variable.json @@ -7,7 +7,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/closure-immutable-outer-variable.rs", + "file_name": "./tests/everything/closure-immutable-outer-variable.rs", "byte_start": 615, "byte_end": 624, "line_start": 19, @@ -34,7 +34,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/closure-immutable-outer-variable.rs", + "file_name": "./tests/everything/closure-immutable-outer-variable.rs", "byte_start": 580, "byte_end": 581, "line_start": 18, @@ -58,7 +58,7 @@ "rendered": null } ], - "rendered": "error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\nIf you want more information on this error, try using \"rustc --explain E0594\"\n" + "rendered": "error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/everything/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\nIf you want more information on this error, try using \"rustc --explain E0594\"\n" } { "message": "aborting due to previous error", diff --git a/tests/fixtures/closure-immutable-outer-variable.rs b/tests/everything/closure-immutable-outer-variable.rs similarity index 100% rename from tests/fixtures/closure-immutable-outer-variable.rs rename to tests/everything/closure-immutable-outer-variable.rs diff --git a/tests/fixtures/lt-generic-comp.fixed.rs b/tests/everything/lt-generic-comp.fixed.rs similarity index 100% rename from tests/fixtures/lt-generic-comp.fixed.rs rename to tests/everything/lt-generic-comp.fixed.rs diff --git a/tests/fixtures/lt-generic-comp.json b/tests/everything/lt-generic-comp.json similarity index 79% rename from tests/fixtures/lt-generic-comp.json rename to tests/everything/lt-generic-comp.json index 4230585dd..0634762e3 100644 --- a/tests/fixtures/lt-generic-comp.json +++ b/tests/everything/lt-generic-comp.json @@ -4,7 +4,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/lt-generic-comp.rs", + "file_name": "./tests/everything/lt-generic-comp.rs", "byte_start": 49, "byte_end": 50, "line_start": 4, @@ -24,7 +24,7 @@ "expansion": null }, { - "file_name": "./tests/fixtures/lt-generic-comp.rs", + "file_name": "./tests/everything/lt-generic-comp.rs", "byte_start": 47, "byte_end": 48, "line_start": 4, @@ -51,7 +51,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/lt-generic-comp.rs", + "file_name": "./tests/everything/lt-generic-comp.rs", "byte_start": 38, "byte_end": 46, "line_start": 4, @@ -75,7 +75,7 @@ "rendered": null } ], - "rendered": "error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison\n --> ./tests/fixtures/lt-generic-comp.rs:4:17\n |\n4 | if x as u32 < 4 {\n | -------- ^ - interpreted as generic arguments\n | | |\n | | not interpreted as comparison\n | help: try comparing the cast value: `(x as u32)`\n\n" + "rendered": "error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison\n --> ./tests/everything/lt-generic-comp.rs:4:17\n |\n4 | if x as u32 < 4 {\n | -------- ^ - interpreted as generic arguments\n | | |\n | | not interpreted as comparison\n | help: try comparing the cast value: `(x as u32)`\n\n" } { "message": "aborting due to previous error", diff --git a/tests/fixtures/lt-generic-comp.rs b/tests/everything/lt-generic-comp.rs similarity index 100% rename from tests/fixtures/lt-generic-comp.rs rename to tests/everything/lt-generic-comp.rs diff --git a/tests/fixtures/str-lit-type-mismatch.fixed.rs b/tests/everything/str-lit-type-mismatch.fixed.rs similarity index 100% rename from tests/fixtures/str-lit-type-mismatch.fixed.rs rename to tests/everything/str-lit-type-mismatch.fixed.rs diff --git a/tests/fixtures/str-lit-type-mismatch.json b/tests/everything/str-lit-type-mismatch.json similarity index 76% rename from tests/fixtures/str-lit-type-mismatch.json rename to tests/everything/str-lit-type-mismatch.json index 0e3e7643c..1c852513a 100644 --- a/tests/fixtures/str-lit-type-mismatch.json +++ b/tests/everything/str-lit-type-mismatch.json @@ -7,7 +7,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 499, "byte_end": 504, "line_start": 13, @@ -42,7 +42,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 499, "byte_end": 504, "line_start": 13, @@ -66,7 +66,7 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/everything/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" } { "message": "mismatched types", @@ -77,7 +77,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 555, "byte_end": 561, "line_start": 14, @@ -112,7 +112,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 555, "byte_end": 561, "line_start": 14, @@ -136,7 +136,7 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/everything/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" } { "message": "mismatched types", @@ -147,7 +147,7 @@ "level": "error", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 608, "byte_end": 614, "line_start": 15, @@ -182,7 +182,7 @@ "level": "help", "spans": [ { - "file_name": "./tests/fixtures/str-lit-type-mismatch.rs", + "file_name": "./tests/everything/str-lit-type-mismatch.rs", "byte_start": 608, "byte_end": 614, "line_start": 15, @@ -206,7 +206,7 @@ "rendered": null } ], - "rendered": "error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" + "rendered": "error[E0308]: mismatched types\n --> ./tests/everything/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\nIf you want more information on this error, try using \"rustc --explain E0308\"\n" } { "message": "aborting due to 3 previous errors", diff --git a/tests/fixtures/str-lit-type-mismatch.rs b/tests/everything/str-lit-type-mismatch.rs similarity index 100% rename from tests/fixtures/str-lit-type-mismatch.rs rename to tests/everything/str-lit-type-mismatch.rs diff --git a/tests/everything.rs b/tests/parse_and_replace.rs similarity index 92% rename from tests/everything.rs rename to tests/parse_and_replace.rs index 0d42e1a33..ec3e29973 100644 --- a/tests/everything.rs +++ b/tests/parse_and_replace.rs @@ -11,7 +11,7 @@ extern crate rustfix; extern crate serde_json; extern crate tempdir; -use std::fs; +use std::{env, fs}; use std::error::Error; use std::path::{Path, PathBuf}; use std::collections::HashSet; @@ -135,8 +135,8 @@ fn test_rustfix_with_file>(file: P) -> Result<(), Box> { Ok(()) } -fn get_fixture_files() -> Result, Box> { - Ok(fs::read_dir("./tests/fixtures")? +fn get_fixture_files(p: &str) -> Result, Box> { + Ok(fs::read_dir(&p)? .into_iter() .map(|e| e.unwrap().path()) .filter(|p| p.is_file()) @@ -147,12 +147,17 @@ fn get_fixture_files() -> Result, Box> { .collect()) } -#[test] -fn fixtures() { - let _ = env_logger::try_init(); - - for file in &get_fixture_files().unwrap() { +fn assert_fixtures(dir: &str, mode: &str) { + for file in &get_fixture_files(&dir).unwrap() { + env::set_var("RUSTFIX_MODE", mode); test_rustfix_with_file(file).unwrap(); + env::remove_var("RUSTFIX_MODE") info!("passed: {:?}", file); } } + +#[test] +fn everything() { + let _ = env_logger::try_init(); + assert_fixtures("./tests/everything", "yolo"); +} From e3d5d6ded619b9ca33cd711fc37a44e44e76ba6f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 17:57:06 +0200 Subject: [PATCH 161/298] Rustfix edition testing setup Also refactors the test setup to finally run as many tests as possible and give useful errors. --- Cargo.toml | 2 +- tests/parse_and_replace.rs | 201 +++++++++++++++++++++++++------------ 2 files changed, 139 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 964d006d5..e6d1321b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,9 @@ log = "0.4.1" duct = "0.8.2" env_logger = "0.5.0-rc.1" log = "0.4.1" -pretty_assertions = "0.4.1" tempdir = "0.3.5" proptest = "0.7.0" +difference = "2.0.0" [workspace] members = [ diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index ec3e29973..6f5d973c8 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -1,39 +1,61 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows -#[macro_use] extern crate duct; extern crate env_logger; #[macro_use] extern crate log; -#[macro_use] -extern crate pretty_assertions; extern crate rustfix; extern crate serde_json; extern crate tempdir; +#[macro_use] +extern crate failure; +extern crate difference; +use std::ffi::OsString; use std::{env, fs}; -use std::error::Error; use std::path::{Path, PathBuf}; use std::collections::HashSet; use std::process::Output; + +use failure::{Error, ResultExt}; use tempdir::TempDir; use rustfix::apply_suggestions; -fn compile(file: &Path) -> Result> { +mod fixmode { + pub const EVERYTHING: &str = "yolo"; + pub const EDITION: &str = "edition"; +} + +mod settings { + // can be set as env var to debug + pub const CHECK_JSON: &str = "RUSTFIX_TEST_CHECK_JSON"; + pub const RECORD_JSON: &str = "RUSTFIX_TEST_RECORD_JSON"; + pub const RECORD_FIXED_RUST: &str = "RUSTFIX_TEST_RECORD_FIXED_RUST"; + + // set automatically + pub const MODE: &str = "RUSTFIX_MODE"; +} + +fn compile(file: &Path, mode: &str) -> Result { let tmp = TempDir::new("rustfix-tests")?; - let better_call_clippy = cmd!( - "rustc", - file, - "--error-format=pretty-json", - "-Zunstable-options", - "--emit=metadata", - "--crate-name=rustfix_test", - "-Zsuggestion-applicability", - "--out-dir", - tmp.path() - ); - let res = better_call_clippy + + let mut args: Vec = vec![ + file.into(), + "--error-format=pretty-json".into(), + "-Zunstable-options".into(), + "--emit=metadata".into(), + "--crate-name=rustfix_test".into(), + "-Zsuggestion-applicability".into(), + "--out-dir".into(), + tmp.path().into(), + ]; + + if mode == fixmode::EDITION { + args.push("--edition=2018".into()); + } + + let res = duct::cmd("rustc", &args) .env("CLIPPY_DISABLE_DOCS_LINKS", "true") .stdout_capture() .stderr_capture() @@ -43,24 +65,19 @@ fn compile(file: &Path) -> Result> { Ok(res) } -fn compile_and_get_json_errors(file: &Path) -> Result> { - let res = compile(file)?; +fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result { + let res = compile(file, mode)?; let stderr = String::from_utf8(res.stderr)?; - use std::io::{Error, ErrorKind}; match res.status.code() { Some(0) | Some(1) | Some(101) => Ok(stderr), - _ => Err(Box::new(Error::new( - ErrorKind::Other, - format!("failed with status {:?}: {}", res.status.code(), stderr), - ))), + _ => Err(format_err!("failed with status {:?}: {}", res.status.code(), stderr)), } } -fn compiles_without_errors(file: &Path) -> Result<(), Box> { - let res = compile(file)?; +fn compiles_without_errors(file: &Path, mode: &str) -> Result<(), Error> { + let res = compile(file, mode)?; - use std::io::{Error, ErrorKind}; match res.status.code() { Some(0) => Ok(()), _ => { @@ -69,18 +86,15 @@ fn compiles_without_errors(file: &Path) -> Result<(), Box> { file, String::from_utf8(res.stderr)? ); - Err(Box::new(Error::new( - ErrorKind::Other, - format!( - "failed with status {:?} (`env RUST_LOG=everything=info` for more info)", - res.status.code(), - ), - ))) + Err(format_err!( + "failed with status {:?} (`env RUST_LOG=parse_and_replace=info` for more info)", + res.status.code(), + )) } } } -fn read_file(path: &Path) -> Result> { +fn read_file(path: &Path) -> Result { use std::io::Read; let mut buffer = String::new(); @@ -89,53 +103,90 @@ fn read_file(path: &Path) -> Result> { Ok(buffer) } -fn test_rustfix_with_file>(file: P) -> Result<(), Box> { +fn diff(expected: &str, actual: &str) -> String { + use std::fmt::Write; + use difference::{Changeset, Difference}; + + let mut res = String::new(); + let changeset = Changeset::new(expected.trim(), actual.trim(), "\n"); + + let mut different = false; + for diff in changeset.diffs { + let (prefix, diff) = match diff { + Difference::Same(_) => continue, + Difference::Add(add) => ("+", add), + Difference::Rem(rem) => ("-", rem), + }; + if !different { + write!(&mut res, "differences found (+ == actual, - == expected):\n"); + different = true; + } + for diff in diff.lines() { + writeln!(&mut res, "{} {}", prefix, diff); + } + } + if different { + write!(&mut res, ""); + } + + res +} + +fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Error> { let file: &Path = file.as_ref(); let json_file = file.with_extension("json"); let fixed_file = file.with_extension("fixed.rs"); debug!("next up: {:?}", file); - let code = read_file(file)?; - let errors = compile_and_get_json_errors(file)?; + let code = read_file(file) + .context(format!("could not read {}", file.display()))?; + let errors = compile_and_get_json_errors(file, mode) + .context(format!("could compile {}", file.display()))?; let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()) - .expect("could not load suggestions"); + .context("could not load suggestions")?; - if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { + if std::env::var(settings::RECORD_JSON).is_ok() { use std::io::Write; - let mut recorded_json = fs::File::create(&file.with_extension("recorded.json"))?; + let mut recorded_json = fs::File::create(&file.with_extension("recorded.json")) + .context(format!("could not create recorded.json for {}", file.display()))?; recorded_json.write_all(errors.as_bytes())?; } - let expected_json = read_file(&json_file)?; - let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) - .expect("could not load expected suggesitons"); - assert_eq!( - expected_suggestions, suggestions, - "got unexpected suggestions from clippy", - ); + if std::env::var(settings::CHECK_JSON).is_ok() { + let expected_json = read_file(&json_file) + .context(format!("could not load json fixtures for {}", file.display()))?;; + let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) + .context("could not load expected suggesitons")?; - let fixed = apply_suggestions(&code, &suggestions)?; + ensure!( + expected_suggestions == suggestions, + "got unexpected suggestions from clippy:\n{}", + diff(&format!("{:?}", expected_suggestions), &format!("{:?}", suggestions)) + ); + } - if std::env::var("RUSTFIX_TEST_RECORD_FIXED_RUST").is_ok() { + let fixed = apply_suggestions(&code, &suggestions) + .context(format!("could not apply suggestions to {}", file.display()))?; + + if std::env::var(settings::RECORD_FIXED_RUST).is_ok() { use std::io::Write; let mut recorded_rust = fs::File::create(&file.with_extension("recorded.rs"))?; recorded_rust.write_all(fixed.as_bytes())?; } - let expected_fixed = read_file(&fixed_file)?; - assert_eq!( - fixed.trim(), - expected_fixed.trim(), - "file {} doesn't look fixed", - file.display() + let expected_fixed = read_file(&fixed_file) + .context(format!("could read fixed file for {}", file.display()))?; + ensure!( + fixed.trim() == expected_fixed.trim(), + "file {} doesn't look fixed:\n{}", file.display(), diff(fixed.trim(), expected_fixed.trim()) ); - compiles_without_errors(&fixed_file)?; + compiles_without_errors(&fixed_file, mode)?; Ok(()) } -fn get_fixture_files(p: &str) -> Result, Box> { +fn get_fixture_files(p: &str) -> Result, Error> { Ok(fs::read_dir(&p)? .into_iter() .map(|e| e.unwrap().path()) @@ -148,16 +199,40 @@ fn get_fixture_files(p: &str) -> Result, Box> { } fn assert_fixtures(dir: &str, mode: &str) { - for file in &get_fixture_files(&dir).unwrap() { - env::set_var("RUSTFIX_MODE", mode); - test_rustfix_with_file(file).unwrap(); - env::remove_var("RUSTFIX_MODE") + let files = get_fixture_files(&dir) + .context(format!("couldn't load dir `{}`", dir)) + .unwrap(); + let mut failures = 0; + + for file in &files { + if let Err(err) = test_rustfix_with_file(file, mode) { + println!("failed: {}", file.display()); + warn!("{}", err); + for cause in err.causes().skip(1) { + info!("\tcaused by: {}", cause); + } + failures += 1; + } info!("passed: {:?}", file); } + + if failures > 0 { + panic!( + "{} out of {} fixture asserts failed\n\ + (run with `env RUST_LOG=parse_and_replace=info` to get more details)", + failures, files.len(), + ); + } } #[test] fn everything() { let _ = env_logger::try_init(); - assert_fixtures("./tests/everything", "yolo"); + assert_fixtures("./tests/everything", fixmode::EVERYTHING); +} + +#[test] +fn edition() { + let _ = env_logger::try_init(); + assert_fixtures("./tests/edition", fixmode::EDITION); } From 8ed4006945d3bea53d3e8bf41f8ec8bcbcdb91f2 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 6 May 2018 21:02:58 +0200 Subject: [PATCH 162/298] Mark edition lints as ignored for now --- tests/edition/.gitignore | 2 ++ tests/parse_and_replace.rs | 1 + 2 files changed, 3 insertions(+) create mode 100644 tests/edition/.gitignore diff --git a/tests/edition/.gitignore b/tests/edition/.gitignore new file mode 100644 index 000000000..bfb599db1 --- /dev/null +++ b/tests/edition/.gitignore @@ -0,0 +1,2 @@ +*.recorded.json +*.recorded.rs diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 6f5d973c8..9d10e9417 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -232,6 +232,7 @@ fn everything() { } #[test] +#[ignore = "Requires custom rustc build"] fn edition() { let _ = env_logger::try_init(); assert_fixtures("./tests/edition", fixmode::EDITION); From cea8fd1cd24617109b5f24c76658593620a5ab41 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 9 May 2018 22:03:42 +0200 Subject: [PATCH 163/298] WIP: Add `--prepare-for` flag This requires #![feature(crate_in_paths)] #![deny(absolute_path_starting_with_module)] on `rustc 1.27.0-nightly (8ff4b4206 2018-05-08)`, so we're not really there yet. --- cargo-fix/src/cli.rs | 16 +++++++++ cargo-fix/tests/all/edition_upgrade.rs | 47 ++++++++++++++++++++++++++ cargo-fix/tests/all/main.rs | 1 + 3 files changed, 64 insertions(+) create mode 100644 cargo-fix/tests/all/edition_upgrade.rs diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index b8dbbc7ed..ba6a47466 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -33,6 +33,13 @@ pub fn run() -> Result<(), Error> { Arg::with_name("broken-code") .long("broken-code") .help("Fix code even if it already has compiler errors"), + ) + .arg( + Arg::with_name("edition") + .long("prepare-for") + .help("Fix warnigns in preparation of an edition upgrade") + .takes_value(true) + .possible_values(&["2018"]), ), ) .get_matches(); @@ -77,6 +84,15 @@ pub fn run() -> Result<(), Error> { cmd.env("RUSTC_ORIGINAL", rustc); } + // Trigger edition-upgrade mode. Currently only supports the 2018 edition. + info!("edition upgrade? {:?}", matches.value_of("edition")); + if let Some("2018") = matches.value_of("edition") { + info!("edition upgrade!"); + let mut rustc_flags = env::var_os("RUSTC_FLAGS").unwrap_or_else(|| "".into()); + rustc_flags.push("-A warnings -W rust_2018_breakage"); + cmd.env("RUSTC_FLAGS", &rustc_flags); + } + // An now execute all of Cargo! This'll fix everything along the way. // // TODO: we probably want to do something fancy here like collect results diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs new file mode 100644 index 000000000..484537e90 --- /dev/null +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -0,0 +1,47 @@ +//! Test that we can use cargo-fix to upgrade our code to work with the 2018 +//! edition. +//! +//! We'll trigger the `absolute_path_starting_with_module` lint which should +//! transform a `use ::foo;` where `foo` is local to `use crate::foo;`. + +use super::project; + +#[test] +fn prepare_for_2018() { + let p = project() + .file( + "src/lib.rs", + r#" + #![allow(unused)] + #![feature(crate_in_paths)] + #![warn(absolute_path_starting_with_module)] + + mod foo { + pub const FOO: &str = "fooo"; + } + + mod bar { + use ::foo::FOO; + } + + fn main() { + let x = ::foo::FOO; + } + "#, + ) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (2 fixes) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo-fix fix --prepare-for 2018") + .stdout("") + .stderr(stderr) + .run(); + + println!("{}", p.read("src/lib.rs")); + assert!(p.read("src/lib.rs").contains("use crate::foo::FOO;")); + assert!(p.read("src/lib.rs").contains("let x = crate::foo::FOO;")); +} diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 62f03dab3..5f90b3dfb 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -318,6 +318,7 @@ fn diff(expected: &str, actual: &str) { mod broken_build; mod broken_lints; mod dependencies; +mod edition_upgrade; mod smoke; mod subtargets; mod warnings; From bb182508987f30e02e10158178f635ce2ebd66b2 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 9 May 2018 23:05:36 +0200 Subject: [PATCH 164/298] Fix typo --- cargo-fix/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index ba6a47466..d3de09f25 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -37,7 +37,7 @@ pub fn run() -> Result<(), Error> { .arg( Arg::with_name("edition") .long("prepare-for") - .help("Fix warnigns in preparation of an edition upgrade") + .help("Fix warnings in preparation of an edition upgrade") .takes_value(true) .possible_values(&["2018"]), ), From fe2526e2323fedf798550e6c4544657149b3c0fb Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 9 May 2018 23:07:34 +0200 Subject: [PATCH 165/298] WIP: Trigger 2018 breakage lints Fix env var name, list explicit allow lints I'd like to have a way to disable all lints and than individually enable the breakage lint group, but sadly `-A warnings -D rust-2018-breakage` doesn't seem to work. So, let's list the default lint groups for now. --- cargo-fix/src/cli.rs | 6 +++--- cargo-fix/tests/all/edition_upgrade.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index d3de09f25..9562adf48 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -88,9 +88,9 @@ pub fn run() -> Result<(), Error> { info!("edition upgrade? {:?}", matches.value_of("edition")); if let Some("2018") = matches.value_of("edition") { info!("edition upgrade!"); - let mut rustc_flags = env::var_os("RUSTC_FLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push("-A warnings -W rust_2018_breakage"); - cmd.env("RUSTC_FLAGS", &rustc_flags); + let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); + rustc_flags.push("-W rust-2018-breakage -A unused -A nonstandard-style -A bad-style"); + cmd.env("RUSTFLAGS", &rustc_flags); } // An now execute all of Cargo! This'll fix everything along the way. diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index 484537e90..cdcf0bab2 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -14,7 +14,6 @@ fn prepare_for_2018() { r#" #![allow(unused)] #![feature(crate_in_paths)] - #![warn(absolute_path_starting_with_module)] mod foo { pub const FOO: &str = "fooo"; From 43d5f18d1d8cedd556b6426e30a8755fc73d8489 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 9 May 2018 23:18:56 +0200 Subject: [PATCH 166/298] No need for the allow(unused) anymore --- cargo-fix/tests/all/edition_upgrade.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index cdcf0bab2..2ff88de9f 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -12,7 +12,6 @@ fn prepare_for_2018() { .file( "src/lib.rs", r#" - #![allow(unused)] #![feature(crate_in_paths)] mod foo { From cd641cda0befed99cba92584da0e498a25171951 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 10 May 2018 18:40:51 +0200 Subject: [PATCH 167/298] Use rust_2018_preview feature --- cargo-fix/tests/all/edition_upgrade.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index 2ff88de9f..11a97f83c 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -12,7 +12,7 @@ fn prepare_for_2018() { .file( "src/lib.rs", r#" - #![feature(crate_in_paths)] + #![feature(rust_2018_preview )] mod foo { pub const FOO: &str = "fooo"; From a956e9e607001bcc0376e1c0f34e42fa7717e106 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 10 May 2018 18:45:01 +0200 Subject: [PATCH 168/298] Let's not disable lints --- cargo-fix/src/cli.rs | 2 +- cargo-fix/tests/all/edition_upgrade.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 9562adf48..c8b22605d 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -89,7 +89,7 @@ pub fn run() -> Result<(), Error> { if let Some("2018") = matches.value_of("edition") { info!("edition upgrade!"); let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push("-W rust-2018-breakage -A unused -A nonstandard-style -A bad-style"); + rustc_flags.push("-W rust-2018-breakage"); cmd.env("RUSTFLAGS", &rustc_flags); } diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index 11a97f83c..66ea90c44 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -12,7 +12,8 @@ fn prepare_for_2018() { .file( "src/lib.rs", r#" - #![feature(rust_2018_preview )] + #![allow(unused)] + #![feature(rust_2018_preview)] mod foo { pub const FOO: &str = "fooo"; From f1f2bbda8e7e4bce9012ad0b0a789e7543702b1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 May 2018 07:35:44 -0700 Subject: [PATCH 169/298] Add tests for some edition lints * Internal `use` paths should be rewritten to `crate::` where possible * Internal `use` paths should not be rewritten if the feature isn't enabled * `extern crate foo` directives should be removed --- cargo-fix/tests/all/edition_upgrade.rs | 124 +++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index 66ea90c44..dba728ef8 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -44,3 +44,127 @@ fn prepare_for_2018() { assert!(p.read("src/lib.rs").contains("use crate::foo::FOO;")); assert!(p.read("src/lib.rs").contains("let x = crate::foo::FOO;")); } + +#[test] +fn local_paths() { + let p = project() + .file( + "src/lib.rs", + r#" + #![feature(rust_2018_preview)] + + use test::foo; + + mod test { + pub fn foo() {} + } + + pub fn f() { + foo(); + } + "#, + ) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (1 fix) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo-fix fix --prepare-for 2018") + .stdout("") + .stderr(stderr) + .run(); + + println!("{}", p.read("src/lib.rs")); + assert!(p.read("src/lib.rs").contains("use crate::test::foo;")); +} + +#[test] +fn local_paths_no_fix() { + let p = project() + .file( + "src/lib.rs", + r#" + use test::foo; + + mod test { + pub fn foo() {} + } + + pub fn f() { + foo(); + } + "#, + ) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo-fix fix --prepare-for 2018") + .stdout("") + .stderr(stderr) + .run(); +} + +#[test] +fn upgrade_extern_crate() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["edition"] + + [package] + name = "foo" + version = "0.1.0" + edition = '2018' + + [workspace] + + [dependencies] + bar = { path = 'bar' } + "#, + ) + .file( + "src/lib.rs", + r#" + #![warn(rust_2018_migration)] + + extern crate bar; + + use bar::bar; + + pub fn foo() { + ::bar::bar(); + bar(); + } + "#, + ) + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + "#, + ) + .file("bar/src/lib.rs", "pub fn bar() {}") + .build(); + + let stderr = "\ +[CHECKING] bar v0.1.0 (CWD/bar) +[CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (1 fix) +[FINISHED] dev [unoptimized + debuginfo] +"; + p.expect_cmd("cargo-fix fix") + .stdout("") + .stderr(stderr) + .run(); + + println!("{}", p.read("src/lib.rs")); + assert!(!p.read("src/lib.rs").contains("extern crate")); +} From c85afe03da99bb70908aa23dbe755d3037613679 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 13 May 2018 13:26:48 +0200 Subject: [PATCH 170/298] Add a simple tool that applies fixes from JSON Useful when you can get rustc to emit JSON but don't want to/can't use `cargo fix` directly. Currently only supports a single source file but it's easy to extend. --- examples/fix-json.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/fix-json.rs diff --git a/examples/fix-json.rs b/examples/fix-json.rs new file mode 100644 index 000000000..1bb8c5245 --- /dev/null +++ b/examples/fix-json.rs @@ -0,0 +1,27 @@ +extern crate failure; +extern crate rustfix; + +use std::{env, fs, process, collections::HashSet}; +use failure::Error; + +fn main() -> Result<(), Error> { + let args: Vec = env::args().collect(); + let (suggestions_file, source_file) = match args.as_slice() { + [_, suggestions_file, source_file] => (suggestions_file, source_file), + _ => { + println!("USAGE: fix-json "); + process::exit(1); + } + }; + + let suggestions = fs::read_to_string(&suggestions_file)?; + let suggestions = rustfix::get_suggestions_from_json(&suggestions, &HashSet::new())?; + + let source = fs::read_to_string(&source_file)?; + + let fixes = rustfix::apply_suggestions(&source, &suggestions)?; + + println!("{}", fixes); + + Ok(()) +} From d9729ee9d11b10dd2cde92de0cbff058d3ceb50b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 13 May 2018 08:24:13 -0700 Subject: [PATCH 171/298] Fix CI for most recent nightly --- cargo-fix/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index c8b22605d..6d5bdaf50 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -89,7 +89,7 @@ pub fn run() -> Result<(), Error> { if let Some("2018") = matches.value_of("edition") { info!("edition upgrade!"); let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push("-W rust-2018-breakage"); + rustc_flags.push("-W rust-2018-compatibility"); cmd.env("RUSTFLAGS", &rustc_flags); } From eebc699a88295bff575e678e3032288c24a23968 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 13 May 2018 17:26:00 +0200 Subject: [PATCH 172/298] Update lint group names Fixes usage on a nightly after https://github.com/rust-lang/rust/pull/50620 --- cargo-fix/src/cli.rs | 2 +- cargo-fix/src/main.rs | 2 +- cargo-fix/tests/all/edition_upgrade.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index c8b22605d..aaca723b0 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -89,7 +89,7 @@ pub fn run() -> Result<(), Error> { if let Some("2018") = matches.value_of("edition") { info!("edition upgrade!"); let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push("-W rust-2018-breakage"); + rustc_flags.push("-W rust_2018_compatibility"); cmd.env("RUSTFLAGS", &rustc_flags); } diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index c54bd3761..edf1221f0 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -197,7 +197,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { .iter() .all(|s| s.file_name == file_name && s.line_range == range) { - trace!("rejecting as it spans mutliple files {:?}", suggestion); + trace!("rejecting as it spans multiple files {:?}", suggestion); continue; } diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index dba728ef8..f66e7f013 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -131,7 +131,7 @@ fn upgrade_extern_crate() { .file( "src/lib.rs", r#" - #![warn(rust_2018_migration)] + #![warn(rust_2018_idioms)] extern crate bar; From ebca9b67a1af4acd3196d22a2fcfc51f1edea778 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sun, 13 May 2018 17:46:46 +0200 Subject: [PATCH 173/298] Prepare rustfix 0.3 --- Cargo.toml | 4 ++-- Readme.md | 6 ++++++ cargo-fix/Cargo.toml | 9 ++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e6d1321b3..fc4f35478 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,10 @@ authors = [ license = "Apache-2.0/MIT" name = "rustfix" description = "Automatically apply the suggestions made by rustc" -repository = "https://github.com/killercup/rustfix" +repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" -version = "0.2.0" +version = "0.3.0" exclude = [ "etc/*", "examples/*", diff --git a/Readme.md b/Readme.md index f2ecf7d41..19831b826 100644 --- a/Readme.md +++ b/Readme.md @@ -16,6 +16,12 @@ The magic of rustfix is entirely dependent on the diagnostics implement in the R [clippy]: https://github.com/rust-lang-nursery/rust-clippy +## Installation + +To use the rustfix libary, add it to your `Cargo.toml`. + +To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. + ## License Licensed under either of diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index c99469733..e5ca0b2c6 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -1,10 +1,13 @@ [package] name = "cargo-fix" version = "0.2.0" -authors = ["Pascal Hertleif "] +authors = [ + "Pascal Hertleif ", + "Alex Crichton ", +] license = "Apache-2.0/MIT" description = "Automatically apply the suggestions made by rustc" -repository = "https://github.com/killercup/rustfix" +repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" @@ -14,7 +17,7 @@ test = false [dependencies] failure = "0.1" -rustfix = { path = "..", version = "0.2" } +rustfix = { path = "..", version = "0.3" } serde_json = "1" log = "0.4" env_logger = { version = "0.5", default-features = false } From 7ed3595ab1795dd394357a68f7328cd6b46b40a4 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 15 May 2018 20:44:32 +0200 Subject: [PATCH 174/298] fix typo --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 19831b826..2e65e5ee7 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ The goal of this tool is to read and apply the suggestions made by rustc. ## Current status -Currently, rustfix is split into to crates: +Currently, rustfix is split into two crates: - `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs - and `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code. From d85336084d8855bfbfd431b85beaa5c094dc5e72 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 12:21:10 -0700 Subject: [PATCH 175/298] Reformat everything with rustfmt from stable 1.26 * executed via `cargo fmt` --- cargo-fix/src/cli.rs | 44 ++++++++++++++--------- cargo-fix/src/diagnostics.rs | 35 ++++++++++++------ cargo-fix/src/lock.rs | 2 +- cargo-fix/src/main.rs | 21 ++++++----- cargo-fix/tests/all/broken_build.rs | 30 ++++++++-------- cargo-fix/tests/all/broken_lints.rs | 22 +++++++----- cargo-fix/tests/all/dependencies.rs | 2 +- cargo-fix/tests/all/main.rs | 2 +- cargo-fix/tests/all/smoke.rs | 4 +-- examples/fix-json.rs | 2 +- src/replace.rs | 21 +++++++---- tests/parse_and_replace.rs | 56 ++++++++++++++++++----------- 12 files changed, 148 insertions(+), 93 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 6d5bdaf50..fbaec73d8 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -1,23 +1,24 @@ use std::env; -use std::process::Command; use std::io::Write; +use std::process::Command; use clap::{App, AppSettings, Arg, SubCommand}; use failure::{Error, ResultExt}; use termcolor::{Color, ColorSpec, StandardStream, WriteColor}; -use lock; -use diagnostics::{Message, Server}; use super::exit_with; +use diagnostics::{Message, Server}; +use lock; -static PLEASE_REPORT_THIS_BUG: &str = "\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ -"; +static PLEASE_REPORT_THIS_BUG: &str = + "\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ + "; pub fn run() -> Result<(), Error> { let matches = App::new("Cargo Fix") @@ -106,7 +107,10 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> use diagnostics::Message::*; match *msg { - Fixing { ref file, ref fixes } => { + Fixing { + ref file, + ref fixes, + } => { log_for_human( "Fixing", &format!( @@ -118,7 +122,10 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> stream, )?; } - ReplaceFailed { ref file, ref message } => { + ReplaceFailed { + ref file, + ref message, + } => { stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; write!(stream, "warning")?; stream.reset()?; @@ -128,7 +135,10 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> write!(stream, "The full error message was:\n\n> {}\n\n", message)?; stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; } - FixFailed { ref files, ref krate } => { + FixFailed { + ref files, + ref krate, + } => { stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; write!(stream, "warning")?; stream.reset()?; @@ -142,7 +152,10 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> krate, )?; } else { - write!(stream, "failed to automatically apply fixes suggested by rustc\n")?; + write!( + stream, + "failed to automatically apply fixes suggested by rustc\n" + )?; } if files.len() > 0 { write!( @@ -154,7 +167,6 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> write!(stream, " * {}\n", file)?; } write!(stream, "\n")?; - } stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; } diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index b6ea61ce4..93fc4be1c 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -2,7 +2,7 @@ //! cross-platform way. use std::env; -use std::io::{BufReader, Write, Read}; +use std::io::{BufReader, Read, Write}; use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; use std::thread::{self, JoinHandle}; @@ -15,9 +15,18 @@ static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; #[derive(Deserialize, Serialize)] pub enum Message { - Fixing { file: String, fixes: usize }, - FixFailed { files: Vec, krate: Option }, - ReplaceFailed { file: String, message: String }, + Fixing { + file: String, + fixes: usize, + }, + FixFailed { + files: Vec, + krate: Option, + }, + ReplaceFailed { + file: String, + message: String, + }, } impl Message { @@ -33,15 +42,17 @@ impl Message { let mut client = TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?; - let s = serde_json::to_string(self) - .context("failed to serialize message")?; - client.write_all(s.as_bytes()) + let s = serde_json::to_string(self).context("failed to serialize message")?; + client + .write_all(s.as_bytes()) .context("failed to write message to diagnostics target")?; - client.shutdown(Shutdown::Write) + client + .shutdown(Shutdown::Write) .context("failed to shutdown")?; let mut tmp = Vec::new(); - client.read_to_end(&mut tmp) + client + .read_to_end(&mut tmp) .context("failed to receive a disconnect")?; Ok(()) @@ -67,7 +78,8 @@ impl Server { } pub fn start(self, on_message: F) -> Result - where F: Fn(Message, &mut StandardStream) + Send + 'static, + where + F: Fn(Message, &mut StandardStream) + Send + 'static, { let _addr = self.listener.local_addr()?; let thread = thread::spawn(move || { @@ -81,7 +93,8 @@ impl Server { } fn run(self, on_message: F) - where F: Fn(Message, &mut StandardStream) + where + F: Fn(Message, &mut StandardStream), { let color_choice = if atty::is(atty::Stream::Stderr) { ColorChoice::Auto diff --git a/cargo-fix/src/lock.rs b/cargo-fix/src/lock.rs index 673267658..c3c6d2be4 100644 --- a/cargo-fix/src/lock.rs +++ b/cargo-fix/src/lock.rs @@ -15,8 +15,8 @@ use std::collections::HashMap; use std::env; use std::io::{BufRead, BufReader, Read, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use std::thread::{self, JoinHandle}; use failure::{Error, ResultExt}; diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index edf1221f0..82c3f4055 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -11,22 +11,22 @@ extern crate serde_derive; extern crate serde_json; extern crate termcolor; -use std::collections::{HashMap, HashSet, BTreeSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::env; use std::fs::File; use std::io::{Read, Write}; +use std::path::Path; use std::process::{self, Command, ExitStatus}; use std::str; -use std::path::Path; -use rustfix::diagnostics::Diagnostic; use failure::{Error, ResultExt}; +use rustfix::diagnostics::Diagnostic; use diagnostics::Message; mod cli; -mod lock; mod diagnostics; +mod lock; fn main() { env_logger::init(); @@ -162,7 +162,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { filename, output.status.code() ); - return Ok(Default::default()) + return Ok(Default::default()); } // Sift through the output of the compiler to look for JSON messages @@ -231,7 +231,10 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { match rustfix::apply_suggestions(&code, &suggestions) { Err(e) => { - diagnostics::Message::ReplaceFailed { file: file, message: e.to_string() }.post()?; + diagnostics::Message::ReplaceFailed { + file: file, + message: e.to_string(), + }.post()?; // TODO: Add flag to decide if we want to continue or bail out continue; } @@ -263,10 +266,10 @@ fn exit_with(status: ExitStatus) -> ! { } fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> { - let stderr = str::from_utf8(stderr) - .context("failed to parse rustc stderr as utf-8")?; + let stderr = str::from_utf8(stderr).context("failed to parse rustc stderr as utf-8")?; - let diagnostics = stderr.lines() + let diagnostics = stderr + .lines() .filter(|x| !x.is_empty()) .filter_map(|line| serde_json::from_str::(line).ok()); let mut files = BTreeSet::new(); diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index ca8f09f09..b10da856e 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -116,21 +116,21 @@ fn broken_fixes_backed_out() { .stderr_contains("not rust code") .stderr_contains( "\ - warning: failed to automatically apply fixes suggested by rustc \ - to crate `bar`\n\ - \n\ - after fixes were automatically applied the compiler reported \ - errors within these files:\n\ - \n \ - * src/lib.rs\n\ - \n\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ - " + warning: failed to automatically apply fixes suggested by rustc \ + to crate `bar`\n\ + \n\ + after fixes were automatically applied the compiler reported \ + errors within these files:\n\ + \n \ + * src/lib.rs\n\ + \n\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ + ", ) .stderr_not_contains("[FIXING]") .status(101) diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs index 046aeeed2..c0118f133 100644 --- a/cargo-fix/tests/all/broken_lints.rs +++ b/cargo-fix/tests/all/broken_lints.rs @@ -21,15 +21,19 @@ fn tell_user_about_broken_lints() { p.expect_cmd("cargo-fix fix") .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") .stderr_contains("The full error message was:") - .stderr_contains("> Could not replace range 56...60 in file -- maybe parts of it were already replaced?") - .stderr_contains("\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ - ") + .stderr_contains( + "> Could not replace range 56...60 in file -- maybe parts of it were already replaced?", + ) + .stderr_contains( + "\ + This likely indicates a bug in either rustc or rustfix itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which rustfix\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang-nursery/rustfix/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\n\ + ", + ) .status(0) .run(); } diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index 54c7ca480..746a2e453 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -26,7 +26,7 @@ fn fix_path_deps() { x } "#, - ) + ) .file( "bar/Cargo.toml", r#" diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 5f90b3dfb..f671c9956 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -2,6 +2,7 @@ extern crate difference; extern crate url; use std::env; +use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -9,7 +10,6 @@ use std::process::Command; use std::str; use std::sync::atomic::*; use std::time::Instant; -use std::ffi::{OsStr, OsString}; use difference::{Changeset, Difference}; use url::Url; diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index d71379841..c3a0974f6 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -96,8 +96,8 @@ fn preserve_line_endings() { .file( "src/lib.rs", "\ - fn add(a: &u32) -> u32 { a + 1 }\r\n\ - pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ + fn add(a: &u32) -> u32 { a + 1 }\r\n\ + pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ ", ) .build(); diff --git a/examples/fix-json.rs b/examples/fix-json.rs index 1bb8c5245..e90cc3eab 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -1,8 +1,8 @@ extern crate failure; extern crate rustfix; -use std::{env, fs, process, collections::HashSet}; use failure::Error; +use std::{env, fs, process, collections::HashSet}; fn main() -> Result<(), Error> { let args: Vec = env::args().collect(); diff --git a/src/replace.rs b/src/replace.rs index a95cf4719..5e4e6b097 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -2,8 +2,8 @@ //! replacement of parts of its content, with the ability to prevent changing //! the same parts multiple times. -use std::rc::Rc; use failure::Error; +use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq)] enum State { @@ -93,19 +93,26 @@ impl Data { if log_enabled!(Debug) { let slices = self.parts .iter() - .map(|p| (p.start, p.end, match p.data { - State::Initial => "initial", - State::Replaced(..) => "replaced", - })) + .map(|p| { + ( + p.start, + p.end, + match p.data { + State::Initial => "initial", + State::Replaced(..) => "replaced", + }, + ) + }) .collect::>(); - debug!("no single slice covering {}...{}, current slices: {:?}", + debug!( + "no single slice covering {}...{}, current slices: {:?}", from, up_to_and_including, slices, ); } format_err!( "Could not replace range {}...{} in file \ - -- maybe parts of it were already replaced?", + -- maybe parts of it were already replaced?", from, up_to_and_including ) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 9d10e9417..f3ec444b9 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -11,11 +11,11 @@ extern crate tempdir; extern crate failure; extern crate difference; -use std::ffi::OsString; -use std::{env, fs}; -use std::path::{Path, PathBuf}; use std::collections::HashSet; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; use std::process::Output; +use std::{env, fs}; use failure::{Error, ResultExt}; use tempdir::TempDir; @@ -71,7 +71,11 @@ fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result match res.status.code() { Some(0) | Some(1) | Some(101) => Ok(stderr), - _ => Err(format_err!("failed with status {:?}: {}", res.status.code(), stderr)), + _ => Err(format_err!( + "failed with status {:?}: {}", + res.status.code(), + stderr + )), } } @@ -104,8 +108,8 @@ fn read_file(path: &Path) -> Result { } fn diff(expected: &str, actual: &str) -> String { - use std::fmt::Write; use difference::{Changeset, Difference}; + use std::fmt::Write; let mut res = String::new(); let changeset = Changeset::new(expected.trim(), actual.trim(), "\n"); @@ -118,7 +122,10 @@ fn diff(expected: &str, actual: &str) -> String { Difference::Rem(rem) => ("-", rem), }; if !different { - write!(&mut res, "differences found (+ == actual, - == expected):\n"); + write!( + &mut res, + "differences found (+ == actual, - == expected):\n" + ); different = true; } for diff in diff.lines() { @@ -138,8 +145,7 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err let fixed_file = file.with_extension("fixed.rs"); debug!("next up: {:?}", file); - let code = read_file(file) - .context(format!("could not read {}", file.display()))?; + let code = read_file(file).context(format!("could not read {}", file.display()))?; let errors = compile_and_get_json_errors(file, mode) .context(format!("could compile {}", file.display()))?; let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()) @@ -147,21 +153,28 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err if std::env::var(settings::RECORD_JSON).is_ok() { use std::io::Write; - let mut recorded_json = fs::File::create(&file.with_extension("recorded.json")) - .context(format!("could not create recorded.json for {}", file.display()))?; + let mut recorded_json = fs::File::create(&file.with_extension("recorded.json")).context( + format!("could not create recorded.json for {}", file.display()), + )?; recorded_json.write_all(errors.as_bytes())?; } if std::env::var(settings::CHECK_JSON).is_ok() { - let expected_json = read_file(&json_file) - .context(format!("could not load json fixtures for {}", file.display()))?;; - let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) - .context("could not load expected suggesitons")?; + let expected_json = read_file(&json_file).context(format!( + "could not load json fixtures for {}", + file.display() + ))?; + let expected_suggestions = + rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) + .context("could not load expected suggesitons")?; ensure!( expected_suggestions == suggestions, "got unexpected suggestions from clippy:\n{}", - diff(&format!("{:?}", expected_suggestions), &format!("{:?}", suggestions)) + diff( + &format!("{:?}", expected_suggestions), + &format!("{:?}", suggestions) + ) ); } @@ -174,11 +187,13 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err recorded_rust.write_all(fixed.as_bytes())?; } - let expected_fixed = read_file(&fixed_file) - .context(format!("could read fixed file for {}", file.display()))?; + let expected_fixed = + read_file(&fixed_file).context(format!("could read fixed file for {}", file.display()))?; ensure!( fixed.trim() == expected_fixed.trim(), - "file {} doesn't look fixed:\n{}", file.display(), diff(fixed.trim(), expected_fixed.trim()) + "file {} doesn't look fixed:\n{}", + file.display(), + diff(fixed.trim(), expected_fixed.trim()) ); compiles_without_errors(&fixed_file, mode)?; @@ -219,8 +234,9 @@ fn assert_fixtures(dir: &str, mode: &str) { if failures > 0 { panic!( "{} out of {} fixture asserts failed\n\ - (run with `env RUST_LOG=parse_and_replace=info` to get more details)", - failures, files.len(), + (run with `env RUST_LOG=parse_and_replace=info` to get more details)", + failures, + files.len(), ); } } From d6f7fe802b44b8c4c412d5d7c44d0ce2fb7d5178 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 16 May 2018 22:28:41 +0200 Subject: [PATCH 176/298] Comment out broken lint test for now The lint in use is fixed in the compiler, so the fixing no longer fails which means this test no longer works. I couldn't write a rustc shim that outputs overlapping suggestions in 5min so I'll do this for now and come back to the real issue later. --- cargo-fix/tests/all/broken_lints.rs | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs index c0118f133..0c939c4af 100644 --- a/cargo-fix/tests/all/broken_lints.rs +++ b/cargo-fix/tests/all/broken_lints.rs @@ -3,37 +3,37 @@ //! TODO: Add rustc shim that outputs wrong suggestions instead of depending on //! actual rustc bugs! -use super::project; +// use super::project; -#[test] -fn tell_user_about_broken_lints() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() { - let mut i = 42; - } - "#, - ) - .build(); +// #[test] +// fn tell_user_about_broken_lints() { +// let p = project() +// .file( +// "src/lib.rs", +// r#" +// pub fn foo() { +// let mut i = 42; +// } +// "#, +// ) +// .build(); - p.expect_cmd("cargo-fix fix") - .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") - .stderr_contains("The full error message was:") - .stderr_contains( - "> Could not replace range 56...60 in file -- maybe parts of it were already replaced?", - ) - .stderr_contains( - "\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ - ", - ) - .status(0) - .run(); -} +// p.expect_cmd("cargo-fix fix") +// .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") +// .stderr_contains("The full error message was:") +// .stderr_contains( +// "> Could not replace range 56...60 in file -- maybe parts of it were already replaced?", +// ) +// .stderr_contains( +// "\ +// This likely indicates a bug in either rustc or rustfix itself,\n\ +// and we would appreciate a bug report! You're likely to see \n\ +// a number of compiler warnings after this message which rustfix\n\ +// attempted to fix but failed. If you could open an issue at\n\ +// https://github.com/rust-lang-nursery/rustfix/issues\n\ +// quoting the full output of this command we'd be very appreciative!\n\n\ +// ", +// ) +// .status(0) +// .run(); +// } From 347bcac97f9c2ee8ebca0ad7f2d1bfcb65a964b8 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 11:58:42 -0700 Subject: [PATCH 177/298] Add test for insert only suggestion * Also remove the ensure that prevents handling of insert only suggestions --- src/replace.rs | 8 +-- tests/everything/handle-insert-only.fixed.rs | 12 ++++ tests/everything/handle-insert-only.json | 67 ++++++++++++++++++ tests/everything/handle-insert-only.rs | 9 +++ .../everything/replace-only-one-char.fixed.rs | 3 + tests/everything/replace-only-one-char.json | 70 +++++++++++++++++++ tests/everything/replace-only-one-char.rs | 3 + 7 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 tests/everything/handle-insert-only.fixed.rs create mode 100644 tests/everything/handle-insert-only.json create mode 100644 tests/everything/handle-insert-only.rs create mode 100644 tests/everything/replace-only-one-char.fixed.rs create mode 100644 tests/everything/replace-only-one-char.json create mode 100644 tests/everything/replace-only-one-char.rs diff --git a/src/replace.rs b/src/replace.rs index 5e4e6b097..c106f492c 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -61,12 +61,6 @@ impl Data { up_to_and_including: usize, data: &[u8], ) -> Result<(), Error> { - ensure!( - from <= up_to_and_including, - "Invalid range {}...{}, start is larger than end", - from, - up_to_and_including - ); ensure!( up_to_and_including <= self.original.len(), "Invalid range {}...{} given, original data is only {} byte long", @@ -75,6 +69,8 @@ impl Data { self.original.len() ); + // let insert_only = from > up_to_and_including; + // Since we error out when replacing an already replaced chunk of data, // we can take some shortcuts here. For example, there can be no // overlapping replacements -- we _always_ split a chunk of 'initial' diff --git a/tests/everything/handle-insert-only.fixed.rs b/tests/everything/handle-insert-only.fixed.rs new file mode 100644 index 000000000..c01a5ce56 --- /dev/null +++ b/tests/everything/handle-insert-only.fixed.rs @@ -0,0 +1,12 @@ +fn main() { + // a single character replace, changes x to _x. + let _x = 42; + + // insert only fix, adds `,` to first match arm + // why doesnt this replace 1 with 1,? + match &Some(3) { + &None => 1, + &Some(2) => 3, + _ => 2, + }; +} diff --git a/tests/everything/handle-insert-only.json b/tests/everything/handle-insert-only.json new file mode 100644 index 000000000..72bb5d107 --- /dev/null +++ b/tests/everything/handle-insert-only.json @@ -0,0 +1,67 @@ +{ + "message": "expected one of `,`, `.`, `?`, `}`, or an operator, found `=>`", + "code": null, + "level": "error", + "spans": [ + { + "file_name": "handle-insert-only.rs", + "byte_start": 163, + "byte_end": 165, + "line_start": 6, + "line_end": 6, + "column_start": 18, + "column_end": 20, + "is_primary": true, + "text": [ + { + "text": " &Some(2) => { 3 }", + "highlight_start": 18, + "highlight_end": 20 + } + ], + "label": "expected one of `,`, `.`, `?`, `}`, or an operator here", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "missing a comma here to end this `match` arm", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "handle-insert-only.rs", + "byte_start": 145, + "byte_end": 145, + "line_start": 5, + "line_end": 5, + "column_start": 19, + "column_end": 19, + "is_primary": true, + "text": [ + { + "text": " &None => 1", + "highlight_start": 19, + "highlight_end": 19 + } + ], + "label": null, + "suggested_replacement": ",", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>`\n --> handle-insert-only.rs:6:18\n |\n5 | &None => 1\n | - help: missing a comma here to end this `match` arm\n6 | &Some(2) => { 3 }\n | ^^ expected one of `,`, `.`, `?`, `}`, or an operator here\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} diff --git a/tests/everything/handle-insert-only.rs b/tests/everything/handle-insert-only.rs new file mode 100644 index 000000000..430be4144 --- /dev/null +++ b/tests/everything/handle-insert-only.rs @@ -0,0 +1,9 @@ +fn main() { + // insert only fix, adds `,` to first match arm + // why doesnt this replace 1 with 1,? + match &Some(3) { + &None => 1 + &Some(2) => { 3 } + _ => 2 + }; +} diff --git a/tests/everything/replace-only-one-char.fixed.rs b/tests/everything/replace-only-one-char.fixed.rs new file mode 100644 index 000000000..1a9298d5f --- /dev/null +++ b/tests/everything/replace-only-one-char.fixed.rs @@ -0,0 +1,3 @@ +fn main() { + let _x = 42; +} diff --git a/tests/everything/replace-only-one-char.json b/tests/everything/replace-only-one-char.json new file mode 100644 index 000000000..9a70c0880 --- /dev/null +++ b/tests/everything/replace-only-one-char.json @@ -0,0 +1,70 @@ +{ + "message": "unused variable: `x`", + "code": { + "code": "unused_variables", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "replace-only-one-char.rs", + "byte_start": 20, + "byte_end": 21, + "line_start": 2, + "line_end": 2, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let x = 42;", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(unused_variables)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "consider using `_x` instead", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "replace-only-one-char.rs", + "byte_start": 20, + "byte_end": 21, + "line_start": 2, + "line_end": 2, + "column_start": 9, + "column_end": 10, + "is_primary": true, + "text": [ + { + "text": " let x = 42;", + "highlight_start": 9, + "highlight_end": 10 + } + ], + "label": null, + "suggested_replacement": "_x", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused variable: `x`\n --> replace-only-one-char.rs:2:9\n |\n2 | let x = 42;\n | ^ help: consider using `_x` instead\n |\n = note: #[warn(unused_variables)] on by default\n\n" +} diff --git a/tests/everything/replace-only-one-char.rs b/tests/everything/replace-only-one-char.rs new file mode 100644 index 000000000..36e44936f --- /dev/null +++ b/tests/everything/replace-only-one-char.rs @@ -0,0 +1,3 @@ +fn main() { + let x = 42; +} From e5dff5ade0702a86c2be8838766f503990c09222 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 13:03:07 -0700 Subject: [PATCH 178/298] Add unit test for multiple pass edge case --- src/replace.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/replace.rs b/src/replace.rs index c106f492c..cd2f066fd 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -200,6 +200,17 @@ mod tests { assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); } + #[test] + fn replace_multiple_lines_with_insert_only() { + let mut d = Data::new(b"foo!"); + + d.replace_range(3, 2, b"bar").unwrap(); + assert_eq!("foobar!", str(&d.to_vec())); + + d.replace_range(0, 2, b"baz").unwrap(); + assert_eq!("bazbar!", str(&d.to_vec())); + } + #[test] #[should_panic(expected = "Cannot replace slice of data that was already replaced")] fn replace_overlapping_stuff_errs() { From 0ef97861fc2457c6db99e23cab230e119710607d Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 16:11:29 -0700 Subject: [PATCH 179/298] Add inserted state --- src/replace.rs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/replace.rs b/src/replace.rs index cd2f066fd..adb5f1790 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -9,6 +9,7 @@ use std::rc::Rc; enum State { Initial, Replaced(Rc<[u8]>), + Inserted(Rc<[u8]>), } #[derive(Debug, Clone, PartialEq, Eq)] @@ -36,7 +37,7 @@ impl Data { Span { data: State::Initial, start: 0, - end: data.len(), + end: data.len() - 1, }, ], } @@ -46,8 +47,8 @@ impl Data { pub fn to_vec(&self) -> Vec { self.parts.iter().fold(Vec::new(), |mut acc, d| { match d.data { - State::Initial => acc.extend_from_slice(&self.original[d.start..d.end]), - State::Replaced(ref d) => acc.extend_from_slice(&d), + State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), + State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(&d), }; acc }) @@ -69,7 +70,7 @@ impl Data { self.original.len() ); - // let insert_only = from > up_to_and_including; + let insert_only = from > up_to_and_including; // Since we error out when replacing an already replaced chunk of data, // we can take some shortcuts here. For example, there can be no @@ -81,9 +82,19 @@ impl Data { // the whole chunk. As an optimization and without loss of generality we // don't add empty parts. let new_parts = { + let is_inserted = |state| { + if let &State::Inserted(..) = state { + true + } else { + false + } + }; + let index_of_part_to_split = self.parts .iter() - .position(|p| p.start <= from && p.end >= up_to_and_including) + .position(|p| { + !is_inserted(&p.data) && p.start <= from && p.end >= up_to_and_including + }) .ok_or_else(|| { use log::Level::Debug; if log_enabled!(Debug) { @@ -96,6 +107,7 @@ impl Data { match p.data { State::Initial => "initial", State::Replaced(..) => "replaced", + State::Inserted(..) => "inserted", }, ) }) @@ -131,7 +143,8 @@ impl Data { if from > part_to_split.start { new_parts.push(Span { start: part_to_split.start, - end: from, + // end: if insert_only { from - 1 } else { from }, + end: from - 1, data: State::Initial, }); } @@ -140,7 +153,11 @@ impl Data { new_parts.push(Span { start: from, end: up_to_and_including, - data: State::Replaced(data.into()), + data: if insert_only { + State::Inserted(data.into()) + } else { + State::Replaced(data.into()) + }, }); // Keep initial data on right side of part @@ -196,7 +213,7 @@ mod tests { d.replace_range(6, 10, b"lol").unwrap(); assert_eq!("lorem\nlol\ndolor", str(&d.to_vec())); - d.replace_range(12, 17, b"lol").unwrap(); + d.replace_range(12, 16, b"lol").unwrap(); assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); } @@ -209,6 +226,9 @@ mod tests { d.replace_range(0, 2, b"baz").unwrap(); assert_eq!("bazbar!", str(&d.to_vec())); + + d.replace_range(3, 3, b"?").unwrap(); + assert_eq!("bazbar?", str(&d.to_vec())); } #[test] From 9ec8a559b8fbfbefd8f8a339cea8ec4b01ca9dea Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 17:50:36 -0700 Subject: [PATCH 180/298] Fix integration to pass compilation --- tests/everything/handle-insert-only.fixed.rs | 6 +----- tests/everything/handle-insert-only.json | 9 +++++---- tests/everything/handle-insert-only.rs | 3 +-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/everything/handle-insert-only.fixed.rs b/tests/everything/handle-insert-only.fixed.rs index c01a5ce56..604bc8503 100644 --- a/tests/everything/handle-insert-only.fixed.rs +++ b/tests/everything/handle-insert-only.fixed.rs @@ -1,12 +1,8 @@ fn main() { - // a single character replace, changes x to _x. - let _x = 42; - // insert only fix, adds `,` to first match arm // why doesnt this replace 1 with 1,? match &Some(3) { &None => 1, - &Some(2) => 3, - _ => 2, + &Some(x) => x, }; } diff --git a/tests/everything/handle-insert-only.json b/tests/everything/handle-insert-only.json index 72bb5d107..c32a71290 100644 --- a/tests/everything/handle-insert-only.json +++ b/tests/everything/handle-insert-only.json @@ -4,7 +4,7 @@ "level": "error", "spans": [ { - "file_name": "handle-insert-only.rs", + "file_name": "./tests/everything/handle-insert-only.rs", "byte_start": 163, "byte_end": 165, "line_start": 6, @@ -14,7 +14,7 @@ "is_primary": true, "text": [ { - "text": " &Some(2) => { 3 }", + "text": " &Some(x) => x,", "highlight_start": 18, "highlight_end": 20 } @@ -31,7 +31,7 @@ "level": "help", "spans": [ { - "file_name": "handle-insert-only.rs", + "file_name": "./tests/everything/handle-insert-only.rs", "byte_start": 145, "byte_end": 145, "line_start": 5, @@ -48,6 +48,7 @@ ], "label": null, "suggested_replacement": ",", + "suggestion_applicability": "Unspecified", "expansion": null } ], @@ -55,7 +56,7 @@ "rendered": null } ], - "rendered": "error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>`\n --> handle-insert-only.rs:6:18\n |\n5 | &None => 1\n | - help: missing a comma here to end this `match` arm\n6 | &Some(2) => { 3 }\n | ^^ expected one of `,`, `.`, `?`, `}`, or an operator here\n\n" + "rendered": "error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>`\n --> ./tests/everything/handle-insert-only.rs:6:18\n |\n5 | &None => 1\n | - help: missing a comma here to end this `match` arm\n6 | &Some(x) => x,\n | ^^ expected one of `,`, `.`, `?`, `}`, or an operator here\n\n" } { "message": "aborting due to previous error", diff --git a/tests/everything/handle-insert-only.rs b/tests/everything/handle-insert-only.rs index 430be4144..d42a4caa8 100644 --- a/tests/everything/handle-insert-only.rs +++ b/tests/everything/handle-insert-only.rs @@ -3,7 +3,6 @@ fn main() { // why doesnt this replace 1 with 1,? match &Some(3) { &None => 1 - &Some(2) => { 3 } - _ => 2 + &Some(x) => x, }; } From 52a9eb820543b0e337a859c34c672394221f44dc Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 16 May 2018 21:50:40 -0700 Subject: [PATCH 181/298] Readd check for invalid ranges * Also adds a test for invalid ranges, specifically looking for ranges that are neither replace nor insert, as in the exclusive_end is less than the start. --- src/replace.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/replace.rs b/src/replace.rs index adb5f1790..664334e4d 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -62,6 +62,15 @@ impl Data { up_to_and_including: usize, data: &[u8], ) -> Result<(), Error> { + let exclusive_end = up_to_and_including + 1; + + ensure!( + from <= exclusive_end, + "Invalid range {}...{}, start is larger than end", + from, + up_to_and_including + ); + ensure!( up_to_and_including <= self.original.len(), "Invalid range {}...{} given, original data is only {} byte long", @@ -70,7 +79,7 @@ impl Data { self.original.len() ); - let insert_only = from > up_to_and_including; + let insert_only = from == exclusive_end; // Since we error out when replacing an already replaced chunk of data, // we can take some shortcuts here. For example, there can be no @@ -143,7 +152,6 @@ impl Data { if from > part_to_split.start { new_parts.push(Span { start: part_to_split.start, - // end: if insert_only { from - 1 } else { from }, end: from - 1, data: State::Initial, }); @@ -231,6 +239,14 @@ mod tests { assert_eq!("bazbar?", str(&d.to_vec())); } + #[test] + fn replace_invalid_range() { + let mut d = Data::new(b"foo!"); + + assert!(d.replace_range(2, 0, b"bar").is_err()); + assert!(d.replace_range(0, 2, b"bar").is_ok()); + } + #[test] #[should_panic(expected = "Cannot replace slice of data that was already replaced")] fn replace_overlapping_stuff_errs() { From a0546dd80bea2ed0773cc7ba84404c07a36376c8 Mon Sep 17 00:00:00 2001 From: Ezinwa Okpoechi Date: Tue, 15 May 2018 11:29:00 +0200 Subject: [PATCH 182/298] Check if in a VCS --- cargo-fix/src/cli.rs | 11 ++++++++++ cargo-fix/src/main.rs | 1 + cargo-fix/src/vcs.rs | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 cargo-fix/src/vcs.rs diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index fbaec73d8..1e7b4aa25 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -9,6 +9,7 @@ use termcolor::{Color, ColorSpec, StandardStream, WriteColor}; use super::exit_with; use diagnostics::{Message, Server}; use lock; +use vcs::VersionControl; static PLEASE_REPORT_THIS_BUG: &str = "\ @@ -41,6 +42,11 @@ pub fn run() -> Result<(), Error> { .help("Fix warnings in preparation of an edition upgrade") .takes_value(true) .possible_values(&["2018"]), + ) + .arg( + Arg::with_name("allow-no-vcs") + .long("allow-no-vcs") + .help("Fix code even if a vcs was not detected"), ), ) .get_matches(); @@ -53,6 +59,11 @@ pub fn run() -> Result<(), Error> { env::set_var("__CARGO_FIX_BROKEN_CODE", "1"); } + let version_control = VersionControl::new(); + if !version_control.is_present() && !matches.is_present("allow-no-vcs") { + bail!("no vcs found, aborting. overwrite this behavior with --allow-no-vcs"); + } + // Spin up our lock server which our subprocesses will use to synchronize // fixes. let _lockserver = lock::Server::new()?.start()?; diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 82c3f4055..d9c8ad4a5 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -27,6 +27,7 @@ use diagnostics::Message; mod cli; mod diagnostics; mod lock; +mod vcs; fn main() { env_logger::init(); diff --git a/cargo-fix/src/vcs.rs b/cargo-fix/src/vcs.rs new file mode 100644 index 000000000..a35d57adc --- /dev/null +++ b/cargo-fix/src/vcs.rs @@ -0,0 +1,48 @@ +use failure::{err_msg, Error, ResultExt}; +use std::env; + +pub enum VersionControl { + Git, + Hg, + Fossil, + Pijul, + None, +} + +impl VersionControl { + pub fn new() -> Self { + if is_in_vcs(".git").is_ok() { + VersionControl::Git + } else if is_in_vcs(".hg").is_ok() { + VersionControl::Hg + } else if is_in_vcs(".pijul").is_ok() { + VersionControl::Pijul + } else if is_in_vcs(".fossil").is_ok() { + VersionControl::Fossil + } else { + VersionControl::None + } + } + + pub fn is_present(&self) -> bool { + match *self { + VersionControl::None => false, + _ => true, + } + } +} + +fn is_in_vcs(vcs_dir: &str) -> Result<(), Error> { + let mut current_dir = env::current_dir().context("could not find the current directory")?; + + loop { + if current_dir.join(vcs_dir).metadata().is_ok() { + return Ok(()); + } + + current_dir = current_dir + .parent() + .ok_or_else(|| err_msg("could not find the parent directory"))? + .to_owned(); + } +} From 38b2ba72219afdc34d6d2639bbc2461612bf8b48 Mon Sep 17 00:00:00 2001 From: Ezinwa Okpoechi Date: Tue, 15 May 2018 16:41:04 +0200 Subject: [PATCH 183/298] Check if VCS working tree is dirty --- cargo-fix/src/cli.rs | 15 +++++++++++++-- cargo-fix/src/vcs.rs | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 1e7b4aa25..f7f5abe52 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -1,6 +1,6 @@ use std::env; use std::io::Write; -use std::process::Command; +use std::process::{self, Command}; use clap::{App, AppSettings, Arg, SubCommand}; use failure::{Error, ResultExt}; @@ -47,6 +47,11 @@ pub fn run() -> Result<(), Error> { Arg::with_name("allow-no-vcs") .long("allow-no-vcs") .help("Fix code even if a vcs was not detected"), + ) + .arg( + Arg::with_name("allow-dirty") + .long("allow-dirty") + .help("Fix code even if the working directory is dirty"), ), ) .get_matches(); @@ -61,7 +66,13 @@ pub fn run() -> Result<(), Error> { let version_control = VersionControl::new(); if !version_control.is_present() && !matches.is_present("allow-no-vcs") { - bail!("no vcs found, aborting. overwrite this behavior with --allow-no-vcs"); + eprintln!("no vcs found, aborting. overwrite this behavior with --allow-no-vcs"); + process::exit(1); + } + + if version_control.is_present() && version_control.is_dirty()? && !matches.is_present("allow-dirty") { + eprintln!("working directory is dirty, aborting. overwrite this behavior with --allow-dirty"); + process::exit(1); } // Spin up our lock server which our subprocesses will use to synchronize diff --git a/cargo-fix/src/vcs.rs b/cargo-fix/src/vcs.rs index a35d57adc..53a0d95f2 100644 --- a/cargo-fix/src/vcs.rs +++ b/cargo-fix/src/vcs.rs @@ -1,5 +1,6 @@ use failure::{err_msg, Error, ResultExt}; use std::env; +use std::process::Command; pub enum VersionControl { Git, @@ -30,6 +31,29 @@ impl VersionControl { _ => true, } } + + pub fn is_dirty(&self) -> Result { + let (program, args) = match *self { + VersionControl::Git => ("git", "status --short"), + VersionControl::Hg => ("hg", "status"), + VersionControl::Pijul => ("pijul", "status"), + VersionControl::Fossil => ("fossil", "changes"), + VersionControl::None => return Ok(false), + }; + + let output = Command::new(program) + .args(args.split_whitespace()) + .output()? + .stdout; + + let changes = String::from_utf8_lossy(&output); + let trimmed = changes.trim(); + if !trimmed.is_empty() { + println!("{}", trimmed); + } + + Ok(!trimmed.is_empty()) + } } fn is_in_vcs(vcs_dir: &str) -> Result<(), Error> { From 81452cbd20e5f282261e286ff5cc5f415609cffa Mon Sep 17 00:00:00 2001 From: Ezinwa Okpoechi Date: Wed, 16 May 2018 10:44:21 +0200 Subject: [PATCH 184/298] Add tests for new VCS functionality --- cargo-fix/src/cli.rs | 10 ++++-- cargo-fix/src/vcs.rs | 2 +- cargo-fix/tests/all/main.rs | 33 +++++++++++++++---- cargo-fix/tests/all/vcs.rs | 65 +++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 cargo-fix/tests/all/vcs.rs diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index f7f5abe52..8e62d8a17 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -66,12 +66,16 @@ pub fn run() -> Result<(), Error> { let version_control = VersionControl::new(); if !version_control.is_present() && !matches.is_present("allow-no-vcs") { - eprintln!("no vcs found, aborting. overwrite this behavior with --allow-no-vcs"); + eprintln!("no VCS found, aborting. overwrite this behavior with --allow-no-vcs"); process::exit(1); } - if version_control.is_present() && version_control.is_dirty()? && !matches.is_present("allow-dirty") { - eprintln!("working directory is dirty, aborting. overwrite this behavior with --allow-dirty"); + if version_control.is_present() && version_control.is_dirty()? + && !matches.is_present("allow-dirty") + { + eprintln!( + "working directory is dirty, aborting. overwrite this behavior with --allow-dirty" + ); process::exit(1); } diff --git a/cargo-fix/src/vcs.rs b/cargo-fix/src/vcs.rs index 53a0d95f2..3267828d1 100644 --- a/cargo-fix/src/vcs.rs +++ b/cargo-fix/src/vcs.rs @@ -49,7 +49,7 @@ impl VersionControl { let changes = String::from_utf8_lossy(&output); let trimmed = changes.trim(); if !trimmed.is_empty() { - println!("{}", trimmed); + eprintln!("{}", trimmed); } Ok(!trimmed.is_empty()) diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index f671c9956..3c18cac0a 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -19,6 +19,7 @@ thread_local!(static IDX: usize = CNT.fetch_add(1, Ordering::SeqCst)); struct ProjectBuilder { files: Vec<(String, String)>, + root: PathBuf, } struct Project { @@ -26,7 +27,10 @@ struct Project { } fn project() -> ProjectBuilder { - ProjectBuilder { files: Vec::new() } + ProjectBuilder { + files: Vec::new(), + root: root(), + } } fn root() -> PathBuf { @@ -42,12 +46,20 @@ fn root() -> PathBuf { } impl ProjectBuilder { - fn file(&mut self, name: &str, contents: &str) -> &mut ProjectBuilder { + fn file(mut self, name: &str, contents: &str) -> ProjectBuilder { self.files.push((name.to_string(), contents.to_string())); self } - fn build(&mut self) -> Project { + fn use_temp_dir(mut self) -> ProjectBuilder { + let mut temp_dir = env::temp_dir(); + temp_dir.push(&format!("rustfix-generated-test{}", IDX.with(|x| *x))); + + self.root = temp_dir; + self + } + + fn build(mut self) -> Project { if !self.files.iter().any(|f| f.0.ends_with("Cargo.toml")) { let manifest = r#" [package] @@ -59,17 +71,16 @@ impl ProjectBuilder { self.files .push(("Cargo.toml".to_string(), manifest.to_string())); } - let root = root(); - drop(fs::remove_dir_all(&root)); + drop(fs::remove_dir_all(&self.root)); for &(ref file, ref contents) in self.files.iter() { - let dst = root.join(file); + let dst = self.root.join(file); fs::create_dir_all(dst.parent().unwrap()).unwrap(); fs::File::create(&dst) .unwrap() .write_all(contents.as_ref()) .unwrap(); } - Project { root } + Project { root: self.root } } } @@ -100,6 +111,13 @@ impl Project { } } +impl Drop for Project { + fn drop(&mut self) { + drop(fs::remove_dir_all(&self.root)); + drop(fs::remove_dir(&self.root)); + } +} + struct ExpectCmd<'a> { ran: bool, project: &'a Project, @@ -321,4 +339,5 @@ mod dependencies; mod edition_upgrade; mod smoke; mod subtargets; +mod vcs; mod warnings; diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs new file mode 100644 index 000000000..1e6be4552 --- /dev/null +++ b/cargo-fix/tests/all/vcs.rs @@ -0,0 +1,65 @@ +use super::project; + +#[test] +fn warns_if_no_vcs_detected() { + let p = project() + .use_temp_dir() + .file( + "src/lib.rs", + r#" + pub fn foo() { + } + "#, + ) + .build(); + + p.expect_cmd("cargo-fix fix") + .stderr("no VCS found, aborting. overwrite this behavior with --allow-no-vcs") + .status(1) + .run(); + p.expect_cmd("cargo-fix fix --allow-no-vcs").status(0).run(); +} + +#[test] +fn warns_about_dirty_working_directory() { + let p = project() + .file( + "src/lib.rs", + r#" + pub fn foo() { + } + "#, + ) + .build(); + + p.expect_cmd("git init").run(); + p.expect_cmd("cargo-fix fix") + .stderr( + "?? Cargo.toml\n\ + ?? src/\n\ + working directory is dirty, aborting. overwrite this behavior with --allow-dirty", + ) + .status(1) + .run(); + p.expect_cmd("cargo-fix fix --allow-dirty").status(0).run(); +} + +#[test] +fn does_not_warn_about_clean_working_directory() { + let p = project() + .file( + "src/lib.rs", + r#" + pub fn foo() { + } + "#, + ) + .build(); + + p.expect_cmd("git init").run(); + p.expect_cmd("git add .").run(); + p.expect_cmd("git config user.email rustfix@rustlang.org").run(); + p.expect_cmd("git config user.name RustFix").run(); + p.expect_cmd("git commit -m Initial-commit").run(); + p.expect_cmd("cargo-fix fix").status(0).run(); +} From f8025f500aaa7c32fae46d129abeaff30104cad8 Mon Sep 17 00:00:00 2001 From: Ezinwa Okpoechi Date: Thu, 17 May 2018 11:26:20 +0200 Subject: [PATCH 185/298] Remove rustup-init.exe to fix appveyor tests --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index 1a31de483..34e2e31ff 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,6 +8,7 @@ install: - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -V - cargo -V + - del rustup-init.exe build: false From 6810c7f2a89533ea41fd016cf0f415e78cbfa956 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 18 May 2018 08:41:50 -0700 Subject: [PATCH 186/298] Add special case for empty string --- proptest-regressions/replace.txt | 8 ++++++++ src/replace.rs | 34 +++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 proptest-regressions/replace.txt diff --git a/proptest-regressions/replace.txt b/proptest-regressions/replace.txt new file mode 100644 index 000000000..fc5bd1a8b --- /dev/null +++ b/proptest-regressions/replace.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 358148376 3634975642 2528447681 3675516813 # shrinks to ref s = "" +xs 3127423015 3362740891 2605681441 2390162043 # shrinks to ref data = "", ref replacements = [(0..0, [])] diff --git a/src/replace.rs b/src/replace.rs index 664334e4d..e78bec9d6 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -12,6 +12,16 @@ enum State { Inserted(Rc<[u8]>), } +impl State { + fn is_inserted(&self) -> bool { + if let &State::Inserted(..) = self { + true + } else { + false + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] struct Span { /// Start of this span in parent data @@ -37,7 +47,7 @@ impl Data { Span { data: State::Initial, start: 0, - end: data.len() - 1, + end: data.len().saturating_sub(1), }, ], } @@ -45,6 +55,10 @@ impl Data { /// Render this data as a vector of bytes pub fn to_vec(&self) -> Vec { + if self.original.is_empty() { + return Vec::new(); + } + self.parts.iter().fold(Vec::new(), |mut acc, d| { match d.data { State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), @@ -91,18 +105,10 @@ impl Data { // the whole chunk. As an optimization and without loss of generality we // don't add empty parts. let new_parts = { - let is_inserted = |state| { - if let &State::Inserted(..) = state { - true - } else { - false - } - }; - let index_of_part_to_split = self.parts .iter() .position(|p| { - !is_inserted(&p.data) && p.start <= from && p.end >= up_to_and_including + !p.data.is_inserted() && p.start <= from && p.end >= up_to_and_including }) .ok_or_else(|| { use log::Level::Debug; @@ -152,7 +158,7 @@ impl Data { if from > part_to_split.start { new_parts.push(Span { start: part_to_split.start, - end: from - 1, + end: from.saturating_sub(1), data: State::Initial, }); } @@ -247,6 +253,12 @@ mod tests { assert!(d.replace_range(0, 2, b"bar").is_ok()); } + #[test] + fn empty_to_vec_roundtrip() { + let s = ""; + assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice()); + } + #[test] #[should_panic(expected = "Cannot replace slice of data that was already replaced")] fn replace_overlapping_stuff_errs() { From 114bdc7c01ec38634ea84f0809ea18877b625345 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 18:30:14 +0200 Subject: [PATCH 187/298] Fix warnings in test --- tests/parse_and_replace.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index f3ec444b9..541c3056d 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -15,7 +15,7 @@ use std::collections::HashSet; use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::Output; -use std::{env, fs}; +use std::fs; use failure::{Error, ResultExt}; use tempdir::TempDir; @@ -32,9 +32,6 @@ mod settings { pub const CHECK_JSON: &str = "RUSTFIX_TEST_CHECK_JSON"; pub const RECORD_JSON: &str = "RUSTFIX_TEST_RECORD_JSON"; pub const RECORD_FIXED_RUST: &str = "RUSTFIX_TEST_RECORD_FIXED_RUST"; - - // set automatically - pub const MODE: &str = "RUSTFIX_MODE"; } fn compile(file: &Path, mode: &str) -> Result { @@ -125,15 +122,15 @@ fn diff(expected: &str, actual: &str) -> String { write!( &mut res, "differences found (+ == actual, - == expected):\n" - ); + ).unwrap(); different = true; } for diff in diff.lines() { - writeln!(&mut res, "{} {}", prefix, diff); + writeln!(&mut res, "{} {}", prefix, diff).unwrap(); } } if different { - write!(&mut res, ""); + write!(&mut res, "").unwrap(); } res From 5583b1a68e397db7f16988460287a4a75c2b996c Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 19:38:43 +0200 Subject: [PATCH 188/298] Uppercase some abbreviations --- cargo-fix/src/cli.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 8e62d8a17..7b34e70ef 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -46,7 +46,7 @@ pub fn run() -> Result<(), Error> { .arg( Arg::with_name("allow-no-vcs") .long("allow-no-vcs") - .help("Fix code even if a vcs was not detected"), + .help("Fix code even if a VCS was not detected"), ) .arg( Arg::with_name("allow-dirty") @@ -57,7 +57,7 @@ pub fn run() -> Result<(), Error> { .get_matches(); let matches = match matches.subcommand() { ("fix", Some(matches)) => matches, - _ => bail!("unknown cli arguments passed"), + _ => bail!("unknown CLI arguments passed"), }; if matches.is_present("broken-code") { From cbfc26cbbe09397766db8a4d13a66038d149082c Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 19:40:11 +0200 Subject: [PATCH 189/298] Refactor diagnostics code Moving more stuff to the diagnostics module to make it easily reusable. --- cargo-fix/src/cli.rs | 24 +++++------------------- cargo-fix/src/diagnostics.rs | 36 +++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 7b34e70ef..660d8f23c 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -4,10 +4,10 @@ use std::process::{self, Command}; use clap::{App, AppSettings, Arg, SubCommand}; use failure::{Error, ResultExt}; -use termcolor::{Color, ColorSpec, StandardStream, WriteColor}; +use termcolor::{ColorSpec, StandardStream, WriteColor}; use super::exit_with; -use diagnostics::{Message, Server}; +use diagnostics::{self, log_for_human, output_stream, write_warning, Message}; use lock; use vcs::VersionControl; @@ -152,11 +152,9 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> ref file, ref message, } => { - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; - write!(stream, "warning")?; - stream.reset()?; + write_warning(stream)?; stream.set_color(ColorSpec::new().set_bold(true))?; - write!(stream, ": error applying suggestions to `{}`\n", file)?; + write!(stream, "error applying suggestions to `{}`\n", file)?; stream.reset()?; write!(stream, "The full error message was:\n\n> {}\n\n", message)?; stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; @@ -165,11 +163,8 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> ref files, ref krate, } => { - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; - write!(stream, "warning")?; - stream.reset()?; + write_warning(stream)?; stream.set_color(ColorSpec::new().set_bold(true))?; - write!(stream, ": ")?; if let Some(ref krate) = *krate { write!( stream, @@ -202,12 +197,3 @@ fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> stream.flush()?; Ok(()) } - -fn log_for_human(kind: &str, msg: &str, stream: &mut StandardStream) -> Result<(), Error> { - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?; - // Justify to 12 chars just like cargo - write!(stream, "{:>12}", kind)?; - stream.reset()?; - write!(stream, " {}\n", msg)?; - Ok(()) -} diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs index 93fc4be1c..9a919801a 100644 --- a/cargo-fix/src/diagnostics.rs +++ b/cargo-fix/src/diagnostics.rs @@ -9,7 +9,7 @@ use std::thread::{self, JoinHandle}; use atty; use failure::{Error, ResultExt}; use serde_json; -use termcolor::{ColorChoice, StandardStream}; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; @@ -96,12 +96,7 @@ impl Server { where F: Fn(Message, &mut StandardStream), { - let color_choice = if atty::is(atty::Stream::Stderr) { - ColorChoice::Auto - } else { - ColorChoice::Never - }; - let mut stream = StandardStream::stderr(color_choice); + let mut stream = output_stream(); while let Ok((client, _)) = self.listener.accept() { let mut client = BufReader::new(client); match serde_json::from_reader(client) { @@ -119,3 +114,30 @@ impl Drop for StartedServer { drop(self.thread.take().unwrap().join()); } } + +pub fn output_stream() -> StandardStream { + let color_choice = if atty::is(atty::Stream::Stderr) { + ColorChoice::Auto + } else { + ColorChoice::Never + }; + StandardStream::stderr(color_choice) +} + +pub fn write_warning(stream: &mut StandardStream) -> Result<(), Error> { + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; + write!(stream, "warning")?; + stream.reset()?; + stream.set_color(ColorSpec::new().set_bold(true))?; + write!(stream, ": ")?; + Ok(()) +} + +pub fn log_for_human(kind: &str, msg: &str, stream: &mut StandardStream) -> Result<(), Error> { + stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?; + // Justify to 12 chars just like cargo + write!(stream, "{:>12}", kind)?; + stream.reset()?; + write!(stream, " {}\n", msg)?; + Ok(()) +} From 7c363fc4e515e6f4b848090b99ef5bfdf8036bcd Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 19:41:07 +0200 Subject: [PATCH 190/298] Reformat error output Aligns style of error output with rustc --- cargo-fix/src/main.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index d9c8ad4a5..07ef19fd8 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -21,8 +21,9 @@ use std::str; use failure::{Error, ResultExt}; use rustfix::diagnostics::Diagnostic; +use termcolor::{ColorSpec, WriteColor, Color}; -use diagnostics::Message; +use diagnostics::{Message, output_stream}; mod cli; mod diagnostics; @@ -42,7 +43,14 @@ fn main() { Ok(()) => return, Err(e) => e, }; - eprintln!("error: {}", err); + + let stream = &mut output_stream(); + let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red))); + write!(stream, "error").unwrap(); + let _ = stream.reset(); + let _ = stream.set_color(ColorSpec::new().set_bold(true)); + writeln!(stream, ": {}", err).unwrap(); + for cause in err.causes().skip(1) { eprintln!("\tcaused by: {}", cause); } From 13a12de71bcf74263ada8cb864bf7475abe8f034 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 19:43:34 +0200 Subject: [PATCH 191/298] Refactor VCS/dirty detection to show warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also uses new diagnostics helpers to format warnings in a consistent way and inject git/svn/hg/… status output with more context. --- cargo-fix/src/cli.rs | 67 ++++++++++++++++++++++++++++---------- cargo-fix/src/vcs.rs | 21 +++++++----- cargo-fix/tests/all/vcs.rs | 21 +++++++----- 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 660d8f23c..5c76b70a2 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -1,6 +1,6 @@ use std::env; use std::io::Write; -use std::process::{self, Command}; +use std::process::Command; use clap::{App, AppSettings, Arg, SubCommand}; use failure::{Error, ResultExt}; @@ -55,6 +55,7 @@ pub fn run() -> Result<(), Error> { ), ) .get_matches(); + let matches = match matches.subcommand() { ("fix", Some(matches)) => matches, _ => bail!("unknown CLI arguments passed"), @@ -64,28 +65,15 @@ pub fn run() -> Result<(), Error> { env::set_var("__CARGO_FIX_BROKEN_CODE", "1"); } - let version_control = VersionControl::new(); - if !version_control.is_present() && !matches.is_present("allow-no-vcs") { - eprintln!("no VCS found, aborting. overwrite this behavior with --allow-no-vcs"); - process::exit(1); - } - - if version_control.is_present() && version_control.is_dirty()? - && !matches.is_present("allow-dirty") - { - eprintln!( - "working directory is dirty, aborting. overwrite this behavior with --allow-dirty" - ); - process::exit(1); - } + check_version_control(matches)?; // Spin up our lock server which our subprocesses will use to synchronize // fixes. - let _lockserver = lock::Server::new()?.start()?; + let _lock_server = lock::Server::new()?.start()?; // Spin up our diagnostics server which our subprocesses will use to send // use their dignostics messages in an ordered way. - let _lockserver = Server::new()?.start(|m, stream| { + let _diagnostics_server = diagnostics::Server::new()?.start(|m, stream| { if let Err(e) = log_message(&m, stream) { warn!("failed to log message: {}", e); } @@ -124,11 +112,54 @@ pub fn run() -> Result<(), Error> { // // TODO: we probably want to do something fancy here like collect results // from the client processes and print out a summary of what happened. - let status = cmd.status() + let status = cmd + .status() .with_context(|e| format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e))?; exit_with(status); } +fn check_version_control(matches: &::clap::ArgMatches) -> Result<(), Error> { + // Useful for tests + if env::var("__CARGO_FIX_IGNORE_VCS").is_ok() { + return Ok(()); + } + + let version_control = VersionControl::new(); + match (version_control.is_present(), version_control.is_dirty()?) { + (true, None) => {} // clean and versioned slate + (false, _) => { + let stream = &mut output_stream(); + + write_warning(stream)?; + stream.set_color(ColorSpec::new().set_bold(true))?; + writeln!(stream, "Could not detect a version control system")?; + stream.reset()?; + writeln!(stream, "You should consider using a VCS so you can easily see and revert rustfix' changes.")?; + + if !matches.is_present("allow-no-vcs") { + bail!("No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`."); + } + } + (true, Some(output)) => { + let stream = &mut output_stream(); + + write_warning(stream)?; + stream.set_color(ColorSpec::new().set_bold(true))?; + writeln!(stream, "Working directory dirty")?; + stream.reset()?; + writeln!(stream, "Make sure your working directory is clean so you can easily revert rustfix' changes.")?; + + stream.write_all(&output)?; + + if !matches.is_present("allow-dirty") { + bail!("Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`."); + } + } + } + + Ok(()) +} + fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> { use diagnostics::Message::*; diff --git a/cargo-fix/src/vcs.rs b/cargo-fix/src/vcs.rs index 3267828d1..85f9d589b 100644 --- a/cargo-fix/src/vcs.rs +++ b/cargo-fix/src/vcs.rs @@ -32,13 +32,20 @@ impl VersionControl { } } - pub fn is_dirty(&self) -> Result { + /// Check if working tree is dirty + /// + /// # Returns + /// + /// - `Err(error)`: anything went wrong + /// - `Ok(None)`: No changes + /// - `Ok(bytes)`: Changes (bytes are VCS's output) + pub fn is_dirty(&self) -> Result>, Error> { let (program, args) = match *self { VersionControl::Git => ("git", "status --short"), VersionControl::Hg => ("hg", "status"), VersionControl::Pijul => ("pijul", "status"), VersionControl::Fossil => ("fossil", "changes"), - VersionControl::None => return Ok(false), + VersionControl::None => return Ok(None), }; let output = Command::new(program) @@ -46,13 +53,11 @@ impl VersionControl { .output()? .stdout; - let changes = String::from_utf8_lossy(&output); - let trimmed = changes.trim(); - if !trimmed.is_empty() { - eprintln!("{}", trimmed); + if output.is_empty() { + Ok(None) + } else { + Ok(Some(output)) } - - Ok(!trimmed.is_empty()) } } diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs index 1e6be4552..4faef351b 100644 --- a/cargo-fix/tests/all/vcs.rs +++ b/cargo-fix/tests/all/vcs.rs @@ -14,10 +14,13 @@ fn warns_if_no_vcs_detected() { .build(); p.expect_cmd("cargo-fix fix") - .stderr("no VCS found, aborting. overwrite this behavior with --allow-no-vcs") - .status(1) + .stderr( + "warning: Could not detect a version control system\n\ + You should consider using a VCS so you can easily see and revert rustfix' changes.\n\ + error: No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`.\n\ + ", + ) .run(); - p.expect_cmd("cargo-fix fix --allow-no-vcs").status(0).run(); } #[test] @@ -35,11 +38,12 @@ fn warns_about_dirty_working_directory() { p.expect_cmd("git init").run(); p.expect_cmd("cargo-fix fix") .stderr( - "?? Cargo.toml\n\ - ?? src/\n\ - working directory is dirty, aborting. overwrite this behavior with --allow-dirty", + "warning: Working directory dirty\n\ + Make sure your working directory is clean so you can easily revert rustfix' changes.\n\ + ?? Cargo.toml\n\ + ?? src/\n\ + error: Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`.\n\n", ) - .status(1) .run(); p.expect_cmd("cargo-fix fix --allow-dirty").status(0).run(); } @@ -58,7 +62,8 @@ fn does_not_warn_about_clean_working_directory() { p.expect_cmd("git init").run(); p.expect_cmd("git add .").run(); - p.expect_cmd("git config user.email rustfix@rustlang.org").run(); + p.expect_cmd("git config user.email rustfix@rustlang.org") + .run(); p.expect_cmd("git config user.name RustFix").run(); p.expect_cmd("git commit -m Initial-commit").run(); p.expect_cmd("cargo-fix fix").status(0).run(); From 2f7a051eda3c01c579d9daf4b94450a3b1159868 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 20:17:43 +0200 Subject: [PATCH 192/298] Default tests to ignore dirty working dir Because the integration tests live somewhere deep inside our repo, they still detect that they are in a git repo and during development error out with "working dir dirty" (or at least warn). This is not a problem with the VCS tests, as they set up a repo explicitly. --- cargo-fix/tests/all/main.rs | 11 +++++++++++ cargo-fix/tests/all/vcs.rs | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 3c18cac0a..8007139aa 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -95,6 +95,7 @@ impl Project { stderr: None, stderr_contains: Vec::new(), stderr_not_contains: Vec::new(), + check_vcs: false, status: 0, ran: false, cwd: None, @@ -128,6 +129,7 @@ struct ExpectCmd<'a> { stderr: Option, stderr_contains: Vec, stderr_not_contains: Vec, + check_vcs: bool, status: i32, cwd: Option, } @@ -169,6 +171,11 @@ impl<'a> ExpectCmd<'a> { self } + fn check_vcs(&mut self, b: bool) -> &mut Self { + self.check_vcs = b; + self + } + fn run(&mut self) { self.ran = true; let mut parts = self.cmd.split_whitespace(); @@ -196,6 +203,10 @@ impl<'a> ExpectCmd<'a> { new_path.extend(env::split_paths(&env::var_os("PATH").unwrap_or(Default::default()))); cmd.env("PATH", env::join_paths(&new_path).unwrap()); + if !self.check_vcs { + cmd.env("__CARGO_FIX_IGNORE_VCS", "true"); + } + println!("\n···················································"); println!("running {:?}", cmd); let start = Instant::now(); diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs index 4faef351b..7e6fa5d86 100644 --- a/cargo-fix/tests/all/vcs.rs +++ b/cargo-fix/tests/all/vcs.rs @@ -14,13 +14,16 @@ fn warns_if_no_vcs_detected() { .build(); p.expect_cmd("cargo-fix fix") + .check_vcs(true) .stderr( "warning: Could not detect a version control system\n\ You should consider using a VCS so you can easily see and revert rustfix' changes.\n\ error: No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`.\n\ ", ) + .status(102) .run(); + p.expect_cmd("cargo-fix fix").status(0).run(); } #[test] @@ -37,6 +40,7 @@ fn warns_about_dirty_working_directory() { p.expect_cmd("git init").run(); p.expect_cmd("cargo-fix fix") + .check_vcs(true) .stderr( "warning: Working directory dirty\n\ Make sure your working directory is clean so you can easily revert rustfix' changes.\n\ @@ -44,6 +48,7 @@ fn warns_about_dirty_working_directory() { ?? src/\n\ error: Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`.\n\n", ) + .status(102) .run(); p.expect_cmd("cargo-fix fix --allow-dirty").status(0).run(); } @@ -66,5 +71,5 @@ fn does_not_warn_about_clean_working_directory() { .run(); p.expect_cmd("git config user.name RustFix").run(); p.expect_cmd("git commit -m Initial-commit").run(); - p.expect_cmd("cargo-fix fix").status(0).run(); + p.expect_cmd("cargo-fix fix").check_vcs(true).status(0).run(); } From f09ed1759dda1675d3f06365eb94ad4481a498b7 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 18 May 2018 09:33:46 -0700 Subject: [PATCH 193/298] Skip suggestions with multiple options --- src/lib.rs | 6 +- .../skip-multi-option-lints.fixed.rs | 5 + tests/everything/skip-multi-option-lints.json | 100 ++++++++++++++++++ tests/everything/skip-multi-option-lints.rs | 5 + 4 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 tests/everything/skip-multi-option-lints.fixed.rs create mode 100644 tests/everything/skip-multi-option-lints.json create mode 100644 tests/everything/skip-multi-option-lints.rs diff --git a/src/lib.rs b/src/lib.rs index d514a7615..d3f3c6611 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,13 +166,13 @@ pub fn collect_suggestions( .iter() .filter_map(|child| { let replacements: Vec<_> = child.spans.iter().filter_map(collect_span).collect(); - if replacements.is_empty() { - None - } else { + if replacements.len() == 1 { Some(Solution { message: child.message.clone(), replacements, }) + } else { + None } }) .collect(); diff --git a/tests/everything/skip-multi-option-lints.fixed.rs b/tests/everything/skip-multi-option-lints.fixed.rs new file mode 100644 index 000000000..9e1237188 --- /dev/null +++ b/tests/everything/skip-multi-option-lints.fixed.rs @@ -0,0 +1,5 @@ +fn main() { + let xs = vec![String::from("foo")]; + let d: &Display = &xs; + println!("{}", d); +} diff --git a/tests/everything/skip-multi-option-lints.json b/tests/everything/skip-multi-option-lints.json new file mode 100644 index 000000000..dc61ae6fb --- /dev/null +++ b/tests/everything/skip-multi-option-lints.json @@ -0,0 +1,100 @@ +{ + "message": "cannot find type `Display` in this scope", + "code": { + "code": "E0412", + "explanation": "\nThe type name used is not in scope.\n\nErroneous code examples:\n\n```compile_fail,E0412\nimpl Something {} // error: type name `Something` is not in scope\n\n// or:\n\ntrait Foo {\n fn bar(N); // error: type name `N` is not in scope\n}\n\n// or:\n\nfn foo(x: T) {} // type name `T` is not in scope\n```\n\nTo fix this error, please verify you didn't misspell the type name, you did\ndeclare it or imported it into the scope. Examples:\n\n```\nstruct Something;\n\nimpl Something {} // ok!\n\n// or:\n\ntrait Foo {\n type N;\n\n fn bar(_: Self::N); // ok!\n}\n\n// or:\n\nfn foo(x: T) {} // ok!\n```\n\nAnother case that causes this error is when a type is imported into a parent\nmodule. To fix this, you can follow the suggestion and use File directly or\n`use super::File;` which will import the types from the parent namespace. An\nexample that causes this error is below:\n\n```compile_fail,E0412\nuse std::fs::File;\n\nmod foo {\n fn some_function(f: File) {}\n}\n```\n\n```\nuse std::fs::File;\n\nmod foo {\n // either\n use super::File;\n // or\n // use std::fs::File;\n fn foo(f: File) {}\n}\n# fn main() {} // don't insert it for us; that'll break imports\n```\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 64, + "byte_end": 71, + "line_start": 3, + "line_end": 3, + "column_start": 13, + "column_end": 20, + "is_primary": true, + "text": [ + { + "text": " let d: &Display = &xs;", + "highlight_start": 13, + "highlight_end": 20 + } + ], + "label": "not found in this scope", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "possible candidates are found in other modules, you can import them into scope", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 1, + "line_end": 1, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::fmt::Display;\n\n", + "suggestion_applicability": "Unspecified", + "expansion": null + }, + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 1, + "line_end": 1, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::path::Display;\n\n", + "suggestion_applicability": "Unspecified", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0412]: cannot find type `Display` in this scope\n --> ./tests/everything/skip-multi-option-lints.rs:3:13\n |\n3 | let d: &Display = &xs;\n | ^^^^^^^ not found in this scope\nhelp: possible candidates are found in other modules, you can import them into scope\n |\n1 | use std::fmt::Display;\n |\n1 | use std::path::Display;\n |\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} +{ + "message": "For more information about this error, try `rustc --explain E0412`.", + "code": null, + "level": "", + "spans": [], + "children": [], + "rendered": "For more information about this error, try `rustc --explain E0412`.\n" +} diff --git a/tests/everything/skip-multi-option-lints.rs b/tests/everything/skip-multi-option-lints.rs new file mode 100644 index 000000000..9e1237188 --- /dev/null +++ b/tests/everything/skip-multi-option-lints.rs @@ -0,0 +1,5 @@ +fn main() { + let xs = vec![String::from("foo")]; + let d: &Display = &xs; + println!("{}", d); +} From e6f1ace4b55506c78c2bad022107bbc1c403c9c1 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 18 May 2018 12:22:02 -0700 Subject: [PATCH 194/298] Add new edge_cases test --- .../skip-multi-option-lints.fixed.rs | 0 .../skip-multi-option-lints.json | 0 .../skip-multi-option-lints.rs | 0 tests/edge_cases.rs | 10 ++++++++++ 4 files changed, 10 insertions(+) rename tests/{everything => edge-cases}/skip-multi-option-lints.fixed.rs (100%) rename tests/{everything => edge-cases}/skip-multi-option-lints.json (100%) rename tests/{everything => edge-cases}/skip-multi-option-lints.rs (100%) create mode 100644 tests/edge_cases.rs diff --git a/tests/everything/skip-multi-option-lints.fixed.rs b/tests/edge-cases/skip-multi-option-lints.fixed.rs similarity index 100% rename from tests/everything/skip-multi-option-lints.fixed.rs rename to tests/edge-cases/skip-multi-option-lints.fixed.rs diff --git a/tests/everything/skip-multi-option-lints.json b/tests/edge-cases/skip-multi-option-lints.json similarity index 100% rename from tests/everything/skip-multi-option-lints.json rename to tests/edge-cases/skip-multi-option-lints.json diff --git a/tests/everything/skip-multi-option-lints.rs b/tests/edge-cases/skip-multi-option-lints.rs similarity index 100% rename from tests/everything/skip-multi-option-lints.rs rename to tests/edge-cases/skip-multi-option-lints.rs diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs new file mode 100644 index 000000000..39aecb2fb --- /dev/null +++ b/tests/edge_cases.rs @@ -0,0 +1,10 @@ +extern crate rustfix; +use std::collections::HashSet; +use std::fs; + +#[test] +fn multiple_fix_options_yield_no_suggestions() { + let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); + let expected_suggestions = rustfix::get_suggestions_from_json(&json, &HashSet::new()).unwrap(); + assert!(expected_suggestions.is_empty()); +} From 1d920330c12e8d2dd46a72c99987e679854eafab Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 18 May 2018 13:34:26 -0700 Subject: [PATCH 195/298] Dont pass RUST_LOG to rustc subprocess in tests Setting RUST_LOG without filtering it causes integration tests to fail because it changes the output of rustc. By upgrading duct to 0.9 we get env_remove which we can use to filter out the RUST_LOG setting and not pass it down to rustc. --- Cargo.toml | 2 +- tests/parse_and_replace.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc4f35478..5461f3df1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ failure = "0.1.1" log = "0.4.1" [dev-dependencies] -duct = "0.8.2" +duct = "0.9" env_logger = "0.5.0-rc.1" log = "0.4.1" tempdir = "0.3.5" diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 541c3056d..9fd3357fe 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -13,9 +13,9 @@ extern crate difference; use std::collections::HashSet; use std::ffi::OsString; +use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; -use std::fs; use failure::{Error, ResultExt}; use tempdir::TempDir; @@ -54,6 +54,7 @@ fn compile(file: &Path, mode: &str) -> Result { let res = duct::cmd("rustc", &args) .env("CLIPPY_DISABLE_DOCS_LINKS", "true") + .env_remove("RUST_LOG") .stdout_capture() .stderr_capture() .unchecked() From a8d0e3f1f87142aac913d2a5a97fdf89d0c28408 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 18 May 2018 22:56:17 +0200 Subject: [PATCH 196/298] Overwrite RUST_LOG env var in cargo-fix tests This prevent the std{err,out} assertions from failing because of unexpected log output. --- cargo-fix/tests/all/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 8007139aa..545799d31 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -203,6 +203,9 @@ impl<'a> ExpectCmd<'a> { new_path.extend(env::split_paths(&env::var_os("PATH").unwrap_or(Default::default()))); cmd.env("PATH", env::join_paths(&new_path).unwrap()); + // Don't output log stuff in tests, because it breaks our std{err,out} assertions + cmd.env("RUST_LOG", "warn"); + if !self.check_vcs { cmd.env("__CARGO_FIX_IGNORE_VCS", "true"); } From f6e423f9f08a7d3ae0b7cfa179e1bea7ff2dad62 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 22 May 2018 21:48:55 +0200 Subject: [PATCH 197/298] Bump rustfix to version 0.3.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5461f3df1..21faea05c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" -version = "0.3.0" +version = "0.3.1" exclude = [ "etc/*", "examples/*", From 7d5bb229c74ec4f1627be5e47a89cf20647ee431 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 23 May 2018 13:59:46 +0200 Subject: [PATCH 198/298] Add filtering by machine applicability --- cargo-fix/src/cli.rs | 3 +-- cargo-fix/src/main.rs | 10 +++++++--- cargo-fix/tests/all/broken_build.rs | 6 +++++- cargo-fix/tests/all/broken_lints.rs | 23 ++++++++++------------- cargo-fix/tests/all/dependencies.rs | 1 + cargo-fix/tests/all/edition_upgrade.rs | 3 +++ cargo-fix/tests/all/smoke.rs | 16 +++++++++++++--- cargo-fix/tests/all/subtargets.rs | 1 + cargo-fix/tests/all/vcs.rs | 5 ++++- examples/fix-json.rs | 6 +++++- src/diagnostics.rs | 9 +++++++++ src/lib.rs | 26 ++++++++++++++++++++++++-- tests/edge_cases.rs | 4 +++- tests/parse_and_replace.rs | 14 ++++++++++---- 14 files changed, 96 insertions(+), 31 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 5c76b70a2..34255ca14 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -112,8 +112,7 @@ pub fn run() -> Result<(), Error> { // // TODO: we probably want to do something fancy here like collect results // from the client processes and print out a summary of what happened. - let status = cmd - .status() + let status = cmd.status() .with_context(|e| format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e))?; exit_with(status); } diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 07ef19fd8..7f81f2f0c 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -21,9 +21,9 @@ use std::str; use failure::{Error, ResultExt}; use rustfix::diagnostics::Diagnostic; -use termcolor::{ColorSpec, WriteColor, Color}; +use termcolor::{Color, ColorSpec, WriteColor}; -use diagnostics::{Message, output_stream}; +use diagnostics::{output_stream, Message}; mod cli; mod diagnostics; @@ -174,6 +174,10 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { return Ok(Default::default()); } + let fix_mode = env::var_os("__CARGO_FIX_YOLO") + .map(|_| rustfix::Filter::Everything) + .unwrap_or(rustfix::Filter::MachineApplicableOnly); + // Sift through the output of the compiler to look for JSON messages // indicating fixes that we can apply. let stderr = str::from_utf8(&output.stderr).context("failed to parse rustc stderr as utf-8")?; @@ -185,7 +189,7 @@ fn rustfix_crate(rustc: &Path, filename: &str) -> Result { .filter_map(|line| serde_json::from_str::(line).ok()) // From each diagnostic try to extract suggestions from rustc - .filter_map(|diag| rustfix::collect_suggestions(&diag, &only)); + .filter_map(|diag| rustfix::collect_suggestions(&diag, &only, fix_mode)); // Collect suggestions by file so we can apply them one at a time later. let mut file_map = HashMap::new(); diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index b10da856e..7329d575a 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -36,7 +36,10 @@ fn fix_broken_if_requested() { ) .build(); - p.expect_cmd("cargo-fix fix --broken-code").status(0).run(); + p.expect_cmd("cargo-fix fix --broken-code") + .env("__CARGO_FIX_YOLO", "true") + .status(0) + .run(); } #[test] @@ -111,6 +114,7 @@ fn broken_fixes_backed_out() { // Attempt to fix code, but our shim will always fail the second compile p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .cwd("bar") .env("RUSTC", p.root.join("foo/target/debug/foo")) .stderr_contains("not rust code") diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs index 0c939c4af..5d8622fc3 100644 --- a/cargo-fix/tests/all/broken_lints.rs +++ b/cargo-fix/tests/all/broken_lints.rs @@ -19,21 +19,18 @@ // .build(); // p.expect_cmd("cargo-fix fix") +// .env("__CARGO_FIX_YOLO", "true") // .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") // .stderr_contains("The full error message was:") -// .stderr_contains( -// "> Could not replace range 56...60 in file -- maybe parts of it were already replaced?", -// ) -// .stderr_contains( -// "\ -// This likely indicates a bug in either rustc or rustfix itself,\n\ -// and we would appreciate a bug report! You're likely to see \n\ -// a number of compiler warnings after this message which rustfix\n\ -// attempted to fix but failed. If you could open an issue at\n\ -// https://github.com/rust-lang-nursery/rustfix/issues\n\ -// quoting the full output of this command we'd be very appreciative!\n\n\ -// ", -// ) +// .stderr_contains("> Could not replace range 56...60 in file -- maybe parts of it were already replaced?") +// .stderr_contains("\ +// This likely indicates a bug in either rustc or rustfix itself,\n\ +// and we would appreciate a bug report! You're likely to see \n\ +// a number of compiler warnings after this message which rustfix\n\ +// attempted to fix but failed. If you could open an issue at\n\ +// https://github.com/rust-lang-nursery/rustfix/issues\n\ +// quoting the full output of this command we'd be very appreciative!\n\n\ +// ") // .status(0) // .run(); // } diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index 746a2e453..373e5a909 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -54,6 +54,7 @@ fn fix_path_deps() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index f66e7f013..4d5473b9b 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -72,6 +72,7 @@ fn local_paths() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix --prepare-for 2018") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -104,6 +105,7 @@ fn local_paths_no_fix() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix --prepare-for 2018") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -161,6 +163,7 @@ fn upgrade_extern_crate() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index c3a0974f6..af568a87c 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -34,6 +34,7 @@ fn fixes_extra_mut() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -60,6 +61,7 @@ fn fixes_two_missing_ampersands() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -85,6 +87,7 @@ fn tricky() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -102,7 +105,9 @@ fn preserve_line_endings() { ) .build(); - p.expect_cmd("cargo-fix fix").run(); + p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") + .run(); assert!(p.read("src/lib.rs").contains("\r\n")); } @@ -118,7 +123,9 @@ fn fix_deny_warnings() { ) .build(); - p.expect_cmd("cargo-fix fix").run(); + p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") + .run(); } #[test] @@ -139,7 +146,9 @@ fn fix_deny_warnings_but_not_others() { ) .build(); - p.expect_cmd("cargo-fix fix").run(); + p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") + .run(); assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); assert!(p.read("src/lib.rs").contains("fn bar() {}")); } @@ -170,6 +179,7 @@ fn fix_two_files() { .build(); p.expect_cmd("cargo-fix fix") + .env("__CARGO_FIX_YOLO", "true") .stderr_contains("[FIXING] src/bar.rs (1 fix)") .stderr_contains("[FIXING] src/lib.rs (1 fix)") .run(); diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index e51bec7a3..b856bda7c 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -40,6 +40,7 @@ fn fixes_missing_ampersand() { .build(); p.expect_cmd("cargo fix -- --all-targets") + .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr_contains("[COMPILING] foo v0.1.0 (CWD)") .stderr_contains("[FIXING] build.rs (1 fix)") diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs index 7e6fa5d86..e045b20aa 100644 --- a/cargo-fix/tests/all/vcs.rs +++ b/cargo-fix/tests/all/vcs.rs @@ -71,5 +71,8 @@ fn does_not_warn_about_clean_working_directory() { .run(); p.expect_cmd("git config user.name RustFix").run(); p.expect_cmd("git commit -m Initial-commit").run(); - p.expect_cmd("cargo-fix fix").check_vcs(true).status(0).run(); + p.expect_cmd("cargo-fix fix") + .check_vcs(true) + .status(0) + .run(); } diff --git a/examples/fix-json.rs b/examples/fix-json.rs index e90cc3eab..b9554856f 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -15,7 +15,11 @@ fn main() -> Result<(), Error> { }; let suggestions = fs::read_to_string(&suggestions_file)?; - let suggestions = rustfix::get_suggestions_from_json(&suggestions, &HashSet::new())?; + let suggestions = rustfix::get_suggestions_from_json( + &suggestions, + &HashSet::new(), + rustfix::Filter::Everything, + )?; let source = fs::read_to_string(&source_file)?; diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a0fe9fe44..e507d568d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -41,10 +41,19 @@ pub struct DiagnosticSpan { /// load the fully rendered version from the parent `Diagnostic`, /// however. pub suggested_replacement: Option, + pub suggestion_applicability: Option, /// Macro invocations that created the code at this span, if any. expansion: Option>, } +#[derive(Copy, Clone, Debug, PartialEq, Deserialize)] +pub enum Applicability { + MachineApplicable, + HasPlaceholders, + MaybeIncorrect, + Unspecified, +} + #[derive(Deserialize, Debug)] pub struct DiagnosticSpanLine { pub text: String, diff --git a/src/lib.rs b/src/lib.rs index d3f3c6611..bb8c837bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,21 @@ pub mod diagnostics; use diagnostics::{Diagnostic, DiagnosticSpan}; mod replace; +#[derive(Debug, Clone, Copy)] +pub enum Filter { + MachineApplicableOnly, + Everything, +} + pub fn get_suggestions_from_json( input: &str, only: &HashSet, + filter: Filter, ) -> serde_json::error::Result> { let mut result = Vec::new(); for cargo_msg in serde_json::Deserializer::from_str(input).into_iter::() { // One diagnostic line might have multiple suggestions - result.extend(collect_suggestions(&cargo_msg?, only)); + result.extend(collect_suggestions(&cargo_msg?, only, filter)); } Ok(result) } @@ -142,6 +149,7 @@ fn collect_span(span: &DiagnosticSpan) -> Option { pub fn collect_suggestions( diagnostic: &Diagnostic, only: &HashSet, + filter: Filter, ) -> Option { if !only.is_empty() { if let Some(ref code) = diagnostic.code { @@ -165,7 +173,21 @@ pub fn collect_suggestions( .children .iter() .filter_map(|child| { - let replacements: Vec<_> = child.spans.iter().filter_map(collect_span).collect(); + let replacements: Vec<_> = child + .spans + .iter() + .filter(|span| { + use Filter::*; + use diagnostics::Applicability::*; + + match (filter, &span.suggestion_applicability) { + (MachineApplicableOnly, Some(MachineApplicable)) => true, + (MachineApplicableOnly, _) => false, + (_, _) => true, + } + }) + .filter_map(collect_span) + .collect(); if replacements.len() == 1 { Some(Solution { message: child.message.clone(), diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 39aecb2fb..88489889d 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -5,6 +5,8 @@ use std::fs; #[test] fn multiple_fix_options_yield_no_suggestions() { let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); - let expected_suggestions = rustfix::get_suggestions_from_json(&json, &HashSet::new()).unwrap(); + let expected_suggestions = + rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) + .unwrap(); assert!(expected_suggestions.is_empty()); } diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 9fd3357fe..cc361cbc9 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -43,7 +43,6 @@ fn compile(file: &Path, mode: &str) -> Result { "-Zunstable-options".into(), "--emit=metadata".into(), "--crate-name=rustfix_test".into(), - "-Zsuggestion-applicability".into(), "--out-dir".into(), tmp.path().into(), ]; @@ -142,12 +141,19 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err let json_file = file.with_extension("json"); let fixed_file = file.with_extension("fixed.rs"); + let filter_suggestions = if mode == fixmode::EVERYTHING { + rustfix::Filter::Everything + } else { + rustfix::Filter::MachineApplicableOnly + }; + debug!("next up: {:?}", file); let code = read_file(file).context(format!("could not read {}", file.display()))?; let errors = compile_and_get_json_errors(file, mode) .context(format!("could compile {}", file.display()))?; - let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()) - .context("could not load suggestions")?; + let suggestions = + rustfix::get_suggestions_from_json(&errors, &HashSet::new(), filter_suggestions) + .context("could not load suggestions")?; if std::env::var(settings::RECORD_JSON).is_ok() { use std::io::Write; @@ -163,7 +169,7 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err file.display() ))?; let expected_suggestions = - rustfix::get_suggestions_from_json(&expected_json, &HashSet::new()) + rustfix::get_suggestions_from_json(&expected_json, &HashSet::new(), filter_suggestions) .context("could not load expected suggesitons")?; ensure!( From 2eaaa757d2ee57a599cd8b3c7b0be5f18ec313d5 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 23 May 2018 16:33:09 +0200 Subject: [PATCH 199/298] Address review feedback --- cargo-fix/tests/all/edition_upgrade.rs | 2 -- src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index 4d5473b9b..fd68f0409 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -72,7 +72,6 @@ fn local_paths() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix --prepare-for 2018") - .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); @@ -105,7 +104,6 @@ fn local_paths_no_fix() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix --prepare-for 2018") - .env("__CARGO_FIX_YOLO", "true") .stdout("") .stderr(stderr) .run(); diff --git a/src/lib.rs b/src/lib.rs index bb8c837bb..c109ef7e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -183,7 +183,7 @@ pub fn collect_suggestions( match (filter, &span.suggestion_applicability) { (MachineApplicableOnly, Some(MachineApplicable)) => true, (MachineApplicableOnly, _) => false, - (_, _) => true, + (Everything, _) => true, } }) .filter_map(collect_span) From 5e71ec214a2ee4352901773db7e6573c3cd4a6eb Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 23 May 2018 16:57:24 +0200 Subject: [PATCH 200/298] Add a `.fix_everything()` test helper --- cargo-fix/tests/all/broken_build.rs | 4 ++-- cargo-fix/tests/all/broken_lints.rs | 2 +- cargo-fix/tests/all/dependencies.rs | 2 +- cargo-fix/tests/all/edition_upgrade.rs | 2 +- cargo-fix/tests/all/main.rs | 5 +++++ cargo-fix/tests/all/smoke.rs | 14 +++++++------- cargo-fix/tests/all/subtargets.rs | 2 +- 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs index 7329d575a..70005a95b 100644 --- a/cargo-fix/tests/all/broken_build.rs +++ b/cargo-fix/tests/all/broken_build.rs @@ -37,7 +37,7 @@ fn fix_broken_if_requested() { .build(); p.expect_cmd("cargo-fix fix --broken-code") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .status(0) .run(); } @@ -114,7 +114,7 @@ fn broken_fixes_backed_out() { // Attempt to fix code, but our shim will always fail the second compile p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .cwd("bar") .env("RUSTC", p.root.join("foo/target/debug/foo")) .stderr_contains("not rust code") diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs index 5d8622fc3..2865b2873 100644 --- a/cargo-fix/tests/all/broken_lints.rs +++ b/cargo-fix/tests/all/broken_lints.rs @@ -19,7 +19,7 @@ // .build(); // p.expect_cmd("cargo-fix fix") -// .env("__CARGO_FIX_YOLO", "true") +// .fix_everything() // .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") // .stderr_contains("The full error message was:") // .stderr_contains("> Could not replace range 56...60 in file -- maybe parts of it were already replaced?") diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs index 373e5a909..c0baeabe0 100644 --- a/cargo-fix/tests/all/dependencies.rs +++ b/cargo-fix/tests/all/dependencies.rs @@ -54,7 +54,7 @@ fn fix_path_deps() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr(stderr) .run(); diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs index fd68f0409..fbdf4a47b 100644 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ b/cargo-fix/tests/all/edition_upgrade.rs @@ -161,7 +161,7 @@ fn upgrade_extern_crate() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr(stderr) .run(); diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 545799d31..46a03c65d 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -151,6 +151,11 @@ impl<'a> ExpectCmd<'a> { self } + fn fix_everything(&mut self) -> &mut Self { + self.env("__CARGO_FIX_YOLO", "true"); + self + } + fn stdout(&mut self, s: &str) -> &mut Self { self.stdout = Some(s.to_string()); self diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index af568a87c..1514acee5 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -34,7 +34,7 @@ fn fixes_extra_mut() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr(stderr) .run(); @@ -61,7 +61,7 @@ fn fixes_two_missing_ampersands() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr(stderr) .run(); @@ -87,7 +87,7 @@ fn tricky() { [FINISHED] dev [unoptimized + debuginfo] "; p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr(stderr) .run(); @@ -106,7 +106,7 @@ fn preserve_line_endings() { .build(); p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .run(); assert!(p.read("src/lib.rs").contains("\r\n")); } @@ -124,7 +124,7 @@ fn fix_deny_warnings() { .build(); p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .run(); } @@ -147,7 +147,7 @@ fn fix_deny_warnings_but_not_others() { .build(); p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .run(); assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); assert!(p.read("src/lib.rs").contains("fn bar() {}")); @@ -179,7 +179,7 @@ fn fix_two_files() { .build(); p.expect_cmd("cargo-fix fix") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stderr_contains("[FIXING] src/bar.rs (1 fix)") .stderr_contains("[FIXING] src/lib.rs (1 fix)") .run(); diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs index b856bda7c..db8721136 100644 --- a/cargo-fix/tests/all/subtargets.rs +++ b/cargo-fix/tests/all/subtargets.rs @@ -40,7 +40,7 @@ fn fixes_missing_ampersand() { .build(); p.expect_cmd("cargo fix -- --all-targets") - .env("__CARGO_FIX_YOLO", "true") + .fix_everything() .stdout("") .stderr_contains("[COMPILING] foo v0.1.0 (CWD)") .stderr_contains("[FIXING] build.rs (1 fix)") From 28dbb436c4bce497096af5c360965ee05cb69c76 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 23 May 2018 21:07:57 +0200 Subject: [PATCH 201/298] Bum rustfix and cargo-fix to 0.4.0 --- Cargo.toml | 2 +- cargo-fix/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 21faea05c..81231a863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" -version = "0.3.1" +version = "0.4.0" exclude = [ "etc/*", "examples/*", diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index e5ca0b2c6..6183fd5ee 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-fix" -version = "0.2.0" +version = "0.4.0" authors = [ "Pascal Hertleif ", "Alex Crichton ", @@ -17,7 +17,7 @@ test = false [dependencies] failure = "0.1" -rustfix = { path = "..", version = "0.3" } +rustfix = { path = "..", version = "0.4" } serde_json = "1" log = "0.4" env_logger = { version = "0.5", default-features = false } From e3608da623c52b141effcab0a0ef7ddd8083e056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 24 May 2018 17:29:35 +0200 Subject: [PATCH 202/298] cli: fix injection of --prepare-for flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When RUSTFLAGS was set, we would previously use "§{RUSTFLAGS}-W rust-2018-compatibility" which can cause errorous invocations like "cargo fix .... -C target-cpu=native-W rust-2018-compatibility ...." if --prepare-for 2018 is used. We need an extra space to separate RUSTFLAGS and "-W rust-2018-compatibility" because we want "-C target-cpu=native -W rust-2018-compatibility". --- cargo-fix/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 34255ca14..ef1e1e917 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -104,7 +104,7 @@ pub fn run() -> Result<(), Error> { if let Some("2018") = matches.value_of("edition") { info!("edition upgrade!"); let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push("-W rust-2018-compatibility"); + rustc_flags.push(" -W rust-2018-compatibility"); cmd.env("RUSTFLAGS", &rustc_flags); } From 3b8982f220f37bdf2a394dfb4b0c16ca5e1a9411 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 2 Jun 2018 20:27:33 -0700 Subject: [PATCH 203/298] =?UTF-8?q?"rustfix'"=20=E2=86=92=20"rustfix's"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cargo-fix/src/cli.rs | 4 ++-- cargo-fix/tests/all/vcs.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs index 34255ca14..543717b49 100644 --- a/cargo-fix/src/cli.rs +++ b/cargo-fix/src/cli.rs @@ -133,7 +133,7 @@ fn check_version_control(matches: &::clap::ArgMatches) -> Result<(), Error> { stream.set_color(ColorSpec::new().set_bold(true))?; writeln!(stream, "Could not detect a version control system")?; stream.reset()?; - writeln!(stream, "You should consider using a VCS so you can easily see and revert rustfix' changes.")?; + writeln!(stream, "You should consider using a VCS so you can easily see and revert rustfix's changes.")?; if !matches.is_present("allow-no-vcs") { bail!("No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`."); @@ -146,7 +146,7 @@ fn check_version_control(matches: &::clap::ArgMatches) -> Result<(), Error> { stream.set_color(ColorSpec::new().set_bold(true))?; writeln!(stream, "Working directory dirty")?; stream.reset()?; - writeln!(stream, "Make sure your working directory is clean so you can easily revert rustfix' changes.")?; + writeln!(stream, "Make sure your working directory is clean so you can easily revert rustfix's changes.")?; stream.write_all(&output)?; diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs index e045b20aa..7f04a490e 100644 --- a/cargo-fix/tests/all/vcs.rs +++ b/cargo-fix/tests/all/vcs.rs @@ -17,7 +17,7 @@ fn warns_if_no_vcs_detected() { .check_vcs(true) .stderr( "warning: Could not detect a version control system\n\ - You should consider using a VCS so you can easily see and revert rustfix' changes.\n\ + You should consider using a VCS so you can easily see and revert rustfix's changes.\n\ error: No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`.\n\ ", ) @@ -43,7 +43,7 @@ fn warns_about_dirty_working_directory() { .check_vcs(true) .stderr( "warning: Working directory dirty\n\ - Make sure your working directory is clean so you can easily revert rustfix' changes.\n\ + Make sure your working directory is clean so you can easily revert rustfix's changes.\n\ ?? Cargo.toml\n\ ?? src/\n\ error: Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`.\n\n", From a3a9d41d314f4ad3a77abfce07b0333db4f67a2e Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 2 Jun 2018 20:45:36 -0700 Subject: [PATCH 204/298] reset terminal color/bold after emitting error This resolves #113, and plausibly also #115. --- cargo-fix/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs index 7f81f2f0c..45e91f481 100644 --- a/cargo-fix/src/main.rs +++ b/cargo-fix/src/main.rs @@ -50,6 +50,7 @@ fn main() { let _ = stream.reset(); let _ = stream.set_color(ColorSpec::new().set_bold(true)); writeln!(stream, ": {}", err).unwrap(); + let _ = stream.reset(); for cause in err.causes().skip(1) { eprintln!("\tcaused by: {}", cause); From 379fabd07a014b6c90d1632cb282901aeb5e779f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jun 2018 10:32:57 +0200 Subject: [PATCH 205/298] Add test for setting RUSTFLAGS --- cargo-fix/tests/all/main.rs | 1 + cargo-fix/tests/all/rust_flags.rs | 34 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 cargo-fix/tests/all/rust_flags.rs diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs index 46a03c65d..43f135fb9 100644 --- a/cargo-fix/tests/all/main.rs +++ b/cargo-fix/tests/all/main.rs @@ -356,6 +356,7 @@ mod broken_build; mod broken_lints; mod dependencies; mod edition_upgrade; +mod rust_flags; mod smoke; mod subtargets; mod vcs; diff --git a/cargo-fix/tests/all/rust_flags.rs b/cargo-fix/tests/all/rust_flags.rs new file mode 100644 index 000000000..1d31c4cbd --- /dev/null +++ b/cargo-fix/tests/all/rust_flags.rs @@ -0,0 +1,34 @@ +use super::project; + +#[test] +fn specify_rustflags() { + let p = project() + .file( + "src/lib.rs", + r#" + #![allow(unused)] + #![feature(rust_2018_preview)] + + mod foo { + pub const FOO: &str = "fooo"; + } + + fn main() { + let x = ::foo::FOO; + } + "#, + ) + .build(); + + let stderr = "\ +[CHECKING] foo v0.1.0 (CWD) +[FIXING] src/lib.rs (1 fix) +[FINISHED] dev [unoptimized + debuginfo] +"; + + p.expect_cmd("cargo-fix fix --prepare-for 2018") + .env("RUSTFLAGS", "-C target-cpu=native") + .stdout("") + .stderr(stderr) + .run(); +} From 88527e6aeeae980353e8111dc61483baf980970f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 7 Jun 2018 10:33:19 +0200 Subject: [PATCH 206/298] Formatting and a typo fix --- cargo-fix/tests/all/smoke.rs | 12 +++--------- src/replace.rs | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs index 1514acee5..d0be80556 100644 --- a/cargo-fix/tests/all/smoke.rs +++ b/cargo-fix/tests/all/smoke.rs @@ -105,9 +105,7 @@ fn preserve_line_endings() { ) .build(); - p.expect_cmd("cargo-fix fix") - .fix_everything() - .run(); + p.expect_cmd("cargo-fix fix").fix_everything().run(); assert!(p.read("src/lib.rs").contains("\r\n")); } @@ -123,9 +121,7 @@ fn fix_deny_warnings() { ) .build(); - p.expect_cmd("cargo-fix fix") - .fix_everything() - .run(); + p.expect_cmd("cargo-fix fix").fix_everything().run(); } #[test] @@ -146,9 +142,7 @@ fn fix_deny_warnings_but_not_others() { ) .build(); - p.expect_cmd("cargo-fix fix") - .fix_everything() - .run(); + p.expect_cmd("cargo-fix fix").fix_everything().run(); assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); assert!(p.read("src/lib.rs").contains("fn bar() {}")); } diff --git a/src/replace.rs b/src/replace.rs index e78bec9d6..6a0676949 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -14,7 +14,7 @@ enum State { impl State { fn is_inserted(&self) -> bool { - if let &State::Inserted(..) = self { + if let State::Inserted(..) = *self { true } else { false @@ -26,7 +26,7 @@ impl State { struct Span { /// Start of this span in parent data start: usize, - /// up to end inculding + /// up to end including end: usize, data: State, } From 47e1e1b9966054f6c8737059a9542fb086178345 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 8 Jun 2018 13:09:28 +0200 Subject: [PATCH 207/298] Bump cargo-fix version to 0.4.1 --- cargo-fix/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml index 6183fd5ee..ba5d92fc1 100644 --- a/cargo-fix/Cargo.toml +++ b/cargo-fix/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-fix" -version = "0.4.0" +version = "0.4.1" authors = [ "Pascal Hertleif ", "Alex Crichton ", From c750e4d470f9973437da72ee5a04e63e4754a5ee Mon Sep 17 00:00:00 2001 From: Aleksei Arbuzov Date: Fri, 22 Jun 2018 16:40:38 +0300 Subject: [PATCH 208/298] Fix typo in Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 2e65e5ee7..c7b96e5bf 100644 --- a/Readme.md +++ b/Readme.md @@ -18,7 +18,7 @@ The magic of rustfix is entirely dependent on the diagnostics implement in the R ## Installation -To use the rustfix libary, add it to your `Cargo.toml`. +To use the rustfix library, add it to your `Cargo.toml`. To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. From 51b666f30148d12fa5d5d11f926a7b3160908d92 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Jul 2018 10:42:19 -0700 Subject: [PATCH 209/298] Ignore duplicate replacements Currently the compiler suffers from bugs like rust-lang/rust#51211 where it will emit duplicate suggestions for code that originates in a macro. This commit allows rustfix to accept and process these suggestions by ignoring exact duplicates of replacements. While not a great solution long term it should hopefully be a non-harmful band-aid until rustc is fixed! --- src/replace.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/replace.rs b/src/replace.rs index 6a0676949..9dfbd4d94 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -142,6 +142,23 @@ impl Data { })?; let part_to_split = &self.parts[index_of_part_to_split]; + + // If this replacement matches exactly the part that we would + // otherwise split then we ignore this for now. This means that you + // can replace the exact same range with the exact same content + // multiple times and we'll process and allow it. + // + // This is currently done to alleviate issues like + // rust-lang/rust#51211 although this clause likely wants to be + // removed if that's fixed deeper in the compiler. + if part_to_split.start == from && part_to_split.end == up_to_and_including { + if let State::Replaced(ref replacement) = part_to_split.data { + if &**replacement == data { + return Ok(()) + } + } + } + ensure!( part_to_split.data == State::Initial, "Cannot replace slice of data that was already replaced" @@ -267,7 +284,7 @@ mod tests { d.replace_range(4, 6, b"lol").unwrap(); assert_eq!("foo lol baz", str(&d.to_vec())); - d.replace_range(4, 6, b"lol").unwrap(); + d.replace_range(4, 6, b"lol2").unwrap(); } #[test] @@ -277,6 +294,14 @@ mod tests { d.replace_range(4, 7, b"lol").unwrap(); } + #[test] + fn replace_same_twice() { + let mut d = Data::new(b"foo"); + d.replace_range(0, 0, b"b").unwrap(); + d.replace_range(0, 0, b"b").unwrap(); + assert_eq!("boo", str(&d.to_vec())); + } + proptest! { #[test] #[ignore] From abcad4cd89ceb14781f4e2c77ea8ebecef52970c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 17 Jul 2018 11:44:11 -0700 Subject: [PATCH 210/298] Delete `cargo fix` This has now moved upstream into Cargo itself at rust-lang/cargo#5723 --- Cargo.toml | 3 - cargo-fix/Cargo.toml | 32 --- cargo-fix/LICENSE-APACHE | 1 - cargo-fix/LICENSE-MIT | 1 - cargo-fix/Readme.md | 35 --- cargo-fix/src/cli.rs | 229 ---------------- cargo-fix/src/diagnostics.rs | 143 ---------- cargo-fix/src/lock.rs | 168 ------------ cargo-fix/src/main.rs | 313 --------------------- cargo-fix/src/vcs.rs | 77 ------ cargo-fix/tests/all/broken_build.rs | 142 ---------- cargo-fix/tests/all/broken_lints.rs | 36 --- cargo-fix/tests/all/dependencies.rs | 101 ------- cargo-fix/tests/all/edition_upgrade.rs | 171 ------------ cargo-fix/tests/all/main.rs | 363 ------------------------- cargo-fix/tests/all/rust_flags.rs | 34 --- cargo-fix/tests/all/smoke.rs | 182 ------------- cargo-fix/tests/all/subtargets.rs | 91 ------- cargo-fix/tests/all/vcs.rs | 78 ------ cargo-fix/tests/all/warnings.rs | 20 -- 20 files changed, 2220 deletions(-) delete mode 100644 cargo-fix/Cargo.toml delete mode 120000 cargo-fix/LICENSE-APACHE delete mode 120000 cargo-fix/LICENSE-MIT delete mode 100644 cargo-fix/Readme.md delete mode 100644 cargo-fix/src/cli.rs delete mode 100644 cargo-fix/src/diagnostics.rs delete mode 100644 cargo-fix/src/lock.rs delete mode 100644 cargo-fix/src/main.rs delete mode 100644 cargo-fix/src/vcs.rs delete mode 100644 cargo-fix/tests/all/broken_build.rs delete mode 100644 cargo-fix/tests/all/broken_lints.rs delete mode 100644 cargo-fix/tests/all/dependencies.rs delete mode 100644 cargo-fix/tests/all/edition_upgrade.rs delete mode 100644 cargo-fix/tests/all/main.rs delete mode 100644 cargo-fix/tests/all/rust_flags.rs delete mode 100644 cargo-fix/tests/all/smoke.rs delete mode 100644 cargo-fix/tests/all/subtargets.rs delete mode 100644 cargo-fix/tests/all/vcs.rs delete mode 100644 cargo-fix/tests/all/warnings.rs diff --git a/Cargo.toml b/Cargo.toml index 81231a863..e4b93fd67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,3 @@ proptest = "0.7.0" difference = "2.0.0" [workspace] -members = [ - "cargo-fix", -] diff --git a/cargo-fix/Cargo.toml b/cargo-fix/Cargo.toml deleted file mode 100644 index ba5d92fc1..000000000 --- a/cargo-fix/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "cargo-fix" -version = "0.4.1" -authors = [ - "Pascal Hertleif ", - "Alex Crichton ", -] -license = "Apache-2.0/MIT" -description = "Automatically apply the suggestions made by rustc" -repository = "https://github.com/rust-lang-nursery/rustfix" -documentation = "https://docs.rs/rustfix" -readme = "README.md" - -[[bin]] -name = "cargo-fix" -test = false - -[dependencies] -failure = "0.1" -rustfix = { path = "..", version = "0.4" } -serde_json = "1" -log = "0.4" -env_logger = { version = "0.5", default-features = false } -clap = "2.31" -termcolor = "0.3.6" -atty = "0.2.10" -serde_derive = "1.0.45" -serde = "1.0.45" - -[dev-dependencies] -difference = "2" -url = "1" diff --git a/cargo-fix/LICENSE-APACHE b/cargo-fix/LICENSE-APACHE deleted file mode 120000 index 965b606f3..000000000 --- a/cargo-fix/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/cargo-fix/LICENSE-MIT b/cargo-fix/LICENSE-MIT deleted file mode 120000 index 76219eb72..000000000 --- a/cargo-fix/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/cargo-fix/Readme.md b/cargo-fix/Readme.md deleted file mode 100644 index d8dc3f463..000000000 --- a/cargo-fix/Readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# cargo fix - -Run `cargo fix` and get better code. - -[![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) -[![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) - -## Installation - -Assuming you have a recent Rust toolchain installed and active, run `cargo install cargo-fix`. - -## Usage - -1. Navigate to a cargo project - 1. Make sure you use version control and have a clean working directory (so you can easily see the changes rustfix makes later on) - 2. Make sure your project compiles -2. Run `cargo fix` -3. ??? (wait for it to compile and fix your code) -4. PROFIT! - -## License - -Licensed under either of - -- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/cargo-fix/src/cli.rs b/cargo-fix/src/cli.rs deleted file mode 100644 index 5dd030bbc..000000000 --- a/cargo-fix/src/cli.rs +++ /dev/null @@ -1,229 +0,0 @@ -use std::env; -use std::io::Write; -use std::process::Command; - -use clap::{App, AppSettings, Arg, SubCommand}; -use failure::{Error, ResultExt}; -use termcolor::{ColorSpec, StandardStream, WriteColor}; - -use super::exit_with; -use diagnostics::{self, log_for_human, output_stream, write_warning, Message}; -use lock; -use vcs::VersionControl; - -static PLEASE_REPORT_THIS_BUG: &str = - "\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ - "; - -pub fn run() -> Result<(), Error> { - let matches = App::new("Cargo Fix") - .bin_name("cargo") - .subcommand( - SubCommand::with_name("fix") - .version(env!("CARGO_PKG_VERSION")) - .author("The Rust Project Developers") - .about("Automatically apply rustc's suggestions about fixing code") - .setting(AppSettings::TrailingVarArg) - .arg(Arg::with_name("args").multiple(true)) - .arg( - Arg::with_name("broken-code") - .long("broken-code") - .help("Fix code even if it already has compiler errors"), - ) - .arg( - Arg::with_name("edition") - .long("prepare-for") - .help("Fix warnings in preparation of an edition upgrade") - .takes_value(true) - .possible_values(&["2018"]), - ) - .arg( - Arg::with_name("allow-no-vcs") - .long("allow-no-vcs") - .help("Fix code even if a VCS was not detected"), - ) - .arg( - Arg::with_name("allow-dirty") - .long("allow-dirty") - .help("Fix code even if the working directory is dirty"), - ), - ) - .get_matches(); - - let matches = match matches.subcommand() { - ("fix", Some(matches)) => matches, - _ => bail!("unknown CLI arguments passed"), - }; - - if matches.is_present("broken-code") { - env::set_var("__CARGO_FIX_BROKEN_CODE", "1"); - } - - check_version_control(matches)?; - - // Spin up our lock server which our subprocesses will use to synchronize - // fixes. - let _lock_server = lock::Server::new()?.start()?; - - // Spin up our diagnostics server which our subprocesses will use to send - // use their dignostics messages in an ordered way. - let _diagnostics_server = diagnostics::Server::new()?.start(|m, stream| { - if let Err(e) = log_message(&m, stream) { - warn!("failed to log message: {}", e); - } - })?; - - let cargo = env::var_os("CARGO").unwrap_or("cargo".into()); - let mut cmd = Command::new(&cargo); - // TODO: shouldn't hardcode `check` here, we want to allow things like - // `cargo fix bench` or something like that - // - // TODO: somehow we need to force `check` to actually do something here, if - // `cargo check` was previously run it won't actually do anything again. - cmd.arg("check"); - if let Some(args) = matches.values_of("args") { - cmd.args(args); - } - - // Override the rustc compiler as ourselves. That way whenever rustc would - // run we run instead and have an opportunity to inject fixes. - let me = env::current_exe().context("failed to learn about path to current exe")?; - cmd.env("RUSTC", &me).env("__CARGO_FIX_NOW_RUSTC", "1"); - if let Some(rustc) = env::var_os("RUSTC") { - cmd.env("RUSTC_ORIGINAL", rustc); - } - - // Trigger edition-upgrade mode. Currently only supports the 2018 edition. - info!("edition upgrade? {:?}", matches.value_of("edition")); - if let Some("2018") = matches.value_of("edition") { - info!("edition upgrade!"); - let mut rustc_flags = env::var_os("RUSTFLAGS").unwrap_or_else(|| "".into()); - rustc_flags.push(" -W rust-2018-compatibility"); - cmd.env("RUSTFLAGS", &rustc_flags); - } - - // An now execute all of Cargo! This'll fix everything along the way. - // - // TODO: we probably want to do something fancy here like collect results - // from the client processes and print out a summary of what happened. - let status = cmd.status() - .with_context(|e| format!("failed to execute `{}`: {}", cargo.to_string_lossy(), e))?; - exit_with(status); -} - -fn check_version_control(matches: &::clap::ArgMatches) -> Result<(), Error> { - // Useful for tests - if env::var("__CARGO_FIX_IGNORE_VCS").is_ok() { - return Ok(()); - } - - let version_control = VersionControl::new(); - match (version_control.is_present(), version_control.is_dirty()?) { - (true, None) => {} // clean and versioned slate - (false, _) => { - let stream = &mut output_stream(); - - write_warning(stream)?; - stream.set_color(ColorSpec::new().set_bold(true))?; - writeln!(stream, "Could not detect a version control system")?; - stream.reset()?; - writeln!(stream, "You should consider using a VCS so you can easily see and revert rustfix's changes.")?; - - if !matches.is_present("allow-no-vcs") { - bail!("No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`."); - } - } - (true, Some(output)) => { - let stream = &mut output_stream(); - - write_warning(stream)?; - stream.set_color(ColorSpec::new().set_bold(true))?; - writeln!(stream, "Working directory dirty")?; - stream.reset()?; - writeln!(stream, "Make sure your working directory is clean so you can easily revert rustfix's changes.")?; - - stream.write_all(&output)?; - - if !matches.is_present("allow-dirty") { - bail!("Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`."); - } - } - } - - Ok(()) -} - -fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> { - use diagnostics::Message::*; - - match *msg { - Fixing { - ref file, - ref fixes, - } => { - log_for_human( - "Fixing", - &format!( - "{name} ({n} {fixes})", - name = file, - n = fixes, - fixes = if *fixes > 1 { "fixes" } else { "fix" }, - ), - stream, - )?; - } - ReplaceFailed { - ref file, - ref message, - } => { - write_warning(stream)?; - stream.set_color(ColorSpec::new().set_bold(true))?; - write!(stream, "error applying suggestions to `{}`\n", file)?; - stream.reset()?; - write!(stream, "The full error message was:\n\n> {}\n\n", message)?; - stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; - } - FixFailed { - ref files, - ref krate, - } => { - write_warning(stream)?; - stream.set_color(ColorSpec::new().set_bold(true))?; - if let Some(ref krate) = *krate { - write!( - stream, - "failed to automatically apply fixes suggested by rustc \ - to crate `{}`\n", - krate, - )?; - } else { - write!( - stream, - "failed to automatically apply fixes suggested by rustc\n" - )?; - } - if files.len() > 0 { - write!( - stream, - "\nafter fixes were automatically applied the compiler \ - reported errors within these files:\n\n" - )?; - for file in files { - write!(stream, " * {}\n", file)?; - } - write!(stream, "\n")?; - } - stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?; - } - } - - stream.reset()?; - stream.flush()?; - Ok(()) -} diff --git a/cargo-fix/src/diagnostics.rs b/cargo-fix/src/diagnostics.rs deleted file mode 100644 index 9a919801a..000000000 --- a/cargo-fix/src/diagnostics.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! A small TCP server to handle collection of diagnostics information in a -//! cross-platform way. - -use std::env; -use std::io::{BufReader, Read, Write}; -use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; -use std::thread::{self, JoinHandle}; - -use atty; -use failure::{Error, ResultExt}; -use serde_json; -use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - -static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; - -#[derive(Deserialize, Serialize)] -pub enum Message { - Fixing { - file: String, - fixes: usize, - }, - FixFailed { - files: Vec, - krate: Option, - }, - ReplaceFailed { - file: String, - message: String, - }, -} - -impl Message { - pub fn fixing(file: &str, num: usize) -> Message { - Message::Fixing { - file: file.into(), - fixes: num, - } - } - - pub fn post(&self) -> Result<(), Error> { - let addr = env::var(DIAGNOSICS_SERVER_VAR).context("diagnostics collector misconfigured")?; - let mut client = - TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?; - - let s = serde_json::to_string(self).context("failed to serialize message")?; - client - .write_all(s.as_bytes()) - .context("failed to write message to diagnostics target")?; - client - .shutdown(Shutdown::Write) - .context("failed to shutdown")?; - - let mut tmp = Vec::new(); - client - .read_to_end(&mut tmp) - .context("failed to receive a disconnect")?; - - Ok(()) - } -} - -pub struct Server { - listener: TcpListener, -} - -pub struct StartedServer { - _addr: SocketAddr, - thread: Option>, -} - -impl Server { - pub fn new() -> Result { - let listener = TcpListener::bind("127.0.0.1:0") - .with_context(|_| "failed to bind TCP listener to manage locking")?; - env::set_var(DIAGNOSICS_SERVER_VAR, listener.local_addr()?.to_string()); - - Ok(Server { listener }) - } - - pub fn start(self, on_message: F) -> Result - where - F: Fn(Message, &mut StandardStream) + Send + 'static, - { - let _addr = self.listener.local_addr()?; - let thread = thread::spawn(move || { - self.run(on_message); - }); - - Ok(StartedServer { - _addr, - thread: Some(thread), - }) - } - - fn run(self, on_message: F) - where - F: Fn(Message, &mut StandardStream), - { - let mut stream = output_stream(); - while let Ok((client, _)) = self.listener.accept() { - let mut client = BufReader::new(client); - match serde_json::from_reader(client) { - Ok(message) => on_message(message, &mut stream), - Err(e) => { - warn!("invalid diagnostics message: {}", e); - } - } - } - } -} - -impl Drop for StartedServer { - fn drop(&mut self) { - drop(self.thread.take().unwrap().join()); - } -} - -pub fn output_stream() -> StandardStream { - let color_choice = if atty::is(atty::Stream::Stderr) { - ColorChoice::Auto - } else { - ColorChoice::Never - }; - StandardStream::stderr(color_choice) -} - -pub fn write_warning(stream: &mut StandardStream) -> Result<(), Error> { - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; - write!(stream, "warning")?; - stream.reset()?; - stream.set_color(ColorSpec::new().set_bold(true))?; - write!(stream, ": ")?; - Ok(()) -} - -pub fn log_for_human(kind: &str, msg: &str, stream: &mut StandardStream) -> Result<(), Error> { - stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?; - // Justify to 12 chars just like cargo - write!(stream, "{:>12}", kind)?; - stream.reset()?; - write!(stream, " {}\n", msg)?; - Ok(()) -} diff --git a/cargo-fix/src/lock.rs b/cargo-fix/src/lock.rs deleted file mode 100644 index c3c6d2be4..000000000 --- a/cargo-fix/src/lock.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! An implementation of IPC locks, guaranteed to be released if a process dies -//! -//! This module implements a locking server/client where the main `cargo fix` -//! process will start up a server and then all the client processes will -//! connect to it. The main purpose of this file is to enusre that each crate -//! (aka file entry point) is only fixed by one process at a time, currently -//! concurrent fixes can't happen. -//! -//! The basic design here is to use a TCP server which is pretty portable across -//! platforms. For simplicity it just uses threads as well. Clients connect to -//! the main server, inform the server what its name is, and then wait for the -//! server to give it the lock (aka write a byte). - -use std::collections::HashMap; -use std::env; -use std::io::{BufRead, BufReader, Read, Write}; -use std::net::{SocketAddr, TcpListener, TcpStream}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; - -use failure::{Error, ResultExt}; - -pub struct Server { - listener: TcpListener, - threads: HashMap, - done: Arc, -} - -pub struct StartedServer { - done: Arc, - addr: SocketAddr, - thread: Option>, -} - -pub struct Client { - _socket: TcpStream, -} - -struct ServerClient { - thread: Option>, - lock: Arc)>>, -} - -impl Server { - pub fn new() -> Result { - let listener = TcpListener::bind("127.0.0.1:0") - .with_context(|_| "failed to bind TCP listener to manage locking")?; - env::set_var("__CARGO_FIX_SERVER", listener.local_addr()?.to_string()); - Ok(Server { - listener, - threads: HashMap::new(), - done: Arc::new(AtomicBool::new(false)), - }) - } - - pub fn start(self) -> Result { - let addr = self.listener.local_addr()?; - let done = self.done.clone(); - let thread = thread::spawn(|| { - self.run(); - }); - Ok(StartedServer { - addr, - thread: Some(thread), - done, - }) - } - - fn run(mut self) { - while let Ok((client, _)) = self.listener.accept() { - if self.done.load(Ordering::SeqCst) { - break; - } - - // Learn the name of our connected client to figure out if it needs - // to wait for another process to release the lock. - let mut client = BufReader::new(client); - let mut name = String::new(); - if client.read_line(&mut name).is_err() { - continue; - } - let client = client.into_inner(); - - // If this "named mutex" is already registered and the thread is - // still going, put it on the queue. Otherwise wait on the previous - // thread and we'll replace it just below. - if let Some(t) = self.threads.get_mut(&name) { - let mut state = t.lock.lock().unwrap(); - if state.0 { - state.1.push(client); - continue; - } - drop(t.thread.take().unwrap().join()); - } - - let lock = Arc::new(Mutex::new((true, vec![client]))); - let lock2 = lock.clone(); - let thread = thread::spawn(move || { - loop { - let mut client = { - let mut state = lock2.lock().unwrap(); - if state.1.len() == 0 { - state.0 = false; - break; - } else { - state.1.remove(0) - } - }; - // Inform this client that it now has the lock and wait for - // it to disconnect by waiting for EOF. - if client.write_all(&[1]).is_err() { - continue; - } - let mut dst = Vec::new(); - drop(client.read_to_end(&mut dst)); - } - }); - - self.threads.insert( - name, - ServerClient { - thread: Some(thread), - lock, - }, - ); - } - } -} - -impl Drop for Server { - fn drop(&mut self) { - for (_, mut client) in self.threads.drain() { - if let Some(thread) = client.thread.take() { - drop(thread.join()); - } - } - } -} - -impl Drop for StartedServer { - fn drop(&mut self) { - self.done.store(true, Ordering::SeqCst); - // Ignore errors here as this is largely best-effort - if TcpStream::connect(&self.addr).is_err() { - return; - } - drop(self.thread.take().unwrap().join()); - } -} - -impl Client { - pub fn lock(name: &str) -> Result { - let addr = env::var("__CARGO_FIX_SERVER") - .map_err(|_| format_err!("locking strategy misconfigured"))?; - let mut client = - TcpStream::connect(&addr).with_context(|_| "failed to connect to parent lock server")?; - client - .write_all(name.as_bytes()) - .and_then(|_| client.write_all(b"\n")) - .with_context(|_| "failed to write to lock server")?; - let mut buf = [0]; - client - .read_exact(&mut buf) - .with_context(|_| "failed to acquire lock")?; - Ok(Client { _socket: client }) - } -} diff --git a/cargo-fix/src/main.rs b/cargo-fix/src/main.rs deleted file mode 100644 index 45e91f481..000000000 --- a/cargo-fix/src/main.rs +++ /dev/null @@ -1,313 +0,0 @@ -extern crate atty; -extern crate clap; -extern crate env_logger; -#[macro_use] -extern crate failure; -#[macro_use] -extern crate log; -extern crate rustfix; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; -extern crate termcolor; - -use std::collections::{BTreeSet, HashMap, HashSet}; -use std::env; -use std::fs::File; -use std::io::{Read, Write}; -use std::path::Path; -use std::process::{self, Command, ExitStatus}; -use std::str; - -use failure::{Error, ResultExt}; -use rustfix::diagnostics::Diagnostic; -use termcolor::{Color, ColorSpec, WriteColor}; - -use diagnostics::{output_stream, Message}; - -mod cli; -mod diagnostics; -mod lock; -mod vcs; - -fn main() { - env_logger::init(); - let result = if env::var("__CARGO_FIX_NOW_RUSTC").is_ok() { - debug!("invoking cargo-fix as rustc wrapper"); - cargo_fix_rustc() - } else { - debug!("invoking cargo-fix as cargo subcommand"); - cli::run() - }; - let err = match result { - Ok(()) => return, - Err(e) => e, - }; - - let stream = &mut output_stream(); - let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red))); - write!(stream, "error").unwrap(); - let _ = stream.reset(); - let _ = stream.set_color(ColorSpec::new().set_bold(true)); - writeln!(stream, ": {}", err).unwrap(); - let _ = stream.reset(); - - for cause in err.causes().skip(1) { - eprintln!("\tcaused by: {}", cause); - } - process::exit(102); -} - -fn cargo_fix_rustc() -> Result<(), Error> { - // Try to figure out what we're compiling by looking for a rust-like file - // that exists. - let filename = env::args() - .skip(1) - .filter(|s| s.ends_with(".rs")) - .filter(|s| Path::new(s).exists()) - .next(); - - trace!("cargo-fix as rustc got file {:?}", filename); - let rustc = env::var_os("RUSTC_ORIGINAL").unwrap_or("rustc".into()); - - // Our goal is to fix only the crates that the end user is interested in. - // That's very likely to only mean the crates in the workspace the user is - // working on, not random crates.io crates. - // - // To that end we only actually try to fix things if it looks like we're - // compiling a Rust file and it *doesn't* have an absolute filename. That's - // not the best heuristic but matches what Cargo does today at least. - let mut fixes = FixedCrate::default(); - if let Some(path) = filename { - if !Path::new(&path).is_absolute() { - trace!("start rustfixing {:?}", path); - fixes = rustfix_crate(rustc.as_ref(), &path)?; - } - } - - // Ok now we have our final goal of testing out the changes that we applied. - // If these changes went awry and actually started to cause the crate to - // *stop* compiling then we want to back them out and continue to print - // warnings to the user. - // - // If we didn't actually make any changes then we can immediately exec the - // new rustc, and otherwise we capture the output to hide it in the scenario - // that we have to back it all out. - let mut cmd = Command::new(&rustc); - cmd.args(env::args().skip(1)); - cmd.arg("--cap-lints=warn"); - cmd.arg("--error-format=json"); - if fixes.original_files.len() > 0 { - let output = cmd.output().context("failed to spawn rustc")?; - - if output.status.success() { - for message in fixes.messages.drain(..) { - message.post()?; - } - } - - // If we succeeded then we'll want to commit to the changes we made, if - // any. If stderr is empty then there's no need for the final exec at - // the end, we just bail out here. - if output.status.success() && output.stderr.len() == 0 { - return Ok(()); - } - - // Otherwise if our rustc just failed then that means that we broke the - // user's code with our changes. Back out everything and fall through - // below to recompile again. - if !output.status.success() { - for (k, v) in fixes.original_files { - File::create(&k) - .and_then(|mut f| f.write_all(v.as_bytes())) - .with_context(|_| format!("failed to write file `{}`", k))?; - } - log_failed_fix(&output.stderr)?; - } - } - - let mut cmd = Command::new(&rustc); - cmd.args(env::args().skip(1)); - cmd.arg("--cap-lints=warn"); - exit_with(cmd.status().context("failed to spawn rustc")?); -} - -#[derive(Default)] -struct FixedCrate { - messages: Vec, - original_files: HashMap, -} - -fn rustfix_crate(rustc: &Path, filename: &str) -> Result { - // If not empty, filter by these lints - // - // TODO: Implement a way to specify this - let only = HashSet::new(); - - // First up we want to make sure that each crate is only checked by one - // process at a time. If two invocations concurrently check a crate then - // it's likely to corrupt it. - // - // Currently we do this by assigning the name on our lock to the first - // argument that looks like a Rust file. - let _lock = lock::Client::lock(filename)?; - - let mut cmd = Command::new(&rustc); - cmd.args(env::args().skip(1)); - cmd.arg("--error-format=json").arg("--cap-lints=warn"); - let output = cmd.output() - .with_context(|_| format!("failed to execute `{}`", rustc.display()))?; - - // If rustc didn't succeed for whatever reasons then we're very likely to be - // looking at otherwise broken code. Let's not make things accidentally - // worse by applying fixes where a bug could cause *more* broken code. - // Instead, punt upwards which will reexec rustc over the original code, - // displaying pretty versions of the diagnostics we just read out. - // - // TODO: this should be configurable by the CLI to sometimes proceed to - // attempt to fix broken code. - if !output.status.success() && env::var_os("__CARGO_FIX_BROKEN_CODE").is_none() { - debug!( - "rustfixing `{:?}` failed, rustc exited with {:?}", - filename, - output.status.code() - ); - return Ok(Default::default()); - } - - let fix_mode = env::var_os("__CARGO_FIX_YOLO") - .map(|_| rustfix::Filter::Everything) - .unwrap_or(rustfix::Filter::MachineApplicableOnly); - - // Sift through the output of the compiler to look for JSON messages - // indicating fixes that we can apply. - let stderr = str::from_utf8(&output.stderr).context("failed to parse rustc stderr as utf-8")?; - - let suggestions = stderr.lines() - .filter(|x| !x.is_empty()) - - // Parse each line of stderr ignoring errors as they may not all be json - .filter_map(|line| serde_json::from_str::(line).ok()) - - // From each diagnostic try to extract suggestions from rustc - .filter_map(|diag| rustfix::collect_suggestions(&diag, &only, fix_mode)); - - // Collect suggestions by file so we can apply them one at a time later. - let mut file_map = HashMap::new(); - let mut num_suggestion = 0; - for suggestion in suggestions { - // Make sure we've got a file associated with this suggestion and all - // snippets point to the same location. Right now it's not clear what - // we would do with multiple locations. - let (file_name, range) = match suggestion.snippets.get(0) { - Some(s) => (s.file_name.clone(), s.line_range), - None => { - trace!("rejecting as it has no snippets {:?}", suggestion); - continue; - } - }; - if !suggestion - .snippets - .iter() - .all(|s| s.file_name == file_name && s.line_range == range) - { - trace!("rejecting as it spans multiple files {:?}", suggestion); - continue; - } - - file_map - .entry(file_name) - .or_insert_with(Vec::new) - .push(suggestion); - num_suggestion += 1; - } - - debug!( - "collected {} suggestions for `{}`", - num_suggestion, filename - ); - - let mut original_files = HashMap::with_capacity(file_map.len()); - let mut messages = Vec::new(); - for (file, suggestions) in file_map { - // Attempt to read the source code for this file. If this fails then - // that'd be pretty surprising, so log a message and otherwise keep - // going. - let mut code = String::new(); - if let Err(e) = File::open(&file).and_then(|mut f| f.read_to_string(&mut code)) { - warn!("failed to read `{}`: {}", file, e); - continue; - } - let num_suggestions = suggestions.len(); - debug!("applying {} fixes to {}", num_suggestions, file); - - messages.push(Message::fixing(&file, num_suggestions)); - - match rustfix::apply_suggestions(&code, &suggestions) { - Err(e) => { - diagnostics::Message::ReplaceFailed { - file: file, - message: e.to_string(), - }.post()?; - // TODO: Add flag to decide if we want to continue or bail out - continue; - } - Ok(new_code) => { - File::create(&file) - .and_then(|mut f| f.write_all(new_code.as_bytes())) - .with_context(|_| format!("failed to write file `{}`", file))?; - original_files.insert(file, code); - } - } - } - - Ok(FixedCrate { - messages, - original_files, - }) -} - -fn exit_with(status: ExitStatus) -> ! { - #[cfg(unix)] - { - use std::os::unix::prelude::*; - if let Some(signal) = status.signal() { - eprintln!("child failed with signal `{}`", signal); - process::exit(2); - } - } - process::exit(status.code().unwrap_or(3)); -} - -fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> { - let stderr = str::from_utf8(stderr).context("failed to parse rustc stderr as utf-8")?; - - let diagnostics = stderr - .lines() - .filter(|x| !x.is_empty()) - .filter_map(|line| serde_json::from_str::(line).ok()); - let mut files = BTreeSet::new(); - for diagnostic in diagnostics { - for span in diagnostic.spans.into_iter() { - files.insert(span.file_name); - } - } - let mut krate = None; - let mut prev_dash_dash_krate_name = false; - for arg in env::args() { - if prev_dash_dash_krate_name { - krate = Some(arg.clone()); - } - - if arg == "--crate-name" { - prev_dash_dash_krate_name = true; - } else { - prev_dash_dash_krate_name = false; - } - } - - let files = files.into_iter().collect(); - Message::FixFailed { files, krate }.post()?; - - Ok(()) -} diff --git a/cargo-fix/src/vcs.rs b/cargo-fix/src/vcs.rs deleted file mode 100644 index 85f9d589b..000000000 --- a/cargo-fix/src/vcs.rs +++ /dev/null @@ -1,77 +0,0 @@ -use failure::{err_msg, Error, ResultExt}; -use std::env; -use std::process::Command; - -pub enum VersionControl { - Git, - Hg, - Fossil, - Pijul, - None, -} - -impl VersionControl { - pub fn new() -> Self { - if is_in_vcs(".git").is_ok() { - VersionControl::Git - } else if is_in_vcs(".hg").is_ok() { - VersionControl::Hg - } else if is_in_vcs(".pijul").is_ok() { - VersionControl::Pijul - } else if is_in_vcs(".fossil").is_ok() { - VersionControl::Fossil - } else { - VersionControl::None - } - } - - pub fn is_present(&self) -> bool { - match *self { - VersionControl::None => false, - _ => true, - } - } - - /// Check if working tree is dirty - /// - /// # Returns - /// - /// - `Err(error)`: anything went wrong - /// - `Ok(None)`: No changes - /// - `Ok(bytes)`: Changes (bytes are VCS's output) - pub fn is_dirty(&self) -> Result>, Error> { - let (program, args) = match *self { - VersionControl::Git => ("git", "status --short"), - VersionControl::Hg => ("hg", "status"), - VersionControl::Pijul => ("pijul", "status"), - VersionControl::Fossil => ("fossil", "changes"), - VersionControl::None => return Ok(None), - }; - - let output = Command::new(program) - .args(args.split_whitespace()) - .output()? - .stdout; - - if output.is_empty() { - Ok(None) - } else { - Ok(Some(output)) - } - } -} - -fn is_in_vcs(vcs_dir: &str) -> Result<(), Error> { - let mut current_dir = env::current_dir().context("could not find the current directory")?; - - loop { - if current_dir.join(vcs_dir).metadata().is_ok() { - return Ok(()); - } - - current_dir = current_dir - .parent() - .ok_or_else(|| err_msg("could not find the parent directory"))? - .to_owned(); - } -} diff --git a/cargo-fix/tests/all/broken_build.rs b/cargo-fix/tests/all/broken_build.rs deleted file mode 100644 index 70005a95b..000000000 --- a/cargo-fix/tests/all/broken_build.rs +++ /dev/null @@ -1,142 +0,0 @@ -use super::project; - -#[test] -fn do_not_fix_broken_builds() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() { - let mut x = 3; - drop(x); - } - - pub fn foo2() { - let _x: u32 = "a"; - } - "#, - ) - .build(); - - p.expect_cmd("cargo-fix fix").status(101).run(); - assert!(p.read("src/lib.rs").contains("let mut x = 3;")); -} - -#[test] -fn fix_broken_if_requested() { - let p = project() - .file( - "src/lib.rs", - r#" - fn foo(a: &u32) -> u32 { a + 1 } - pub fn bar() { - foo(1); - } - "#, - ) - .build(); - - p.expect_cmd("cargo-fix fix --broken-code") - .fix_everything() - .status(0) - .run(); -} - -#[test] -fn broken_fixes_backed_out() { - let p = project() - .file( - "foo/Cargo.toml", - r#" - [package] - name = 'foo' - version = '0.1.0' - [workspace] - "#, - ) - .file( - "foo/src/main.rs", - r##" - use std::env; - use std::fs; - use std::io::Write; - use std::path::{Path, PathBuf}; - use std::process::{self, Command}; - - fn main() { - let is_lib_rs = env::args_os() - .map(PathBuf::from) - .any(|l| l == Path::new("src/lib.rs")); - if is_lib_rs { - let path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let path = path.join("foo"); - if path.exists() { - fs::File::create("src/lib.rs") - .unwrap() - .write_all(b"not rust code") - .unwrap(); - } else { - fs::File::create(&path).unwrap(); - } - } - - let status = Command::new("rustc") - .args(env::args().skip(1)) - .status() - .expect("failed to run rustc"); - process::exit(status.code().unwrap_or(2)); - } - "##, - ) - .file( - "bar/Cargo.toml", - r#" - [package] - name = 'bar' - version = '0.1.0' - [workspace] - "#, - ) - .file("bar/build.rs", "fn main() {}") - .file( - "bar/src/lib.rs", - r#" - pub fn foo() { - let mut x = 3; - drop(x); - } - "#, - ) - .build(); - - // Build our rustc shim - p.expect_cmd("cargo build").cwd("foo").run(); - - // Attempt to fix code, but our shim will always fail the second compile - p.expect_cmd("cargo-fix fix") - .fix_everything() - .cwd("bar") - .env("RUSTC", p.root.join("foo/target/debug/foo")) - .stderr_contains("not rust code") - .stderr_contains( - "\ - warning: failed to automatically apply fixes suggested by rustc \ - to crate `bar`\n\ - \n\ - after fixes were automatically applied the compiler reported \ - errors within these files:\n\ - \n \ - * src/lib.rs\n\ - \n\ - This likely indicates a bug in either rustc or rustfix itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which rustfix\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang-nursery/rustfix/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\n\ - ", - ) - .stderr_not_contains("[FIXING]") - .status(101) - .run(); -} diff --git a/cargo-fix/tests/all/broken_lints.rs b/cargo-fix/tests/all/broken_lints.rs deleted file mode 100644 index 2865b2873..000000000 --- a/cargo-fix/tests/all/broken_lints.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Ensure we give good error message when rustfix failes to apply changes -//! -//! TODO: Add rustc shim that outputs wrong suggestions instead of depending on -//! actual rustc bugs! - -// use super::project; - -// #[test] -// fn tell_user_about_broken_lints() { -// let p = project() -// .file( -// "src/lib.rs", -// r#" -// pub fn foo() { -// let mut i = 42; -// } -// "#, -// ) -// .build(); - -// p.expect_cmd("cargo-fix fix") -// .fix_everything() -// .stderr_contains(r"warning: error applying suggestions to `src/lib.rs`") -// .stderr_contains("The full error message was:") -// .stderr_contains("> Could not replace range 56...60 in file -- maybe parts of it were already replaced?") -// .stderr_contains("\ -// This likely indicates a bug in either rustc or rustfix itself,\n\ -// and we would appreciate a bug report! You're likely to see \n\ -// a number of compiler warnings after this message which rustfix\n\ -// attempted to fix but failed. If you could open an issue at\n\ -// https://github.com/rust-lang-nursery/rustfix/issues\n\ -// quoting the full output of this command we'd be very appreciative!\n\n\ -// ") -// .status(0) -// .run(); -// } diff --git a/cargo-fix/tests/all/dependencies.rs b/cargo-fix/tests/all/dependencies.rs deleted file mode 100644 index c0baeabe0..000000000 --- a/cargo-fix/tests/all/dependencies.rs +++ /dev/null @@ -1,101 +0,0 @@ -use super::project; - -#[test] -fn fix_path_deps() { - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.1.0" - - [dependencies] - bar = { path = 'bar' } - - [workspace] - "#, - ) - .file( - "src/lib.rs", - r#" - extern crate bar; - - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#, - ) - .file( - "bar/Cargo.toml", - r#" - [package] - name = "bar" - version = "0.1.0" - "#, - ) - .file( - "bar/src/lib.rs", - r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] bar v0.1.0 (CWD/bar) -[FIXING] bar/src/lib.rs (1 fix) -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (1 fix) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn do_not_fix_non_relevant_deps() { - let p = project() - .file( - "foo/Cargo.toml", - r#" - [package] - name = "foo" - version = "0.1.0" - - [dependencies] - bar = { path = '../bar' } - - [workspace] - "#, - ) - .file("foo/src/lib.rs", "") - .file( - "bar/Cargo.toml", - r#" - [package] - name = "bar" - version = "0.1.0" - "#, - ) - .file( - "bar/src/lib.rs", - r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#, - ) - .build(); - - p.expect_cmd("cargo-fix fix").cwd("foo").status(0).run(); - assert!(p.read("bar/src/lib.rs").contains("mut")); -} diff --git a/cargo-fix/tests/all/edition_upgrade.rs b/cargo-fix/tests/all/edition_upgrade.rs deleted file mode 100644 index fbdf4a47b..000000000 --- a/cargo-fix/tests/all/edition_upgrade.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Test that we can use cargo-fix to upgrade our code to work with the 2018 -//! edition. -//! -//! We'll trigger the `absolute_path_starting_with_module` lint which should -//! transform a `use ::foo;` where `foo` is local to `use crate::foo;`. - -use super::project; - -#[test] -fn prepare_for_2018() { - let p = project() - .file( - "src/lib.rs", - r#" - #![allow(unused)] - #![feature(rust_2018_preview)] - - mod foo { - pub const FOO: &str = "fooo"; - } - - mod bar { - use ::foo::FOO; - } - - fn main() { - let x = ::foo::FOO; - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (2 fixes) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix --prepare-for 2018") - .stdout("") - .stderr(stderr) - .run(); - - println!("{}", p.read("src/lib.rs")); - assert!(p.read("src/lib.rs").contains("use crate::foo::FOO;")); - assert!(p.read("src/lib.rs").contains("let x = crate::foo::FOO;")); -} - -#[test] -fn local_paths() { - let p = project() - .file( - "src/lib.rs", - r#" - #![feature(rust_2018_preview)] - - use test::foo; - - mod test { - pub fn foo() {} - } - - pub fn f() { - foo(); - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (1 fix) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix --prepare-for 2018") - .stdout("") - .stderr(stderr) - .run(); - - println!("{}", p.read("src/lib.rs")); - assert!(p.read("src/lib.rs").contains("use crate::test::foo;")); -} - -#[test] -fn local_paths_no_fix() { - let p = project() - .file( - "src/lib.rs", - r#" - use test::foo; - - mod test { - pub fn foo() {} - } - - pub fn f() { - foo(); - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix --prepare-for 2018") - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn upgrade_extern_crate() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["edition"] - - [package] - name = "foo" - version = "0.1.0" - edition = '2018' - - [workspace] - - [dependencies] - bar = { path = 'bar' } - "#, - ) - .file( - "src/lib.rs", - r#" - #![warn(rust_2018_idioms)] - - extern crate bar; - - use bar::bar; - - pub fn foo() { - ::bar::bar(); - bar(); - } - "#, - ) - .file( - "bar/Cargo.toml", - r#" - [package] - name = "bar" - version = "0.1.0" - "#, - ) - .file("bar/src/lib.rs", "pub fn bar() {}") - .build(); - - let stderr = "\ -[CHECKING] bar v0.1.0 (CWD/bar) -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (1 fix) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stdout("") - .stderr(stderr) - .run(); - - println!("{}", p.read("src/lib.rs")); - assert!(!p.read("src/lib.rs").contains("extern crate")); -} diff --git a/cargo-fix/tests/all/main.rs b/cargo-fix/tests/all/main.rs deleted file mode 100644 index 43f135fb9..000000000 --- a/cargo-fix/tests/all/main.rs +++ /dev/null @@ -1,363 +0,0 @@ -extern crate difference; -extern crate url; - -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fs::{self, File}; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::str; -use std::sync::atomic::*; -use std::time::Instant; - -use difference::{Changeset, Difference}; -use url::Url; - -static CNT: AtomicUsize = ATOMIC_USIZE_INIT; -thread_local!(static IDX: usize = CNT.fetch_add(1, Ordering::SeqCst)); - -struct ProjectBuilder { - files: Vec<(String, String)>, - root: PathBuf, -} - -struct Project { - root: PathBuf, -} - -fn project() -> ProjectBuilder { - ProjectBuilder { - files: Vec::new(), - root: root(), - } -} - -fn root() -> PathBuf { - let idx = IDX.with(|x| *x); - - let mut me = env::current_exe().unwrap(); - me.pop(); // chop off exe name - me.pop(); // chop off `deps` - me.pop(); // chop off `debug` / `release` - me.push("generated-tests"); - me.push(&format!("test{}", idx)); - return me; -} - -impl ProjectBuilder { - fn file(mut self, name: &str, contents: &str) -> ProjectBuilder { - self.files.push((name.to_string(), contents.to_string())); - self - } - - fn use_temp_dir(mut self) -> ProjectBuilder { - let mut temp_dir = env::temp_dir(); - temp_dir.push(&format!("rustfix-generated-test{}", IDX.with(|x| *x))); - - self.root = temp_dir; - self - } - - fn build(mut self) -> Project { - if !self.files.iter().any(|f| f.0.ends_with("Cargo.toml")) { - let manifest = r#" - [package] - name = "foo" - version = "0.1.0" - - [workspace] - "#; - self.files - .push(("Cargo.toml".to_string(), manifest.to_string())); - } - drop(fs::remove_dir_all(&self.root)); - for &(ref file, ref contents) in self.files.iter() { - let dst = self.root.join(file); - fs::create_dir_all(dst.parent().unwrap()).unwrap(); - fs::File::create(&dst) - .unwrap() - .write_all(contents.as_ref()) - .unwrap(); - } - Project { root: self.root } - } -} - -impl Project { - fn expect_cmd<'a>(&'a self, cmd: &'a str) -> ExpectCmd<'a> { - ExpectCmd { - project: self, - cmd: cmd, - env: Vec::new(), - stdout: None, - stdout_contains: Vec::new(), - stderr: None, - stderr_contains: Vec::new(), - stderr_not_contains: Vec::new(), - check_vcs: false, - status: 0, - ran: false, - cwd: None, - } - } - - fn read(&self, path: &str) -> String { - let mut ret = String::new(); - File::open(self.root.join(path)) - .unwrap() - .read_to_string(&mut ret) - .unwrap(); - return ret; - } -} - -impl Drop for Project { - fn drop(&mut self) { - drop(fs::remove_dir_all(&self.root)); - drop(fs::remove_dir(&self.root)); - } -} - -struct ExpectCmd<'a> { - ran: bool, - project: &'a Project, - cmd: &'a str, - env: Vec<(OsString, OsString)>, - stdout: Option, - stdout_contains: Vec, - stderr: Option, - stderr_contains: Vec, - stderr_not_contains: Vec, - check_vcs: bool, - status: i32, - cwd: Option, -} - -impl<'a> ExpectCmd<'a> { - fn status(&mut self, status: i32) -> &mut Self { - self.status = status; - self - } - - fn cwd>(&mut self, path: P) -> &mut Self { - self.cwd = Some(self.project.root.join(path)); - self - } - - fn env, V: AsRef>(&mut self, k: K, v: V) -> &mut Self { - self.env - .push((k.as_ref().to_owned(), v.as_ref().to_owned())); - self - } - - fn fix_everything(&mut self) -> &mut Self { - self.env("__CARGO_FIX_YOLO", "true"); - self - } - - fn stdout(&mut self, s: &str) -> &mut Self { - self.stdout = Some(s.to_string()); - self - } - - fn stderr(&mut self, s: &str) -> &mut Self { - self.stderr = Some(s.to_string()); - self - } - - fn stderr_contains(&mut self, s: &str) -> &mut Self { - self.stderr_contains.push(s.to_string()); - self - } - - fn stderr_not_contains(&mut self, s: &str) -> &mut Self { - self.stderr_not_contains.push(s.to_string()); - self - } - - fn check_vcs(&mut self, b: bool) -> &mut Self { - self.check_vcs = b; - self - } - - fn run(&mut self) { - self.ran = true; - let mut parts = self.cmd.split_whitespace(); - let mut cmd = Command::new(parts.next().unwrap()); - cmd.args(parts); - match self.cwd { - Some(ref p) => { - cmd.current_dir(p); - } - None => { - cmd.current_dir(&self.project.root); - } - } - - for &(ref k, ref v) in self.env.iter() { - cmd.env(k, v); - } - - let mut me = env::current_exe().unwrap(); - me.pop(); // chop off exe name - me.pop(); // chop off `deps` - - let mut new_path = Vec::new(); - new_path.push(me); - new_path.extend(env::split_paths(&env::var_os("PATH").unwrap_or(Default::default()))); - cmd.env("PATH", env::join_paths(&new_path).unwrap()); - - // Don't output log stuff in tests, because it breaks our std{err,out} assertions - cmd.env("RUST_LOG", "warn"); - - if !self.check_vcs { - cmd.env("__CARGO_FIX_IGNORE_VCS", "true"); - } - - println!("\n···················································"); - println!("running {:?}", cmd); - let start = Instant::now(); - let output = match cmd.output() { - Ok(output) => output, - Err(err) => panic!("failed to spawn: {}", err), - }; - let dur = start.elapsed(); - println!( - "dur: {}.{:03}ms", - dur.as_secs(), - dur.subsec_nanos() / 1_000_000 - ); - println!("exit: {}", output.status); - if output.stdout.len() > 0 { - println!("stdout ---\n{}", String::from_utf8_lossy(&output.stdout)); - } - if output.stderr.len() > 0 { - println!("stderr ---\n{}", String::from_utf8_lossy(&output.stderr)); - } - println!("···················································"); - let code = match output.status.code() { - Some(code) => code, - None => panic!("super extra failure: {}", output.status), - }; - if code != self.status { - panic!("expected exit code `{}` got `{}`", self.status, code); - } - self.match_std(&output.stdout, &self.stdout, &self.stdout_contains, &[]); - self.match_std( - &output.stderr, - &self.stderr, - &self.stderr_contains, - &self.stderr_not_contains, - ); - } - - fn match_std( - &self, - actual: &[u8], - expected: &Option, - contains: &[String], - not_contains: &[String], - ) { - let actual = match str::from_utf8(actual) { - Ok(s) => s, - Err(_) => panic!("std wasn't utf8"), - }; - let actual = self.clean(actual); - if let Some(ref expected) = *expected { - diff(&self.clean(expected), &actual); - } - for s in contains { - let s = self.clean(s); - if actual.contains(&s) { - continue; - } - println!( - "\nfailed to find contents within output stream\n\ - expected to find\n {}\n\nwithin:\n\n{}\n\n", - s, actual - ); - panic!("test failed"); - } - for s in not_contains { - let s = self.clean(s); - if !actual.contains(&s) { - continue; - } - println!("expected to not find `{}`", s); - panic!("test failed"); - } - } - - fn clean(&self, s: &str) -> String { - let url = Url::from_file_path(&self.project.root).unwrap(); - let s = s.replace("[CHECKING]", " Checking") - .replace("[FINISHED]", " Finished") - .replace("[COMPILING]", " Compiling") - .replace("[FIXING]", " Fixing") - .replace(&url.to_string(), "CWD") - .replace(&self.project.root.display().to_string(), "CWD") - .replace("\\", "/"); - let lines = s.lines().map(|s| { - let i = match s.find("target(s) in") { - Some(i) => i, - None => return s.to_string(), - }; - if s.trim().starts_with("Finished") { - s[..i].to_string() - } else { - s.to_string() - } - }); - let mut ret = String::new(); - for (i, line) in lines.enumerate() { - if i != 0 { - ret.push_str("\n"); - } - ret.push_str(&line); - } - ret - } -} - -impl<'a> Drop for ExpectCmd<'a> { - fn drop(&mut self) { - if !self.ran { - panic!("forgot to run this command"); - } - } -} - -fn diff(expected: &str, actual: &str) { - let changeset = Changeset::new(expected.trim(), actual.trim(), "\n"); - - let mut different = false; - for diff in changeset.diffs { - let (prefix, diff) = match diff { - Difference::Same(_) => continue, - Difference::Add(add) => ("+", add), - Difference::Rem(rem) => ("-", rem), - }; - if !different { - println!("differences found (+ == actual, - == expected):\n"); - different = true; - } - for diff in diff.lines() { - println!("{} {}", prefix, diff); - } - } - if different { - println!(""); - panic!("found some differences"); - } -} - -mod broken_build; -mod broken_lints; -mod dependencies; -mod edition_upgrade; -mod rust_flags; -mod smoke; -mod subtargets; -mod vcs; -mod warnings; diff --git a/cargo-fix/tests/all/rust_flags.rs b/cargo-fix/tests/all/rust_flags.rs deleted file mode 100644 index 1d31c4cbd..000000000 --- a/cargo-fix/tests/all/rust_flags.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::project; - -#[test] -fn specify_rustflags() { - let p = project() - .file( - "src/lib.rs", - r#" - #![allow(unused)] - #![feature(rust_2018_preview)] - - mod foo { - pub const FOO: &str = "fooo"; - } - - fn main() { - let x = ::foo::FOO; - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (1 fix) -[FINISHED] dev [unoptimized + debuginfo] -"; - - p.expect_cmd("cargo-fix fix --prepare-for 2018") - .env("RUSTFLAGS", "-C target-cpu=native") - .stdout("") - .stderr(stderr) - .run(); -} diff --git a/cargo-fix/tests/all/smoke.rs b/cargo-fix/tests/all/smoke.rs deleted file mode 100644 index d0be80556..000000000 --- a/cargo-fix/tests/all/smoke.rs +++ /dev/null @@ -1,182 +0,0 @@ -use super::project; - -#[test] -fn no_changes_necessary() { - let p = project().file("src/lib.rs", "").build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn fixes_extra_mut() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() -> u32 { - let mut x = 3; - x - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (1 fix) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn fixes_two_missing_ampersands() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() -> u32 { - let mut x = 3; - let mut y = 3; - x + y - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (2 fixes) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn tricky() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() -> u32 { - let mut x = 3; let mut y = 3; - x + y - } - "#, - ) - .build(); - - let stderr = "\ -[CHECKING] foo v0.1.0 (CWD) -[FIXING] src/lib.rs (2 fixes) -[FINISHED] dev [unoptimized + debuginfo] -"; - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stdout("") - .stderr(stderr) - .run(); -} - -#[test] -fn preserve_line_endings() { - let p = project() - .file( - "src/lib.rs", - "\ - fn add(a: &u32) -> u32 { a + 1 }\r\n\ - pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ - ", - ) - .build(); - - p.expect_cmd("cargo-fix fix").fix_everything().run(); - assert!(p.read("src/lib.rs").contains("\r\n")); -} - -#[test] -fn fix_deny_warnings() { - let p = project() - .file( - "src/lib.rs", - "\ - #![deny(warnings)] - pub fn foo() { let mut x = 3; drop(x); } - ", - ) - .build(); - - p.expect_cmd("cargo-fix fix").fix_everything().run(); -} - -#[test] -fn fix_deny_warnings_but_not_others() { - let p = project() - .file( - "src/lib.rs", - " - #![deny(warnings)] - - pub fn foo() -> u32 { - let mut x = 3; - x - } - - fn bar() {} - ", - ) - .build(); - - p.expect_cmd("cargo-fix fix").fix_everything().run(); - assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); - assert!(p.read("src/lib.rs").contains("fn bar() {}")); -} - -#[test] -fn fix_two_files() { - let p = project() - .file( - "src/lib.rs", - " - pub mod bar; - - pub fn foo() -> u32 { - let mut x = 3; - x - } - ", - ) - .file( - "src/bar.rs", - " - pub fn foo() -> u32 { - let mut x = 3; - x - } - ", - ) - .build(); - - p.expect_cmd("cargo-fix fix") - .fix_everything() - .stderr_contains("[FIXING] src/bar.rs (1 fix)") - .stderr_contains("[FIXING] src/lib.rs (1 fix)") - .run(); - assert!(!p.read("src/lib.rs").contains("let mut x = 3;")); - assert!(!p.read("src/bar.rs").contains("let mut x = 3;")); -} diff --git a/cargo-fix/tests/all/subtargets.rs b/cargo-fix/tests/all/subtargets.rs deleted file mode 100644 index db8721136..000000000 --- a/cargo-fix/tests/all/subtargets.rs +++ /dev/null @@ -1,91 +0,0 @@ -use super::project; - -#[test] -fn fixes_missing_ampersand() { - let p = project() - .file( - "src/main.rs", - r#" - fn main() { let mut x = 3; drop(x); } - "#, - ) - .file( - "src/lib.rs", - r#" - pub fn foo() { let mut x = 3; drop(x); } - - #[test] - pub fn foo2() { let mut x = 3; drop(x); } - "#, - ) - .file( - "tests/a.rs", - r#" - #[test] - pub fn foo() { let mut x = 3; drop(x); } - "#, - ) - .file( - "examples/foo.rs", - r#" - fn main() { let mut x = 3; drop(x); } - "#, - ) - .file( - "build.rs", - r#" - fn main() { let mut x = 3; drop(x); } - "#, - ) - .build(); - - p.expect_cmd("cargo fix -- --all-targets") - .fix_everything() - .stdout("") - .stderr_contains("[COMPILING] foo v0.1.0 (CWD)") - .stderr_contains("[FIXING] build.rs (1 fix)") - // Don't assert number of fixes for this one, as we don't know if we're - // fixing it once or twice! We run this all concurrently, and if we - // compile (and fix) in `--test` mode first, we get two fixes. Otherwise - // we'll fix one non-test thing, and then fix another one later in - // test mode. - .stderr_contains("[FIXING] src/lib.rs") - .stderr_contains("[FIXING] src/main.rs (1 fix)") - .stderr_contains("[FIXING] examples/foo.rs (1 fix)") - .stderr_contains("[FIXING] tests/a.rs (1 fix)") - .stderr_contains("[FINISHED] dev [unoptimized + debuginfo]") - .run(); - p.expect_cmd("cargo build").run(); - p.expect_cmd("cargo test").run(); -} - -#[test] -fn fix_features() { - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.1.0" - - [features] - bar = [] - - [workspace] - "#, - ) - .file( - "src/lib.rs", - r#" - #[cfg(feature = "bar")] - pub fn foo() -> u32 { let mut x = 3; x } - "#, - ) - .build(); - - p.expect_cmd("cargo fix").run(); - p.expect_cmd("cargo build").run(); - p.expect_cmd("cargo fix -- --features bar").run(); - p.expect_cmd("cargo build --features bar").run(); -} diff --git a/cargo-fix/tests/all/vcs.rs b/cargo-fix/tests/all/vcs.rs deleted file mode 100644 index 7f04a490e..000000000 --- a/cargo-fix/tests/all/vcs.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::project; - -#[test] -fn warns_if_no_vcs_detected() { - let p = project() - .use_temp_dir() - .file( - "src/lib.rs", - r#" - pub fn foo() { - } - "#, - ) - .build(); - - p.expect_cmd("cargo-fix fix") - .check_vcs(true) - .stderr( - "warning: Could not detect a version control system\n\ - You should consider using a VCS so you can easily see and revert rustfix's changes.\n\ - error: No VCS found, aborting. Overwrite this behavior with `--allow-no-vcs`.\n\ - ", - ) - .status(102) - .run(); - p.expect_cmd("cargo-fix fix").status(0).run(); -} - -#[test] -fn warns_about_dirty_working_directory() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() { - } - "#, - ) - .build(); - - p.expect_cmd("git init").run(); - p.expect_cmd("cargo-fix fix") - .check_vcs(true) - .stderr( - "warning: Working directory dirty\n\ - Make sure your working directory is clean so you can easily revert rustfix's changes.\n\ - ?? Cargo.toml\n\ - ?? src/\n\ - error: Aborting because of dirty working directory. Overwrite this behavior with `--allow-dirty`.\n\n", - ) - .status(102) - .run(); - p.expect_cmd("cargo-fix fix --allow-dirty").status(0).run(); -} - -#[test] -fn does_not_warn_about_clean_working_directory() { - let p = project() - .file( - "src/lib.rs", - r#" - pub fn foo() { - } - "#, - ) - .build(); - - p.expect_cmd("git init").run(); - p.expect_cmd("git add .").run(); - p.expect_cmd("git config user.email rustfix@rustlang.org") - .run(); - p.expect_cmd("git config user.name RustFix").run(); - p.expect_cmd("git commit -m Initial-commit").run(); - p.expect_cmd("cargo-fix fix") - .check_vcs(true) - .status(0) - .run(); -} diff --git a/cargo-fix/tests/all/warnings.rs b/cargo-fix/tests/all/warnings.rs deleted file mode 100644 index fa53ea881..000000000 --- a/cargo-fix/tests/all/warnings.rs +++ /dev/null @@ -1,20 +0,0 @@ -use super::project; - -#[test] -fn shows_warnings() { - let p = project() - .file( - "src/lib.rs", - r#" - use std::default::Default; - - pub fn foo() { - } - "#, - ) - .build(); - - p.expect_cmd("cargo fix") - .stderr_contains("warning: unused import") - .run(); -} From 27646304a672bf79b313c161fe2ca639b4b7ad5d Mon Sep 17 00:00:00 2001 From: Without Boats Date: Fri, 20 Jul 2018 16:09:44 +0200 Subject: [PATCH 211/298] Add link to edition guide to README --- Readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Readme.md b/Readme.md index c7b96e5bf..c5a9d78ca 100644 --- a/Readme.md +++ b/Readme.md @@ -22,6 +22,11 @@ To use the rustfix library, add it to your `Cargo.toml`. To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. +## Using `cargo fix` to transition to Rust 2018 + +Instructions on how to use this tool to transition a crate to Rust 2018 can be +found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning.html) + ## License Licensed under either of From d0a60f0f22ec6af9d83f65b9c05f510ff38ae75a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jul 2018 17:18:48 -0700 Subject: [PATCH 212/298] Bump to 0.4.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e4b93fd67..0fb4efac8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "README.md" -version = "0.4.0" +version = "0.4.1" exclude = [ "etc/*", "examples/*", From ac3022e5560e0dc087ca2538de5df9bf24cc2b65 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jul 2018 17:20:32 -0700 Subject: [PATCH 213/298] Update manifest metadata --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0fb4efac8..71f7ff315 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ name = "rustfix" description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" -readme = "README.md" +readme = "Readme.md" version = "0.4.1" exclude = [ "etc/*", From c9d3e0964969ddf687bb868432b6ef99077ad6b7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Jul 2018 15:40:50 -0700 Subject: [PATCH 214/298] Handle invalid snippets instead of panicking This'll fix a panic encountered in rust-lang/cargo#5833 --- src/lib.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c109ef7e5..28840b4e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,7 +92,7 @@ pub struct Replacement { pub replacement: String, } -fn parse_snippet(span: &DiagnosticSpan) -> Snippet { +fn parse_snippet(span: &DiagnosticSpan) -> Option { // unindent the snippet let indent = span.text .iter() @@ -103,8 +103,7 @@ fn parse_snippet(span: &DiagnosticSpan) -> Snippet { .count(); std::cmp::min(indent, line.highlight_start) }) - .min() - .expect("text to replace is empty"); + .min()?; let start = span.text[0].highlight_start - 1; let end = span.text[0].highlight_end - 1; let lead = span.text[0].text[indent..start].to_string(); @@ -120,7 +119,7 @@ fn parse_snippet(span: &DiagnosticSpan) -> Snippet { body.push_str(&last.text[indent..last.highlight_end - 1]); } tail.push_str(&last.text[last.highlight_end - 1..]); - Snippet { + Some(Snippet { file_name: span.file_name.clone(), line_range: LineRange { start: LinePosition { @@ -134,16 +133,13 @@ fn parse_snippet(span: &DiagnosticSpan) -> Snippet { }, range: (span.byte_start as usize)..(span.byte_end as usize), text: (lead, body, tail), - } + }) } fn collect_span(span: &DiagnosticSpan) -> Option { - span.suggested_replacement - .clone() - .map(|replacement| Replacement { - snippet: parse_snippet(span), - replacement, - }) + let snippet = parse_snippet(span)?; + let replacement = span.suggested_replacement.clone()?; + Some(Replacement { snippet, replacement }) } pub fn collect_suggestions( @@ -166,7 +162,7 @@ pub fn collect_suggestions( let snippets = diagnostic .spans .iter() - .map(|span| parse_snippet(span)) + .filter_map(|span| parse_snippet(span)) .collect(); let solutions: Vec<_> = diagnostic From cb3229b8de756324c27c71b308537bb9f000f2f9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 31 Jul 2018 12:22:54 -0700 Subject: [PATCH 215/298] Expose an interface to apply fixes on-by-one This commit exposes an interface that Cargo can use to apply fixes one-by-one and know which fixes failed and which succeeded. --- src/lib.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c109ef7e5..1532e4b17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -210,22 +210,39 @@ pub fn collect_suggestions( } } -pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result { - use replace::Data; +pub struct CodeFix { + data: replace::Data, +} - let mut fixed = Data::new(code.as_bytes()); +impl CodeFix { + pub fn new(s: &str) -> CodeFix { + CodeFix { + data: replace::Data::new(s.as_bytes()), + } + } - for sug in suggestions.iter().rev() { - for sol in &sug.solutions { + pub fn apply(&mut self, suggestion: &Suggestion) -> Result<(), Error> { + for sol in &suggestion.solutions { for r in &sol.replacements { - fixed.replace_range( + self.data.replace_range( r.snippet.range.start, r.snippet.range.end.saturating_sub(1), r.replacement.as_bytes(), )?; } } + Ok(()) } - Ok(String::from_utf8(fixed.to_vec())?) + pub fn finish(&self) -> Result { + Ok(String::from_utf8(self.data.to_vec())?) + } +} + +pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result { + let mut fix = CodeFix::new(code); + for suggestion in suggestions.iter().rev() { + fix.apply(suggestion)?; + } + fix.finish() } From 28b9ec5bd7ac541f7092ec6a0d885a7918d68546 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 31 Jul 2018 13:39:18 -0700 Subject: [PATCH 216/298] Bump to 0.4.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 71f7ff315..4490f6522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "Readme.md" -version = "0.4.1" +version = "0.4.2" exclude = [ "etc/*", "examples/*", From da6b20dde55f4731f572a4fef7a8080da466ad63 Mon Sep 17 00:00:00 2001 From: lightning1141 Date: Tue, 14 Aug 2018 11:10:01 +0800 Subject: [PATCH 217/298] update links --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index c5a9d78ca..2026f0788 100644 --- a/Readme.md +++ b/Readme.md @@ -25,7 +25,7 @@ To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. ## Using `cargo fix` to transition to Rust 2018 Instructions on how to use this tool to transition a crate to Rust 2018 can be -found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning.html) +found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-your-code-to-a-new-edition.html) ## License From c6663426201ef9be3f51fb0b972236cefaf41bb0 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Mon, 20 Aug 2018 10:22:55 -0700 Subject: [PATCH 218/298] use RUSTC environment var in `parse_and_replace::compile` if present Cargo respects this environment variable (to specify the path to what rustc binary to use), but the Rustfix test suite did not. However, this capability is useful when developing new compiler diagnostics that one wants Rustfix to be able to handle (this being inspired by work on the endeavor that is rust-lang/rust#53013). --- tests/parse_and_replace.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index cc361cbc9..43e695d2e 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -13,6 +13,7 @@ extern crate difference; use std::collections::HashSet; use std::ffi::OsString; +use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; @@ -51,7 +52,7 @@ fn compile(file: &Path, mode: &str) -> Result { args.push("--edition=2018".into()); } - let res = duct::cmd("rustc", &args) + let res = duct::cmd(env::var_os("RUSTC").unwrap_or("rustc".into()), &args) .env("CLIPPY_DISABLE_DOCS_LINKS", "true") .env_remove("RUST_LOG") .stdout_capture() From 0476da8f7d29466dba278755a7d0238ecc0b43bf Mon Sep 17 00:00:00 2001 From: PSeitz Date: Sun, 7 Oct 2018 09:43:23 +0200 Subject: [PATCH 219/298] fix link --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 2026f0788..7efee7dc4 100644 --- a/Readme.md +++ b/Readme.md @@ -25,7 +25,7 @@ To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. ## Using `cargo fix` to transition to Rust 2018 Instructions on how to use this tool to transition a crate to Rust 2018 can be -found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-your-code-to-a-new-edition.html) +found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html) ## License From a0eb55d593899dc92925c6b5de59e409e8ce8c84 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 8 Dec 2018 22:38:57 +0100 Subject: [PATCH 220/298] allow multiple solutions --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7d510804c..c44a099e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ pub fn collect_suggestions( }) .filter_map(collect_span) .collect(); - if replacements.len() == 1 { + if replacements.len() >= 1 { Some(Solution { message: child.message.clone(), replacements, From 4a577a6999124054b25d0dbef114aded0ef29729 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 8 Dec 2018 23:10:01 +0100 Subject: [PATCH 221/298] remove test about multi-option lints --- .../skip-multi-option-lints.fixed.rs | 5 - tests/edge-cases/skip-multi-option-lints.json | 100 ------------------ tests/edge-cases/skip-multi-option-lints.rs | 5 - tests/edge_cases.rs | 12 --- 4 files changed, 122 deletions(-) delete mode 100644 tests/edge-cases/skip-multi-option-lints.fixed.rs delete mode 100644 tests/edge-cases/skip-multi-option-lints.json delete mode 100644 tests/edge-cases/skip-multi-option-lints.rs delete mode 100644 tests/edge_cases.rs diff --git a/tests/edge-cases/skip-multi-option-lints.fixed.rs b/tests/edge-cases/skip-multi-option-lints.fixed.rs deleted file mode 100644 index 9e1237188..000000000 --- a/tests/edge-cases/skip-multi-option-lints.fixed.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let xs = vec![String::from("foo")]; - let d: &Display = &xs; - println!("{}", d); -} diff --git a/tests/edge-cases/skip-multi-option-lints.json b/tests/edge-cases/skip-multi-option-lints.json deleted file mode 100644 index dc61ae6fb..000000000 --- a/tests/edge-cases/skip-multi-option-lints.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "message": "cannot find type `Display` in this scope", - "code": { - "code": "E0412", - "explanation": "\nThe type name used is not in scope.\n\nErroneous code examples:\n\n```compile_fail,E0412\nimpl Something {} // error: type name `Something` is not in scope\n\n// or:\n\ntrait Foo {\n fn bar(N); // error: type name `N` is not in scope\n}\n\n// or:\n\nfn foo(x: T) {} // type name `T` is not in scope\n```\n\nTo fix this error, please verify you didn't misspell the type name, you did\ndeclare it or imported it into the scope. Examples:\n\n```\nstruct Something;\n\nimpl Something {} // ok!\n\n// or:\n\ntrait Foo {\n type N;\n\n fn bar(_: Self::N); // ok!\n}\n\n// or:\n\nfn foo(x: T) {} // ok!\n```\n\nAnother case that causes this error is when a type is imported into a parent\nmodule. To fix this, you can follow the suggestion and use File directly or\n`use super::File;` which will import the types from the parent namespace. An\nexample that causes this error is below:\n\n```compile_fail,E0412\nuse std::fs::File;\n\nmod foo {\n fn some_function(f: File) {}\n}\n```\n\n```\nuse std::fs::File;\n\nmod foo {\n // either\n use super::File;\n // or\n // use std::fs::File;\n fn foo(f: File) {}\n}\n# fn main() {} // don't insert it for us; that'll break imports\n```\n" - }, - "level": "error", - "spans": [ - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 64, - "byte_end": 71, - "line_start": 3, - "line_end": 3, - "column_start": 13, - "column_end": 20, - "is_primary": true, - "text": [ - { - "text": " let d: &Display = &xs;", - "highlight_start": 13, - "highlight_end": 20 - } - ], - "label": "not found in this scope", - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "possible candidates are found in other modules, you can import them into scope", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 0, - "byte_end": 0, - "line_start": 1, - "line_end": 1, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::fmt::Display;\n\n", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 0, - "byte_end": 0, - "line_start": 1, - "line_end": 1, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::path::Display;\n\n", - "suggestion_applicability": "Unspecified", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "error[E0412]: cannot find type `Display` in this scope\n --> ./tests/everything/skip-multi-option-lints.rs:3:13\n |\n3 | let d: &Display = &xs;\n | ^^^^^^^ not found in this scope\nhelp: possible candidates are found in other modules, you can import them into scope\n |\n1 | use std::fmt::Display;\n |\n1 | use std::path::Display;\n |\n\n" -} -{ - "message": "aborting due to previous error", - "code": null, - "level": "error", - "spans": [], - "children": [], - "rendered": "error: aborting due to previous error\n\n" -} -{ - "message": "For more information about this error, try `rustc --explain E0412`.", - "code": null, - "level": "", - "spans": [], - "children": [], - "rendered": "For more information about this error, try `rustc --explain E0412`.\n" -} diff --git a/tests/edge-cases/skip-multi-option-lints.rs b/tests/edge-cases/skip-multi-option-lints.rs deleted file mode 100644 index 9e1237188..000000000 --- a/tests/edge-cases/skip-multi-option-lints.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let xs = vec![String::from("foo")]; - let d: &Display = &xs; - println!("{}", d); -} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs deleted file mode 100644 index 88489889d..000000000 --- a/tests/edge_cases.rs +++ /dev/null @@ -1,12 +0,0 @@ -extern crate rustfix; -use std::collections::HashSet; -use std::fs; - -#[test] -fn multiple_fix_options_yield_no_suggestions() { - let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) - .unwrap(); - assert!(expected_suggestions.is_empty()); -} From 5f1c320c3276fc6a786c30a4dd840f06e3451435 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 18:47:30 +0100 Subject: [PATCH 222/298] tests: use the cached json errors instead of calling rustc --- tests/parse_and_replace.rs | 50 +++----------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index cc361cbc9..dfdfc77c3 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -29,8 +29,6 @@ mod fixmode { mod settings { // can be set as env var to debug - pub const CHECK_JSON: &str = "RUSTFIX_TEST_CHECK_JSON"; - pub const RECORD_JSON: &str = "RUSTFIX_TEST_RECORD_JSON"; pub const RECORD_FIXED_RUST: &str = "RUSTFIX_TEST_RECORD_FIXED_RUST"; } @@ -62,20 +60,6 @@ fn compile(file: &Path, mode: &str) -> Result { Ok(res) } -fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result { - let res = compile(file, mode)?; - let stderr = String::from_utf8(res.stderr)?; - - match res.status.code() { - Some(0) | Some(1) | Some(101) => Ok(stderr), - _ => Err(format_err!( - "failed with status {:?}: {}", - res.status.code(), - stderr - )), - } -} - fn compiles_without_errors(file: &Path, mode: &str) -> Result<(), Error> { let res = compile(file, mode)?; @@ -122,7 +106,8 @@ fn diff(expected: &str, actual: &str) -> String { write!( &mut res, "differences found (+ == actual, - == expected):\n" - ).unwrap(); + ) + .unwrap(); different = true; } for diff in diff.lines() { @@ -149,39 +134,12 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err debug!("next up: {:?}", file); let code = read_file(file).context(format!("could not read {}", file.display()))?; - let errors = compile_and_get_json_errors(file, mode) - .context(format!("could compile {}", file.display()))?; + let errors = read_file(&json_file) + .with_context(|_| format!("could not load json suggestions for {}", file.display()))?; let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new(), filter_suggestions) .context("could not load suggestions")?; - if std::env::var(settings::RECORD_JSON).is_ok() { - use std::io::Write; - let mut recorded_json = fs::File::create(&file.with_extension("recorded.json")).context( - format!("could not create recorded.json for {}", file.display()), - )?; - recorded_json.write_all(errors.as_bytes())?; - } - - if std::env::var(settings::CHECK_JSON).is_ok() { - let expected_json = read_file(&json_file).context(format!( - "could not load json fixtures for {}", - file.display() - ))?; - let expected_suggestions = - rustfix::get_suggestions_from_json(&expected_json, &HashSet::new(), filter_suggestions) - .context("could not load expected suggesitons")?; - - ensure!( - expected_suggestions == suggestions, - "got unexpected suggestions from clippy:\n{}", - diff( - &format!("{:?}", expected_suggestions), - &format!("{:?}", suggestions) - ) - ); - } - let fixed = apply_suggestions(&code, &suggestions) .context(format!("could not apply suggestions to {}", file.display()))?; From 4595c3bf5182db006b6ad4f9ace6771553bcebfa Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 18:47:54 +0100 Subject: [PATCH 223/298] tests: add test for multiple suggestions --- tests/everything/multiple-solutions.fixed.rs | 5 + tests/everything/multiple-solutions.json | 114 +++++++++++++++++++ tests/everything/multiple-solutions.rs | 5 + 3 files changed, 124 insertions(+) create mode 100644 tests/everything/multiple-solutions.fixed.rs create mode 100644 tests/everything/multiple-solutions.json create mode 100644 tests/everything/multiple-solutions.rs diff --git a/tests/everything/multiple-solutions.fixed.rs b/tests/everything/multiple-solutions.fixed.rs new file mode 100644 index 000000000..1a261785d --- /dev/null +++ b/tests/everything/multiple-solutions.fixed.rs @@ -0,0 +1,5 @@ +use std::collections::{HashSet}; + +fn main() { + let _: HashSet<()>; +} diff --git a/tests/everything/multiple-solutions.json b/tests/everything/multiple-solutions.json new file mode 100644 index 000000000..89b14ccc8 --- /dev/null +++ b/tests/everything/multiple-solutions.json @@ -0,0 +1,114 @@ +{ + "message": "unused imports: `HashMap`, `VecDeque`", + "code": { + "code": "unused_imports", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "src/main.rs", + "byte_start": 23, + "byte_end": 30, + "line_start": 1, + "line_end": 1, + "column_start": 24, + "column_end": 31, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 24, + "highlight_end": 31 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + }, + { + "file_name": "src/main.rs", + "byte_start": 41, + "byte_end": 49, + "line_start": 1, + "line_end": 1, + "column_start": 42, + "column_end": 50, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 42, + "highlight_end": 50 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(unused_imports)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "remove the unused imports", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "src/main.rs", + "byte_start": 23, + "byte_end": 32, + "line_start": 1, + "line_end": 1, + "column_start": 24, + "column_end": 33, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 24, + "highlight_end": 33 + } + ], + "label": null, + "suggested_replacement": "", + "suggestion_applicability": "MachineApplicable", + "expansion": null + }, + { + "file_name": "src/main.rs", + "byte_start": 39, + "byte_end": 49, + "line_start": 1, + "line_end": 1, + "column_start": 40, + "column_end": 50, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 40, + "highlight_end": 50 + } + ], + "label": null, + "suggested_replacement": "", + "suggestion_applicability": "MachineApplicable", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused imports: `HashMap`, `VecDeque`\n --> src/main.rs:1:24\n |\n1 | use std::collections::{HashMap, HashSet, VecDeque};\n | ^^^^^^^ ^^^^^^^^\n |\n = note: #[warn(unused_imports)] on by default\nhelp: remove the unused imports\n |\n1 | use std::collections::{HashSet};\n | -- --\n\n" +} diff --git a/tests/everything/multiple-solutions.rs b/tests/everything/multiple-solutions.rs new file mode 100644 index 000000000..401198f7e --- /dev/null +++ b/tests/everything/multiple-solutions.rs @@ -0,0 +1,5 @@ +use std::collections::{HashMap, HashSet, VecDeque}; + +fn main() { + let _: HashSet<()>; +} From 298d740341a222d5f1e3c12b7610c0738c194bd9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 19:11:12 +0100 Subject: [PATCH 224/298] fix failure deprecation warning --- Cargo.toml | 2 +- tests/parse_and_replace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4490f6522..712f256b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -failure = "0.1.1" +failure = "0.1.2" log = "0.4.1" [dev-dependencies] diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index db2648f43..55bbe6d1e 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -186,7 +186,7 @@ fn assert_fixtures(dir: &str, mode: &str) { if let Err(err) = test_rustfix_with_file(file, mode) { println!("failed: {}", file.display()); warn!("{}", err); - for cause in err.causes().skip(1) { + for cause in err.iter_chain().skip(1) { info!("\tcaused by: {}", cause); } failures += 1; From 557ebdf2471e37f72a1e07cbdf9b10bf97735d36 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 19:12:23 +0100 Subject: [PATCH 225/298] release rustfix 0.4.3 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 712f256b3..3e6e0c6a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "Readme.md" -version = "0.4.2" +version = "0.4.3" exclude = [ "etc/*", "examples/*", From 42fd66debb29125356d42aad0eb88f72ce99bc0e Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 21:55:58 +0100 Subject: [PATCH 226/298] Revert "Allow multiple solutions in a suggestion" --- src/lib.rs | 2 +- .../skip-multi-option-lints.fixed.rs | 5 + tests/edge-cases/skip-multi-option-lints.json | 100 +++++++++++++++ tests/edge-cases/skip-multi-option-lints.rs | 5 + tests/edge_cases.rs | 12 ++ tests/everything/multiple-solutions.fixed.rs | 5 - tests/everything/multiple-solutions.json | 114 ------------------ tests/everything/multiple-solutions.rs | 5 - tests/parse_and_replace.rs | 50 +++++++- 9 files changed, 169 insertions(+), 129 deletions(-) create mode 100644 tests/edge-cases/skip-multi-option-lints.fixed.rs create mode 100644 tests/edge-cases/skip-multi-option-lints.json create mode 100644 tests/edge-cases/skip-multi-option-lints.rs create mode 100644 tests/edge_cases.rs delete mode 100644 tests/everything/multiple-solutions.fixed.rs delete mode 100644 tests/everything/multiple-solutions.json delete mode 100644 tests/everything/multiple-solutions.rs diff --git a/src/lib.rs b/src/lib.rs index c44a099e9..7d510804c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ pub fn collect_suggestions( }) .filter_map(collect_span) .collect(); - if replacements.len() >= 1 { + if replacements.len() == 1 { Some(Solution { message: child.message.clone(), replacements, diff --git a/tests/edge-cases/skip-multi-option-lints.fixed.rs b/tests/edge-cases/skip-multi-option-lints.fixed.rs new file mode 100644 index 000000000..9e1237188 --- /dev/null +++ b/tests/edge-cases/skip-multi-option-lints.fixed.rs @@ -0,0 +1,5 @@ +fn main() { + let xs = vec![String::from("foo")]; + let d: &Display = &xs; + println!("{}", d); +} diff --git a/tests/edge-cases/skip-multi-option-lints.json b/tests/edge-cases/skip-multi-option-lints.json new file mode 100644 index 000000000..dc61ae6fb --- /dev/null +++ b/tests/edge-cases/skip-multi-option-lints.json @@ -0,0 +1,100 @@ +{ + "message": "cannot find type `Display` in this scope", + "code": { + "code": "E0412", + "explanation": "\nThe type name used is not in scope.\n\nErroneous code examples:\n\n```compile_fail,E0412\nimpl Something {} // error: type name `Something` is not in scope\n\n// or:\n\ntrait Foo {\n fn bar(N); // error: type name `N` is not in scope\n}\n\n// or:\n\nfn foo(x: T) {} // type name `T` is not in scope\n```\n\nTo fix this error, please verify you didn't misspell the type name, you did\ndeclare it or imported it into the scope. Examples:\n\n```\nstruct Something;\n\nimpl Something {} // ok!\n\n// or:\n\ntrait Foo {\n type N;\n\n fn bar(_: Self::N); // ok!\n}\n\n// or:\n\nfn foo(x: T) {} // ok!\n```\n\nAnother case that causes this error is when a type is imported into a parent\nmodule. To fix this, you can follow the suggestion and use File directly or\n`use super::File;` which will import the types from the parent namespace. An\nexample that causes this error is below:\n\n```compile_fail,E0412\nuse std::fs::File;\n\nmod foo {\n fn some_function(f: File) {}\n}\n```\n\n```\nuse std::fs::File;\n\nmod foo {\n // either\n use super::File;\n // or\n // use std::fs::File;\n fn foo(f: File) {}\n}\n# fn main() {} // don't insert it for us; that'll break imports\n```\n" + }, + "level": "error", + "spans": [ + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 64, + "byte_end": 71, + "line_start": 3, + "line_end": 3, + "column_start": 13, + "column_end": 20, + "is_primary": true, + "text": [ + { + "text": " let d: &Display = &xs;", + "highlight_start": 13, + "highlight_end": 20 + } + ], + "label": "not found in this scope", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "possible candidates are found in other modules, you can import them into scope", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 1, + "line_end": 1, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::fmt::Display;\n\n", + "suggestion_applicability": "Unspecified", + "expansion": null + }, + { + "file_name": "./tests/everything/skip-multi-option-lints.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 1, + "line_end": 1, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::path::Display;\n\n", + "suggestion_applicability": "Unspecified", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0412]: cannot find type `Display` in this scope\n --> ./tests/everything/skip-multi-option-lints.rs:3:13\n |\n3 | let d: &Display = &xs;\n | ^^^^^^^ not found in this scope\nhelp: possible candidates are found in other modules, you can import them into scope\n |\n1 | use std::fmt::Display;\n |\n1 | use std::path::Display;\n |\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} +{ + "message": "For more information about this error, try `rustc --explain E0412`.", + "code": null, + "level": "", + "spans": [], + "children": [], + "rendered": "For more information about this error, try `rustc --explain E0412`.\n" +} diff --git a/tests/edge-cases/skip-multi-option-lints.rs b/tests/edge-cases/skip-multi-option-lints.rs new file mode 100644 index 000000000..9e1237188 --- /dev/null +++ b/tests/edge-cases/skip-multi-option-lints.rs @@ -0,0 +1,5 @@ +fn main() { + let xs = vec![String::from("foo")]; + let d: &Display = &xs; + println!("{}", d); +} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs new file mode 100644 index 000000000..88489889d --- /dev/null +++ b/tests/edge_cases.rs @@ -0,0 +1,12 @@ +extern crate rustfix; +use std::collections::HashSet; +use std::fs; + +#[test] +fn multiple_fix_options_yield_no_suggestions() { + let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); + let expected_suggestions = + rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) + .unwrap(); + assert!(expected_suggestions.is_empty()); +} diff --git a/tests/everything/multiple-solutions.fixed.rs b/tests/everything/multiple-solutions.fixed.rs deleted file mode 100644 index 1a261785d..000000000 --- a/tests/everything/multiple-solutions.fixed.rs +++ /dev/null @@ -1,5 +0,0 @@ -use std::collections::{HashSet}; - -fn main() { - let _: HashSet<()>; -} diff --git a/tests/everything/multiple-solutions.json b/tests/everything/multiple-solutions.json deleted file mode 100644 index 89b14ccc8..000000000 --- a/tests/everything/multiple-solutions.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "message": "unused imports: `HashMap`, `VecDeque`", - "code": { - "code": "unused_imports", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "src/main.rs", - "byte_start": 23, - "byte_end": 30, - "line_start": 1, - "line_end": 1, - "column_start": 24, - "column_end": 31, - "is_primary": true, - "text": [ - { - "text": "use std::collections::{HashMap, HashSet, VecDeque};", - "highlight_start": 24, - "highlight_end": 31 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - }, - { - "file_name": "src/main.rs", - "byte_start": 41, - "byte_end": 49, - "line_start": 1, - "line_end": 1, - "column_start": 42, - "column_end": 50, - "is_primary": true, - "text": [ - { - "text": "use std::collections::{HashMap, HashSet, VecDeque};", - "highlight_start": 42, - "highlight_end": 50 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "#[warn(unused_imports)] on by default", - "code": null, - "level": "note", - "spans": [], - "children": [], - "rendered": null - }, - { - "message": "remove the unused imports", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "src/main.rs", - "byte_start": 23, - "byte_end": 32, - "line_start": 1, - "line_end": 1, - "column_start": 24, - "column_end": 33, - "is_primary": true, - "text": [ - { - "text": "use std::collections::{HashMap, HashSet, VecDeque};", - "highlight_start": 24, - "highlight_end": 33 - } - ], - "label": null, - "suggested_replacement": "", - "suggestion_applicability": "MachineApplicable", - "expansion": null - }, - { - "file_name": "src/main.rs", - "byte_start": 39, - "byte_end": 49, - "line_start": 1, - "line_end": 1, - "column_start": 40, - "column_end": 50, - "is_primary": true, - "text": [ - { - "text": "use std::collections::{HashMap, HashSet, VecDeque};", - "highlight_start": 40, - "highlight_end": 50 - } - ], - "label": null, - "suggested_replacement": "", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unused imports: `HashMap`, `VecDeque`\n --> src/main.rs:1:24\n |\n1 | use std::collections::{HashMap, HashSet, VecDeque};\n | ^^^^^^^ ^^^^^^^^\n |\n = note: #[warn(unused_imports)] on by default\nhelp: remove the unused imports\n |\n1 | use std::collections::{HashSet};\n | -- --\n\n" -} diff --git a/tests/everything/multiple-solutions.rs b/tests/everything/multiple-solutions.rs deleted file mode 100644 index 401198f7e..000000000 --- a/tests/everything/multiple-solutions.rs +++ /dev/null @@ -1,5 +0,0 @@ -use std::collections::{HashMap, HashSet, VecDeque}; - -fn main() { - let _: HashSet<()>; -} diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 55bbe6d1e..7879b9643 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -30,6 +30,8 @@ mod fixmode { mod settings { // can be set as env var to debug + pub const CHECK_JSON: &str = "RUSTFIX_TEST_CHECK_JSON"; + pub const RECORD_JSON: &str = "RUSTFIX_TEST_RECORD_JSON"; pub const RECORD_FIXED_RUST: &str = "RUSTFIX_TEST_RECORD_FIXED_RUST"; } @@ -61,6 +63,20 @@ fn compile(file: &Path, mode: &str) -> Result { Ok(res) } +fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result { + let res = compile(file, mode)?; + let stderr = String::from_utf8(res.stderr)?; + + match res.status.code() { + Some(0) | Some(1) | Some(101) => Ok(stderr), + _ => Err(format_err!( + "failed with status {:?}: {}", + res.status.code(), + stderr + )), + } +} + fn compiles_without_errors(file: &Path, mode: &str) -> Result<(), Error> { let res = compile(file, mode)?; @@ -107,8 +123,7 @@ fn diff(expected: &str, actual: &str) -> String { write!( &mut res, "differences found (+ == actual, - == expected):\n" - ) - .unwrap(); + ).unwrap(); different = true; } for diff in diff.lines() { @@ -135,12 +150,39 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err debug!("next up: {:?}", file); let code = read_file(file).context(format!("could not read {}", file.display()))?; - let errors = read_file(&json_file) - .with_context(|_| format!("could not load json suggestions for {}", file.display()))?; + let errors = compile_and_get_json_errors(file, mode) + .context(format!("could compile {}", file.display()))?; let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new(), filter_suggestions) .context("could not load suggestions")?; + if std::env::var(settings::RECORD_JSON).is_ok() { + use std::io::Write; + let mut recorded_json = fs::File::create(&file.with_extension("recorded.json")).context( + format!("could not create recorded.json for {}", file.display()), + )?; + recorded_json.write_all(errors.as_bytes())?; + } + + if std::env::var(settings::CHECK_JSON).is_ok() { + let expected_json = read_file(&json_file).context(format!( + "could not load json fixtures for {}", + file.display() + ))?; + let expected_suggestions = + rustfix::get_suggestions_from_json(&expected_json, &HashSet::new(), filter_suggestions) + .context("could not load expected suggesitons")?; + + ensure!( + expected_suggestions == suggestions, + "got unexpected suggestions from clippy:\n{}", + diff( + &format!("{:?}", expected_suggestions), + &format!("{:?}", suggestions) + ) + ); + } + let fixed = apply_suggestions(&code, &suggestions) .context(format!("could not apply suggestions to {}", file.display()))?; From d9042713d2989a95f696ff272d7ea503ee935f93 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 11 Dec 2018 16:09:38 -0800 Subject: [PATCH 227/298] Make Diagnostic::rendered public. This is so that Cargo can show a rendered diagnostic. --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e507d568d..4b720eff9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -15,7 +15,7 @@ pub struct Diagnostic { /// The message as rustc would render it. Currently this is only /// `Some` for "suggestions", but eventually it will include all /// snippets. - rendered: Option, + pub rendered: Option, } #[derive(Deserialize, Debug)] From 7e88e7661532fcdeafe1b733dac44a7e95f1fd15 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 13 Dec 2018 08:23:24 -0800 Subject: [PATCH 228/298] Bump to 0.4.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3e6e0c6a0..0098fcf3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" readme = "Readme.md" -version = "0.4.3" +version = "0.4.4" exclude = [ "etc/*", "examples/*", From e03175e1d8b9898d0b6d5bd5937a379f3bbccddb Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 11 Jan 2019 11:57:30 -0800 Subject: [PATCH 229/298] Implement common traits for Diagnostic and associated types --- src/diagnostics.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4b720eff9..d81c2c4aa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -2,7 +2,7 @@ //! //! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Hash, Eq, PartialEq)] pub struct Diagnostic { /// The primary error message. pub message: String, @@ -18,7 +18,7 @@ pub struct Diagnostic { pub rendered: Option, } -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Hash, Eq, PartialEq)] pub struct DiagnosticSpan { pub file_name: String, pub byte_start: u32, @@ -46,7 +46,7 @@ pub struct DiagnosticSpan { expansion: Option>, } -#[derive(Copy, Clone, Debug, PartialEq, Deserialize)] +#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)] pub enum Applicability { MachineApplicable, HasPlaceholders, @@ -54,7 +54,7 @@ pub enum Applicability { Unspecified, } -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] pub struct DiagnosticSpanLine { pub text: String, @@ -64,7 +64,7 @@ pub struct DiagnosticSpanLine { pub highlight_end: usize, } -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] struct DiagnosticSpanMacroExpansion { /// span where macro was applied to generate this code; note that /// this may itself derive from a macro (if @@ -78,7 +78,7 @@ struct DiagnosticSpanMacroExpansion { def_site_span: Option, } -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] pub struct DiagnosticCode { /// The code itself. pub code: String, From dff0dba9d15a06b266f8e57c4d749734df46b9cf Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 11 Jan 2019 12:33:37 -0800 Subject: [PATCH 230/298] Derive Eq for Suggestion and related types --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7d510804c..83f7e3765 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ pub fn get_suggestions_from_json( Ok(result) } -#[derive(Debug, Copy, Clone, Hash, PartialEq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct LinePosition { pub line: usize, pub column: usize, @@ -49,7 +49,7 @@ impl std::fmt::Display for LinePosition { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct LineRange { pub start: LinePosition, pub end: LinePosition, @@ -61,7 +61,7 @@ impl std::fmt::Display for LineRange { } } -#[derive(Debug, Clone, Hash, PartialEq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] /// An error/warning and possible solutions for fixing it pub struct Suggestion { pub message: String, @@ -69,13 +69,13 @@ pub struct Suggestion { pub solutions: Vec, } -#[derive(Debug, Clone, Hash, PartialEq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Solution { pub message: String, pub replacements: Vec, } -#[derive(Debug, Clone, Hash, PartialEq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Snippet { pub file_name: String, pub line_range: LineRange, @@ -86,7 +86,7 @@ pub struct Snippet { pub text: (String, String, String), } -#[derive(Debug, Clone, Hash, PartialEq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Replacement { pub snippet: Snippet, pub replacement: String, From df1bba0f3b83413a329e47239b71a0f446997dea Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sun, 24 Mar 2019 18:32:46 +0100 Subject: [PATCH 231/298] Fix out of bounds access --- src/lib.rs | 13 +++++- tests/edge-cases/out_of_bounds.recorded.json | 43 ++++++++++++++++++++ tests/edge_cases.rs | 9 ++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/edge-cases/out_of_bounds.recorded.json diff --git a/src/lib.rs b/src/lib.rs index 83f7e3765..3c01bfcb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,11 +114,20 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { } let mut tail = String::new(); let last = &span.text[span.text.len() - 1]; + + // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of + // bounds' access by using text.len() - 1 instead. + let last_tail_index = if (last.highlight_end - 1) > last.text.len() { + last.text.len() - 1 + } else { + last.highlight_end - 1 + }; + if span.text.len() > 1 { body.push('\n'); - body.push_str(&last.text[indent..last.highlight_end - 1]); + body.push_str(&last.text[indent..last_tail_index]); } - tail.push_str(&last.text[last.highlight_end - 1..]); + tail.push_str(&last.text[last_tail_index..]); Some(Snippet { file_name: span.file_name.clone(), line_range: LineRange { diff --git a/tests/edge-cases/out_of_bounds.recorded.json b/tests/edge-cases/out_of_bounds.recorded.json new file mode 100644 index 000000000..147debb6c --- /dev/null +++ b/tests/edge-cases/out_of_bounds.recorded.json @@ -0,0 +1,43 @@ +{ + "message": "unterminated double quote string", + "code": null, + "level": "error", + "spans": [ + { + "file_name": "./tests/everything/tab_2.rs", + "byte_start": 485, + "byte_end": 526, + "line_start": 12, + "line_end": 13, + "column_start": 7, + "column_end": 3, + "is_primary": true, + "text": [ + { + "text": " \"\"\"; //~ ERROR unterminated double quote", + "highlight_start": 7, + "highlight_end": 45 + }, + { + "text": "}", + "highlight_start": 1, + "highlight_end": 3 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [], + "rendered": "error: unterminated double quote string\n --> ./tests/everything/tab_2.rs:12:7\n |\n12 | \"\"\"; //~ ERROR unterminated double quote\n | _______^\n13 | | }\n | |__^\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 88489889d..e787480f8 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -10,3 +10,12 @@ fn multiple_fix_options_yield_no_suggestions() { .unwrap(); assert!(expected_suggestions.is_empty()); } + +#[test] +fn out_of_bounds_test() { + let json = fs::read_to_string("./tests/edge-cases/out_of_bounds.recorded.json").unwrap(); + let expected_suggestions = + rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) + .unwrap(); + assert!(expected_suggestions.is_empty()); +} From cf0be8b970ff782b9e89c2650ba7e8ec4f4b20ce Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 25 Mar 2019 22:04:41 +0100 Subject: [PATCH 232/298] Replace conditional with min() --- src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3c01bfcb4..8b7e575b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,12 +116,8 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { let last = &span.text[span.text.len() - 1]; // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of - // bounds' access by using text.len() - 1 instead. - let last_tail_index = if (last.highlight_end - 1) > last.text.len() { - last.text.len() - 1 - } else { - last.highlight_end - 1 - }; + // bounds' access by making sure the index is within the array bounds. + let last_tail_index = last.highlight_end.min(last.text.len()) - 1; if span.text.len() > 1 { body.push('\n'); From 5d4c8c86e361718af4f8acd8daefdbb19943b58d Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Wed, 3 Apr 2019 16:42:52 +1000 Subject: [PATCH 233/298] Change example to automatically determine filename --- examples/fix-json.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/fix-json.rs b/examples/fix-json.rs index b9554856f..e3f91d668 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -2,14 +2,14 @@ extern crate failure; extern crate rustfix; use failure::Error; -use std::{env, fs, process, collections::HashSet}; +use std::{collections::HashMap, collections::HashSet, env, fs, process}; fn main() -> Result<(), Error> { let args: Vec = env::args().collect(); - let (suggestions_file, source_file) = match args.as_slice() { - [_, suggestions_file, source_file] => (suggestions_file, source_file), + let suggestions_file = match args.as_slice() { + [_, suggestions_file] => suggestions_file, _ => { - println!("USAGE: fix-json "); + println!("USAGE: fix-json "); process::exit(1); } }; @@ -21,11 +21,21 @@ fn main() -> Result<(), Error> { rustfix::Filter::Everything, )?; - let source = fs::read_to_string(&source_file)?; + let mut files = HashMap::new(); + for suggestion in suggestions { + let file = suggestion.solutions[0].replacements[0] + .snippet + .file_name + .clone(); + let entry = files.entry(file).or_insert(Vec::new()); + entry.push(suggestion); + } - let fixes = rustfix::apply_suggestions(&source, &suggestions)?; - - println!("{}", fixes); + for (source_file, suggestions) in &files { + let source = fs::read_to_string(&source_file)?; + let fixes = rustfix::apply_suggestions(&source, suggestions)?; + fs::write(&source_file, fixes)?; + } Ok(()) } From 47e9aab8833f1a1eeef82adae7ce5b875c38eb19 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Wed, 3 Apr 2019 18:29:42 +1000 Subject: [PATCH 234/298] example/fix-json: Apply suggestions from code review --- examples/fix-json.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/examples/fix-json.rs b/examples/fix-json.rs index e3f91d668..b8a73b451 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -2,19 +2,18 @@ extern crate failure; extern crate rustfix; use failure::Error; -use std::{collections::HashMap, collections::HashSet, env, fs, process}; +use std::io::{stdin, BufReader, Read}; +use std::{collections::HashMap, collections::HashSet, env, fs}; fn main() -> Result<(), Error> { - let args: Vec = env::args().collect(); - let suggestions_file = match args.as_slice() { - [_, suggestions_file] => suggestions_file, - _ => { - println!("USAGE: fix-json "); - process::exit(1); - } + let suggestions_file = env::args().nth(1).expect("USAGE: fix-json "); + let suggestions = if suggestions_file == "--" { + let mut buffer = String::new(); + BufReader::new(stdin()).read_to_string(&mut buffer)?; + buffer + } else { + fs::read_to_string(&suggestions_file)? }; - - let suggestions = fs::read_to_string(&suggestions_file)?; let suggestions = rustfix::get_suggestions_from_json( &suggestions, &HashSet::new(), @@ -27,14 +26,13 @@ fn main() -> Result<(), Error> { .snippet .file_name .clone(); - let entry = files.entry(file).or_insert(Vec::new()); - entry.push(suggestion); + files.entry(file).or_insert_with(Vec::new).push(suggestion); } for (source_file, suggestions) in &files { - let source = fs::read_to_string(&source_file)?; + let source = fs::read_to_string(source_file)?; let fixes = rustfix::apply_suggestions(&source, suggestions)?; - fs::write(&source_file, fixes)?; + fs::write(source_file, fixes)?; } Ok(()) From f126ec846cf1fe8e80ec88fcb76e26a8847fa5c6 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Wed, 3 Apr 2019 18:54:17 +1000 Subject: [PATCH 235/298] example/fix-json: skip suggestions that don't apply --- examples/fix-json.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/fix-json.rs b/examples/fix-json.rs index b8a73b451..f198ace34 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -31,7 +31,13 @@ fn main() -> Result<(), Error> { for (source_file, suggestions) in &files { let source = fs::read_to_string(source_file)?; - let fixes = rustfix::apply_suggestions(&source, suggestions)?; + let mut fix = rustfix::CodeFix::new(&source); + for suggestion in suggestions.iter().rev() { + if let Err(e) = fix.apply(suggestion) { + eprintln!("Failed to apply suggestion to {}: {}", source_file, e); + } + } + let fixes = fix.finish()?; fs::write(source_file, fixes)?; } From 0cc670dd5b40d71152eb334e841918f968779fc2 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 4 Apr 2019 20:03:13 +0200 Subject: [PATCH 236/298] Fix string indexing Previously rustfix was treating the highlight indices as byte offsets. This caused it to crash when a highlight index was pointing inside a multi-byte character. This fix makes sure to index into the characters of the string instead of the bytes. --- src/lib.rs | 14 +++-- tests/edge-cases/utf8_idents.recorded.json | 59 ++++++++++++++++++++++ tests/edge_cases.rs | 9 ++++ 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 tests/edge-cases/utf8_idents.recorded.json diff --git a/src/lib.rs b/src/lib.rs index 8b7e575b5..5f5e64099 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,10 +104,15 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { std::cmp::min(indent, line.highlight_start) }) .min()?; + + let text_slice = span.text[0].text.chars().collect::>(); + + // We subtract `1` because these highlights are 1-based let start = span.text[0].highlight_start - 1; let end = span.text[0].highlight_end - 1; - let lead = span.text[0].text[indent..start].to_string(); - let mut body = span.text[0].text[start..end].to_string(); + let lead = text_slice[indent..start].iter().collect(); + let mut body: String = text_slice[start..end].iter().collect(); + for line in span.text.iter().take(span.text.len() - 1).skip(1) { body.push('\n'); body.push_str(&line.text[indent..]); @@ -118,12 +123,13 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of // bounds' access by making sure the index is within the array bounds. let last_tail_index = last.highlight_end.min(last.text.len()) - 1; + let last_slice = last.text.chars().collect::>(); if span.text.len() > 1 { body.push('\n'); - body.push_str(&last.text[indent..last_tail_index]); + body.push_str(&last_slice[indent..last_tail_index].iter().collect::()); } - tail.push_str(&last.text[last_tail_index..]); + tail.push_str(&last_slice[last_tail_index..].iter().collect::()); Some(Snippet { file_name: span.file_name.clone(), line_range: LineRange { diff --git a/tests/edge-cases/utf8_idents.recorded.json b/tests/edge-cases/utf8_idents.recorded.json new file mode 100644 index 000000000..28950d694 --- /dev/null +++ b/tests/edge-cases/utf8_idents.recorded.json @@ -0,0 +1,59 @@ +{ + "message": "expected one of `,`, `:`, `=`, or `>`, found `'β`", + "code": null, + "level": "error", + "spans": [ + { + "file_name": "./tests/everything/utf8_idents.rs", + "byte_start": 14, + "byte_end": 14, + "line_start": 2, + "line_end": 2, + "column_start": 6, + "column_end": 6, + "is_primary": false, + "text": [ + { + "text": " γ //~ ERROR non-ascii idents are not fully supported", + "highlight_start": 6, + "highlight_end": 6 + } + ], + "label": "expected one of `,`, `:`, `=`, or `>` here", + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + }, + { + "file_name": "./tests/everything/utf8_idents.rs", + "byte_start": 145, + "byte_end": 148, + "line_start": 4, + "line_end": 4, + "column_start": 5, + "column_end": 7, + "is_primary": true, + "text": [ + { + "text": " 'β, //~ ERROR non-ascii idents are not fully supported", + "highlight_start": 5, + "highlight_end": 7 + } + ], + "label": "unexpected token", + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [], + "rendered": "error: expected one of `,`, `:`, `=`, or `>`, found `'β`\n --> ./tests/everything/utf8_idents.rs:4:5\n |\n2 | γ //~ ERROR non-ascii idents are not fully supported\n | - expected one of `,`, `:`, `=`, or `>` here\n3 | //~^ WARN type parameter `γ` should have an upper camel case name\n4 | 'β, //~ ERROR non-ascii idents are not fully supported\n | ^^ unexpected token\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index e787480f8..a93a1dc6d 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -19,3 +19,12 @@ fn out_of_bounds_test() { .unwrap(); assert!(expected_suggestions.is_empty()); } + +#[test] +fn utf8_identifiers_test() { + let json = fs::read_to_string("./tests/edge-cases/utf8_idents.recorded.json").unwrap(); + let expected_suggestions = + rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) + .unwrap(); + assert!(expected_suggestions.is_empty()); +} From e6b66f0e04e2670c808449b0d1d00e7b8261e58d Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 4 Apr 2019 20:05:14 +0200 Subject: [PATCH 237/298] Migrate to Rust 2018 --- Cargo.toml | 1 + examples/fix-json.rs | 4 ++-- src/lib.rs | 14 ++++++++------ tests/edge_cases.rs | 2 +- tests/parse_and_replace.rs | 12 ++++++------ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0098fcf3e..51059434b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ name = "rustfix" description = "Automatically apply the suggestions made by rustc" repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" +edition = "2018" readme = "Readme.md" version = "0.4.4" exclude = [ diff --git a/examples/fix-json.rs b/examples/fix-json.rs index f198ace34..96bdac403 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -1,5 +1,5 @@ -extern crate failure; -extern crate rustfix; + +use rustfix; use failure::Error; use std::io::{stdin, BufReader, Read}; diff --git a/src/lib.rs b/src/lib.rs index 8b7e575b5..49a8573e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(rust_2018_idioms)] + #[macro_use] extern crate log; #[macro_use] @@ -7,7 +9,7 @@ extern crate failure; extern crate proptest; #[macro_use] extern crate serde_derive; -extern crate serde_json; +use serde_json; use std::collections::HashSet; use std::ops::Range; @@ -15,7 +17,7 @@ use std::ops::Range; use failure::Error; pub mod diagnostics; -use diagnostics::{Diagnostic, DiagnosticSpan}; +use crate::diagnostics::{Diagnostic, DiagnosticSpan}; mod replace; #[derive(Debug, Clone, Copy)] @@ -44,7 +46,7 @@ pub struct LinePosition { } impl std::fmt::Display for LinePosition { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}:{}", self.line, self.column) } } @@ -56,7 +58,7 @@ pub struct LineRange { } impl std::fmt::Display for LineRange { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}-{}", self.start, self.end) } } @@ -178,8 +180,8 @@ pub fn collect_suggestions( .spans .iter() .filter(|span| { - use Filter::*; - use diagnostics::Applicability::*; + use crate::Filter::*; + use crate::diagnostics::Applicability::*; match (filter, &span.suggestion_applicability) { (MachineApplicableOnly, Some(MachineApplicable)) => true, diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index e787480f8..b2c1670bc 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -1,4 +1,4 @@ -extern crate rustfix; +use rustfix; use std::collections::HashSet; use std::fs; diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 7879b9643..b97b5ce2b 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -1,15 +1,15 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows -extern crate duct; -extern crate env_logger; +use duct; +use env_logger; #[macro_use] extern crate log; -extern crate rustfix; -extern crate serde_json; -extern crate tempdir; +use rustfix; + + #[macro_use] extern crate failure; -extern crate difference; + use std::collections::HashSet; use std::ffi::OsString; From 9ddee0e7843a240802238a5e62199821ee170009 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 13 May 2019 14:23:51 -0400 Subject: [PATCH 238/298] use `derive` feature over `serde_derive` crate --- Cargo.toml | 3 +-- src/diagnostics.rs | 2 ++ src/lib.rs | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51059434b..2b1149630 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,8 @@ exclude = [ ] [dependencies] -serde = "1.0" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde_derive = "1.0" failure = "0.1.2" log = "0.4.1" diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d81c2c4aa..9e0be81e7 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -2,6 +2,8 @@ //! //! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) +use serde::Deserialize; + #[derive(Clone, Deserialize, Debug, Hash, Eq, PartialEq)] pub struct Diagnostic { /// The primary error message. diff --git a/src/lib.rs b/src/lib.rs index 49a8573e8..28c660de8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,6 @@ extern crate failure; #[cfg(test)] #[macro_use] extern crate proptest; -#[macro_use] -extern crate serde_derive; use serde_json; use std::collections::HashSet; From b9c2ea221ff21d85c336aeab03f405b7f6dc66ca Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 6 Aug 2019 16:22:21 -0700 Subject: [PATCH 239/298] Update tests for `bare_trait_objects` warning. --- tests/everything/E0178.fixed.rs | 2 +- tests/everything/E0178.rs | 2 +- tests/everything/closure-immutable-outer-variable.fixed.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/everything/E0178.fixed.rs b/tests/everything/E0178.fixed.rs index e8f318813..07e611774 100644 --- a/tests/everything/E0178.fixed.rs +++ b/tests/everything/E0178.fixed.rs @@ -3,7 +3,7 @@ trait Foo {} struct Bar<'a> { - w: &'a (Foo + Send), + w: &'a (dyn Foo + Send), } fn main() { diff --git a/tests/everything/E0178.rs b/tests/everything/E0178.rs index c04e2a8cd..24226fe0e 100644 --- a/tests/everything/E0178.rs +++ b/tests/everything/E0178.rs @@ -3,7 +3,7 @@ trait Foo {} struct Bar<'a> { - w: &'a Foo + Send, + w: &'a dyn Foo + Send, } fn main() { diff --git a/tests/everything/closure-immutable-outer-variable.fixed.rs b/tests/everything/closure-immutable-outer-variable.fixed.rs index 80a5a45a3..0c41b6aa3 100644 --- a/tests/everything/closure-immutable-outer-variable.fixed.rs +++ b/tests/everything/closure-immutable-outer-variable.fixed.rs @@ -10,7 +10,7 @@ // Point at the captured immutable outer variable -fn foo(mut f: Box) { +fn foo(mut f: Box) { f(); } From e6bb424420ccacb0c9b4a53ae71c1d17288e4b3a Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Tue, 16 Jul 2019 21:46:07 +0200 Subject: [PATCH 240/298] Bump version to 0.4.6 and add change log --- Cargo.toml | 2 +- Changelog.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 Changelog.md diff --git a/Cargo.toml b/Cargo.toml index 2b1149630..0ee7b233c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" edition = "2018" readme = "Readme.md" -version = "0.4.4" +version = "0.4.6" exclude = [ "etc/*", "examples/*", diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 000000000..1b57320e6 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,79 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.4.6] - 2019-07-16 + +### Changed + +Internal changes: + +- Change example to automatically determine filename +- Migrate to Rust 2018 +- use `derive` feature over `serde_derive` crate + +## [0.4.5] - 2019-03-26 + +### Added + +- Implement common traits for Diagnostic and related types + +### Fixed + +- Fix out of bounds access in parse_snippet + +## [0.4.4] - 2018-12-13 + +### Added + +- Make Diagnostic::rendered public. + +### Changed + +- Revert faulty "Allow multiple solutions in a suggestion" + +## [0.4.3] - 2018-12-09 - *yanked!* + +### Added + +- Allow multiple solutions in a suggestion + +### Changed + +- use `RUSTC` environment var if present + +## [0.4.2] - 2018-07-31 + +### Added + +- Expose an interface to apply fixes on-by-one + +### Changed + +- Handle invalid snippets instead of panicking + +## [0.4.1] - 2018-07-26 + +### Changed + +- Ignore duplicate replacements + +## [0.4.0] - 2018-05-23 + +### Changed + +- Filter by machine applicability by default + +[Unreleased]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.6...HEAD +[0.4.6]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.5...rustfix-0.4.6 +[0.4.5]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.4...rustfix-0.4.5 +[0.4.4]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.3...rustfix-0.4.4 +[0.4.3]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.2...rustfix-0.4.3 +[0.4.2]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.1...rustfix-0.4.2 +[0.4.1]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.0...rustfix-0.4.1 +[0.4.0]: https://github.com/rust-lang-nursery/rustfix/compare/rustfix-0.4.0 From 8a5949dd9af97679d12169fe77530ad5df679691 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Thu, 8 Aug 2019 21:50:26 -0700 Subject: [PATCH 241/298] Update Travis CI URL --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 7efee7dc4..bec178065 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ The goal of this tool is to read and apply the suggestions made by rustc. -[![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) +[![Build Status](https://travis-ci.com/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/rustfix) [![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) ## Current status From 4cd5108aa9b68225d35b99d6c681376087425568 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Oct 2019 20:29:18 -0700 Subject: [PATCH 242/298] Switch from Travis/AppVeyor to Github Actions --- .appveyor.yml | 16 ---------------- .github/workflows/main.yml | 32 ++++++++++++++++++++++++++++++++ .travis.yml | 9 --------- 3 files changed, 32 insertions(+), 25 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 34e2e31ff..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,16 +0,0 @@ -environment: - matrix: - - TARGET: x86_64-pc-windows-msvc - -install: - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - rustc -V - - cargo -V - - del rustup-init.exe - -build: false - -test_script: - - cargo test --all diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..161808c5d --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,32 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + steps: + - uses: actions/checkout@master + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + if: matrix.os != 'macos-latest' + shell: bash + - name: Install Rust (macos) + run: | + curl https://sh.rustup.rs | sh -s -- -y + echo ::add-path::$HOME/.cargo/bin + if: matrix.os == 'macos-latest' + - run: cargo test --all + - run: cargo test --all -- --ignored + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 297b02d77..000000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: rust -rust: - - nightly -script: - - cargo test --all - - cargo test --all -- --ignored -notifications: - email: - on_success: never From ba81441f297c6d9799473a62af021236b8bc9ed8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Oct 2019 20:31:31 -0700 Subject: [PATCH 243/298] Run rustfmt --- examples/fix-json.rs | 1 - src/lib.rs | 19 ++++++++++++++----- src/replace.rs | 20 ++++++++++---------- tests/parse_and_replace.rs | 7 +++---- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/examples/fix-json.rs b/examples/fix-json.rs index 96bdac403..46330fb95 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -1,4 +1,3 @@ - use rustfix; use failure::Error; diff --git a/src/lib.rs b/src/lib.rs index 124f9fdc2..7015d8091 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,10 +94,12 @@ pub struct Replacement { fn parse_snippet(span: &DiagnosticSpan) -> Option { // unindent the snippet - let indent = span.text + let indent = span + .text .iter() .map(|line| { - let indent = line.text + let indent = line + .text .chars() .take_while(|&c| char::is_whitespace(c)) .count(); @@ -127,7 +129,11 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { if span.text.len() > 1 { body.push('\n'); - body.push_str(&last_slice[indent..last_tail_index].iter().collect::()); + body.push_str( + &last_slice[indent..last_tail_index] + .iter() + .collect::(), + ); } tail.push_str(&last_slice[last_tail_index..].iter().collect::()); Some(Snippet { @@ -150,7 +156,10 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { fn collect_span(span: &DiagnosticSpan) -> Option { let snippet = parse_snippet(span)?; let replacement = span.suggested_replacement.clone()?; - Some(Replacement { snippet, replacement }) + Some(Replacement { + snippet, + replacement, + }) } pub fn collect_suggestions( @@ -184,8 +193,8 @@ pub fn collect_suggestions( .spans .iter() .filter(|span| { - use crate::Filter::*; use crate::diagnostics::Applicability::*; + use crate::Filter::*; match (filter, &span.suggestion_applicability) { (MachineApplicableOnly, Some(MachineApplicable)) => true, diff --git a/src/replace.rs b/src/replace.rs index 9dfbd4d94..a920a5490 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -43,13 +43,11 @@ impl Data { pub fn new(data: &[u8]) -> Self { Data { original: data.into(), - parts: vec![ - Span { - data: State::Initial, - start: 0, - end: data.len().saturating_sub(1), - }, - ], + parts: vec![Span { + data: State::Initial, + start: 0, + end: data.len().saturating_sub(1), + }], } } @@ -105,7 +103,8 @@ impl Data { // the whole chunk. As an optimization and without loss of generality we // don't add empty parts. let new_parts = { - let index_of_part_to_split = self.parts + let index_of_part_to_split = self + .parts .iter() .position(|p| { !p.data.is_inserted() && p.start <= from && p.end >= up_to_and_including @@ -113,7 +112,8 @@ impl Data { .ok_or_else(|| { use log::Level::Debug; if log_enabled!(Debug) { - let slices = self.parts + let slices = self + .parts .iter() .map(|p| { ( @@ -154,7 +154,7 @@ impl Data { if part_to_split.start == from && part_to_split.end == up_to_and_including { if let State::Replaced(ref replacement) = part_to_split.data { if &**replacement == data { - return Ok(()) + return Ok(()); } } } diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index b97b5ce2b..433861236 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -6,14 +6,12 @@ use env_logger; extern crate log; use rustfix; - #[macro_use] extern crate failure; - use std::collections::HashSet; -use std::ffi::OsString; use std::env; +use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; @@ -123,7 +121,8 @@ fn diff(expected: &str, actual: &str) -> String { write!( &mut res, "differences found (+ == actual, - == expected):\n" - ).unwrap(); + ) + .unwrap(); different = true; } for diff in diff.lines() { From 653533315ce96c87f9553c485cff7431920ad5e4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 29 Oct 2019 06:57:20 -0700 Subject: [PATCH 244/298] Remove outdated build badges --- Readme.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/Readme.md b/Readme.md index bec178065..fb5eda843 100644 --- a/Readme.md +++ b/Readme.md @@ -2,9 +2,6 @@ The goal of this tool is to read and apply the suggestions made by rustc. -[![Build Status](https://travis-ci.com/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/rustfix) -[![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) - ## Current status Currently, rustfix is split into two crates: From e7241b32092d3f2fa9603d2267963233313b1f20 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 29 Oct 2019 06:57:28 -0700 Subject: [PATCH 245/298] Remove bors configuration --- bors.toml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 bors.toml diff --git a/bors.toml b/bors.toml deleted file mode 100644 index 611828927..000000000 --- a/bors.toml +++ /dev/null @@ -1,4 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push", -] -required_approvals = 1 From 5553ac436d4f54f4b23e0d21589140c704648d80 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Jan 2020 13:21:16 -0800 Subject: [PATCH 246/298] Migrate from `failure` to `anyhow` This moves from a custom error trait to the standard `Error` trait, improving ecosystem interoperability. --- Cargo.toml | 2 +- src/lib.rs | 4 +--- src/replace.rs | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ee7b233c..d2245c84d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -failure = "0.1.2" +anyhow = "1.0.0" log = "0.4.1" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 7015d8091..8026f00c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ #[macro_use] extern crate log; -#[macro_use] -extern crate failure; #[cfg(test)] #[macro_use] extern crate proptest; @@ -12,7 +10,7 @@ use serde_json; use std::collections::HashSet; use std::ops::Range; -use failure::Error; +use anyhow::Error; pub mod diagnostics; use crate::diagnostics::{Diagnostic, DiagnosticSpan}; diff --git a/src/replace.rs b/src/replace.rs index a920a5490..ecdce4f09 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -2,7 +2,7 @@ //! replacement of parts of its content, with the ability to prevent changing //! the same parts multiple times. -use failure::Error; +use anyhow::{Error, ensure, anyhow}; use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq)] @@ -133,7 +133,7 @@ impl Data { ); } - format_err!( + anyhow!( "Could not replace range {}...{} in file \ -- maybe parts of it were already replaced?", from, From c3f8cd3cd2999949c49c8f0e76108ffe7a37bec0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Jan 2020 13:24:35 -0800 Subject: [PATCH 247/298] Run rustfmt --- src/replace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/replace.rs b/src/replace.rs index ecdce4f09..807104939 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -2,7 +2,7 @@ //! replacement of parts of its content, with the ability to prevent changing //! the same parts multiple times. -use anyhow::{Error, ensure, anyhow}; +use anyhow::{anyhow, ensure, Error}; use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq)] From c43a5ec7e5b24ab17d92470d7c2bc2b3056af110 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Jan 2020 13:28:59 -0800 Subject: [PATCH 248/298] More updates to anyhow --- examples/fix-json.rs | 4 +--- tests/parse_and_replace.rs | 23 +++++------------------ 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/examples/fix-json.rs b/examples/fix-json.rs index 46330fb95..6d77a8ddb 100644 --- a/examples/fix-json.rs +++ b/examples/fix-json.rs @@ -1,6 +1,4 @@ -use rustfix; - -use failure::Error; +use anyhow::Error; use std::io::{stdin, BufReader, Read}; use std::{collections::HashMap, collections::HashSet, env, fs}; diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 433861236..5028f5aee 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -1,25 +1,15 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows -use duct; -use env_logger; -#[macro_use] -extern crate log; -use rustfix; - -#[macro_use] -extern crate failure; - use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; - -use failure::{Error, ResultExt}; +use anyhow::{Error, Context, ensure, anyhow}; use tempdir::TempDir; - use rustfix::apply_suggestions; +use log::{info, warn, debug}; mod fixmode { pub const EVERYTHING: &str = "yolo"; @@ -67,7 +57,7 @@ fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result match res.status.code() { Some(0) | Some(1) | Some(101) => Ok(stderr), - _ => Err(format_err!( + _ => Err(anyhow!( "failed with status {:?}: {}", res.status.code(), stderr @@ -86,7 +76,7 @@ fn compiles_without_errors(file: &Path, mode: &str) -> Result<(), Error> { file, String::from_utf8(res.stderr)? ); - Err(format_err!( + Err(anyhow!( "failed with status {:?} (`env RUST_LOG=parse_and_replace=info` for more info)", res.status.code(), )) @@ -226,10 +216,7 @@ fn assert_fixtures(dir: &str, mode: &str) { for file in &files { if let Err(err) = test_rustfix_with_file(file, mode) { println!("failed: {}", file.display()); - warn!("{}", err); - for cause in err.iter_chain().skip(1) { - info!("\tcaused by: {}", cause); - } + warn!("{:?}", err); failures += 1; } info!("passed: {:?}", file); From c56cb4287fa98a42dafea36d0b88bb4441f63c1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Jan 2020 13:30:22 -0800 Subject: [PATCH 249/298] Run rustfmt --- tests/parse_and_replace.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 5028f5aee..c3f570163 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -1,15 +1,15 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows +use anyhow::{anyhow, ensure, Context, Error}; +use log::{debug, info, warn}; +use rustfix::apply_suggestions; use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; -use anyhow::{Error, Context, ensure, anyhow}; use tempdir::TempDir; -use rustfix::apply_suggestions; -use log::{info, warn, debug}; mod fixmode { pub const EVERYTHING: &str = "yolo"; From 715eff0b15b6ffc5adcb016b6713132159681723 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Jan 2020 13:36:48 -0800 Subject: [PATCH 250/298] Bump to 0.5.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d2245c84d..66ed77ff8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" edition = "2018" readme = "Readme.md" -version = "0.4.6" +version = "0.5.0" exclude = [ "etc/*", "examples/*", From 9986e9a560c1a5ce7fd836da4a765dd54fb91a49 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 28 Jan 2020 00:44:28 -0800 Subject: [PATCH 251/298] Update CI installation of Rust on macos --- .github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 161808c5d..de576448b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,13 +12,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - if: matrix.os != 'macos-latest' shell: bash - - name: Install Rust (macos) - run: | - curl https://sh.rustup.rs | sh -s -- -y - echo ::add-path::$HOME/.cargo/bin - if: matrix.os == 'macos-latest' - run: cargo test --all - run: cargo test --all -- --ignored From f3f1035b701ba3f0aad51a2c48740a99288aaa79 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 16:51:46 -0700 Subject: [PATCH 252/298] Remove duplicate in edge-cases tests. --- tests/edge_cases.rs | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index e1f380a37..a265c04dc 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -2,29 +2,22 @@ use rustfix; use std::collections::HashSet; use std::fs; -#[test] -fn multiple_fix_options_yield_no_suggestions() { - let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) +macro_rules! expect_empty_json_test { + ($name:ident, $file:expr) => { + #[test] + fn $name() { + let json = fs::read_to_string(concat!("./tests/edge-cases/", $file)).unwrap(); + let expected_suggestions = rustfix::get_suggestions_from_json( + &json, + &HashSet::new(), + rustfix::Filter::Everything, + ) .unwrap(); - assert!(expected_suggestions.is_empty()); + assert!(expected_suggestions.is_empty()); + } + }; } -#[test] -fn out_of_bounds_test() { - let json = fs::read_to_string("./tests/edge-cases/out_of_bounds.recorded.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) - .unwrap(); - assert!(expected_suggestions.is_empty()); -} - -#[test] -fn utf8_identifiers_test() { - let json = fs::read_to_string("./tests/edge-cases/utf8_idents.recorded.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) - .unwrap(); - assert!(expected_suggestions.is_empty()); -} +expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi-option-lints.json"} +expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} +expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} From 892a95c714a4c1792200d18e42970c05c0a0debb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 16:55:49 -0700 Subject: [PATCH 253/298] Don't panic on span for empty file. --- src/lib.rs | 3 ++- tests/edge-cases/empty.json | 42 +++++++++++++++++++++++++++++++++++++ tests/edge-cases/empty.rs | 0 tests/edge_cases.rs | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/edge-cases/empty.json create mode 100644 tests/edge-cases/empty.rs diff --git a/src/lib.rs b/src/lib.rs index 8026f00c0..93006eebb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,8 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of // bounds' access by making sure the index is within the array bounds. - let last_tail_index = last.highlight_end.min(last.text.len()) - 1; + // `saturating_sub` is used in case of an empty file + let last_tail_index = last.highlight_end.min(last.text.len()).saturating_sub(1); let last_slice = last.text.chars().collect::>(); if span.text.len() > 1 { diff --git a/tests/edge-cases/empty.json b/tests/edge-cases/empty.json new file mode 100644 index 000000000..62df0b936 --- /dev/null +++ b/tests/edge-cases/empty.json @@ -0,0 +1,42 @@ +{ + "message": "`main` function not found in crate `empty`", + "code": { + "code": "E0601", + "explanation": "No `main` function was found in a binary crate. To fix this error, add a\n`main` function. For example:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can go look to the Rust Book to get\nstarted: https://doc.rust-lang.org/book/\n" + }, + "level": "error", + "spans": [ + { + "file_name": "empty.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 0, + "line_end": 0, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [ + { + "message": "consider adding a `main` function to `empty.rs`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0601]: `main` function not found in crate `empty`\n |\n = note: consider adding a `main` function to `empty.rs`\n\n" +} diff --git a/tests/edge-cases/empty.rs b/tests/edge-cases/empty.rs new file mode 100644 index 000000000..e69de29bb diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index a265c04dc..8e8c9c905 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -21,3 +21,4 @@ macro_rules! expect_empty_json_test { expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi-option-lints.json"} expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} +expect_empty_json_test! {empty, "empty.json"} From d244f66dabc43e98d37bbfe61f2a2d79fd75e2e2 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 17:20:51 -0700 Subject: [PATCH 254/298] Provide helpful error message if not using nightly. --- tests/parse_and_replace.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index c3f570163..1b6ffa993 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -54,6 +54,9 @@ fn compile(file: &Path, mode: &str) -> Result { fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result { let res = compile(file, mode)?; let stderr = String::from_utf8(res.stderr)?; + if stderr.contains("is only accepted on the nightly compiler") { + panic!("rustfix tests require a nightly compiler"); + } match res.status.code() { Some(0) | Some(1) | Some(101) => Ok(stderr), @@ -160,7 +163,7 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err ))?; let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new(), filter_suggestions) - .context("could not load expected suggesitons")?; + .context("could not load expected suggestions")?; ensure!( expected_suggestions == suggestions, From df8401b0b248f10e9b54df297b1270b3db66b72a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 17:22:15 -0700 Subject: [PATCH 255/298] Prevent panic when span points past end of line. --- src/lib.rs | 9 +++++++-- tests/edge-cases/no_main.json | 33 +++++++++++++++++++++++++++++++++ tests/edge-cases/no_main.rs | 1 + tests/edge_cases.rs | 1 + 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/edge-cases/no_main.json create mode 100644 tests/edge-cases/no_main.rs diff --git a/src/lib.rs b/src/lib.rs index 93006eebb..83040477e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,8 +108,13 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { let text_slice = span.text[0].text.chars().collect::>(); // We subtract `1` because these highlights are 1-based - let start = span.text[0].highlight_start - 1; - let end = span.text[0].highlight_end - 1; + // Check the `min` so that it doesn't attempt to index out-of-bounds when + // the span points to the "end" of the line. For example, a line of + // "foo\n" with a highlight_start of 5 is intended to highlight *after* + // the line. This needs to compensate since the newline has been removed + // from the text slice. + let start = (span.text[0].highlight_start - 1).min(text_slice.len()); + let end = (span.text[0].highlight_end - 1).min(text_slice.len()); let lead = text_slice[indent..start].iter().collect(); let mut body: String = text_slice[start..end].iter().collect(); diff --git a/tests/edge-cases/no_main.json b/tests/edge-cases/no_main.json new file mode 100644 index 000000000..e4b1c8f97 --- /dev/null +++ b/tests/edge-cases/no_main.json @@ -0,0 +1,33 @@ +{ + "message": "`main` function not found in crate `no_main`", + "code": { + "code": "E0601", + "explanation": "No `main` function was found in a binary crate. To fix this error, add a\n`main` function. For example:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can go look to the Rust Book to get\nstarted: https://doc.rust-lang.org/book/\n" + }, + "level": "error", + "spans": [ + { + "file_name": "no_main.rs", + "byte_start": 26, + "byte_end": 26, + "line_start": 1, + "line_end": 1, + "column_start": 27, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": "// This file has no main.", + "highlight_start": 27, + "highlight_end": 27 + } + ], + "label": "consider adding a `main` function to `no_main.rs`", + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [], + "rendered": "error[E0601]: `main` function not found in crate `no_main`\n --> no_main.rs:1:27\n |\n1 | // This file has no main.\n | ^ consider adding a `main` function to `no_main.rs`\n\n" +} diff --git a/tests/edge-cases/no_main.rs b/tests/edge-cases/no_main.rs new file mode 100644 index 000000000..0147ba726 --- /dev/null +++ b/tests/edge-cases/no_main.rs @@ -0,0 +1 @@ +// This file has no main. diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 8e8c9c905..191713b98 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -22,3 +22,4 @@ expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi- expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} expect_empty_json_test! {empty, "empty.json"} +expect_empty_json_test! {no_main, "no_main.json"} From cb85f85a45e2ec3953a704e721b0fba9832c4df0 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 2 Apr 2020 11:16:29 +0200 Subject: [PATCH 256/298] Bump version to 0.5.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 66ed77ff8..4fa1ffaa4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" edition = "2018" readme = "Readme.md" -version = "0.5.0" +version = "0.5.1" exclude = [ "etc/*", "examples/*", From fd1f32da007b0e164e250535e120cc0aa96550ab Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Mon, 5 Oct 2020 20:54:34 +0200 Subject: [PATCH 257/298] Removed unnecessary `use` statement --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 83040477e..6c012ae47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ extern crate log; #[cfg(test)] #[macro_use] extern crate proptest; -use serde_json; use std::collections::HashSet; use std::ops::Range; From 1ddf2b2ffc28c431d00baf9519d6753463303d26 Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Mon, 5 Oct 2020 20:57:11 +0200 Subject: [PATCH 258/298] Replaced is_inserted implementation of State with matches! macro to improve code readability --- src/replace.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/replace.rs b/src/replace.rs index 807104939..ff5e58ad7 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -14,11 +14,7 @@ enum State { impl State { fn is_inserted(&self) -> bool { - if let State::Inserted(..) = *self { - true - } else { - false - } + matches!(*self, State::Inserted(..)) } } From 6974044425702c4c078582a8e628f848a6bbd70a Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Mon, 5 Oct 2020 21:04:12 +0200 Subject: [PATCH 259/298] Added IDE-specific ignores to .gitignore --- .gitignore | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index c45ad780d..9c3e13d56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ target Cargo.lock tests/crates/**/output.txt + +# Editor and IDE-specific ignores +## VSCode +.vscode + +## Eclipse +.project + +## All JetBrains IDE's +*.iml \ No newline at end of file From 50f1708001adca5daed308b937c0d87844a10a40 Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Tue, 6 Oct 2020 19:07:11 +0200 Subject: [PATCH 260/298] Added newline at EOF --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9c3e13d56..beb765831 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ tests/crates/**/output.txt .project ## All JetBrains IDE's -*.iml \ No newline at end of file +*.iml From 304bf5282d72fdeac5121eb46aa2d90acce98265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lanteri=20Thauvin?= Date: Sun, 13 Dec 2020 23:12:54 +0100 Subject: [PATCH 261/298] Fix typo in Readme --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index fb5eda843..ce9021ac9 100644 --- a/Readme.md +++ b/Readme.md @@ -9,7 +9,7 @@ Currently, rustfix is split into two crates: - `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs - and `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code. -The magic of rustfix is entirely dependent on the diagnostics implement in the Rust compiler (and external lints, like [clippy]). +The magic of rustfix is entirely dependent on the diagnostics implemented in the Rust compiler (and external lints, like [clippy]). [clippy]: https://github.com/rust-lang-nursery/rust-clippy From dfbce93f8e3bd4dac14f4a9d174a10b5dcb09af0 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 31 Jan 2021 00:10:30 +0100 Subject: [PATCH 262/298] Switch to similar from difference --- Cargo.toml | 2 +- tests/parse_and_replace.rs | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4fa1ffaa4..66126a5dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,6 @@ env_logger = "0.5.0-rc.1" log = "0.4.1" tempdir = "0.3.5" proptest = "0.7.0" -difference = "2.0.0" +similar = "0.4.0" [workspace] diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 1b6ffa993..003578e11 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -97,29 +97,29 @@ fn read_file(path: &Path) -> Result { } fn diff(expected: &str, actual: &str) -> String { - use difference::{Changeset, Difference}; + use similar::text::{ChangeTag, TextDiff}; use std::fmt::Write; let mut res = String::new(); - let changeset = Changeset::new(expected.trim(), actual.trim(), "\n"); + let diff = TextDiff::from_lines(expected.trim(), actual.trim()); let mut different = false; - for diff in changeset.diffs { - let (prefix, diff) = match diff { - Difference::Same(_) => continue, - Difference::Add(add) => ("+", add), - Difference::Rem(rem) => ("-", rem), - }; - if !different { - write!( - &mut res, - "differences found (+ == actual, - == expected):\n" - ) - .unwrap(); - different = true; - } - for diff in diff.lines() { - writeln!(&mut res, "{} {}", prefix, diff).unwrap(); + for op in diff.ops() { + for change in diff.iter_changes(op) { + let prefix = match change.tag() { + ChangeTag::Equal => continue, + ChangeTag::Insert => "+", + ChangeTag::Delete => "-", + }; + if !different { + write!( + &mut res, + "differences found (+ == actual, - == expected):\n" + ) + .unwrap(); + different = true; + } + write!(&mut res, "{} {}", prefix, change.value()).unwrap(); } } if different { From d4f016aac67a595692b55b292167f4ab216a8c3f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 8 Dec 2018 22:38:57 +0100 Subject: [PATCH 263/298] allow multiple solutions --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6c012ae47..0be5f52ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -207,7 +207,7 @@ pub fn collect_suggestions( }) .filter_map(collect_span) .collect(); - if replacements.len() == 1 { + if replacements.len() >= 1 { Some(Solution { message: child.message.clone(), replacements, From 37e974e86005318c7195dbfb4ee3e4f31211aed2 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 8 Dec 2018 23:10:01 +0100 Subject: [PATCH 264/298] remove test about multi-option lints --- .../skip-multi-option-lints.fixed.rs | 5 - tests/edge-cases/skip-multi-option-lints.json | 100 ------------------ tests/edge-cases/skip-multi-option-lints.rs | 5 - tests/edge_cases.rs | 1 - 4 files changed, 111 deletions(-) delete mode 100644 tests/edge-cases/skip-multi-option-lints.fixed.rs delete mode 100644 tests/edge-cases/skip-multi-option-lints.json delete mode 100644 tests/edge-cases/skip-multi-option-lints.rs diff --git a/tests/edge-cases/skip-multi-option-lints.fixed.rs b/tests/edge-cases/skip-multi-option-lints.fixed.rs deleted file mode 100644 index 9e1237188..000000000 --- a/tests/edge-cases/skip-multi-option-lints.fixed.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let xs = vec![String::from("foo")]; - let d: &Display = &xs; - println!("{}", d); -} diff --git a/tests/edge-cases/skip-multi-option-lints.json b/tests/edge-cases/skip-multi-option-lints.json deleted file mode 100644 index dc61ae6fb..000000000 --- a/tests/edge-cases/skip-multi-option-lints.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "message": "cannot find type `Display` in this scope", - "code": { - "code": "E0412", - "explanation": "\nThe type name used is not in scope.\n\nErroneous code examples:\n\n```compile_fail,E0412\nimpl Something {} // error: type name `Something` is not in scope\n\n// or:\n\ntrait Foo {\n fn bar(N); // error: type name `N` is not in scope\n}\n\n// or:\n\nfn foo(x: T) {} // type name `T` is not in scope\n```\n\nTo fix this error, please verify you didn't misspell the type name, you did\ndeclare it or imported it into the scope. Examples:\n\n```\nstruct Something;\n\nimpl Something {} // ok!\n\n// or:\n\ntrait Foo {\n type N;\n\n fn bar(_: Self::N); // ok!\n}\n\n// or:\n\nfn foo(x: T) {} // ok!\n```\n\nAnother case that causes this error is when a type is imported into a parent\nmodule. To fix this, you can follow the suggestion and use File directly or\n`use super::File;` which will import the types from the parent namespace. An\nexample that causes this error is below:\n\n```compile_fail,E0412\nuse std::fs::File;\n\nmod foo {\n fn some_function(f: File) {}\n}\n```\n\n```\nuse std::fs::File;\n\nmod foo {\n // either\n use super::File;\n // or\n // use std::fs::File;\n fn foo(f: File) {}\n}\n# fn main() {} // don't insert it for us; that'll break imports\n```\n" - }, - "level": "error", - "spans": [ - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 64, - "byte_end": 71, - "line_start": 3, - "line_end": 3, - "column_start": 13, - "column_end": 20, - "is_primary": true, - "text": [ - { - "text": " let d: &Display = &xs;", - "highlight_start": 13, - "highlight_end": 20 - } - ], - "label": "not found in this scope", - "suggested_replacement": null, - "expansion": null - } - ], - "children": [ - { - "message": "possible candidates are found in other modules, you can import them into scope", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 0, - "byte_end": 0, - "line_start": 1, - "line_end": 1, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::fmt::Display;\n\n", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "./tests/everything/skip-multi-option-lints.rs", - "byte_start": 0, - "byte_end": 0, - "line_start": 1, - "line_end": 1, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::path::Display;\n\n", - "suggestion_applicability": "Unspecified", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "error[E0412]: cannot find type `Display` in this scope\n --> ./tests/everything/skip-multi-option-lints.rs:3:13\n |\n3 | let d: &Display = &xs;\n | ^^^^^^^ not found in this scope\nhelp: possible candidates are found in other modules, you can import them into scope\n |\n1 | use std::fmt::Display;\n |\n1 | use std::path::Display;\n |\n\n" -} -{ - "message": "aborting due to previous error", - "code": null, - "level": "error", - "spans": [], - "children": [], - "rendered": "error: aborting due to previous error\n\n" -} -{ - "message": "For more information about this error, try `rustc --explain E0412`.", - "code": null, - "level": "", - "spans": [], - "children": [], - "rendered": "For more information about this error, try `rustc --explain E0412`.\n" -} diff --git a/tests/edge-cases/skip-multi-option-lints.rs b/tests/edge-cases/skip-multi-option-lints.rs deleted file mode 100644 index 9e1237188..000000000 --- a/tests/edge-cases/skip-multi-option-lints.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let xs = vec![String::from("foo")]; - let d: &Display = &xs; - println!("{}", d); -} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 191713b98..1b981ef6f 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -18,7 +18,6 @@ macro_rules! expect_empty_json_test { }; } -expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi-option-lints.json"} expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} expect_empty_json_test! {empty, "empty.json"} From a2b6e674fe91b8842c5e6ba805eff2f3bebae123 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 9 Dec 2018 18:47:54 +0100 Subject: [PATCH 265/298] tests: add test for multiple suggestions --- tests/everything/multiple-solutions.fixed.rs | 5 + tests/everything/multiple-solutions.json | 114 +++++++++++++++++++ tests/everything/multiple-solutions.rs | 5 + 3 files changed, 124 insertions(+) create mode 100644 tests/everything/multiple-solutions.fixed.rs create mode 100644 tests/everything/multiple-solutions.json create mode 100644 tests/everything/multiple-solutions.rs diff --git a/tests/everything/multiple-solutions.fixed.rs b/tests/everything/multiple-solutions.fixed.rs new file mode 100644 index 000000000..1a261785d --- /dev/null +++ b/tests/everything/multiple-solutions.fixed.rs @@ -0,0 +1,5 @@ +use std::collections::{HashSet}; + +fn main() { + let _: HashSet<()>; +} diff --git a/tests/everything/multiple-solutions.json b/tests/everything/multiple-solutions.json new file mode 100644 index 000000000..89b14ccc8 --- /dev/null +++ b/tests/everything/multiple-solutions.json @@ -0,0 +1,114 @@ +{ + "message": "unused imports: `HashMap`, `VecDeque`", + "code": { + "code": "unused_imports", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "src/main.rs", + "byte_start": 23, + "byte_end": 30, + "line_start": 1, + "line_end": 1, + "column_start": 24, + "column_end": 31, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 24, + "highlight_end": 31 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + }, + { + "file_name": "src/main.rs", + "byte_start": 41, + "byte_end": 49, + "line_start": 1, + "line_end": 1, + "column_start": 42, + "column_end": 50, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 42, + "highlight_end": 50 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [ + { + "message": "#[warn(unused_imports)] on by default", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + }, + { + "message": "remove the unused imports", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "src/main.rs", + "byte_start": 23, + "byte_end": 32, + "line_start": 1, + "line_end": 1, + "column_start": 24, + "column_end": 33, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 24, + "highlight_end": 33 + } + ], + "label": null, + "suggested_replacement": "", + "suggestion_applicability": "MachineApplicable", + "expansion": null + }, + { + "file_name": "src/main.rs", + "byte_start": 39, + "byte_end": 49, + "line_start": 1, + "line_end": 1, + "column_start": 40, + "column_end": 50, + "is_primary": true, + "text": [ + { + "text": "use std::collections::{HashMap, HashSet, VecDeque};", + "highlight_start": 40, + "highlight_end": 50 + } + ], + "label": null, + "suggested_replacement": "", + "suggestion_applicability": "MachineApplicable", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": "warning: unused imports: `HashMap`, `VecDeque`\n --> src/main.rs:1:24\n |\n1 | use std::collections::{HashMap, HashSet, VecDeque};\n | ^^^^^^^ ^^^^^^^^\n |\n = note: #[warn(unused_imports)] on by default\nhelp: remove the unused imports\n |\n1 | use std::collections::{HashSet};\n | -- --\n\n" +} diff --git a/tests/everything/multiple-solutions.rs b/tests/everything/multiple-solutions.rs new file mode 100644 index 000000000..401198f7e --- /dev/null +++ b/tests/everything/multiple-solutions.rs @@ -0,0 +1,5 @@ +use std::collections::{HashMap, HashSet, VecDeque}; + +fn main() { + let _: HashSet<()>; +} From e6dabf15236e0a1bb05fc54718cb5f83b0e82da5 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Wed, 9 Jun 2021 19:49:06 +0200 Subject: [PATCH 266/298] Bump version to 0.6.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 66126a5dd..14033f68c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" edition = "2018" readme = "Readme.md" -version = "0.5.1" +version = "0.6.0" exclude = [ "etc/*", "examples/*", From 635eef76315c389017b1d41f443db50c89a8a2ba Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 30 Aug 2021 13:45:21 -0700 Subject: [PATCH 267/298] Fix panic computing indentation. --- src/lib.rs | 2 +- tests/edge-cases/indented_whitespace.json | 60 +++++++++++++++++++++++ tests/edge_cases.rs | 1 + 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/edge-cases/indented_whitespace.json diff --git a/src/lib.rs b/src/lib.rs index 0be5f52ab..64d2f28d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { .chars() .take_while(|&c| char::is_whitespace(c)) .count(); - std::cmp::min(indent, line.highlight_start) + std::cmp::min(indent, line.highlight_start - 1) }) .min()?; diff --git a/tests/edge-cases/indented_whitespace.json b/tests/edge-cases/indented_whitespace.json new file mode 100644 index 000000000..b25189aaf --- /dev/null +++ b/tests/edge-cases/indented_whitespace.json @@ -0,0 +1,60 @@ +{ + "message": "non-ASCII whitespace symbol '\\u{a0}' is not skipped", + "code": null, + "level": "warning", + "spans": + [ + { + "file_name": "lib.rs", + "byte_start": 26, + "byte_end": 28, + "line_start": 2, + "line_end": 2, + "column_start": 1, + "column_end": 2, + "is_primary": false, + "text": + [ + { + "text": " indented\";", + "highlight_start": 1, + "highlight_end": 2 + } + ], + "label": "non-ASCII whitespace symbol '\\u{a0}' is not skipped", + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + }, + { + "file_name": "lib.rs", + "byte_start": 24, + "byte_end": 28, + "line_start": 1, + "line_end": 2, + "column_start": 25, + "column_end": 2, + "is_primary": true, + "text": + [ + { + "text": "pub static FOO: &str = \"\\", + "highlight_start": 25, + "highlight_end": 26 + }, + { + "text": " indented\";", + "highlight_start": 1, + "highlight_end": 2 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": + [], + "rendered": "warning: non-ASCII whitespace symbol '\\u{a0}' is not skipped\n --> lib.rs:1:25\n |\n1 | pub static FOO: &str = \"\\\n | _________________________^\n2 | |  indented\";\n | | ^ non-ASCII whitespace symbol '\\u{a0}' is not skipped\n | |_|\n | \n\n" +} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 1b981ef6f..42d1e405a 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -22,3 +22,4 @@ expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} expect_empty_json_test! {empty, "empty.json"} expect_empty_json_test! {no_main, "no_main.json"} +expect_empty_json_test! {indented_whitespace, "indented_whitespace.json"} From 370a7787ce5bbec10f442da1f7ba68a25f2aaa37 Mon Sep 17 00:00:00 2001 From: Yvan Sraka Date: Fri, 22 Oct 2021 22:47:43 +0200 Subject: [PATCH 268/298] Update Readme.md `cargo fix --edition` is now mainly used to transition to Rust edition 2021! --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index ce9021ac9..541b9d4da 100644 --- a/Readme.md +++ b/Readme.md @@ -19,9 +19,9 @@ To use the rustfix library, add it to your `Cargo.toml`. To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. -## Using `cargo fix` to transition to Rust 2018 +## Using `cargo fix --edition` to transition to Rust 2021 -Instructions on how to use this tool to transition a crate to Rust 2018 can be +Instructions on how to use this tool to transition a crate to Rust 2021 can be found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html) ## License From 6801cf1df465e54b327a9c4a0af4ffbf5ffd16ff Mon Sep 17 00:00:00 2001 From: Yvan Sraka Date: Sat, 30 Oct 2021 09:57:23 +0200 Subject: [PATCH 269/298] Fix few clippy lints --- src/lib.rs | 8 ++------ src/replace.rs | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 64d2f28d9..f83223306 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,11 +182,7 @@ pub fn collect_suggestions( } } - let snippets = diagnostic - .spans - .iter() - .filter_map(|span| parse_snippet(span)) - .collect(); + let snippets = diagnostic.spans.iter().filter_map(parse_snippet).collect(); let solutions: Vec<_> = diagnostic .children @@ -207,7 +203,7 @@ pub fn collect_suggestions( }) .filter_map(collect_span) .collect(); - if replacements.len() >= 1 { + if !replacements.is_empty() { Some(Solution { message: child.message.clone(), replacements, diff --git a/src/replace.rs b/src/replace.rs index ff5e58ad7..8deba5e9f 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -56,7 +56,7 @@ impl Data { self.parts.iter().fold(Vec::new(), |mut acc, d| { match d.data { State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), - State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(&d), + State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(d), }; acc }) @@ -164,7 +164,7 @@ impl Data { // Previous parts if let Some(ps) = self.parts.get(..index_of_part_to_split) { - new_parts.extend_from_slice(&ps); + new_parts.extend_from_slice(ps); } // Keep initial data on left side of part @@ -198,7 +198,7 @@ impl Data { // Following parts if let Some(ps) = self.parts.get(index_of_part_to_split + 1..) { - new_parts.extend_from_slice(&ps); + new_parts.extend_from_slice(ps); } new_parts From cf6f7edab311f4cbbb291d2450525bb99161fef4 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Thu, 13 Jan 2022 17:14:16 -0600 Subject: [PATCH 270/298] ci: use new cargo fmt option --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de576448b..f8ba23f8e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,4 +23,4 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update stable && rustup default stable && rustup component add rustfmt - - run: cargo fmt -- --check + - run: cargo fmt --check From a653fcdf97f59c4e54a3597491a12398f53d23a9 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 30 Jan 2022 00:59:57 +0000 Subject: [PATCH 271/298] Fix for anynow causing semver-breakage The `anyhow` crate intentionally breaks semver rules, and adds new features in "patch" releases. This crate uses `ensure` macro that has been added in a version after 1.0.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 14033f68c..1d2beca37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -anyhow = "1.0.0" +anyhow = "1.0.6" log = "0.4.1" [dev-dependencies] From ab6029d365e47237d4bc0e6191f77787cb077bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Kj=C3=A4ll?= Date: Sun, 13 Feb 2022 10:56:06 +0100 Subject: [PATCH 272/298] replace the tempdir crate with the tempfile one, as tempfile have superseded tempdir --- Cargo.toml | 2 +- tests/parse_and_replace.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d2beca37..3e842df60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ log = "0.4.1" duct = "0.9" env_logger = "0.5.0-rc.1" log = "0.4.1" -tempdir = "0.3.5" +tempfile = "3" proptest = "0.7.0" similar = "0.4.0" diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index 003578e11..f7dbb31e3 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -9,7 +9,7 @@ use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; -use tempdir::TempDir; +use tempfile::tempdir; mod fixmode { pub const EVERYTHING: &str = "yolo"; @@ -24,7 +24,7 @@ mod settings { } fn compile(file: &Path, mode: &str) -> Result { - let tmp = TempDir::new("rustfix-tests")?; + let tmp = tempdir()?; let mut args: Vec = vec![ file.into(), From 4e6192237c00612056970ae85576a625bc064826 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Wed, 16 Feb 2022 13:23:44 -0800 Subject: [PATCH 273/298] Make Diagnostic::is_primary public --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9e0be81e7..f745b0b2a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -33,7 +33,7 @@ pub struct DiagnosticSpan { pub column_end: usize, /// Is this a "primary" span -- meaning the point, or one of the points, /// where the error occurred? - is_primary: bool, + pub is_primary: bool, /// Source text from the start of line_start to the end of line_end. pub text: Vec, /// Label that should be placed at this location (if any) From 3cdeffdd6db28333a829d970fa99cc4b68c6770a Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 23 May 2022 14:01:33 -0400 Subject: [PATCH 274/298] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3e842df60..62ddbe1c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" edition = "2018" readme = "Readme.md" -version = "0.6.0" +version = "0.6.1" exclude = [ "etc/*", "examples/*", From c249c973c463de7a44c342362618e2f429df42d4 Mon Sep 17 00:00:00 2001 From: 3tilley <1138504+3tilley@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:25:03 +0100 Subject: [PATCH 275/298] README update aiming to clarify things for less experienced rustaceans --- Readme.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Readme.md b/Readme.md index 541b9d4da..924733c92 100644 --- a/Readme.md +++ b/Readme.md @@ -1,24 +1,31 @@ # rustfix -The goal of this tool is to read and apply the suggestions made by rustc. +[![Latest Version](https://img.shields.io/crates/v/rustfix.svg)](https://crates.io/crates/rustfix) +[![Rust Documentation](https://docs.rs/rustfix/badge.svg)](https://docs.rs/rustfix) + +Rustfix is a library defining useful structures that represent fix suggestions from rustc ## Current status Currently, rustfix is split into two crates: -- `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs -- and `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code. +- `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs (this crate) +- `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code (maintained in the [cargo](https://github.com/rust-lang/cargo/blob/master/src/cargo/ops/fix.rs) repo). -The magic of rustfix is entirely dependent on the diagnostics implemented in the Rust compiler (and external lints, like [clippy]). + +The library (and therefore this repo) is considered largely feature-complete. This is because: +* There is no compiler or even rust-specific logic here +* New lints and suggestions come from the Rust compiler (and external lints, like [clippy]). +* `rustfix` doesn't touch the filesystem to implement fixes, or read from disk [clippy]: https://github.com/rust-lang-nursery/rust-clippy ## Installation -To use the rustfix library, add it to your `Cargo.toml`. - To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. +To use the rustfix library for use in your own fix project, add it to your `Cargo.toml`. + ## Using `cargo fix --edition` to transition to Rust 2021 Instructions on how to use this tool to transition a crate to Rust 2021 can be From b416b98fabec98c2daed8caf8252d19d1962379d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 15 Oct 2023 19:51:10 -0700 Subject: [PATCH 276/298] Update Readme.md Co-authored-by: Weihang Lo --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 924733c92..d2c444798 100644 --- a/Readme.md +++ b/Readme.md @@ -22,7 +22,7 @@ The library (and therefore this repo) is considered largely feature-complete. Th ## Installation -To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. +`cargo fix` is a built-in command in Cargo since Rust 1.29. There is no need to install it separately from crates.io. To use the rustfix library for use in your own fix project, add it to your `Cargo.toml`. From 7806962967931453c3422d2336a999bfe5878a02 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 15 Oct 2023 19:51:19 -0700 Subject: [PATCH 277/298] Update Readme.md Co-authored-by: Weihang Lo --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index d2c444798..fe0748fc5 100644 --- a/Readme.md +++ b/Readme.md @@ -3,7 +3,7 @@ [![Latest Version](https://img.shields.io/crates/v/rustfix.svg)](https://crates.io/crates/rustfix) [![Rust Documentation](https://docs.rs/rustfix/badge.svg)](https://docs.rs/rustfix) -Rustfix is a library defining useful structures that represent fix suggestions from rustc +Rustfix is a library defining useful structures that represent fix suggestions from rustc. ## Current status From ab332236f6c746c4739508f5065e52e5c6061bad Mon Sep 17 00:00:00 2001 From: 3tilley <1138504+3tilley@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:19:31 +0100 Subject: [PATCH 278/298] Apply PR suggestion from #222 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index fe0748fc5..e4056de86 100644 --- a/Readme.md +++ b/Readme.md @@ -10,7 +10,7 @@ Rustfix is a library defining useful structures that represent fix suggestions f Currently, rustfix is split into two crates: - `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs (this crate) -- `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code (maintained in the [cargo](https://github.com/rust-lang/cargo/blob/master/src/cargo/ops/fix.rs) repo). +- `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code (maintained in the [cargo](https://github.com/rust-lang/cargo/blob/master/src/bin/cargo/commands/fix.rs) repo). The library (and therefore this repo) is considered largely feature-complete. This is because: From d34d36d29df83cf21713de3cef8b94a90dbb04e5 Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Wed, 8 Nov 2023 19:06:12 +0100 Subject: [PATCH 279/298] fix insert at beginning --- src/lib.rs | 7 +--- src/replace.rs | 99 ++++++++++++++++++++++++++++---------------------- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f83223306..aeb245443 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,11 +239,8 @@ impl CodeFix { pub fn apply(&mut self, suggestion: &Suggestion) -> Result<(), Error> { for sol in &suggestion.solutions { for r in &sol.replacements { - self.data.replace_range( - r.snippet.range.start, - r.snippet.range.end.saturating_sub(1), - r.replacement.as_bytes(), - )?; + self.data + .replace_range(r.snippet.range.clone(), r.replacement.as_bytes())?; } } Ok(()) diff --git a/src/replace.rs b/src/replace.rs index 8deba5e9f..9045b2754 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -22,7 +22,7 @@ impl State { struct Span { /// Start of this span in parent data start: usize, - /// up to end including + /// up to end excluding end: usize, data: State, } @@ -42,7 +42,7 @@ impl Data { parts: vec![Span { data: State::Initial, start: 0, - end: data.len().saturating_sub(1), + end: data.len(), }], } } @@ -55,7 +55,7 @@ impl Data { self.parts.iter().fold(Vec::new(), |mut acc, d| { match d.data { - State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), + State::Initial => acc.extend_from_slice(&self.original[d.start..d.end]), State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(d), }; acc @@ -66,28 +66,27 @@ impl Data { /// was already changed previously. pub fn replace_range( &mut self, - from: usize, - up_to_and_including: usize, + range: std::ops::Range, data: &[u8], ) -> Result<(), Error> { - let exclusive_end = up_to_and_including + 1; + let exclusive_end = range.end; ensure!( - from <= exclusive_end, - "Invalid range {}...{}, start is larger than end", - from, - up_to_and_including + range.start <= exclusive_end, + "Invalid range {}..{}, start is larger than end", + range.start, + range.end ); ensure!( - up_to_and_including <= self.original.len(), - "Invalid range {}...{} given, original data is only {} byte long", - from, - up_to_and_including, + exclusive_end <= self.original.len(), + "Invalid range {}..{} given, original data is only {} byte long", + range.start, + range.end, self.original.len() ); - let insert_only = from == exclusive_end; + let insert_only = range.start == range.end; // Since we error out when replacing an already replaced chunk of data, // we can take some shortcuts here. For example, there can be no @@ -103,7 +102,7 @@ impl Data { .parts .iter() .position(|p| { - !p.data.is_inserted() && p.start <= from && p.end >= up_to_and_including + !p.data.is_inserted() && p.start <= range.start && p.end >= range.end }) .ok_or_else(|| { use log::Level::Debug; @@ -124,16 +123,16 @@ impl Data { }) .collect::>(); debug!( - "no single slice covering {}...{}, current slices: {:?}", - from, up_to_and_including, slices, + "no single slice covering {}..{}, current slices: {:?}", + range.start, range.end, slices, ); } anyhow!( - "Could not replace range {}...{} in file \ + "Could not replace range {}..{} in file \ -- maybe parts of it were already replaced?", - from, - up_to_and_including + range.start, + range.end, ) })?; @@ -147,7 +146,7 @@ impl Data { // This is currently done to alleviate issues like // rust-lang/rust#51211 although this clause likely wants to be // removed if that's fixed deeper in the compiler. - if part_to_split.start == from && part_to_split.end == up_to_and_including { + if part_to_split.start == range.start && part_to_split.end == range.end { if let State::Replaced(ref replacement) = part_to_split.data { if &**replacement == data { return Ok(()); @@ -168,18 +167,18 @@ impl Data { } // Keep initial data on left side of part - if from > part_to_split.start { + if range.start > part_to_split.start { new_parts.push(Span { start: part_to_split.start, - end: from.saturating_sub(1), + end: range.start, data: State::Initial, }); } // New part new_parts.push(Span { - start: from, - end: up_to_and_including, + start: range.start, + end: range.end, data: if insert_only { State::Inserted(data.into()) } else { @@ -188,9 +187,9 @@ impl Data { }); // Keep initial data on right side of part - if up_to_and_including < part_to_split.end { + if range.end < part_to_split.end { new_parts.push(Span { - start: up_to_and_including + 1, + start: range.end, end: part_to_split.end, data: State::Initial, }); @@ -219,17 +218,31 @@ mod tests { ::std::str::from_utf8(i).unwrap() } + #[test] + fn insert_at_beginning() { + let mut d = Data::new(b"foo bar baz"); + d.replace_range(0..0, b"oh no ").unwrap(); + assert_eq!("oh no foo bar baz", str(&d.to_vec())); + } + + #[test] + fn insert_at_end() { + let mut d = Data::new(b"foo bar baz"); + d.replace_range(11..11, b" oh no").unwrap(); + assert_eq!("foo bar baz oh no", str(&d.to_vec())); + } + #[test] fn replace_some_stuff() { let mut d = Data::new(b"foo bar baz"); - d.replace_range(4, 6, b"lol").unwrap(); + d.replace_range(4..7, b"lol").unwrap(); assert_eq!("foo lol baz", str(&d.to_vec())); } #[test] fn replace_a_single_char() { let mut d = Data::new(b"let y = true;"); - d.replace_range(4, 4, b"mut y").unwrap(); + d.replace_range(4..5, b"mut y").unwrap(); assert_eq!("let mut y = true;", str(&d.to_vec())); } @@ -237,10 +250,10 @@ mod tests { fn replace_multiple_lines() { let mut d = Data::new(b"lorem\nipsum\ndolor"); - d.replace_range(6, 10, b"lol").unwrap(); + d.replace_range(6..11, b"lol").unwrap(); assert_eq!("lorem\nlol\ndolor", str(&d.to_vec())); - d.replace_range(12, 16, b"lol").unwrap(); + d.replace_range(12..17, b"lol").unwrap(); assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); } @@ -248,13 +261,13 @@ mod tests { fn replace_multiple_lines_with_insert_only() { let mut d = Data::new(b"foo!"); - d.replace_range(3, 2, b"bar").unwrap(); + d.replace_range(3..3, b"bar").unwrap(); assert_eq!("foobar!", str(&d.to_vec())); - d.replace_range(0, 2, b"baz").unwrap(); + d.replace_range(0..3, b"baz").unwrap(); assert_eq!("bazbar!", str(&d.to_vec())); - d.replace_range(3, 3, b"?").unwrap(); + d.replace_range(3..4, b"?").unwrap(); assert_eq!("bazbar?", str(&d.to_vec())); } @@ -262,8 +275,8 @@ mod tests { fn replace_invalid_range() { let mut d = Data::new(b"foo!"); - assert!(d.replace_range(2, 0, b"bar").is_err()); - assert!(d.replace_range(0, 2, b"bar").is_ok()); + assert!(d.replace_range(2..1, b"bar").is_err()); + assert!(d.replace_range(0..3, b"bar").is_ok()); } #[test] @@ -277,24 +290,24 @@ mod tests { fn replace_overlapping_stuff_errs() { let mut d = Data::new(b"foo bar baz"); - d.replace_range(4, 6, b"lol").unwrap(); + d.replace_range(4..7, b"lol").unwrap(); assert_eq!("foo lol baz", str(&d.to_vec())); - d.replace_range(4, 6, b"lol2").unwrap(); + d.replace_range(4..7, b"lol2").unwrap(); } #[test] #[should_panic(expected = "original data is only 3 byte long")] fn broken_replacements() { let mut d = Data::new(b"foo"); - d.replace_range(4, 7, b"lol").unwrap(); + d.replace_range(4..8, b"lol").unwrap(); } #[test] fn replace_same_twice() { let mut d = Data::new(b"foo"); - d.replace_range(0, 0, b"b").unwrap(); - d.replace_range(0, 0, b"b").unwrap(); + d.replace_range(0..1, b"b").unwrap(); + d.replace_range(0..1, b"b").unwrap(); assert_eq!("boo", str(&d.to_vec())); } @@ -316,7 +329,7 @@ mod tests { ) { let mut d = Data::new(data.as_bytes()); for &(ref range, ref bytes) in replacements { - let _ = d.replace_range(range.start, range.end, bytes); + let _ = d.replace_range(range.clone(), bytes); } } } From da51cd2781f67fd09e8ce39e9aaa05b404dde1fa Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Wed, 8 Nov 2023 19:29:45 +0100 Subject: [PATCH 280/298] fix fmt --- src/replace.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/replace.rs b/src/replace.rs index 9045b2754..5dfa61a98 100644 --- a/src/replace.rs +++ b/src/replace.rs @@ -101,9 +101,7 @@ impl Data { let index_of_part_to_split = self .parts .iter() - .position(|p| { - !p.data.is_inserted() && p.start <= range.start && p.end >= range.end - }) + .position(|p| !p.data.is_inserted() && p.start <= range.start && p.end >= range.end) .ok_or_else(|| { use log::Level::Debug; if log_enabled!(Debug) { From 3ca00ad8cdc5150634c434e2e01df57813d887a6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 17:03:18 -0800 Subject: [PATCH 281/298] Integrate rustfix's manifest into the workspace. --- Cargo.lock | 277 ++++++++++++++++++++++++++++++++------ Cargo.toml | 2 +- crates/rustfix/Cargo.toml | 25 ++-- 3 files changed, 253 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 158acbcc7..512b727bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", "version_check", ] @@ -100,6 +100,17 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -132,7 +143,7 @@ dependencies = [ "cargo-util", "criterion", "flate2", - "rand", + "rand 0.8.5", "tar", "url", ] @@ -272,13 +283,13 @@ dependencies = [ "hmac", "home 0.5.5", "http-auth", - "humantime", + "humantime 2.1.0", "ignore", "im-rc", "indexmap", "itertools 0.11.0", "jobserver", - "lazycell", + "lazycell 1.3.0", "libc", "libgit2-sys", "memchr", @@ -288,7 +299,7 @@ dependencies = [ "pasetors", "pathdiff", "pulldown-cmark", - "rand", + "rand 0.8.5", "regex", "rusqlite", "rustfix", @@ -464,6 +475,12 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -616,7 +633,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -661,7 +678,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -671,7 +688,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] @@ -683,7 +700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "memoffset", "scopeguard", @@ -695,7 +712,7 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -705,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -795,6 +812,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "duct" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c553d79f40e74f7f611e49bf3429b6760cff79596b61818291c27cc0b18549d" +dependencies = [ + "lazycell 0.5.1", + "libc", + "os_pipe", + "shared_child", +] + [[package]] name = "dunce" version = "1.0.4" @@ -845,7 +874,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -857,7 +886,20 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "env_logger" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" +dependencies = [ + "atty", + "humantime 1.3.0", + "log", + "regex", + "termcolor", ] [[package]] @@ -941,7 +983,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -957,7 +999,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.3.5", "windows-sys", @@ -1004,6 +1046,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "generic-array" version = "0.14.7" @@ -1021,7 +1069,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi", @@ -1810,7 +1858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1854,6 +1902,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -1918,6 +1975,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error 1.2.3", +] + [[package]] name = "humantime" version = "2.1.0" @@ -1958,7 +2024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" dependencies = [ "bitmaps", - "rand_core", + "rand_core 0.6.4", "rand_xoshiro", "sized-chunks", "typenum", @@ -2049,6 +2115,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" + [[package]] name = "lazycell" version = "1.3.0" @@ -2087,7 +2159,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys", ] @@ -2247,6 +2319,19 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nix" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + [[package]] name = "nom" version = "7.1.3" @@ -2341,7 +2426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.4.0", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -2419,6 +2504,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "os_pipe" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe033225d563042c3eeb22ffd1d2ea1aefcc48e7e37151a064c9e0bae64b253f" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "overload" version = "0.1.1" @@ -2453,7 +2548,7 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.3.5", "smallvec", @@ -2491,7 +2586,7 @@ dependencies = [ "getrandom", "orion", "p384", - "rand_core", + "rand_core 0.6.4", "regex", "serde", "serde_json", @@ -2659,6 +2754,23 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "proptest" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f275a76b824714046ce0b1e00323e06437e027f2d31b2b6272cae30afaf18d" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "lazy_static", + "num-traits", + "quick-error 1.2.3", + "rand 0.4.6", + "regex-syntax 0.4.2", + "rusty-fork 0.2.2", + "tempfile", +] + [[package]] name = "proptest" version = "1.3.1" @@ -2670,11 +2782,11 @@ dependencies = [ "bitflags 2.4.0", "lazy_static", "num-traits", - "rand", + "rand 0.8.5", "rand_chacha", "rand_xorshift", "regex-syntax 0.7.5", - "rusty-fork", + "rusty-fork 0.3.0", "tempfile", "unarray", ] @@ -2711,6 +2823,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -2719,7 +2844,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2729,9 +2854,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -2747,7 +2887,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2756,7 +2896,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2781,6 +2921,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -2831,6 +2980,12 @@ dependencies = [ "regex-syntax 0.7.5", ] +[[package]] +name = "regex-syntax" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -2849,7 +3004,7 @@ version = "0.0.0" dependencies = [ "cargo", "cargo-util", - "proptest", + "proptest 1.3.1", "varisat", ] @@ -2886,13 +3041,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustfix" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" dependencies = [ "anyhow", + "duct", + "env_logger", "log", + "proptest 0.7.2", "serde", "serde_json", + "similar 0.4.0", + "tempfile", ] [[package]] @@ -2908,6 +3066,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rusty-fork" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + [[package]] name = "rusty-fork" version = "0.3.0" @@ -3078,7 +3248,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest", ] @@ -3095,7 +3265,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest", ] @@ -3109,6 +3279,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared_child" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be9f7d5565b1483af3e72975e2dee33879b3b86bd48c0929fccf6585d79e65a" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -3122,9 +3302,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "similar" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823f59ff8efe59c4cf706349651b0e19dd6f501fdf3521666fbe498e8d18d0ec" + [[package]] name = "similar" version = "2.2.1" @@ -3160,7 +3346,7 @@ dependencies = [ "escargot", "filetime", "normalize-line-endings", - "similar", + "similar 2.2.1", "snapbox-macros", "tempfile", "walkdir", @@ -3272,13 +3458,22 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "redox_syscall 0.4.1", "rustix", "windows-sys", ] +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.3.0" @@ -3315,7 +3510,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", ] @@ -3657,6 +3852,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -3688,7 +3889,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] diff --git a/Cargo.toml b/Cargo.toml index 63e294d6d..853536b6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ pulldown-cmark = { version = "0.9.3", default-features = false } rand = "0.8.5" regex = "1.9.3" rusqlite = { version = "0.29.0", features = ["bundled"] } -rustfix = "0.6.1" +rustfix = { version = "0.6.1", path = "crates/rustfix" } same-file = "1.0.6" security-framework = "2.9.2" semver = { version = "1.0.20", features = ["serde"] } diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index 62ddbe1c2..65e3c16cd 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -1,34 +1,35 @@ [package] +name = "rustfix" +version = "0.6.1" authors = [ "Pascal Hertleif ", "Oliver Schneider ", ] -license = "Apache-2.0/MIT" -name = "rustfix" +rust-version = "1.70.0" # MSRV:3 +edition.workspace = true +license.workspace = true +homepage = "https://github.com/rust-lang/cargo" +repository = "https://github.com/rust-lang/cargo" description = "Automatically apply the suggestions made by rustc" -repository = "https://github.com/rust-lang-nursery/rustfix" documentation = "https://docs.rs/rustfix" -edition = "2018" -readme = "Readme.md" -version = "0.6.1" exclude = [ - "etc/*", "examples/*", "tests/*", ] [dependencies] -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -anyhow = "1.0.6" +anyhow.workspace = true log = "0.4.1" +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true [dev-dependencies] duct = "0.9" env_logger = "0.5.0-rc.1" log = "0.4.1" -tempfile = "3" proptest = "0.7.0" similar = "0.4.0" +tempfile.workspace = true -[workspace] +[lints] +workspace = true From 9cb59bc2026c0be909580cef9eaa7100fe7cd487 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 17:49:18 -0800 Subject: [PATCH 282/298] Idiom lints are now configured in the manifest. --- crates/rustfix/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/rustfix/src/lib.rs b/crates/rustfix/src/lib.rs index aeb245443..a3e797fd4 100644 --- a/crates/rustfix/src/lib.rs +++ b/crates/rustfix/src/lib.rs @@ -1,5 +1,3 @@ -#![warn(rust_2018_idioms)] - #[macro_use] extern crate log; #[cfg(test)] From d0d9bd5cbbd9fe9afb99de882afba49654ea851a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:10:44 -0800 Subject: [PATCH 283/298] Switch rustfix to using tracing instead of log. This helps bring it in line with the rust of cargo. --- Cargo.lock | 57 ++--------------------- crates/rustfix/Cargo.toml | 5 +- crates/rustfix/src/lib.rs | 2 - crates/rustfix/src/replace.rs | 9 ++-- crates/rustfix/tests/parse_and_replace.rs | 6 +-- 5 files changed, 13 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 512b727bc..92cfd803d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,17 +100,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -283,7 +272,7 @@ dependencies = [ "hmac", "home 0.5.5", "http-auth", - "humantime 2.1.0", + "humantime", "ignore", "im-rc", "indexmap", @@ -889,19 +878,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "env_logger" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1902,15 +1878,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1975,15 +1942,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error 1.2.3", -] - [[package]] name = "humantime" version = "2.1.0" @@ -3044,13 +3002,13 @@ version = "0.6.1" dependencies = [ "anyhow", "duct", - "env_logger", - "log", "proptest 0.7.2", "serde", "serde_json", "similar 0.4.0", "tempfile", + "tracing", + "tracing-subscriber", ] [[package]] @@ -3465,15 +3423,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "termcolor" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.3.0" diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index 65e3c16cd..2fbd7c051 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -19,17 +19,16 @@ exclude = [ [dependencies] anyhow.workspace = true -log = "0.4.1" serde = { workspace = true, features = ["derive"] } serde_json.workspace = true +tracing.workspace = true [dev-dependencies] duct = "0.9" -env_logger = "0.5.0-rc.1" -log = "0.4.1" proptest = "0.7.0" similar = "0.4.0" tempfile.workspace = true +tracing-subscriber.workspace = true [lints] workspace = true diff --git a/crates/rustfix/src/lib.rs b/crates/rustfix/src/lib.rs index a3e797fd4..a223ef41c 100644 --- a/crates/rustfix/src/lib.rs +++ b/crates/rustfix/src/lib.rs @@ -1,5 +1,3 @@ -#[macro_use] -extern crate log; #[cfg(test)] #[macro_use] extern crate proptest; diff --git a/crates/rustfix/src/replace.rs b/crates/rustfix/src/replace.rs index 5dfa61a98..01a781f7c 100644 --- a/crates/rustfix/src/replace.rs +++ b/crates/rustfix/src/replace.rs @@ -103,8 +103,7 @@ impl Data { .iter() .position(|p| !p.data.is_inserted() && p.start <= range.start && p.end >= range.end) .ok_or_else(|| { - use log::Level::Debug; - if log_enabled!(Debug) { + if tracing::enabled!(tracing::Level::DEBUG) { let slices = self .parts .iter() @@ -120,9 +119,11 @@ impl Data { ) }) .collect::>(); - debug!( + tracing::debug!( "no single slice covering {}..{}, current slices: {:?}", - range.start, range.end, slices, + range.start, + range.end, + slices, ); } diff --git a/crates/rustfix/tests/parse_and_replace.rs b/crates/rustfix/tests/parse_and_replace.rs index f7dbb31e3..935de0aaa 100644 --- a/crates/rustfix/tests/parse_and_replace.rs +++ b/crates/rustfix/tests/parse_and_replace.rs @@ -1,7 +1,6 @@ #![cfg(not(windows))] // TODO: should fix these tests on Windows use anyhow::{anyhow, ensure, Context, Error}; -use log::{debug, info, warn}; use rustfix::apply_suggestions; use std::collections::HashSet; use std::env; @@ -10,6 +9,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Output; use tempfile::tempdir; +use tracing::{debug, info, warn}; mod fixmode { pub const EVERYTHING: &str = "yolo"; @@ -237,13 +237,13 @@ fn assert_fixtures(dir: &str, mode: &str) { #[test] fn everything() { - let _ = env_logger::try_init(); + tracing_subscriber::fmt::init(); assert_fixtures("./tests/everything", fixmode::EVERYTHING); } #[test] #[ignore = "Requires custom rustc build"] fn edition() { - let _ = env_logger::try_init(); + tracing_subscriber::fmt::init(); assert_fixtures("./tests/edition", fixmode::EDITION); } From f25cc6361759dd78a91dbea76392a27503e4dee8 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:14:00 -0800 Subject: [PATCH 284/298] Update rustfix to use a newer proptest. This uses the same version used elsewhere in cargo. --- Cargo.lock | 112 ++++++-------------------------------- crates/rustfix/Cargo.toml | 2 +- crates/rustfix/src/lib.rs | 4 -- 3 files changed, 18 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92cfd803d..6207d63b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,7 +132,7 @@ dependencies = [ "cargo-util", "criterion", "flate2", - "rand 0.8.5", + "rand", "tar", "url", ] @@ -288,7 +288,7 @@ dependencies = [ "pasetors", "pathdiff", "pulldown-cmark", - "rand 0.8.5", + "rand", "regex", "rusqlite", "rustfix", @@ -711,7 +711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -863,7 +863,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -959,7 +959,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1022,12 +1022,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "generic-array" version = "0.14.7" @@ -1834,7 +1828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1982,7 +1976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" dependencies = [ "bitmaps", - "rand_core 0.6.4", + "rand_core", "rand_xoshiro", "sized-chunks", "typenum", @@ -2544,7 +2538,7 @@ dependencies = [ "getrandom", "orion", "p384", - "rand_core 0.6.4", + "rand_core", "regex", "serde", "serde_json", @@ -2712,23 +2706,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "proptest" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f275a76b824714046ce0b1e00323e06437e027f2d31b2b6272cae30afaf18d" -dependencies = [ - "bit-set", - "bitflags 1.3.2", - "lazy_static", - "num-traits", - "quick-error 1.2.3", - "rand 0.4.6", - "regex-syntax 0.4.2", - "rusty-fork 0.2.2", - "tempfile", -] - [[package]] name = "proptest" version = "1.3.1" @@ -2740,11 +2717,11 @@ dependencies = [ "bitflags 2.4.0", "lazy_static", "num-traits", - "rand 0.8.5", + "rand", "rand_chacha", "rand_xorshift", "regex-syntax 0.7.5", - "rusty-fork 0.3.0", + "rusty-fork", "tempfile", "unarray", ] @@ -2781,19 +2758,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - [[package]] name = "rand" version = "0.8.5" @@ -2802,7 +2766,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2812,24 +2776,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.6.4" @@ -2845,7 +2794,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2854,7 +2803,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2879,15 +2828,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -2938,12 +2878,6 @@ dependencies = [ "regex-syntax 0.7.5", ] -[[package]] -name = "regex-syntax" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" - [[package]] name = "regex-syntax" version = "0.6.29" @@ -2962,7 +2896,7 @@ version = "0.0.0" dependencies = [ "cargo", "cargo-util", - "proptest 1.3.1", + "proptest", "varisat", ] @@ -3002,7 +2936,7 @@ version = "0.6.1" dependencies = [ "anyhow", "duct", - "proptest 0.7.2", + "proptest", "serde", "serde_json", "similar 0.4.0", @@ -3024,18 +2958,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "rusty-fork" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" -dependencies = [ - "fnv", - "quick-error 1.2.3", - "tempfile", - "wait-timeout", -] - [[package]] name = "rusty-fork" version = "0.3.0" @@ -3260,7 +3182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest", - "rand_core 0.6.4", + "rand_core", ] [[package]] diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index 2fbd7c051..b1c364da4 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -25,7 +25,7 @@ tracing.workspace = true [dev-dependencies] duct = "0.9" -proptest = "0.7.0" +proptest.workspace = true similar = "0.4.0" tempfile.workspace = true tracing-subscriber.workspace = true diff --git a/crates/rustfix/src/lib.rs b/crates/rustfix/src/lib.rs index a223ef41c..954564e1a 100644 --- a/crates/rustfix/src/lib.rs +++ b/crates/rustfix/src/lib.rs @@ -1,7 +1,3 @@ -#[cfg(test)] -#[macro_use] -extern crate proptest; - use std::collections::HashSet; use std::ops::Range; From 3c0126aec472cb3ab856626d7cbbf3149b7cd14e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:21:01 -0800 Subject: [PATCH 285/298] rustfix: Drop test dependency on duct It didn't seem to be doing anything that `Command` doesn't already support. This helps lighten the dependency size. --- Cargo.lock | 100 ++++------------------ crates/rustfix/Cargo.toml | 1 - crates/rustfix/tests/parse_and_replace.rs | 10 +-- 3 files changed, 22 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6207d63b4..ced8c4a56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "version_check", ] @@ -278,7 +278,7 @@ dependencies = [ "indexmap", "itertools 0.11.0", "jobserver", - "lazycell 1.3.0", + "lazycell", "libc", "libgit2-sys", "memchr", @@ -464,12 +464,6 @@ dependencies = [ "jobserver", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -622,7 +616,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -667,7 +661,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -677,7 +671,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -689,7 +683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "memoffset", "scopeguard", @@ -701,7 +695,7 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -801,18 +795,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "duct" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c553d79f40e74f7f611e49bf3429b6760cff79596b61818291c27cc0b18549d" -dependencies = [ - "lazycell 0.5.1", - "libc", - "os_pipe", - "shared_child", -] - [[package]] name = "dunce" version = "1.0.4" @@ -875,7 +857,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -975,7 +957,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.3.5", "windows-sys", @@ -1039,7 +1021,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi", @@ -2067,12 +2049,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" - [[package]] name = "lazycell" version = "1.3.0" @@ -2111,7 +2087,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys", ] @@ -2271,19 +2247,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "nix" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - [[package]] name = "nom" version = "7.1.3" @@ -2378,7 +2341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.4.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -2456,16 +2419,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "os_pipe" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe033225d563042c3eeb22ffd1d2ea1aefcc48e7e37151a064c9e0bae64b253f" -dependencies = [ - "nix", - "winapi", -] - [[package]] name = "overload" version = "0.1.1" @@ -2500,7 +2453,7 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.3.5", "smallvec", @@ -2935,7 +2888,6 @@ name = "rustfix" version = "0.6.1" dependencies = [ "anyhow", - "duct", "proptest", "serde", "serde_json", @@ -3128,7 +3080,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] @@ -3145,7 +3097,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] @@ -3159,16 +3111,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared_child" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be9f7d5565b1483af3e72975e2dee33879b3b86bd48c0929fccf6585d79e65a" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "shell-escape" version = "0.1.5" @@ -3338,7 +3280,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "redox_syscall 0.4.1", "rustix", @@ -3381,7 +3323,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -3723,12 +3665,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "wait-timeout" version = "0.2.0" @@ -3760,7 +3696,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index b1c364da4..1b1cba5bc 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -24,7 +24,6 @@ serde_json.workspace = true tracing.workspace = true [dev-dependencies] -duct = "0.9" proptest.workspace = true similar = "0.4.0" tempfile.workspace = true diff --git a/crates/rustfix/tests/parse_and_replace.rs b/crates/rustfix/tests/parse_and_replace.rs index 935de0aaa..74c338b0f 100644 --- a/crates/rustfix/tests/parse_and_replace.rs +++ b/crates/rustfix/tests/parse_and_replace.rs @@ -7,7 +7,7 @@ use std::env; use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; -use std::process::Output; +use std::process::{Command, Output}; use tempfile::tempdir; use tracing::{debug, info, warn}; @@ -40,13 +40,11 @@ fn compile(file: &Path, mode: &str) -> Result { args.push("--edition=2018".into()); } - let res = duct::cmd(env::var_os("RUSTC").unwrap_or("rustc".into()), &args) + let res = Command::new(env::var_os("RUSTC").unwrap_or("rustc".into())) + .args(&args) .env("CLIPPY_DISABLE_DOCS_LINKS", "true") .env_remove("RUST_LOG") - .stdout_capture() - .stderr_capture() - .unchecked() - .run()?; + .output()?; Ok(res) } From 63830afedefbbeff290747d875666e49ee7cf5e9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:29:58 -0800 Subject: [PATCH 286/298] Remove some unused rustfix files. --- crates/rustfix/.editorconfig | 25 ---------------------- crates/rustfix/.github/workflows/main.yml | 26 ----------------------- crates/rustfix/.gitignore | 13 ------------ crates/rustfix/.gitmodules | 0 4 files changed, 64 deletions(-) delete mode 100644 crates/rustfix/.editorconfig delete mode 100644 crates/rustfix/.github/workflows/main.yml delete mode 100644 crates/rustfix/.gitignore delete mode 100644 crates/rustfix/.gitmodules diff --git a/crates/rustfix/.editorconfig b/crates/rustfix/.editorconfig deleted file mode 100644 index 3c1f41bdc..000000000 --- a/crates/rustfix/.editorconfig +++ /dev/null @@ -1,25 +0,0 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# editorconfig.org - -root = true - - -[*] -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -indent_style = space -indent_size = 4 - -[*.rs] -indent_style = space -indent_size = 4 - -[*.toml] -indent_style = space -indent_size = 4 - -[*.md] -trim_trailing_whitespace = false diff --git a/crates/rustfix/.github/workflows/main.yml b/crates/rustfix/.github/workflows/main.yml deleted file mode 100644 index f8ba23f8e..000000000 --- a/crates/rustfix/.github/workflows/main.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: CI -on: [push, pull_request] - -jobs: - test: - name: Test - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - steps: - - uses: actions/checkout@master - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - shell: bash - - run: cargo test --all - - run: cargo test --all -- --ignored - - rustfmt: - name: Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt - - run: cargo fmt --check diff --git a/crates/rustfix/.gitignore b/crates/rustfix/.gitignore deleted file mode 100644 index beb765831..000000000 --- a/crates/rustfix/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -target -Cargo.lock -tests/crates/**/output.txt - -# Editor and IDE-specific ignores -## VSCode -.vscode - -## Eclipse -.project - -## All JetBrains IDE's -*.iml diff --git a/crates/rustfix/.gitmodules b/crates/rustfix/.gitmodules deleted file mode 100644 index e69de29bb..000000000 From a4fd77ce35c7ca97737a0e5a82e7357bd3d2e16c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:31:08 -0800 Subject: [PATCH 287/298] Switch rustfix license files to be symlinks --- crates/rustfix/LICENSE-APACHE | 203 +--------------------------------- crates/rustfix/LICENSE-MIT | 22 +--- 2 files changed, 2 insertions(+), 223 deletions(-) mode change 100644 => 120000 crates/rustfix/LICENSE-APACHE mode change 100644 => 120000 crates/rustfix/LICENSE-MIT diff --git a/crates/rustfix/LICENSE-APACHE b/crates/rustfix/LICENSE-APACHE deleted file mode 100644 index 8f71f43fe..000000000 --- a/crates/rustfix/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/crates/rustfix/LICENSE-APACHE b/crates/rustfix/LICENSE-APACHE new file mode 120000 index 000000000..1cd601d0a --- /dev/null +++ b/crates/rustfix/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/rustfix/LICENSE-MIT b/crates/rustfix/LICENSE-MIT deleted file mode 100644 index 458e9c6ce..000000000 --- a/crates/rustfix/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Pascal Hertleif - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/rustfix/LICENSE-MIT b/crates/rustfix/LICENSE-MIT new file mode 120000 index 000000000..b2cfbdc7b --- /dev/null +++ b/crates/rustfix/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file From 6e798b39bd7391b05e06018f74f50973558f1559 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:44:40 -0800 Subject: [PATCH 288/298] Update rustfix readme to be a little more current. --- crates/rustfix/Readme.md | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/crates/rustfix/Readme.md b/crates/rustfix/Readme.md index e4056de86..0546e6018 100644 --- a/crates/rustfix/Readme.md +++ b/crates/rustfix/Readme.md @@ -5,31 +5,12 @@ Rustfix is a library defining useful structures that represent fix suggestions from rustc. -## Current status +This is a low-level library. You pass it the JSON output from `rustc`, and you can then use it to apply suggestions to in-memory strings. This library doesn't execute commands, or read or write from the filesystem. -Currently, rustfix is split into two crates: +If you are looking for the [`cargo fix`] implementation, the core of it is located in [`cargo::ops::fix`]. -- `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs (this crate) -- `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code (maintained in the [cargo](https://github.com/rust-lang/cargo/blob/master/src/bin/cargo/commands/fix.rs) repo). - - -The library (and therefore this repo) is considered largely feature-complete. This is because: -* There is no compiler or even rust-specific logic here -* New lints and suggestions come from the Rust compiler (and external lints, like [clippy]). -* `rustfix` doesn't touch the filesystem to implement fixes, or read from disk - -[clippy]: https://github.com/rust-lang-nursery/rust-clippy - -## Installation - -`cargo fix` is a built-in command in Cargo since Rust 1.29. There is no need to install it separately from crates.io. - -To use the rustfix library for use in your own fix project, add it to your `Cargo.toml`. - -## Using `cargo fix --edition` to transition to Rust 2021 - -Instructions on how to use this tool to transition a crate to Rust 2021 can be -found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html) +[`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html +[`cargo::ops::fix`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/ops/fix.rs ## License From b8ba6cd333e1d55620805d6aef3c2735d5039b06 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 18 Nov 2023 18:46:34 -0800 Subject: [PATCH 289/298] Bump the rustfix version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- crates/rustfix/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ced8c4a56..7368ed98c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2885,7 +2885,7 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustfix" -version = "0.6.1" +version = "0.6.2" dependencies = [ "anyhow", "proptest", diff --git a/Cargo.toml b/Cargo.toml index 853536b6c..c9d82e01c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ pulldown-cmark = { version = "0.9.3", default-features = false } rand = "0.8.5" regex = "1.9.3" rusqlite = { version = "0.29.0", features = ["bundled"] } -rustfix = { version = "0.6.1", path = "crates/rustfix" } +rustfix = { version = "0.6.2", path = "crates/rustfix" } same-file = "1.0.6" security-framework = "2.9.2" semver = { version = "1.0.20", features = ["serde"] } diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index 1b1cba5bc..1ef43e5a6 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustfix" -version = "0.6.1" +version = "0.6.2" authors = [ "Pascal Hertleif ", "Oliver Schneider ", From 7e04d1910f6833c1fe4660481a8a019e9cbf1de9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 19 Nov 2023 07:29:54 -0800 Subject: [PATCH 290/298] Add rustfix to publish. --- publish.py | 1 + 1 file changed, 1 insertion(+) diff --git a/publish.py b/publish.py index 87ea0e896..114d7dbbd 100755 --- a/publish.py +++ b/publish.py @@ -21,6 +21,7 @@ TO_PUBLISH = [ 'credential/cargo-credential-wincred', 'credential/cargo-credential-1password', 'credential/cargo-credential-macos-keychain', + 'crates/rustfix', 'crates/cargo-platform', 'crates/cargo-util', 'crates/crates-io', From d6e49ca06b583bf80824c3771b1aed1f846d7acf Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 19 Nov 2023 08:07:37 -0800 Subject: [PATCH 291/298] Fix clippy warnings. --- crates/rustfix/examples/fix-json.rs | 2 ++ crates/rustfix/tests/parse_and_replace.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/crates/rustfix/examples/fix-json.rs b/crates/rustfix/examples/fix-json.rs index 6d77a8ddb..676171106 100644 --- a/crates/rustfix/examples/fix-json.rs +++ b/crates/rustfix/examples/fix-json.rs @@ -1,3 +1,5 @@ +#![allow(clippy::disallowed_methods, clippy::print_stdout, clippy::print_stderr)] + use anyhow::Error; use std::io::{stdin, BufReader, Read}; use std::{collections::HashMap, collections::HashSet, env, fs}; diff --git a/crates/rustfix/tests/parse_and_replace.rs b/crates/rustfix/tests/parse_and_replace.rs index 74c338b0f..1f8c5610c 100644 --- a/crates/rustfix/tests/parse_and_replace.rs +++ b/crates/rustfix/tests/parse_and_replace.rs @@ -1,3 +1,4 @@ +#![allow(clippy::disallowed_methods, clippy::print_stdout, clippy::print_stderr)] #![cfg(not(windows))] // TODO: should fix these tests on Windows use anyhow::{anyhow, ensure, Context, Error}; From b5308f648be8941a848d621e9b01d3e629546997 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 19 Nov 2023 08:17:17 -0800 Subject: [PATCH 292/298] Fix tests to run on stable. --- crates/rustfix/tests/parse_and_replace.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/rustfix/tests/parse_and_replace.rs b/crates/rustfix/tests/parse_and_replace.rs index 1f8c5610c..c4d6f8b99 100644 --- a/crates/rustfix/tests/parse_and_replace.rs +++ b/crates/rustfix/tests/parse_and_replace.rs @@ -29,8 +29,7 @@ fn compile(file: &Path, mode: &str) -> Result { let mut args: Vec = vec![ file.into(), - "--error-format=pretty-json".into(), - "-Zunstable-options".into(), + "--error-format=json".into(), "--emit=metadata".into(), "--crate-name=rustfix_test".into(), "--out-dir".into(), From f99a494c31d6d28ea5ede539f7f5058e006e7b03 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 19 Nov 2023 08:20:21 -0800 Subject: [PATCH 293/298] Remove copyright headers in tests. These were all removed a while ago in https://github.com/rust-lang/rust/pull/57108 --- .../closure-immutable-outer-variable.fixed.rs | 10 ---------- .../everything/closure-immutable-outer-variable.rs | 10 ---------- .../tests/everything/str-lit-type-mismatch.fixed.rs | 11 ----------- .../rustfix/tests/everything/str-lit-type-mismatch.rs | 11 ----------- 4 files changed, 42 deletions(-) diff --git a/crates/rustfix/tests/everything/closure-immutable-outer-variable.fixed.rs b/crates/rustfix/tests/everything/closure-immutable-outer-variable.fixed.rs index 0c41b6aa3..e443e024b 100644 --- a/crates/rustfix/tests/everything/closure-immutable-outer-variable.fixed.rs +++ b/crates/rustfix/tests/everything/closure-immutable-outer-variable.fixed.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Point at the captured immutable outer variable fn foo(mut f: Box) { diff --git a/crates/rustfix/tests/everything/closure-immutable-outer-variable.rs b/crates/rustfix/tests/everything/closure-immutable-outer-variable.rs index 1d14afd6a..c97ec3589 100644 --- a/crates/rustfix/tests/everything/closure-immutable-outer-variable.rs +++ b/crates/rustfix/tests/everything/closure-immutable-outer-variable.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Point at the captured immutable outer variable fn foo(mut f: Box) { diff --git a/crates/rustfix/tests/everything/str-lit-type-mismatch.fixed.rs b/crates/rustfix/tests/everything/str-lit-type-mismatch.fixed.rs index b1ee5c63e..d5a81a8a8 100644 --- a/crates/rustfix/tests/everything/str-lit-type-mismatch.fixed.rs +++ b/crates/rustfix/tests/everything/str-lit-type-mismatch.fixed.rs @@ -1,14 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - fn main() { let x: &[u8] = b"foo"; //~ ERROR mismatched types let y: &[u8; 4] = b"baaa"; //~ ERROR mismatched types diff --git a/crates/rustfix/tests/everything/str-lit-type-mismatch.rs b/crates/rustfix/tests/everything/str-lit-type-mismatch.rs index 4a062f78a..12637c7b9 100644 --- a/crates/rustfix/tests/everything/str-lit-type-mismatch.rs +++ b/crates/rustfix/tests/everything/str-lit-type-mismatch.rs @@ -1,14 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - fn main() { let x: &[u8] = "foo"; //~ ERROR mismatched types let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types From 402d072d728577636422fbf8cf5ee1b3ad4d75df Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Nov 2023 10:02:14 -0800 Subject: [PATCH 294/298] Ignore rustfix for semver-checks since it doesn't exist on the beta branch. --- crates/xtask-bump-check/src/xtask.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/xtask-bump-check/src/xtask.rs b/crates/xtask-bump-check/src/xtask.rs index cba420f05..fb1f59e30 100644 --- a/crates/xtask-bump-check/src/xtask.rs +++ b/crates/xtask-bump-check/src/xtask.rs @@ -166,6 +166,7 @@ fn bump_check(args: &clap::ArgMatches, config: &cargo::util::Config) -> CargoRes let mut cmd = ProcessBuilder::new("cargo"); cmd.arg("semver-checks") .arg("--workspace") + .args(&["--exclude", "rustfix"]) // FIXME: Remove once 1.76 is stable .arg("--baseline-rev") .arg(referenced_commit.id().to_string()); config.shell().status("Running", &cmd)?; From 70f56e9004b3e87f99b67e63319865449e325e19 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Nov 2023 10:10:22 -0800 Subject: [PATCH 295/298] Add a general introduction to the rustfix library docs. --- crates/rustfix/src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/rustfix/src/lib.rs b/crates/rustfix/src/lib.rs index 954564e1a..50c10f2b3 100644 --- a/crates/rustfix/src/lib.rs +++ b/crates/rustfix/src/lib.rs @@ -1,3 +1,23 @@ +//! Library for applying diagnostic suggestions to source code. +//! +//! This is a low-level library. You pass it the JSON output from `rustc`, and +//! you can then use it to apply suggestions to in-memory strings. This +//! library doesn't execute commands, or read or write from the filesystem. +//! +//! If you are looking for the [`cargo fix`] implementation, the core of it is +//! located in [`cargo::ops::fix`]. +//! +//! [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html +//! [`cargo::ops::fix`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/ops/fix.rs +//! +//! The general outline of how to use this library is: +//! +//! 1. Call `rustc` and collect the JSON data. +//! 2. Pass the json data to [`get_suggestions_from_json`]. +//! 3. Create a [`CodeFix`] with the source of a file to modify. +//! 4. Call [`CodeFix::apply`] to apply a change. +//! 5. Write the source back to disk. + use std::collections::HashSet; use std::ops::Range; From 5cb98b94a1e7650ac5c134760febc2c353620248 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Nov 2023 10:11:31 -0800 Subject: [PATCH 296/298] Add rustfix lib to autolabel triggers. --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index cdf1090a1..c344a0b4d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -262,6 +262,7 @@ trigger_files = [ "src/bin/cargo/commands/fix.rs", "src/cargo/ops/fix.rs", "src/cargo/util/lockserver.rs", + "crates/rustfix/", ] [autolabel."Command-generate-lockfile"] From 5c2b9d75df9b542d310e29fb0abef71ec3c44144 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Nov 2023 10:14:34 -0800 Subject: [PATCH 297/298] Update contrib docs on rustfix issue tracking. --- src/doc/contrib/src/issues.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/doc/contrib/src/issues.md b/src/doc/contrib/src/issues.md index b82492d27..c77c083b2 100644 --- a/src/doc/contrib/src/issues.md +++ b/src/doc/contrib/src/issues.md @@ -33,10 +33,9 @@ relevant are: * [`rust-lang/crates.io`] --- Home for the [crates.io] website. Issues with [`cargo fix`] can be tricky to know where they should be filed, -since the fixes are driven by `rustc`, processed by [`rustfix`], and the -front-interface is implemented in Cargo. Feel free to file in the Cargo issue -tracker, and it will get moved to one of the other issue trackers if -necessary. +since the fixes are driven by `rustc`, and the front-interface is implemented +in Cargo. Feel free to file in the Cargo issue tracker, and it will get moved +to the [`rust-lang/rust`] issue tracker if necessary. [Process]: process/index.md [security policy]: https://www.rust-lang.org/security.html @@ -51,7 +50,6 @@ necessary. [`rustup`]: https://rust-lang.github.io/rustup/ [`rust-lang/crates.io`]: https://github.com/rust-lang/crates.io [crates.io]: https://crates.io/ -[`rustfix`]: https://github.com/rust-lang/rustfix/ [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html ## Issue labels From 47c7ff0f96d5ee0718d342704830d3d936ef1091 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 21 Nov 2023 10:18:15 -0800 Subject: [PATCH 298/298] Deduplicate the similar dependency. --- Cargo.lock | 10 ++-------- crates/rustfix/Cargo.toml | 2 +- crates/rustfix/tests/parse_and_replace.rs | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7368ed98c..8bbc65321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2891,7 +2891,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "similar 0.4.0", + "similar", "tempfile", "tracing", "tracing-subscriber", @@ -3127,12 +3127,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "similar" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823f59ff8efe59c4cf706349651b0e19dd6f501fdf3521666fbe498e8d18d0ec" - [[package]] name = "similar" version = "2.2.1" @@ -3168,7 +3162,7 @@ dependencies = [ "escargot", "filetime", "normalize-line-endings", - "similar 2.2.1", + "similar", "snapbox-macros", "tempfile", "walkdir", diff --git a/crates/rustfix/Cargo.toml b/crates/rustfix/Cargo.toml index 1ef43e5a6..0acaf4f8e 100644 --- a/crates/rustfix/Cargo.toml +++ b/crates/rustfix/Cargo.toml @@ -25,7 +25,7 @@ tracing.workspace = true [dev-dependencies] proptest.workspace = true -similar = "0.4.0" +similar = "2.2.1" tempfile.workspace = true tracing-subscriber.workspace = true diff --git a/crates/rustfix/tests/parse_and_replace.rs b/crates/rustfix/tests/parse_and_replace.rs index c4d6f8b99..8d7a2561f 100644 --- a/crates/rustfix/tests/parse_and_replace.rs +++ b/crates/rustfix/tests/parse_and_replace.rs @@ -95,7 +95,7 @@ fn read_file(path: &Path) -> Result { } fn diff(expected: &str, actual: &str) -> String { - use similar::text::{ChangeTag, TextDiff}; + use similar::{ChangeTag, TextDiff}; use std::fmt::Write; let mut res = String::new();