169 lines
5.8 KiB
Rust
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"));
|
|
}
|
|
}
|