1 use crate::location::{LocationIndex, LocationTable};
2 use crate::BorrowIndex;
3 use polonius_engine::AllFacts as PoloniusFacts;
4 use polonius_engine::Atom;
5 use rustc_index::vec::Idx;
6 use rustc_middle::mir::Local;
7 use rustc_middle::ty::{RegionVid, TyCtxt};
8 use rustc_mir_dataflow::move_paths::MovePathIndex;
11 use std::fs::{self, File};
12 use std::io::{BufWriter, Write};
15 #[derive(Copy, Clone, Debug)]
16 pub struct RustcFacts;
18 impl polonius_engine::FactTypes for RustcFacts {
19 type Origin = RegionVid;
20 type Loan = BorrowIndex;
21 type Point = LocationIndex;
22 type Variable = Local;
23 type Path = MovePathIndex;
26 pub type AllFacts = PoloniusFacts<RustcFacts>;
28 pub(crate) trait AllFactsExt {
29 /// Returns `true` if there is a need to gather `AllFacts` given the
30 /// current `-Z` flags.
31 fn enabled(tcx: TyCtxt<'_>) -> bool;
35 dir: impl AsRef<Path>,
36 location_table: &LocationTable,
37 ) -> Result<(), Box<dyn Error>>;
40 impl AllFactsExt for AllFacts {
42 fn enabled(tcx: TyCtxt<'_>) -> bool {
43 tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius
48 dir: impl AsRef<Path>,
49 location_table: &LocationTable,
50 ) -> Result<(), Box<dyn Error>> {
51 let dir: &Path = dir.as_ref();
52 fs::create_dir_all(dir)?;
53 let wr = FactWriter { location_table, dir };
54 macro_rules! write_facts_to_path {
55 ($wr:ident . write_facts_to_path($this:ident . [
59 $wr.write_facts_to_path(
61 &format!("{}.facts", stringify!($field))
66 write_facts_to_path! {
67 wr.write_facts_to_path(self.[
77 use_of_var_derefs_origin,
78 drop_of_var_derefs_origin,
81 path_assigned_at_base,
83 path_accessed_at_base,
84 known_placeholder_subset,
92 impl Atom for BorrowIndex {
93 fn index(self) -> usize {
98 impl Atom for LocationIndex {
99 fn index(self) -> usize {
104 struct FactWriter<'w> {
105 location_table: &'w LocationTable,
109 impl<'w> FactWriter<'w> {
110 fn write_facts_to_path<T>(&self, rows: &[T], file_name: &str) -> Result<(), Box<dyn Error>>
114 let file = &self.dir.join(file_name);
115 let mut file = BufWriter::new(File::create(file)?);
117 row.write(&mut file, self.location_table)?;
127 location_table: &LocationTable,
128 ) -> Result<(), Box<dyn Error>>;
131 impl FactRow for RegionVid {
135 location_table: &LocationTable,
136 ) -> Result<(), Box<dyn Error>> {
137 write_row(out, location_table, &[self])
141 impl<A, B> FactRow for (A, B)
149 location_table: &LocationTable,
150 ) -> Result<(), Box<dyn Error>> {
151 write_row(out, location_table, &[&self.0, &self.1])
155 impl<A, B, C> FactRow for (A, B, C)
164 location_table: &LocationTable,
165 ) -> Result<(), Box<dyn Error>> {
166 write_row(out, location_table, &[&self.0, &self.1, &self.2])
170 impl<A, B, C, D> FactRow for (A, B, C, D)
180 location_table: &LocationTable,
181 ) -> Result<(), Box<dyn Error>> {
182 write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
188 location_table: &LocationTable,
189 columns: &[&dyn FactCell],
190 ) -> Result<(), Box<dyn Error>> {
191 for (index, c) in columns.iter().enumerate() {
192 let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
193 write!(out, "{:?}{}", c.to_string(location_table), tail)?;
199 fn to_string(&self, location_table: &LocationTable) -> String;
202 impl<A: Debug> FactCell for A {
203 default fn to_string(&self, _location_table: &LocationTable) -> String {
204 format!("{:?}", self)
208 impl FactCell for LocationIndex {
209 fn to_string(&self, location_table: &LocationTable) -> String {
210 format!("{:?}", location_table.to_location(*self))