//! 义务实现检查Lint //! //! 检测代码中是否正确实现了宪法义务 use super::{LintViolation, Severity}; use regex::Regex; use std::collections::{HashMap, HashSet}; /// 义务定义 #[derive(Debug, Clone)] pub struct Obligation { pub name: String, pub clause: String, pub frequency: String, pub enforcer: String, } /// 义务实现检查器 pub struct ObligationImplLint { obligations: HashMap, } impl ObligationImplLint { pub fn new(obligations: Vec) -> Self { let mut map = HashMap::new(); for obl in obligations { map.insert(obl.name.clone(), obl); } Self { obligations: map } } /// 检查Rust源代码中的义务实现 pub fn check(&self, source: &str, file_path: &str) -> Vec { let mut violations = Vec::new(); // 1. 检测义务函数定义 // 格式: fn obligation_name() { ... } let fn_def_re = Regex::new(r"fn\s+([a-z_][a-z0-9_]*)\s*\(").unwrap(); let mut implemented_obligations = HashSet::new(); for cap in fn_def_re.captures_iter(source) { if let Some(fn_match) = cap.get(1) { let fn_name = fn_match.as_str(); // 检查是否是义务函数 if self.obligations.contains_key(fn_name) { implemented_obligations.insert(fn_name.to_string()); } } } // 2. 检查continuous义务是否有定时器 let timer_re = Regex::new(r"tokio::time::interval|std::time::Duration").unwrap(); let has_timer = timer_re.is_match(source); for (obl_name, obl) in &self.obligations { if obl.frequency == "continuous" { // continuous义务必须实现 if !implemented_obligations.contains(obl_name) { violations.push(LintViolation { file: file_path.to_string(), line: 1, column: 0, message: format!( "Continuous obligation '{}' from clause '{}' is not implemented", obl_name, obl.clause ), severity: Severity::Error, context: "obligation implementation".to_string(), }); } else if !has_timer { // continuous义务必须有定时器 violations.push(LintViolation { file: file_path.to_string(), line: 1, column: 0, message: format!( "Continuous obligation '{}' must use a timer (tokio::time::interval or std::time::Duration)", obl_name ), severity: Severity::Warning, context: "obligation implementation".to_string(), }); } } } // 3. 检查AI enforcer义务是否调用AI服务 let ai_call_re = Regex::new(r"ai_service|openai|anthropic|llm").unwrap(); let has_ai_call = ai_call_re.is_match(source); for (obl_name, obl) in &self.obligations { if obl.enforcer.contains("ai") && implemented_obligations.contains(obl_name) { if !has_ai_call { violations.push(LintViolation { file: file_path.to_string(), line: 1, column: 0, message: format!( "AI-enforced obligation '{}' should call AI service", obl_name ), severity: Severity::Warning, context: "obligation implementation".to_string(), }); } } } violations } } #[cfg(test)] mod tests { use super::*; #[test] fn test_continuous_obligation_not_implemented() { let obligations = vec![Obligation { name: "maintain_coverage".to_string(), clause: "XTZH_GOLD_COVERAGE".to_string(), frequency: "continuous".to_string(), enforcer: "ai_system".to_string(), }]; let lint = ObligationImplLint::new(obligations); let source = "fn other_function() {}"; let violations = lint.check(source, "test.rs"); assert_eq!(violations.len(), 1); assert!(violations[0].message.contains("not implemented")); } #[test] fn test_continuous_obligation_without_timer() { let obligations = vec![Obligation { name: "maintain_coverage".to_string(), clause: "XTZH_GOLD_COVERAGE".to_string(), frequency: "continuous".to_string(), enforcer: "ai_system".to_string(), }]; let lint = ObligationImplLint::new(obligations); let source = "fn maintain_coverage() { println!(\"test\"); }"; let violations = lint.check(source, "test.rs"); assert_eq!(violations.len(), 1); assert!(violations[0].message.contains("must use a timer")); } #[test] fn test_ai_obligation_without_ai_call() { let obligations = vec![Obligation { name: "check_compliance".to_string(), clause: "COMPLIANCE_CHECK".to_string(), frequency: "on_demand".to_string(), enforcer: "ai_system".to_string(), }]; let lint = ObligationImplLint::new(obligations); let source = "fn check_compliance() { println!(\"test\"); }"; let violations = lint.check(source, "test.rs"); assert_eq!(violations.len(), 1); assert!(violations[0].message.contains("should call AI service")); } }