#![allow(clippy::type_complexity)]
use rustc_driver::Callbacks;
use rustc_errors::FatalError;
use rustc_interface::interface::Config;
use rustc_lint::LintStore;
use rustc_session::config::ErrorOutputType;
use rustc_session::EarlyDiagCtxt;
use rustc_span::Symbol;
use std::sync::Arc;
struct Lints {
callback: Arc<Box<dyn Fn(&mut LintStore) + Send + Sync + 'static>>,
tracked_files: Arc<Vec<String>>,
}
impl Callbacks for Lints {
fn config(&mut self, config: &mut Config) {
let previous = config.register_lints.take();
let tracked_files = Arc::clone(&self.tracked_files);
config.psess_created = Some(Box::new(move |parse_sess| {
if tracked_files.is_empty() {
return;
}
let file_depinfo = parse_sess.file_depinfo.get_mut();
for tracked_file in tracked_files.iter() {
file_depinfo.insert(Symbol::intern(tracked_file));
}
}));
let callback = Arc::clone(&self.callback);
config.register_lints = Some(Box::new(move |sess, lint_store| {
if let Some(previous) = &previous {
(previous)(sess, lint_store);
}
(*callback)(lint_store);
}));
}
}
pub fn with_lints<F: Fn(&mut LintStore) + Send + Sync + 'static>(
args: &[String],
tracked_files: Vec<String>,
callback: F,
) -> Result<(), FatalError> {
with_lints_and_error_output(args, tracked_files, ErrorOutputType::default(), callback)
}
pub fn with_lints_and_error_output<F: Fn(&mut LintStore) + Send + Sync + 'static>(
args: &[String],
tracked_files: Vec<String>,
error_output: ErrorOutputType,
callback: F,
) -> Result<(), FatalError> {
let handler = EarlyDiagCtxt::new(error_output);
rustc_driver::init_rustc_env_logger(&handler);
if rustc_driver::catch_fatal_errors(move || {
rustc_driver::RunCompiler::new(
args,
&mut Lints {
callback: Arc::new(Box::new(callback)),
tracked_files: Arc::new(tracked_files),
},
)
.run()
.map(|_| ())
})
.is_err()
{
Err(FatalError)
} else {
Ok(())
}
}