Skip to content

Commit

Permalink
Move some rustfix code into separate functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexendoo committed Jul 4, 2024
1 parent dfdb88e commit 482e3d9
Showing 1 changed file with 126 additions and 113 deletions.
239 changes: 126 additions & 113 deletions src/custom_flags/rustfix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::{
collections::HashSet,
path::Path,
process::{Command, Output},
};

Expand Down Expand Up @@ -57,79 +58,15 @@ impl Flag for RustfixMode {
};
let output = output.clone();
let no_run_rustfix = config.find_one_custom("no-rustfix")?;
let fixed_code = (no_run_rustfix.is_none() && global_rustfix.enabled())
.then_some(())
.and_then(|()| {
let suggestions = std::str::from_utf8(&output.stderr)
.unwrap()
.lines()
.flat_map(|line| {
if !line.starts_with('{') {
return vec![];
}
rustfix::get_suggestions_from_json(
line,
&HashSet::new(),
if global_rustfix == RustfixMode::Everything {
rustfix::Filter::Everything
} else {
rustfix::Filter::MachineApplicableOnly
},
)
.unwrap_or_else(|err| {
panic!("could not deserialize diagnostics json for rustfix {err}:{line}")
})
})
.collect::<Vec<_>>();
if suggestions.is_empty() {
None
} else {
let path_str = display(config.status.path());
for sugg in &suggestions {
for snip in &sugg.snippets {
let file_name = snip.file_name.replace('\\', "/");
if file_name != path_str {
return Some(Err(anyhow::anyhow!("cannot apply suggestions for `{file_name}` since main file is `{path_str}`. Please use `//@no-rustfix` to disable rustfix")));
}
}
}
Some(rustfix::apply_suggestions(
&std::fs::read_to_string(config.status.path()).unwrap(),
&suggestions,
).map_err(|e| e.into()))
}
})
.transpose()
.map_err(|err| Errored {
let fixed_code = if no_run_rustfix.is_none() && global_rustfix.enabled() {
fix(&output.stderr, config.status.path(), global_rustfix).map_err(|err| Errored {
command: format!("rustfix {}", display(config.status.path())),
errors: vec![Error::Rustfix(err)],
stderr: output.stderr,
stdout: output.stdout,
})?;

let rustfix_comments = Comments {
revisions: None,
revisioned: std::iter::once((
vec![],
Revisioned {
span: Span::default(),
ignore: vec![],
only: vec![],
stderr_per_bitwidth: false,
compile_flags: config.collect(|r| r.compile_flags.iter().cloned()),
env_vars: config.collect(|r| r.env_vars.iter().cloned()),
normalize_stderr: vec![],
normalize_stdout: vec![],
error_in_other_files: vec![],
error_matches: vec![],
require_annotations_for_level: Default::default(),
diagnostic_code_prefix: OptWithLine::new(String::new(), Span::default()),
custom: config.comments().flat_map(|r| r.custom.clone()).collect(),
exit_status: OptWithLine::new(0, Span::default()),
require_annotations: OptWithLine::default(),
},
))
.collect(),
})?
} else {
None
};

let run = fixed_code.is_some();
Expand All @@ -141,16 +78,6 @@ impl Flag for RustfixMode {
&mut errors,
"fixed",
);
// picking the crate name from the file name is problematic when `.revision_name` is inserted,
// so we compute it here before replacing the path.
let crate_name = config
.status
.path()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.replace('-', "_");

if !errors.is_empty() {
return Ok(Some(TestRun {
Expand All @@ -168,42 +95,128 @@ impl Flag for RustfixMode {
return Ok(None);
}

let config = TestConfig {
config: config.config.clone(),
comments: &rustfix_comments,
aux_dir: config.aux_dir,
status: config.status.for_path(&rustfix_path),
};
compile_fixed(config, build_manager, &rustfix_path)
}
}

let mut cmd = config.build_command(build_manager)?;
cmd.arg("--crate-name").arg(crate_name);
let output = cmd.output().unwrap();
if output.status.success() {
Ok(Some(TestRun {
result: Ok(TestOk::Ok),
status: config.status,
}))
} else {
let diagnostics = config.process(&output.stderr);
Err(Errored {
command: format!("{cmd:?}"),
errors: vec![Error::ExitStatus {
expected: 0,
status: output.status,
reason: Spanned::new(
"after rustfix is applied, all errors should be gone, but weren't".into(),
diagnostics
.messages
.iter()
.flatten()
.chain(diagnostics.messages_from_unknown_file_or_line.iter())
.find_map(|message| message.line_col.clone())
.unwrap_or_default(),
),
}],
stderr: diagnostics.rendered,
stdout: output.stdout,
fn fix(stderr: &[u8], path: &Path, global_rustfix: RustfixMode) -> anyhow::Result<Option<String>> {
let suggestions = std::str::from_utf8(stderr)
.unwrap()
.lines()
.flat_map(|line| {
if !line.starts_with('{') {
return vec![];
}
rustfix::get_suggestions_from_json(
line,
&HashSet::new(),
if global_rustfix == RustfixMode::Everything {
rustfix::Filter::Everything
} else {
rustfix::Filter::MachineApplicableOnly
},
)
.unwrap_or_else(|err| {
panic!("could not deserialize diagnostics json for rustfix {err}:{line}")
})
})
.collect::<Vec<_>>();
if suggestions.is_empty() {
Ok(None)
} else {
let path_str = display(path);
for sugg in &suggestions {
for snip in &sugg.snippets {
let file_name = snip.file_name.replace('\\', "/");
anyhow::ensure!(
file_name == path_str,
"cannot apply suggestions for `{file_name}` since main file is `{path_str}`. Please use `//@no-rustfix` to disable rustfix",
)
}
}
Ok(Some(rustfix::apply_suggestions(
&std::fs::read_to_string(path).unwrap(),
&suggestions,
)?))
}
}

fn compile_fixed(
config: &TestConfig,
build_manager: &BuildManager<'_>,
rustfix_path: &Path,
) -> Result<Option<TestRun>, Errored> {
// picking the crate name from the file name is problematic when `.revision_name` is inserted,
// so we compute it here before replacing the path.
let crate_name = config
.status
.path()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.replace('-', "_");

let rustfix_comments = Comments {
revisions: None,
revisioned: std::iter::once((
vec![],
Revisioned {
span: Span::default(),
ignore: vec![],
only: vec![],
stderr_per_bitwidth: false,
compile_flags: config.collect(|r| r.compile_flags.iter().cloned()),
env_vars: config.collect(|r| r.env_vars.iter().cloned()),
normalize_stderr: vec![],
normalize_stdout: vec![],
error_in_other_files: vec![],
error_matches: vec![],
require_annotations_for_level: Default::default(),
diagnostic_code_prefix: OptWithLine::new(String::new(), Span::default()),
custom: config.comments().flat_map(|r| r.custom.clone()).collect(),
exit_status: OptWithLine::new(0, Span::default()),
require_annotations: OptWithLine::default(),
},
))
.collect(),
};

let fixed_config = TestConfig {
config: config.config.clone(),
comments: &rustfix_comments,
aux_dir: config.aux_dir,
status: config.status.for_path(&rustfix_path),
};

let mut cmd = fixed_config.build_command(build_manager)?;
cmd.arg("--crate-name").arg(crate_name);
let output = cmd.output().unwrap();
if output.status.success() {
Ok(Some(TestRun {
result: Ok(TestOk::Ok),
status: fixed_config.status,
}))
} else {
let diagnostics = fixed_config.process(&output.stderr);
Err(Errored {
command: format!("{cmd:?}"),
errors: vec![Error::ExitStatus {
expected: 0,
status: output.status,
reason: Spanned::new(
"after rustfix is applied, all errors should be gone, but weren't".into(),
diagnostics
.messages
.iter()
.flatten()
.chain(diagnostics.messages_from_unknown_file_or_line.iter())
.find_map(|message| message.line_col.clone())
.unwrap_or_default(),
),
}],
stderr: diagnostics.rendered,
stdout: output.stdout,
})
}
}

0 comments on commit 482e3d9

Please sign in to comment.