#![feature(rustc_private)]
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_span;
mod apply;
mod callbacks;
mod classify;
mod fixup;
mod strip_allows;
mod visitor;
use std::path::PathBuf;
use std::process;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LintTarget {
ArithmeticSideEffects,
AsConversions,
All,
}
impl LintTarget {
pub fn includes_arithmetic(self) -> bool {
matches!(self, LintTarget::ArithmeticSideEffects | LintTarget::All)
}
pub fn includes_as_conversions(self) -> bool {
matches!(self, LintTarget::AsConversions | LintTarget::All)
}
}
#[derive(Clone, Debug)]
pub struct Rewrite {
pub file: PathBuf,
pub full_start: u32,
pub full_end: u32,
pub inner_snippet: String,
pub rhs_snippet: Option<String>,
pub kind: RewriteKind,
}
#[derive(Clone, Debug)]
pub enum RewriteKind {
TypeFrom { dst: String },
TryFrom { dst: String },
CharFrom,
WrappingBinop { method: &'static str, lhs_ty: String },
WrappingAssignOp { method: &'static str, lhs_snippet: String },
WrappingNeg { operand_ty: String },
AllowConstCast,
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() >= 2 && (args[1].contains("rustc") || args[1].ends_with("rustc")) {
run_as_rustc_wrapper(&args[1..]);
} else {
run_direct(&args[1..]);
}
}
fn run_as_rustc_wrapper(args: &[String]) {
let lint = parse_lint_from_env();
let dry_run = std::env::var("WARN_REWRITE_DRY_RUN").map(|v| v == "1").unwrap_or(false);
let rustc_args: Vec<String> = args.to_vec();
callbacks::run_with_callbacks(rustc_args, lint, dry_run);
}
fn run_direct(args: &[String]) {
let mut lint = LintTarget::All;
let mut folder: Option<PathBuf> = None;
let mut dry_run = false;
let mut extra_cargo_args: Vec<String> = Vec::new();
let mut i = 0;
while i < args.len() {
match args[i].as_str() {
"--lint" => {
i += 1;
lint = match args.get(i).map(String::as_str) {
Some("arithmetic_side_effects") => LintTarget::ArithmeticSideEffects,
Some("as_conversions") => LintTarget::AsConversions,
Some("all") => LintTarget::All,
other => {
eprintln!("Unknown lint: {:?}", other);
process::exit(1);
}
};
}
"--folder" => {
i += 1;
folder = args.get(i).map(PathBuf::from);
}
"--dry-run" => dry_run = true,
other => extra_cargo_args.push(other.to_owned()),
}
i += 1;
}
let folder = folder.unwrap_or_else(|| PathBuf::from("."));
println!("warn-rewrite: running on {:?} for {:?}", folder, lint);
if !dry_run {
let stripped = strip_allows::strip_project(&folder, lint);
if stripped > 0 {
println!("warn-rewrite: stripped crate-level allows from {} file(s)", stripped);
}
}
let self_path = std::env::current_exe().expect("can't find own path");
let status = process::Command::new("cargo")
.arg("check")
.arg("--manifest-path")
.arg(folder.join("Cargo.toml"))
.args(&extra_cargo_args)
.env("RUSTC_WRAPPER", &self_path)
.env("WARN_REWRITE_LINT", format!("{:?}", lint))
.env("WARN_REWRITE_DRY_RUN", if dry_run { "1" } else { "" })
.status()
.expect("failed to run cargo");
if dry_run || !status.success() {
process::exit(status.code().unwrap_or(1));
}
fixup::fixup_loop(&folder, &extra_cargo_args);
}
fn parse_lint_from_env() -> LintTarget {
match std::env::var("WARN_REWRITE_LINT").as_deref() {
Ok("ArithmeticSideEffects") => LintTarget::ArithmeticSideEffects,
Ok("AsConversions") => LintTarget::AsConversions,
_ => LintTarget::All,
}
}