flowistry_ide/
spans.rs

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}