Skip to content

Commit c38f341

Browse files
committed
filter verus_spec warning
1 parent 504e219 commit c38f341

1 file changed

Lines changed: 101 additions & 2 deletions

File tree

src/verus.rs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use colored::Colorize;
22
use indexmap::IndexMap;
33
use memoize::memoize;
44
use std::collections::{HashMap, HashSet};
5+
use std::ffi::OsStr;
56
use std::fs::{self, File};
6-
use std::io::{Read, Write};
7+
use std::io::{BufRead, BufReader, IsTerminal, Read, Write};
78
use std::path::{Path, PathBuf};
89
use std::process::{Command, Stdio};
910
use std::time::Instant;
@@ -648,7 +649,7 @@ pub fn exec_verify(targets: &[VerusTarget], options: &ExtraOptions) -> Result<()
648649
);
649650
debug!(">> {:?}", cmd);
650651

651-
let status = cmd.status().unwrap_or_else(|e| {
652+
let status = run_verify_command(cmd).unwrap_or_else(|e| {
652653
error!("Error during verification: {}", e);
653654
});
654655

@@ -712,6 +713,104 @@ pub fn exec_verify(targets: &[VerusTarget], options: &ExtraOptions) -> Result<()
712713
Ok(())
713714
}
714715

716+
const VERUS_SPEC_WARNING_START: &str =
717+
"warning: #[verus_spec] is likely used inside a verus! block.";
718+
const VERUS_SPEC_WARNING_END: &str =
719+
"= note: this warning originates in the attribute macro `verus_spec`";
720+
721+
fn run_verify_command(cmd: &mut Command) -> std::io::Result<std::process::ExitStatus> {
722+
let configured_color = std::env::var_os("CARGO_TERM_COLOR");
723+
if should_force_cargo_color(std::io::stderr().is_terminal(), configured_color.as_deref()) {
724+
// Piping stderr for filtering would otherwise make Cargo disable the
725+
// colors it normally emits to an interactive terminal.
726+
cmd.env("CARGO_TERM_COLOR", "always");
727+
}
728+
cmd.stderr(Stdio::piped());
729+
let mut child = cmd.spawn()?;
730+
let child_stderr = child.stderr.take().ok_or_else(|| {
731+
std::io::Error::new(
732+
std::io::ErrorKind::Other,
733+
"could not capture the verification process stderr",
734+
)
735+
})?;
736+
737+
let filter_result =
738+
filter_verus_spec_warnings(BufReader::new(child_stderr), &mut std::io::stderr().lock());
739+
let status_result = child.wait();
740+
741+
filter_result?;
742+
status_result
743+
}
744+
745+
fn should_force_cargo_color(stderr_is_terminal: bool, configured: Option<&OsStr>) -> bool {
746+
stderr_is_terminal
747+
&& configured
748+
.map(|value| value.eq_ignore_ascii_case("auto"))
749+
.unwrap_or(true)
750+
}
751+
752+
fn filter_verus_spec_warnings<R: BufRead, W: Write>(
753+
reader: R,
754+
writer: &mut W,
755+
) -> std::io::Result<()> {
756+
let mut candidate = Vec::new();
757+
let mut suppress_following_blank_line = false;
758+
759+
for line in reader.lines() {
760+
let line = line?;
761+
let plain_line = strip_ansi_escape_codes(&line);
762+
763+
if suppress_following_blank_line {
764+
suppress_following_blank_line = false;
765+
if plain_line.trim().is_empty() {
766+
continue;
767+
}
768+
}
769+
770+
if !candidate.is_empty() {
771+
let is_warning_end = plain_line.contains(VERUS_SPEC_WARNING_END);
772+
candidate.push(line);
773+
if is_warning_end {
774+
candidate.clear();
775+
suppress_following_blank_line = true;
776+
}
777+
continue;
778+
}
779+
780+
if plain_line.contains(VERUS_SPEC_WARNING_START) {
781+
candidate.push(line);
782+
} else {
783+
writeln!(writer, "{line}")?;
784+
}
785+
}
786+
787+
// A truncated or changed diagnostic is not a confirmed match. Preserve it
788+
// instead of accidentally hiding unrelated compiler output.
789+
for line in candidate {
790+
writeln!(writer, "{line}")?;
791+
}
792+
writer.flush()
793+
}
794+
795+
fn strip_ansi_escape_codes(line: &str) -> String {
796+
let mut plain = String::with_capacity(line.len());
797+
let mut chars = line.chars().peekable();
798+
799+
while let Some(ch) = chars.next() {
800+
if ch == '\u{1b}' && chars.next_if_eq(&'[').is_some() {
801+
for code in chars.by_ref() {
802+
if ('@'..='~').contains(&code) {
803+
break;
804+
}
805+
}
806+
} else {
807+
plain.push(ch);
808+
}
809+
}
810+
811+
plain
812+
}
813+
715814
fn verus_args_should_apply_to_roots_only(args: &[String]) -> bool {
716815
args.iter().any(|arg| {
717816
matches!(

0 commit comments

Comments
 (0)