#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn apply_file_ranking<T>(
results: Vec<T>,
config: &RankingConfig,
extractor: impl Fn(&T) -> AnalysisResult,
) -> Vec<(T, usize)> {
if config.top_files == 0 && config.min_score.is_none() {
return results
.into_iter()
.enumerate()
.map(|(i, r)| (r, i + 1))
.collect();
}
let defects: Vec<Defect> = results
.iter()
.enumerate()
.map(|(i, result)| {
let analysis = extractor(result);
result_to_defect(&analysis, i)
})
.collect();
let engine = FileRankingEngine::new(Box::new(SimpleScorer));
let ranked = engine.rank_files(defects, config.top_files);
let rank_map: BTreeMap<PathBuf, usize> = ranked.into_iter().map(|r| (r.path, r.rank)).collect();
let mut ranked_results: Vec<(T, usize)> = results
.into_iter()
.filter_map(|result| {
let analysis = extractor(&result);
rank_map
.get(&analysis.file_path)
.map(|&rank| (result, rank))
})
.collect();
ranked_results.sort_by_key(|(_, rank)| *rank);
ranked_results
}
fn result_to_defect(result: &AnalysisResult, index: usize) -> Defect {
let severity = compute_severity_from_metrics(&result.metrics);
let mut metrics = std::collections::HashMap::new();
for (key, value) in &result.metrics {
if let MetricValue::Float(f) = value {
metrics.insert(key.clone(), *f);
} else if let MetricValue::Integer(i) = value {
metrics.insert(key.clone(), *i as f64);
}
}
Defect {
id: format!("RANK-{index:04}"),
severity,
category: DefectCategory::Complexity, file_path: result.file_path.clone(),
line_start: result.line_range.start.line,
line_end: result.line_range.end.as_ref().map(|e| e.line),
column_start: Some(result.line_range.start.column),
column_end: result.line_range.end.as_ref().map(|e| e.column),
message: result.context.description.clone(),
rule_id: "ranking".to_string(),
fix_suggestion: None,
metrics,
}
}
fn compute_severity_from_metrics(metrics: &BTreeMap<String, MetricValue>) -> Severity {
let complexity_score = metrics
.iter()
.filter_map(|(k, v)| {
if k.contains("complexity") || k.contains("cyclomatic") || k.contains("cognitive") {
match v {
MetricValue::Integer(i) => Some(*i as f64),
MetricValue::Float(f) => Some(*f),
_ => None,
}
} else {
None
}
})
.max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.unwrap_or(0.0);
if complexity_score > 50.0 {
Severity::Critical
} else if complexity_score > 20.0 {
Severity::High
} else if complexity_score > 10.0 {
Severity::Medium
} else {
Severity::Low
}
}