use quote::ToTokens;
mod fold;
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Span {
label: Option<String>,
}
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Code {
code: String,
}
#[derive(Debug, serde::Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
enum Level {
Error,
Warning,
Note,
Help,
FailureNote,
#[serde(rename = "error: internal compiler error")]
Ice,
}
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Message {
message: String,
code: Option<Code>,
level: Level,
spans: Vec<Span>,
children: Vec<Message>,
}
static MESSAGES_RE_RAW: &[&str] = &[
"first, the lifetime cannot outlive the lifetime `\'.*` as defined on the function body at (?P<R>.*)...",
];
static MESSAGES_REGEX_SET: once_cell::sync::Lazy<regex::RegexSet> =
once_cell::sync::Lazy::new(|| regex::RegexSet::new(MESSAGES_RE_RAW).unwrap());
static MESSAGES_REGEXES: once_cell::sync::Lazy<Vec<regex::Regex>> =
once_cell::sync::Lazy::new(|| {
MESSAGES_RE_RAW
.iter()
.map(|r| regex::Regex::new(r).unwrap())
.collect()
});
impl Message {
fn cleanup(&mut self) {
for i in MESSAGES_REGEX_SET.matches(&self.message) {
let re = &MESSAGES_REGEXES[i];
self.message = re
.replace_all(&self.message, |_: ®ex::Captures| String::new())
.to_string();
}
for m in &mut self.children {
m.cleanup();
}
}
}
fn compile(content: &syn::File) -> Vec<Message> {
let mut child = std::process::Command::new("rustc")
.args(&[
"--error-format=json",
"-",
"--out-dir",
"/tmp",
"--emit",
"metadata",
"--crate-type",
"lib",
])
.stdin(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.expect("Failed to spawn rustc process");
{
use std::io::Write;
let stdin = child.stdin.as_mut().expect("Failed to open rustc stdin");
stdin
.write_all(content.to_token_stream().to_string().as_bytes())
.expect("Failed to write to stdin");
}
let output = child
.wait_with_output()
.expect("Failed to read rustc output")
.stderr;
output
.split(|&b| b == b'\n')
.filter(|s| !s.is_empty())
.map(|line| serde_json::from_slice::<Message>(line).expect("Could not parse message"))
.map(|mut m| {
m.cleanup();
m
})
.collect()
}
pub fn simplify(content: &mut syn::File) {
loop {
let expected_errors = compile(content);
let mut made_change = false;
made_change = fold::fold::<fold::SimplifyFunctionBodyVisitor>(&expected_errors, content) && made_change;
made_change = fold::fold::<fold::RemoveItemImplVisitor>(&expected_errors, content) && made_change;
made_change = fold::fold::<fold::RemoveReturnValueVisitor>(&expected_errors, content) && made_change;
made_change = fold::fold::<fold::RemoveStatementVisitor>(&expected_errors, content) && made_change;
if !made_change {
return;
}
}
}