Crate debtmap

Crate debtmap 

Source
Expand description

§Debtmap

A code complexity and technical debt analyzer that identifies which code to refactor for maximum cognitive debt reduction and which code to test for maximum risk reduction.

§Why Debtmap?

Unlike traditional static analysis tools that simply flag complex code, debtmap answers two critical questions:

  1. “What should I refactor to reduce cognitive burden?” - Identifies overly complex code that slows down development
  2. “What should I test first to reduce the most risk?” - Pinpoints untested complex code that threatens stability

Unique Capabilities:

  • Coverage-Risk Correlation - Combines complexity metrics with test coverage to identify genuinely risky code (high complexity + low coverage = critical risk)
  • Reduced False Positives - Uses entropy analysis and pattern detection to distinguish genuinely complex code from repetitive patterns, reducing false positives by up to 70%
  • Actionable Recommendations - Provides specific guidance with quantified impact metrics instead of generic warnings
  • Multi-Factor Analysis - Analyzes complexity, coverage, dependencies, and call graphs for comprehensive prioritization
  • Fast & Open Source - Written in Rust for 10-100x faster analysis, MIT licensed

§Quick Start

§Basic File Analysis

use debtmap::{analyzers::get_analyzer, Language};

// Get language-specific analyzer
let analyzer = get_analyzer(Language::Rust);

// Parse source code
let content = r#"
    fn example() {
        if true {
            println!("hello");
        }
    }
"#;
let ast = analyzer.parse(&content, "example.rs".into()).unwrap();

// Analyze complexity metrics
let metrics = analyzer.analyze(&ast);

println!("Functions analyzed: {}", metrics.complexity.functions.len());
if !metrics.complexity.functions.is_empty() {
    let avg = metrics.complexity.functions.iter()
        .map(|f| f.cyclomatic as f64).sum::<f64>()
        / metrics.complexity.functions.len() as f64;
    println!("Average complexity: {:.2}", avg);
}

§Code Smell Detection

use debtmap::debt::patterns::find_code_smells;
use std::path::Path;

let content = r#"
    fn example() {
        // TODO: Fix this later
        let x = 1;
    }
"#;

// Find TODOs, FIXMEs, and other code smells
let smells = find_code_smells(&content, Path::new("example.rs"));
for smell in smells {
    println!("{:?} at line {}", smell.debt_type, smell.line);
}

§Coverage-Based Risk Analysis

use debtmap::{
    analyzers::get_analyzer,
    risk::{lcov::parse_lcov_file, RiskAnalyzer},
    Language,
};
use std::path::PathBuf;

// Parse coverage data (skip if file doesn't exist)
let coverage_path = std::path::Path::new("target/coverage/lcov.info");
if !coverage_path.exists() {
    println!("Generate coverage with: cargo llvm-cov --lcov --output-path target/coverage/lcov.info");
    return;
}

let coverage_data = parse_lcov_file(coverage_path).unwrap();

// Analyze a file
let analyzer = get_analyzer(Language::Rust);
let content = std::fs::read_to_string("src/main.rs").unwrap();
let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
let metrics = analyzer.analyze(&ast);

// Calculate risk scores for each function
let risk_analyzer = RiskAnalyzer::default();
let file_path = std::path::Path::new("src/main.rs");
for func in &metrics.complexity.functions {
    let coverage = coverage_data.get_function_coverage(file_path, &func.name);
    let risk = risk_analyzer.analyze_function(
        PathBuf::from("src/main.rs"),
        func.name.clone(),
        (func.start_line, func.end_line),
        &func.complexity,
        coverage,
        false,
    );
    if risk.risk_score > 5.0 {
        println!("HIGH RISK: {} (score: {:.1})", risk.function_name, risk.risk_score);
    }
}

§Features

§Multi-Language Support

Debtmap analyzes code across multiple programming languages:

  • Rust - Full support with comprehensive AST analysis using syn
  • Python - Partial support via rustpython-parser

§Performance Characteristics

  • Parallel Processing - Uses rayon for CPU-intensive analysis across multiple files
  • Concurrent Data Structures - Leverages dashmap for lock-free concurrent access
  • Immutable Collections - Uses im crate for persistent data structures
  • Performance - 10-100x faster than Java/Python-based competitors

§Coverage Integration

Debtmap works with any tool generating LCOV format:

§Architecture

Debtmap follows a functional architecture with clear separation of concerns:

┌─────────────────────────────────────────────────────────────┐
│                     Input Layer (I/O)                        │
│  File Discovery → Content Reading → Coverage Parsing         │
└────────────────────────┬────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────────┐
│                    Parser Layer (Pure)                       │
│  Language Detection → AST Generation → Symbol Extraction     │
└────────────────────────┬────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────────┐
│                   Analysis Layer (Pure)                      │
│  Complexity → Debt Detection → Risk Assessment → Dependency  │
└────────────────────────┬────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────────┐
│                 Aggregation Layer (Functional)               │
│  Combine Results → Priority Scoring → Recommendation Gen    │
└────────────────────────┬────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────────┐
│                    Output Layer (I/O)                        │
│  Format Selection → Report Generation → File Writing         │
└─────────────────────────────────────────────────────────────┘

