#![cfg_attr(coverage_nightly, coverage(off))]
use super::utilities::{
is_macro_in_string_literal, DOT_UNWRAP, EPRINTLN_DBG, EPRINTLN_DEBUG, EPRINTLN_TRACE,
MAP_ERR_DISCARD, UNWRAP_OR_ELSE_DISCARD,
};
use crate::cli::handlers::comply_cb_detect::types::*;
use std::fs;
use std::path::Path;
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb507_panic_macros(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let entries = match walkdir_rs_files(&src_dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let panic_macros = ["todo!(", "unimplemented!("];
let mut violations = Vec::new();
for entry in &entries {
if is_test_file(entry) {
continue;
}
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
let lines: Vec<&str> = content.lines().collect();
let test_lines = compute_test_code_lines(&lines);
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
for (i, line) in lines.iter().enumerate() {
if test_lines.contains(&i) {
continue;
}
let trimmed = line.trim();
if trimmed.starts_with("//") || trimmed.starts_with("*") {
continue;
}
if is_macro_in_string_literal(trimmed, &panic_macros) {
continue;
}
for mac in &panic_macros {
if trimmed.contains(mac) {
violations.push(CbPatternViolation {
pattern_id: "CB-507".to_string(),
file: file.clone(),
line: i + 1,
description: format!(
"Panic macro `{}` in production code",
mac.trim_end_matches('(')
),
severity: Severity::Warning,
});
break;
}
}
}
}
violations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb510_include_macro_hygiene(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let entries = match walkdir_rs_files(&src_dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let mut violations = Vec::new();
for entry in &entries {
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
for (i, line) in content.lines().enumerate() {
let trimmed = line.trim();
if trimmed.starts_with("//") {
continue;
}
if trimmed.contains("include!(") && !trimmed.contains("include_str!") {
violations.push(CbPatternViolation {
pattern_id: "CB-510".to_string(),
file: file.clone(),
line: i + 1,
description: "include!() macro - included files are not standalone compilable"
.to_string(),
severity: Severity::Info,
});
}
}
}
violations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb511_flaky_timing_tests(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let test_dir = project_path.join("tests");
let mut all_files = walkdir_rs_files(&src_dir).unwrap_or_default();
all_files.extend(walkdir_rs_files(&test_dir).unwrap_or_default());
let mut violations = Vec::new();
for entry in &all_files {
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
if !content.contains("#[test]") && !content.contains("#[tokio::test]") {
continue;
}
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
let lines: Vec<&str> = content.lines().collect();
let mut in_test_fn = false;
let mut test_fn_start: usize = 0;
let mut brace_depth: u32 = 0;
let mut fn_has_instant = false;
let mut fn_has_elapsed = false;
let mut fn_has_duration_assert = false;
for (i, line) in lines.iter().enumerate() {
let trimmed = line.trim();
if !in_test_fn
&& (trimmed.starts_with("fn ") || trimmed.starts_with("async fn "))
&& i > 0
{
let has_test_attr = (1..=3).any(|back| {
i >= back && {
let prev = lines[i - back].trim();
prev == "#[test]" || prev == "#[tokio::test]"
}
});
if has_test_attr {
in_test_fn = true;
test_fn_start = i + 1;
brace_depth = 0;
fn_has_instant = false;
fn_has_elapsed = false;
fn_has_duration_assert = false;
}
}
if in_test_fn {
brace_depth += trimmed.matches('{').count() as u32;
brace_depth = brace_depth.saturating_sub(trimmed.matches('}').count() as u32);
if trimmed.contains("Instant::now()") {
fn_has_instant = true;
}
if trimmed.contains(".elapsed()") {
fn_has_elapsed = true;
}
if (trimmed.contains("assert!")
|| trimmed.contains("assert_eq!")
|| trimmed.contains("assert_ne!")
|| trimmed.contains("assert_lt!")
|| trimmed.contains("assert_le!"))
&& trimmed.contains(".elapsed()")
{
fn_has_duration_assert = true;
}
if brace_depth == 0 && i > test_fn_start {
if fn_has_instant && fn_has_elapsed && fn_has_duration_assert {
violations.push(CbPatternViolation {
pattern_id: "CB-511".to_string(),
file: file.clone(),
line: test_fn_start,
description: "Test uses Instant::now() with duration assertions — may be flaky under load".to_string(),
severity: Severity::Warning,
});
}
in_test_fn = false;
}
}
}
}
violations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb512_error_propagation_gap(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let entries = match walkdir_rs_files(&src_dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let mut violations = Vec::new();
for entry in &entries {
if is_test_file(entry) {
continue;
}
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
let lines: Vec<&str> = content.lines().collect();
let test_lines = compute_test_code_lines(&lines);
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
let mut in_result_fn = false;
let mut fn_line = 0;
let mut fn_depth = 0u32;
let mut unwrap_count = 0u32;
for (i, line) in lines.iter().enumerate() {
if test_lines.contains(&i) {
continue;
}
let trimmed = line.trim();
if (trimmed.starts_with("pub fn ")
|| trimmed.starts_with("fn ")
|| trimmed.starts_with("pub async fn ")
|| trimmed.starts_with("async fn "))
&& trimmed.contains("Result<")
{
in_result_fn = true;
fn_line = i;
fn_depth = 0;
unwrap_count = 0;
}
if in_result_fn {
fn_depth += trimmed.matches('{').count() as u32;
fn_depth = fn_depth.saturating_sub(trimmed.matches('}').count() as u32);
if trimmed.contains(DOT_UNWRAP) {
unwrap_count += 1;
}
if fn_depth == 0 && i > fn_line {
if unwrap_count >= 3 {
violations.push(CbPatternViolation {
pattern_id: "CB-512".to_string(),
file: file.clone(),
line: fn_line + 1,
description: format!(
"Function returns Result but has {unwrap_count} unwrap() calls - consider using ? operator"
),
severity: Severity::Warning,
});
}
in_result_fn = false;
}
}
}
}
violations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb513_silent_error_swallowing(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let entries = match walkdir_rs_files(&src_dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let mut violations = Vec::new();
for entry in &entries {
if is_test_file(entry) {
continue;
}
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
let lines: Vec<&str> = content.lines().collect();
let test_lines = compute_test_code_lines(&lines);
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
for (i, line) in lines.iter().enumerate() {
if test_lines.contains(&i) {
continue;
}
let trimmed = line.trim();
if trimmed.starts_with("//") || trimmed.starts_with("*") {
continue;
}
if trimmed.contains(UNWRAP_OR_ELSE_DISCARD) {
violations.push(CbPatternViolation {
pattern_id: "CB-513".to_string(),
file: file.clone(),
line: i + 1,
description:
"Silent error swallowing: .unwrap_or_else(|_| discards error context"
.to_string(),
severity: Severity::Warning,
});
continue;
}
if trimmed.contains(MAP_ERR_DISCARD) {
violations.push(CbPatternViolation {
pattern_id: "CB-513".to_string(),
file: file.clone(),
line: i + 1,
description:
"Silent error swallowing: .map_err(|_| discards original error context"
.to_string(),
severity: Severity::Warning,
});
}
}
}
violations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_cb514_debug_eprintln_leaks(project_path: &Path) -> Vec<CbPatternViolation> {
let src_dir = project_path.join("src");
let entries = match walkdir_rs_files(&src_dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let mut violations = Vec::new();
for entry in &entries {
if is_test_file(entry) {
continue;
}
let content = match fs::read_to_string(entry) {
Ok(c) => c,
Err(_) => continue,
};
let lines: Vec<&str> = content.lines().collect();
let test_lines = compute_test_code_lines(&lines);
let file = entry
.strip_prefix(project_path)
.unwrap_or(entry)
.display()
.to_string();
for (i, line) in lines.iter().enumerate() {
if test_lines.contains(&i) {
continue;
}
let trimmed = line.trim();
if trimmed.starts_with("//") || trimmed.starts_with("*") {
continue;
}
if trimmed.contains(EPRINTLN_DEBUG)
|| trimmed.contains(EPRINTLN_DBG)
|| trimmed.contains(EPRINTLN_TRACE)
{
violations.push(CbPatternViolation {
pattern_id: "CB-514".to_string(),
file: file.clone(),
line: i + 1,
description: "Debug eprintln! leak in production code".to_string(),
severity: Severity::Warning,
});
}
}
}
violations
}