1use rustc_middle::ty::TyCtxt;
2use rustc_utils::source_map::{
3 filename::Filename, find_bodies::find_bodies, range::CharRange,
4};
5use serde::Serialize;
6
7use crate::plugin::{FlowistryError, FlowistryResult};
8
9#[derive(Serialize)]
10pub struct SpansOutput {
11 spans: Vec<CharRange>,
12}
13
14unsafe impl Send for SpansOutput {}
15
16struct Callbacks {
17 filename: String,
18 output: Option<FlowistryResult<SpansOutput>>,
19}
20
21impl rustc_driver::Callbacks for Callbacks {
22 fn after_analysis<'tcx>(
23 &mut self,
24 _compiler: &rustc_interface::interface::Compiler,
25 tcx: TyCtxt<'tcx>,
26 ) -> rustc_driver::Compilation {
27 let spans = find_bodies(tcx).into_iter().map(|(span, _)| span);
28
29 self.output = Some((|| {
30 let source_map = tcx.sess.source_map();
31 let source_file = Filename::intern(&self.filename)
32 .find_source_file(source_map)
33 .map_err(|_| FlowistryError::FileNotFound)?;
34
35 let spans = spans
36 .into_iter()
37 .filter(|span| source_map.lookup_source_file(span.lo()).name == source_file.name)
38 .filter_map(|span| CharRange::from_span(span, source_map).ok())
39 .collect::<Vec<_>>();
40 Ok(SpansOutput { spans })
41 })());
42
43 rustc_driver::Compilation::Stop
44 }
45}
46
47pub fn spans(args: &[String], filename: String) -> FlowistryResult<SpansOutput> {
48 let mut callbacks = Callbacks {
49 filename,
50 output: None,
51 };
52 crate::plugin::run_with_callbacks(args, &mut callbacks)?;
53 callbacks.output.unwrap()
54}