§Core Modules

§Data Flow Principles

Debtmap is built on functional programming principles:

  1. Pure Core - All analysis logic is pure functions with no side effects
  2. I/O at Boundaries - File operations and network calls isolated to edges
  3. Immutable Data - Uses persistent data structures for safe concurrent access
  4. Function Composition - Complex behavior built from simple, testable units
  5. Parallel Processing - Embarrassingly parallel analysis across files

§CLI Usage

For command-line usage, see the CLI Reference.

# Basic analysis
debtmap analyze .

# With coverage integration
cargo llvm-cov --lcov --output-path target/coverage/lcov.info
debtmap analyze . --lcov target/coverage/lcov.info

# Generate JSON report
debtmap analyze . --format json --output report.json

§Examples

§Custom Complexity Thresholds

use debtmap::{analyzers::get_analyzer, Language};

let analyzer = get_analyzer(Language::Rust);
let content = std::fs::read_to_string("src/main.rs").unwrap();
let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
let metrics = analyzer.analyze(&ast);

// Filter functions by custom complexity threshold
let high_complexity_threshold = 10;
let complex_functions: Vec<_> = metrics.complexity.functions.iter()
    .filter(|f| f.cyclomatic > high_complexity_threshold)
    .collect();

println!("Found {} highly complex functions", complex_functions.len());
for func in complex_functions {
    println!("  {} (complexity: {})", func.name, func.cyclomatic);
}

§Detecting Circular Dependencies

use debtmap::debt::circular::analyze_module_dependencies;
use debtmap::core::Dependency;
use std::path::PathBuf;

// Example: Analyze module dependencies from parsed files
// In practice, you would gather dependencies during file parsing
let files: Vec<(PathBuf, Vec<Dependency>)> = vec![
    (PathBuf::from("src/main.rs"), vec![]),
    (PathBuf::from("src/lib.rs"), vec![]),
];

let _dependency_graph = analyze_module_dependencies(&files);
// The dependency graph can be used to detect circular dependencies
// and analyze module coupling

§Generating Risk Insights

use debtmap::{
    analyzers::get_analyzer,
    risk::{lcov::parse_lcov_file, RiskAnalyzer, insights::generate_risk_insights},
    Language,
};
use std::path::PathBuf;
use im::Vector;

// Parse coverage and analyze file
let coverage = parse_lcov_file(std::path::Path::new("target/coverage/lcov.info")).unwrap();
let analyzer = get_analyzer(Language::Rust);
let content = std::fs::read_to_string("src/main.rs").unwrap();
let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
let metrics = analyzer.analyze(&ast);

// Calculate risks for all functions
let risk_analyzer = RiskAnalyzer::default();
let mut risks = Vector::new();
let file_path = std::path::Path::new("src/main.rs");
for func in &metrics.complexity.functions {
    let coverage_pct = coverage.get_function_coverage(file_path, &func.name);
    let risk = risk_analyzer.analyze_function(
        PathBuf::from("src/main.rs"),
        func.name.clone(),
        (func.start_line, func.end_line),
        &func.complexity,
        coverage_pct,
        false,
    );
    risks.push_back(risk);
}

// Generate actionable insights
let insights = generate_risk_insights(risks, &risk_analyzer);

// Display top recommendations
for rec in insights.risk_reduction_opportunities.iter().take(5) {
    println!("{}", rec.recommendation);
}

§Resources

§License

Debtmap is licensed under the MIT License.

Re-exports§

