debtmap/
lib.rs

1//! # Debtmap
2//!
3//! A code complexity and technical debt analyzer that identifies which code to refactor
4//! for maximum cognitive debt reduction and which code to test for maximum risk reduction.
5//!
6//! ## Why Debtmap?
7//!
8//! Unlike traditional static analysis tools that simply flag complex code, debtmap answers two critical questions:
9//!
10//! 1. **"What should I refactor to reduce cognitive burden?"** - Identifies overly complex code that slows down development
11//! 2. **"What should I test first to reduce the most risk?"** - Pinpoints untested complex code that threatens stability
12//!
13//! **Unique Capabilities:**
14//!
15//! - **Coverage-Risk Correlation** - Combines complexity metrics with test coverage to identify genuinely risky code (high complexity + low coverage = critical risk)
16//! - **Reduced False Positives** - Uses entropy analysis and pattern detection to distinguish genuinely complex code from repetitive patterns, reducing false positives by up to 70%
17//! - **Actionable Recommendations** - Provides specific guidance with quantified impact metrics instead of generic warnings
18//! - **Multi-Factor Analysis** - Analyzes complexity, coverage, dependencies, and call graphs for comprehensive prioritization
19//! - **Fast & Open Source** - Written in Rust for 10-100x faster analysis, MIT licensed
20//!
21//! ## Quick Start
22//!
23//! ### Basic File Analysis
24//!
25//! ```rust
26//! use debtmap::{analyzers::get_analyzer, Language};
27//!
28//! // Get language-specific analyzer
29//! let analyzer = get_analyzer(Language::Rust);
30//!
31//! // Parse source code
32//! let content = r#"
33//!     fn example() {
34//!         if true {
35//!             println!("hello");
36//!         }
37//!     }
38//! "#;
39//! let ast = analyzer.parse(&content, "example.rs".into()).unwrap();
40//!
41//! // Analyze complexity metrics
42//! let metrics = analyzer.analyze(&ast);
43//!
44//! println!("Functions analyzed: {}", metrics.complexity.functions.len());
45//! if !metrics.complexity.functions.is_empty() {
46//!     let avg = metrics.complexity.functions.iter()
47//!         .map(|f| f.cyclomatic as f64).sum::<f64>()
48//!         / metrics.complexity.functions.len() as f64;
49//!     println!("Average complexity: {:.2}", avg);
50//! }
51//! ```
52//!
53//! ### Code Smell Detection
54//!
55//! ```rust
56//! use debtmap::debt::patterns::find_code_smells;
57//! use std::path::Path;
58//!
59//! let content = r#"
60//!     fn example() {
61//!         // TODO: Fix this later
62//!         let x = 1;
63//!     }
64//! "#;
65//!
66//! // Find TODOs, FIXMEs, and other code smells
67//! let smells = find_code_smells(&content, Path::new("example.rs"));
68//! for smell in smells {
69//!     println!("{:?} at line {}", smell.debt_type, smell.line);
70//! }
71//! ```
72//!
73//! ### Coverage-Based Risk Analysis
74//!
75//! ```rust,ignore
76//! use debtmap::{
77//!     analyzers::get_analyzer,
78//!     risk::{lcov::parse_lcov_file, RiskAnalyzer},
79//!     Language,
80//! };
81//! use std::path::PathBuf;
82//!
83//! // Parse coverage data (skip if file doesn't exist)
84//! let coverage_path = std::path::Path::new("target/coverage/lcov.info");
85//! if !coverage_path.exists() {
86//!     println!("Generate coverage with: cargo llvm-cov --lcov --output-path target/coverage/lcov.info");
87//!     return;
88//! }
89//!
90//! let coverage_data = parse_lcov_file(coverage_path).unwrap();
91//!
92//! // Analyze a file
93//! let analyzer = get_analyzer(Language::Rust);
94//! let content = std::fs::read_to_string("src/main.rs").unwrap();
95//! let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
96//! let metrics = analyzer.analyze(&ast);
97//!
98//! // Calculate risk scores for each function
99//! let risk_analyzer = RiskAnalyzer::default();
100//! let file_path = std::path::Path::new("src/main.rs");
101//! for func in &metrics.complexity.functions {
102//!     let coverage = coverage_data.get_function_coverage(file_path, &func.name);
103//!     let risk = risk_analyzer.analyze_function(
104//!         PathBuf::from("src/main.rs"),
105//!         func.name.clone(),
106//!         (func.start_line, func.end_line),
107//!         &func.complexity,
108//!         coverage,
109//!         false,
110//!     );
111//!     if risk.risk_score > 5.0 {
112//!         println!("HIGH RISK: {} (score: {:.1})", risk.function_name, risk.risk_score);
113//!     }
114//! }
115//! ```
116//!
117//! ## Features
118//!
119//! ### Multi-Language Support
120//!
121//! Debtmap analyzes code across multiple programming languages:
122//!
123//! - **Rust** - Full support with comprehensive AST analysis using [`syn`](https://docs.rs/syn)
124//! - **Python** - Partial support via [`rustpython-parser`](https://docs.rs/rustpython-parser)
125//!
126//! ### Performance Characteristics
127//!
128//! - **Parallel Processing** - Uses [`rayon`](https://docs.rs/rayon) for CPU-intensive analysis across multiple files
129//! - **Concurrent Data Structures** - Leverages [`dashmap`](https://docs.rs/dashmap) for lock-free concurrent access
130//! - **Immutable Collections** - Uses [`im`](https://docs.rs/im) crate for persistent data structures
131//! - **Performance** - 10-100x faster than Java/Python-based competitors
132//!
133//! ### Coverage Integration
134//!
135//! Debtmap works with any tool generating LCOV format:
136//! - **Rust**: [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) (recommended), [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin)
137//! - **Python**: `pytest-cov`, `coverage.py`
138//! - **JavaScript**: `jest --coverage`, `nyc`
139//!
140//! ## Architecture
141//!
142//! Debtmap follows a functional architecture with clear separation of concerns:
143//!
144//! ```text
145//! ┌─────────────────────────────────────────────────────────────┐
146//! │                     Input Layer (I/O)                        │
147//! │  File Discovery → Content Reading → Coverage Parsing         │
148//! └────────────────────────┬────────────────────────────────────┘
149//!                          ↓
150//! ┌─────────────────────────────────────────────────────────────┐
151//! │                    Parser Layer (Pure)                       │
152//! │  Language Detection → AST Generation → Symbol Extraction     │
153//! └────────────────────────┬────────────────────────────────────┘
154//!                          ↓
155//! ┌─────────────────────────────────────────────────────────────┐
156//! │                   Analysis Layer (Pure)                      │
157//! │  Complexity → Debt Detection → Risk Assessment → Dependency  │
158//! └────────────────────────┬────────────────────────────────────┘
159//!                          ↓
160//! ┌─────────────────────────────────────────────────────────────┐
161//! │                 Aggregation Layer (Functional)               │
162//! │  Combine Results → Priority Scoring → Recommendation Gen    │
163//! └────────────────────────┬────────────────────────────────────┘
164//!                          ↓
165//! ┌─────────────────────────────────────────────────────────────┐
166//! │                    Output Layer (I/O)                        │
167//! │  Format Selection → Report Generation → File Writing         │
168//! └─────────────────────────────────────────────────────────────┘
169//! ```
170//!
171//! ### Core Modules
172//!
173//! - **[`analyzers`]** - Language-specific parsers and AST analysis
174//!   - [`analyzers::get_analyzer`] - Factory for language-specific analyzers
175//!   - [`analyzers::analyze_file`] - High-level file analysis API
176//!
177//! - **[`debt`]** - Technical debt pattern detection
178//!   - [`debt::patterns`] - Code smell detection (TODOs, magic numbers, etc.)
179//!   - [`debt::smells`] - Function-level smell analysis (long methods, deep nesting)
180//!   - [`debt::duplication`] - Duplicate code detection
181//!   - [`debt::coupling`] - Module coupling analysis
182//!
183//! - **[`risk`]** - Risk assessment and prioritization
184//!   - [`risk::RiskAnalyzer`] - Coverage-based risk scoring
185//!   - [`risk::lcov::parse_lcov_file`] - LCOV format parser
186//!   - [`risk::insights::generate_risk_insights`] - Actionable recommendation generation
187//!
188//! - **[`complexity`]** - Complexity metric calculations
189//!   - Cyclomatic complexity (control flow branching)
190//!   - Cognitive complexity (human comprehension difficulty)
191//!   - Halstead metrics (vocabulary and volume)
192//!
193//! - **[`io`]** - Input/output formatting and handling
194//!   - [`io::output`] - Multiple output formats (JSON, YAML, table)
195//!   - [`io::output::OutputWriter`] - Trait for custom output formats
196//!
197//! - **[`analysis`]** - Advanced analysis algorithms
198//!   - [`analysis::RustCallGraph`] - Function call graph construction
199//!   - [`analysis::DeadCodeAnalysis`] - Unused code detection
200//!   - [`analysis::FrameworkPatternDetector`] - Framework-specific patterns
201//!
202//! - **[`testing`]** - Test quality analysis
203//!   - Test coverage correlation
204//!   - Test effectiveness scoring
205//!
206//! ### Data Flow Principles
207//!
208//! Debtmap is built on functional programming principles:
209//!
210//! 1. **Pure Core** - All analysis logic is pure functions with no side effects
211//! 2. **I/O at Boundaries** - File operations and network calls isolated to edges
212//! 3. **Immutable Data** - Uses persistent data structures for safe concurrent access
213//! 4. **Function Composition** - Complex behavior built from simple, testable units
214//! 5. **Parallel Processing** - Embarrassingly parallel analysis across files
215//!
216//! ## CLI Usage
217//!
218//! For command-line usage, see the [CLI Reference](https://iepathos.github.io/debtmap/cli-reference.html).
219//!
220//! ```bash
221//! # Basic analysis
222//! debtmap analyze .
223//!
224//! # With coverage integration
225//! cargo llvm-cov --lcov --output-path target/coverage/lcov.info
226//! debtmap analyze . --lcov target/coverage/lcov.info
227//!
228//! # Generate JSON report
229//! debtmap analyze . --format json --output report.json
230//! ```
231//!
232//! ## Examples
233//!
234//! ### Custom Complexity Thresholds
235//!
236//! ```rust,no_run
237//! use debtmap::{analyzers::get_analyzer, Language};
238//!
239//! let analyzer = get_analyzer(Language::Rust);
240//! let content = std::fs::read_to_string("src/main.rs").unwrap();
241//! let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
242//! let metrics = analyzer.analyze(&ast);
243//!
244//! // Filter functions by custom complexity threshold
245//! let high_complexity_threshold = 10;
246//! let complex_functions: Vec<_> = metrics.complexity.functions.iter()
247//!     .filter(|f| f.cyclomatic > high_complexity_threshold)
248//!     .collect();
249//!
250//! println!("Found {} highly complex functions", complex_functions.len());
251//! for func in complex_functions {
252//!     println!("  {} (complexity: {})", func.name, func.cyclomatic);
253//! }
254//! ```
255//!
256//! ### Detecting Circular Dependencies
257//!
258//! ```rust,no_run
259//! use debtmap::debt::circular::analyze_module_dependencies;
260//! use debtmap::core::Dependency;
261//! use std::path::PathBuf;
262//!
263//! // Example: Analyze module dependencies from parsed files
264//! // In practice, you would gather dependencies during file parsing
265//! let files: Vec<(PathBuf, Vec<Dependency>)> = vec![
266//!     (PathBuf::from("src/main.rs"), vec![]),
267//!     (PathBuf::from("src/lib.rs"), vec![]),
268//! ];
269//!
270//! let _dependency_graph = analyze_module_dependencies(&files);
271//! // The dependency graph can be used to detect circular dependencies
272//! // and analyze module coupling
273//! ```
274//!
275//! ### Generating Risk Insights
276//!
277//! ```rust,ignore
278//! use debtmap::{
279//!     analyzers::get_analyzer,
280//!     risk::{lcov::parse_lcov_file, RiskAnalyzer, insights::generate_risk_insights},
281//!     Language,
282//! };
283//! use std::path::PathBuf;
284//! use im::Vector;
285//!
286//! // Parse coverage and analyze file
287//! let coverage = parse_lcov_file(std::path::Path::new("target/coverage/lcov.info")).unwrap();
288//! let analyzer = get_analyzer(Language::Rust);
289//! let content = std::fs::read_to_string("src/main.rs").unwrap();
290//! let ast = analyzer.parse(&content, "src/main.rs".into()).unwrap();
291//! let metrics = analyzer.analyze(&ast);
292//!
293//! // Calculate risks for all functions
294//! let risk_analyzer = RiskAnalyzer::default();
295//! let mut risks = Vector::new();
296//! let file_path = std::path::Path::new("src/main.rs");
297//! for func in &metrics.complexity.functions {
298//!     let coverage_pct = coverage.get_function_coverage(file_path, &func.name);
299//!     let risk = risk_analyzer.analyze_function(
300//!         PathBuf::from("src/main.rs"),
301//!         func.name.clone(),
302//!         (func.start_line, func.end_line),
303//!         &func.complexity,
304//!         coverage_pct,
305//!         false,
306//!     );
307//!     risks.push_back(risk);
308//! }
309//!
310//! // Generate actionable insights
311//! let insights = generate_risk_insights(risks, &risk_analyzer);
312//!
313//! // Display top recommendations
314//! for rec in insights.risk_reduction_opportunities.iter().take(5) {
315//!     println!("{}", rec.recommendation);
316//! }
317//! ```
318//!
319//! ## Resources
320//!
321//! - **Documentation**: [iepathos.github.io/debtmap](https://iepathos.github.io/debtmap/)
322//! - **Repository**: [github.com/iepathos/debtmap](https://github.com/iepathos/debtmap)
323//! - **Crate**: [crates.io/crates/debtmap](https://crates.io/crates/debtmap)
324//! - **Issues**: [github.com/iepathos/debtmap/issues](https://github.com/iepathos/debtmap/issues)
325//!
326//! ## License
327//!
328//! Debtmap is licensed under the [MIT License](https://github.com/iepathos/debtmap/blob/master/LICENSE).
329
330// Export modules for library usage
331pub mod analysis;
332pub mod analysis_utils;
333pub mod analyzers;
334pub mod builders;
335pub mod cli;
336pub mod commands;
337pub mod common;
338pub mod comparison;
339pub mod complexity;
340pub mod config;
341pub mod context;
342pub mod core;
343pub mod data_flow;
344pub mod database;
345pub mod debt;
346pub mod debtmap_error;
347pub mod di;
348pub mod effects;
349pub mod env;
350pub mod error;
351pub mod errors;
352pub mod extraction;
353pub mod extraction_patterns;
354pub mod formatting;
355pub mod io;
356pub mod metrics;
357pub mod observability;
358pub mod organization;
359pub mod output;
360pub mod patterns;
361pub mod pipeline;
362pub mod priority;
363pub mod progress;
364pub mod refactoring;
365pub mod resource;
366pub mod resources;
367pub mod risk;
368pub mod testing;
369pub mod testkit;
370pub mod transformers;
371pub mod tui;
372pub mod utils;
373
374// Re-export commonly used types
375pub use crate::core::{
376    AnalysisResults, CircularDependency, ComplexityMetrics, ComplexityReport, ComplexitySummary,
377    DebtItem, DebtType, Dependency, DependencyKind, DependencyReport, DuplicationBlock,
378    DuplicationLocation, FileMetrics, FunctionMetrics, Language, ModuleDependency, Priority,
379    TechnicalDebtReport,
380};
381
382pub use crate::debt::{
383    circular::{analyze_module_dependencies, DependencyGraph},
384    coupling::{calculate_coupling_metrics, identify_coupling_issues, CouplingMetrics},
385    duplication::detect_duplication,
386    patterns::{
387        detect_duplicate_strings, find_code_smells, find_code_smells_with_suppression,
388        find_todos_and_fixmes, find_todos_and_fixmes_with_suppression,
389    },
390    smells::{
391        analyze_function_smells, analyze_module_smells, detect_deep_nesting, detect_long_method,
392        detect_long_parameter_list, CodeSmell, SmellType,
393    },
394    suppression::{parse_suppression_comments, SuppressionContext, SuppressionStats},
395};
396
397pub use crate::core::metrics::{
398    calculate_average_complexity, count_high_complexity, find_max_complexity,
399};
400
401pub use crate::io::output::{create_writer, OutputFormat, OutputWriter};
402
403pub use crate::analyzers::{analyze_file, get_analyzer, Analyzer};
404
405pub use crate::risk::{
406    insights::generate_risk_insights, lcov::parse_lcov_file, FunctionRisk, RiskAnalyzer,
407    RiskCategory, RiskInsight, TestingRecommendation,
408};
409
410pub use crate::analysis::{
411    AnalysisConfig, CrossModuleTracker, DeadCodeAnalysis, FrameworkPatternDetector,
412    FunctionPointerTracker, RustCallGraph, RustCallGraphBuilder, TraitRegistry,
413};
414
415// Stillwater integration: Effect system and environment (spec 195)
416pub use crate::effects::{
417    combine_validations, effect_fail, effect_from_fn, effect_pure, run_effect, run_effect_async,
418    run_validation, validation_failure, validation_failures, validation_map, validation_success,
419    AnalysisEffect, AnalysisErrors, AnalysisValidation,
420};
421pub use crate::env::{AnalysisEnv, RealEnv};
422pub use crate::errors::{errors_to_anyhow, format_error_list, AnalysisError};
423
424// Reader pattern helpers (spec 199) - zero-cost config access without parameter threading
425pub use crate::effects::{
426    ask_env, asks_config, asks_entropy, asks_scoring, asks_thresholds, local_with_config,
427};
428
429// Progress effects (spec 262) - composable progress reporting
430pub use crate::effects::progress::{
431    par_traverse_with_progress, report_progress, traverse_with_progress, warn_progress, with_stage,
432};
433
434// Progress traits and implementations (spec 262)
435pub use crate::progress::traits::{HasProgress, ProgressSink};
436pub use crate::progress::{
437    CliProgressSink, ProgressEvent, RecordingProgressSink, SilentProgressSink,
438};
439
440// Bracket pattern resource management (spec 206)
441pub use crate::resources::{
442    bracket_io, with_file_read, with_lock_file, with_progress, with_spinner, with_temp_dir,
443    FileHandle, LockFile, ProgressHandle, TempDir,
444};
445
446// Testing infrastructure (spec 200) - MockEnv and test helpers
447// Note: Assertion macros are exported via #[macro_export] in testkit::assertions
448pub use crate::testkit::{ConfigBuilder, DebtmapTestEnv};
449
450// Observability infrastructure (spec 207) - panic hook and context tracking
451pub use crate::observability::{
452    get_current_context, get_progress, increment_processed, install_panic_hook, set_current_file,
453    set_phase, set_phase_persistent, set_progress, AnalysisContext, AnalysisPhase,
454};
455
456// Unified error types (spec 005) - consolidated error handling with context chaining
457pub use crate::debtmap_error::{DebtmapError, ErrorCode};