This repository has been archived by the owner on Nov 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathglue.rs
75 lines (58 loc) · 2.16 KB
/
glue.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
process::Command,
str::FromStr,
};
use anyhow::{bail, Context, Result as AnyResult};
use syn::Error as SynError;
use crate::{ast::CrateAst, comparator::ApiComparator, public_api::PublicApi};
pub(crate) fn extract_api() -> AnyResult<PublicApi> {
let output = Command::new("cargo")
.arg("+nightly")
.arg("rustc")
.arg("--lib")
.arg("--")
.args(&["-Z", "unpretty=expanded"])
.args(&["-Z", "unpretty=everybody_loops"])
.arg("--emit=mir")
.output()
.context("Failed to run `cargo rustc`")?;
if !output.status.success() {
let stderr = String::from_utf8(output.stderr)
.map_err(|_| InvalidRustcOutputEncoding)
.context("Failed to get rustc error message")?;
bail!(stderr);
}
let expanded_code = String::from_utf8(output.stdout)
.map_err(|_| InvalidRustcOutputEncoding)
.context("Failed to get rustc-expanded crate code")?;
let ast = CrateAst::from_str(&expanded_code)
.map_err(InvalidRustcAst)
.context("Failed to parse rustc-provided crate AST")?;
let api = PublicApi::from_ast(&ast);
Ok(api)
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct InvalidRustcOutputEncoding;
impl Display for InvalidRustcOutputEncoding {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "rustc yielded non-UTF-8 output")
}
}
impl Error for InvalidRustcOutputEncoding {}
#[derive(Clone, Debug)]
struct InvalidRustcAst(SynError);
impl Display for InvalidRustcAst {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "rustc yielded an invalid program: {}", self.0)
}
}
impl Error for InvalidRustcAst {}
pub fn compare(prev: &str, curr: &str) -> AnyResult<ApiComparator> {
let prev_ast = CrateAst::from_str(prev).context("Failed to parse code for previous version")?;
let curr_ast = CrateAst::from_str(curr).context("Failed to parse code for current version")?;
let prev_api = PublicApi::from_ast(&prev_ast);
let curr_api = PublicApi::from_ast(&curr_ast);
Ok(ApiComparator::new(prev_api, curr_api))
}