pub use crate::core::AnalysisResults;
pub use crate::core::CircularDependency;
pub use crate::core::ComplexityMetrics;
pub use crate::core::ComplexityReport;
pub use crate::core::ComplexitySummary;
pub use crate::core::DebtItem;
pub use crate::core::DebtType;
pub use crate::core::Dependency;
pub use crate::core::DependencyKind;
pub use crate::core::DependencyReport;
pub use crate::core::DuplicationBlock;
pub use crate::core::DuplicationLocation;
pub use crate::core::FileMetrics;
pub use crate::core::FunctionMetrics;
pub use crate::core::Language;
pub use crate::core::ModuleDependency;
pub use crate::core::Priority;
pub use crate::core::TechnicalDebtReport;
pub use crate::debt::circular::analyze_module_dependencies;
pub use crate::debt::circular::DependencyGraph;
pub use crate::debt::coupling::calculate_coupling_metrics;
pub use crate::debt::coupling::identify_coupling_issues;
pub use crate::debt::coupling::CouplingMetrics;
pub use crate::debt::duplication::detect_duplication;
pub use crate::debt::patterns::detect_duplicate_strings;
pub use crate::debt::patterns::find_code_smells;
pub use crate::debt::patterns::find_code_smells_with_suppression;
pub use crate::debt::patterns::find_todos_and_fixmes;
pub use crate::debt::patterns::find_todos_and_fixmes_with_suppression;
pub use crate::debt::smells::analyze_function_smells;
pub use crate::debt::smells::analyze_module_smells;
pub use crate::debt::smells::detect_deep_nesting;
pub use crate::debt::smells::detect_long_method;
pub use crate::debt::smells::detect_long_parameter_list;
pub use crate::debt::smells::CodeSmell;
pub use crate::debt::smells::SmellType;
pub use crate::debt::suppression::parse_suppression_comments;
pub use crate::debt::suppression::SuppressionContext;
pub use crate::debt::suppression::SuppressionStats;
pub use crate::core::metrics::calculate_average_complexity;
pub use crate::core::metrics::count_high_complexity;
pub use crate::core::metrics::find_max_complexity;
pub use crate::io::output::create_writer;
pub use crate::io::output::OutputFormat;
pub use crate::io::output::OutputWriter;
pub use crate::analyzers::analyze_file;
pub use crate::analyzers::get_analyzer;
pub use crate::analyzers::Analyzer;
pub use crate::risk::insights::generate_risk_insights;
pub use crate::risk::lcov::parse_lcov_file;
pub use crate::risk::FunctionRisk;
pub use crate::risk::RiskAnalyzer;
pub use crate::risk::RiskCategory;
pub use crate::risk::RiskInsight;
pub use crate::risk::TestingRecommendation;
pub use crate::analysis::AnalysisConfig;
pub use crate::analysis::CrossModuleTracker;
pub use crate::analysis::DeadCodeAnalysis;
pub use crate::analysis::FrameworkPatternDetector;
pub use crate::analysis::FunctionPointerTracker;
pub use crate::analysis::RustCallGraph;
pub use crate::analysis::RustCallGraphBuilder;
pub use crate::analysis::TraitRegistry;
pub use crate::effects::combine_validations;
pub use crate::effects::effect_fail;
pub use crate::effects::effect_from_fn;
pub use crate::effects::effect_pure;
pub use crate::effects::run_effect;
pub use crate::effects::run_effect_async;
pub use crate::effects::run_validation;
pub use crate::effects::validation_failure;
pub use crate::effects::validation_failures;
pub use crate::effects::validation_map;
pub use crate::effects::validation_success;
pub use crate::effects::AnalysisEffect;
pub use crate::effects::AnalysisErrors;
pub use crate::effects::AnalysisValidation;
pub use crate::env::AnalysisEnv;
pub use crate::env::RealEnv;
pub use crate::errors::errors_to_anyhow;
pub use crate::errors::format_error_list;
pub use crate::errors::AnalysisError;
pub use crate::effects::ask_env;
pub use crate::effects::asks_config;
pub use crate::effects::asks_entropy;
pub use crate::effects::asks_scoring;
pub use crate::effects::asks_thresholds;
pub use crate::effects::local_with_config;
pub use crate::resources::bracket_io;
pub use crate::resources::with_file_read;
pub use crate::resources::with_lock_file;
pub use crate::resources::with_progress;
pub use crate::resources::with_spinner;
pub use crate::resources::with_temp_dir;
pub use crate::resources::FileHandle;
pub use crate::resources::LockFile;
pub use crate::resources::ProgressHandle;
pub use crate::resources::TempDir;
pub use crate::testkit::ConfigBuilder;
pub use crate::testkit::DebtmapTestEnv;

Modules§

analysis
Advanced Analysis Module
analysis_utils
analyzers
builders
cli
commands
common
comparison
complexity
config
context
Context-aware detection system for reducing false positives
core
data_flow
database
debt
effects
Effect type aliases and helpers for debtmap analysis.
env
Environment trait and implementations for debtmap analysis.
errors
Unified error types for debtmap analysis operations.
extraction_patterns
formatting
io
metrics
Metrics calculation module
organization
output
patterns
pipeline
Pure functional pipeline for technical debt analysis.
priority
progress
Progress feedback infrastructure for debtmap analysis.
refactoring
resource
resources
Bracket pattern for resource management (Spec 206).
risk
testing
testkit
Testing infrastructure for debtmap using stillwater’s MockEnv.
transformers
tui
Terminal User Interface (TUI) for debtmap analysis progress.
utils

Macros§

assert_contains_error
Assert that an error message contains a specific pattern.
assert_result_err
Assert that a Result is Err and extract the error.
assert_result_ok
Assert that a Result is Ok and extract the value.
assert_validation_err
Assert that a Validation has failures and extract the errors.
assert_validation_error_count
Assert that a Validation has a specific number of errors.
assert_validation_ok
Assert that a Validation is successful and extract the value.