use rustc_hir::def_id::DefId;
use super::{contract::Property, helpers::CallsiteLocation};
#[derive(Clone, Debug)]
pub enum CheckResult {
Proved,
Failed,
Unknown,
}
#[derive(Clone, Debug)]
pub struct PropertyCheckResult<'tcx> {
pub callsite: CallsiteLocation,
pub callsite_index: usize,
pub path_index: usize,
pub property_index: usize,
pub property: Property<'tcx>,
pub result: CheckResult,
pub diagnostics: Option<VisitDiagnostics>,
pub path_description: String,
pub callee_name: String,
}
#[derive(Clone, Debug)]
pub struct VisitDiagnostics {
pub backward: String,
pub forward: String,
}
impl VisitDiagnostics {
pub fn new(backward: String, forward: String) -> Self {
Self { backward, forward }
}
}
#[derive(Clone, Debug)]
pub struct VerificationReport<'tcx> {
pub function: DefId,
pub results: Vec<PropertyCheckResult<'tcx>>,
}
impl<'tcx> VerificationReport<'tcx> {
pub fn new(function: DefId) -> Self {
Self {
function,
results: Vec::new(),
}
}
pub fn push(&mut self, result: PropertyCheckResult<'tcx>) {
self.results.push(result);
}
pub fn len(&self) -> usize {
self.results.len()
}
pub fn is_empty(&self) -> bool {
self.results.is_empty()
}
pub fn describe(&self) -> String {
let mut out = String::new();
out.push_str(&format!(
"[rapx::verify::diagnostics] function {:?}: {} check item(s)\n",
self.function,
self.results.len()
));
for (index, result) in self.results.iter().enumerate() {
out.push_str(&format!(
" check #{index}: callsite #{}, bb{}, path #{}, property #{} {:?}, result {:?}\n",
result.callsite_index,
result.callsite.block.as_usize(),
result.path_index,
result.property_index,
result.property.kind,
result.result
));
if let Some(diagnostics) = &result.diagnostics {
out.push_str(&diagnostics.backward);
if !diagnostics.backward.ends_with('\n') {
out.push('\n');
}
out.push_str(&diagnostics.forward);
if !diagnostics.forward.ends_with('\n') {
out.push('\n');
}
}
}
out
}
}