use crate::complexity::EntropyAnalysis;
use crate::core::FunctionMetrics;
use crate::priority::{DebtType, ImpactMetrics, UnifiedScore};
pub fn calculate_entropy_analysis(func: &FunctionMetrics) -> Option<EntropyAnalysis> {
func.entropy_score.as_ref().map(|entropy_score| {
let is_repetitive = entropy_score.token_entropy < 0.4;
let dampening_factor = if is_repetitive {
let repetition_dampening = 1.0 - (entropy_score.pattern_repetition * 0.5);
repetition_dampening.clamp(0.5, 1.0)
} else {
1.0
};
let adjusted_cognitive = (func.cognitive as f64 * dampening_factor) as u32;
let mut reasoning = Vec::new();
if entropy_score.pattern_repetition > 0.6 {
reasoning.push(format!(
"High pattern repetition detected ({}%)",
(entropy_score.pattern_repetition * 100.0) as i32
));
}
if entropy_score.token_entropy < 0.4 {
reasoning.push(format!(
"Low token entropy indicates simple patterns ({:.2})",
entropy_score.token_entropy
));
}
if entropy_score.branch_similarity > 0.7 {
reasoning.push(format!(
"Similar branch structures found ({}% similarity)",
(entropy_score.branch_similarity * 100.0) as i32
));
}
if dampening_factor < 1.0 {
let reduction_pct = ((1.0 - dampening_factor) * 100.0) as i32;
reasoning.push(format!(
"Complexity reduced by {}% due to pattern-based code",
reduction_pct
));
} else {
reasoning.push("Genuine complexity detected - no reduction applied".to_string());
}
EntropyAnalysis {
entropy_score: entropy_score.token_entropy,
pattern_repetition: entropy_score.pattern_repetition,
branch_similarity: entropy_score.branch_similarity,
dampening_factor,
dampening_was_applied: dampening_factor < 1.0,
original_complexity: func.cognitive,
adjusted_complexity: adjusted_cognitive,
reasoning,
}
})
}
pub(super) fn is_function_complex(cyclomatic: u32, cognitive: u32) -> bool {
cyclomatic > 10 || cognitive > 15
}
pub(super) fn calculate_risk_factor(debt_type: &DebtType) -> f64 {
match debt_type {
DebtType::TestingGap { .. } => 0.42,
DebtType::ComplexityHotspot { .. } => 0.35,
DebtType::ErrorSwallowing { .. } => 0.35, DebtType::DeadCode { .. } => 0.3,
DebtType::Duplication { .. } => 0.25,
DebtType::Risk { .. } => 0.2,
DebtType::TestComplexityHotspot { .. } => 0.15,
DebtType::TestTodo { .. } | DebtType::TestDuplication { .. } => 0.1,
DebtType::BlockingIO { .. } => 0.45,
DebtType::NestedLoops { .. } => 0.4,
DebtType::AllocationInefficiency { .. } => 0.3,
DebtType::StringConcatenation { .. } => 0.25,
DebtType::SuboptimalDataStructure { .. } => 0.2,
DebtType::GodObject { .. } => 0.4,
DebtType::FeatureEnvy { .. } => 0.25,
DebtType::PrimitiveObsession { .. } => 0.2,
DebtType::MagicValues { .. } => 0.15,
DebtType::FlakyTestPattern { .. } => 0.3,
DebtType::AssertionComplexity { .. } => 0.15,
DebtType::ResourceLeak { .. } => 0.5,
DebtType::AsyncMisuse { .. } => 0.4,
DebtType::CollectionInefficiency { .. } => 0.2,
DebtType::ScatteredType { .. } => 0.25,
DebtType::OrphanedFunctions { .. } => 0.15,
DebtType::UtilitiesSprawl { .. } => 0.3,
_ => 0.5,
}
}
pub(super) fn calculate_coverage_improvement(coverage: f64, is_complex: bool) -> f64 {
let potential = 1.0 - coverage;
if is_complex {
potential * 50.0 } else {
potential * 100.0 }
}
pub(super) fn calculate_lines_reduction(debt_type: &DebtType) -> u32 {
match debt_type {
DebtType::DeadCode {
cyclomatic,
cognitive,
..
} => *cyclomatic + *cognitive,
DebtType::Duplication {
instances,
total_lines,
}
| DebtType::TestDuplication {
instances,
total_lines,
..
} => *total_lines - (*total_lines / instances),
_ => 0,
}
}
pub(super) fn calculate_complexity_reduction(debt_type: &DebtType, is_complex: bool) -> f64 {
match debt_type {
DebtType::DeadCode {
cyclomatic,
cognitive,
..
} => (*cyclomatic + *cognitive) as f64 * 0.5,
DebtType::TestingGap { cyclomatic, .. } if is_complex => *cyclomatic as f64 * 0.3,
DebtType::ComplexityHotspot { cyclomatic, .. } => {
*cyclomatic as f64 * 0.5
}
DebtType::TestComplexityHotspot { cyclomatic, .. } => *cyclomatic as f64 * 0.3,
DebtType::GodObject {
god_object_score, ..
} => god_object_score * 0.4,
DebtType::NestedLoops { depth, .. } => (*depth as f64).powf(2.0) * 0.3, DebtType::FeatureEnvy { .. } => 2.0, _ => 0.0,
}
}
pub(super) fn calculate_expected_impact(
_func: &FunctionMetrics,
debt_type: &DebtType,
score: &UnifiedScore,
) -> ImpactMetrics {
let risk_factor = calculate_risk_factor(debt_type);
let risk_reduction = score.final_score * risk_factor;
let (coverage_improvement, lines_reduction, complexity_reduction) = match debt_type {
DebtType::TestingGap {
coverage,
cyclomatic,
cognitive,
} => {
let is_complex = is_function_complex(*cyclomatic, *cognitive);
(
calculate_coverage_improvement(*coverage, is_complex),
0,
calculate_complexity_reduction(debt_type, is_complex),
)
}
_ => (
0.0,
calculate_lines_reduction(debt_type),
calculate_complexity_reduction(debt_type, false),
),
};
ImpactMetrics {
coverage_improvement,
lines_reduction,
complexity_reduction,
risk_reduction,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_function_complex() {
assert!(!is_function_complex(5, 8));
assert!(is_function_complex(15, 8));
assert!(is_function_complex(8, 20));
assert!(is_function_complex(15, 20));
}
#[test]
fn test_calculate_coverage_improvement_simple() {
let improvement = calculate_coverage_improvement(0.5, false);
assert!((improvement - 50.0).abs() < 0.01);
}
#[test]
fn test_calculate_coverage_improvement_complex() {
let improvement = calculate_coverage_improvement(0.5, true);
assert!((improvement - 25.0).abs() < 0.01);
}
#[test]
fn test_calculate_risk_factor() {
assert_eq!(
calculate_risk_factor(&DebtType::TestingGap {
coverage: 0.5,
cyclomatic: 10,
cognitive: 8
}),
0.42
);
assert_eq!(
calculate_risk_factor(&DebtType::ComplexityHotspot {
cyclomatic: 20,
cognitive: 15,
}),
0.35
);
assert_eq!(
calculate_risk_factor(&DebtType::DeadCode {
cyclomatic: 5,
cognitive: 3,
visibility: crate::priority::FunctionVisibility::Private,
usage_hints: vec![]
}),
0.3
);
}
}