@@ -109,7 +109,6 @@ fn broken_fixes_backed_out() {
109109 fs::File::create(&first).unwrap();
110110 }
111111 }
112-
113112 let status = Command::new("rustc")
114113 .args(env::args().skip(1))
115114 .status()
@@ -160,7 +159,157 @@ fn broken_fixes_backed_out() {
160159 and we would appreciate a bug report! You're likely to see \n \
161160 a number of compiler warnings after this message which cargo\n \
162161 attempted to fix but failed. If you could open an issue at\n \
163- [..]\n \
162+ https://github.com/rust-lang/rust/issues\n \
163+ quoting the full output of this command we'd be very appreciative!\n \
164+ Note that you may be able to make some more progress in the near-term\n \
165+ fixing code with the `--broken-code` flag\n \
166+ \n \
167+ The following errors were reported:\n \
168+ error: expected one of `!` or `::`, found `rust`\n \
169+ ",
170+ )
171+ . with_stderr_contains ( "Original diagnostics will follow." )
172+ . with_stderr_contains ( "[WARNING] variable does not need to be mutable" )
173+ . with_stderr_does_not_contain ( "[..][FIXED][..]" )
174+ . run ( ) ;
175+
176+ // Make sure the fix which should have been applied was backed out
177+ assert ! ( p. read_file( "bar/src/lib.rs" ) . contains( "let mut x = 3;" ) ) ;
178+ }
179+
180+ #[ cargo_test]
181+ fn broken_clippy_fixes_backed_out ( ) {
182+ // A wrapper around `rustc` instead of calling `clippy`
183+ let clippy_driver = project ( )
184+ . at ( cargo_test_support:: paths:: global_root ( ) . join ( "clippy-driver" ) )
185+ . file ( "Cargo.toml" , & basic_manifest ( "clippy-driver" , "0.0.1" ) )
186+ . file (
187+ "src/main.rs" ,
188+ r#"
189+ fn main() {
190+ let mut args = std::env::args_os();
191+ let _me = args.next().unwrap();
192+ let rustc = args.next().unwrap();
193+ let status = std::process::Command::new(rustc).args(args).status().unwrap();
194+ std::process::exit(status.code().unwrap_or(1));
195+ }
196+ "# ,
197+ )
198+ . build ( ) ;
199+ clippy_driver. cargo ( "build" ) . run ( ) ;
200+
201+ // This works as follows:
202+ // - Create a `rustc` shim (the "foo" project) which will pretend that the
203+ // verification step fails.
204+ // - There is an empty build script so `foo` has `OUT_DIR` to track the steps.
205+ // - The first "check", `foo` creates a file in OUT_DIR, and it completes
206+ // successfully with a warning diagnostic to remove unused `mut`.
207+ // - rustfix removes the `mut`.
208+ // - The second "check" to verify the changes, `foo` swaps out the content
209+ // with something that fails to compile. It creates a second file so it
210+ // won't do anything in the third check.
211+ // - cargo fix discovers that the fix failed, and it backs out the changes.
212+ // - The third "check" is done to display the original diagnostics of the
213+ // original code.
214+ let p = project ( )
215+ . file (
216+ "foo/Cargo.toml" ,
217+ r#"
218+ [package]
219+ name = 'foo'
220+ version = '0.1.0'
221+ [workspace]
222+ "# ,
223+ )
224+ . file (
225+ "foo/src/main.rs" ,
226+ r#"
227+ use std::env;
228+ use std::fs;
229+ use std::io::Write;
230+ use std::path::{Path, PathBuf};
231+ use std::process::{self, Command};
232+
233+ fn main() {
234+ // Ignore calls to things like --print=file-names and compiling build.rs.
235+ // Also compatible for rustc invocations with `@path` argfile.
236+ let is_lib_rs = env::args_os()
237+ .map(PathBuf::from)
238+ .flat_map(|p| if let Some(p) = p.to_str().unwrap_or_default().strip_prefix("@") {
239+ fs::read_to_string(p).unwrap().lines().map(PathBuf::from).collect()
240+ } else {
241+ vec![p]
242+ })
243+ .any(|l| l == Path::new("src/lib.rs"));
244+ if is_lib_rs {
245+ let path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
246+ let first = path.join("first");
247+ let second = path.join("second");
248+ if first.exists() && !second.exists() {
249+ fs::write("src/lib.rs", b"not rust code").unwrap();
250+ fs::File::create(&second).unwrap();
251+ } else {
252+ fs::File::create(&first).unwrap();
253+ }
254+ }
255+ let status = Command::new("rustc")
256+ .args(env::args().skip(1))
257+ .status()
258+ .expect("failed to run rustc");
259+ process::exit(status.code().unwrap_or(2));
260+ }
261+ "# ,
262+ )
263+ . file (
264+ "bar/Cargo.toml" ,
265+ r#"
266+ [package]
267+ name = 'bar'
268+ version = '0.1.0'
269+ [workspace]
270+ "# ,
271+ )
272+ . file ( "bar/build.rs" , "fn main() {}" )
273+ . file (
274+ "bar/src/lib.rs" ,
275+ r#"
276+ pub fn foo() {
277+ let mut x = 3;
278+ drop(x);
279+ }
280+ "# ,
281+ )
282+ . build ( ) ;
283+
284+ // Build our rustc shim
285+ p. cargo ( "build" ) . cwd ( "foo" ) . run ( ) ;
286+
287+ // Attempt to fix code, but our shim will always fail the second compile.
288+ // Also, we use `clippy` as a workspace wrapper to make sure that we properly
289+ // generate the report bug text.
290+ p. cargo ( "fix --allow-no-vcs --lib" )
291+ . cwd ( "bar" )
292+ . env ( "__CARGO_FIX_YOLO" , "1" )
293+ . env ( "RUSTC" , p. root ( ) . join ( "foo/target/debug/foo" ) )
294+ // We can't use `clippy` so we use a `rustc` workspace wrapper instead
295+ . env (
296+ "RUSTC_WORKSPACE_WRAPPER" ,
297+ clippy_driver. bin ( "clippy-driver" ) ,
298+ )
299+ . with_stderr_contains (
300+ "warning: failed to automatically apply fixes suggested by rustc \
301+ to crate `bar`\n \
302+ \n \
303+ after fixes were automatically applied the compiler reported \
304+ errors within these files:\n \
305+ \n \
306+ * src/lib.rs\n \
307+ \n \
308+ This likely indicates a bug in either rustc or cargo itself,\n \
309+ and we would appreciate a bug report! You're likely to see \n \
310+ a number of compiler warnings after this message which cargo\n \
311+ attempted to fix but failed. If you could open an issue at\n \
312+ https://github.com/rust-lang/rust-clippy/issues\n \
164313 quoting the full output of this command we'd be very appreciative!\n \
165314 Note that you may be able to make some more progress in the near-term\n \
166315 fixing code with the `--broken-code` flag\n \
0 commit comments