NAC_Blockchain/cargo-constitution/src/lints/obligation_impl.rs

169 lines
5.8 KiB
Rust

//! 义务实现检查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<String, Obligation>,
}
impl ObligationImplLint {
pub fn new(obligations: Vec<Obligation>) -> 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<LintViolation> {
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"));
}
}