Halstead & Maintainability Index
Relevant source files
The following files were used as context for generating this wiki page:
The Halstead and Maintainability Index (MI) metrics are core components of the rust-code-analysis library used to evaluate software complexity, maintenance effort, and overall code quality. The Halstead suite provides quantitative measures based on the count of operators and operands, offering insights into implementation time, potential bugs, and cognitive difficulty.
The Maintainability Index leverages Halstead metrics alongside Cyclomatic complexity and Lines of Code (LoC) to produce a single value representing the ease of maintaining the codebase. These metrics are computed statically across various supported languages like Rust, Python, C++, and Java.
Sources: src/metrics/mi.rs:94-110, rust-code-analysis-book/src/metrics.md:14-20, src/lib.rs:27-40
Halstead Metrics Suite
The Halstead suite is a set of software metrics that measures the program's complexity based on the distribution of operators and operands within the source code.
Core Components and Data Structures
The implementation uses a Stats struct to store the raw counts of unique and total operators and operands. During the parsing phase, HalsteadMaps uses HashMap collections to track these elements by their node IDs or literal byte values.
The diagram above illustrates the relationship between the temporary map storage and the finalized statistical structure.
Sources: src/metrics/halstead.rs:16-56
Calculated Metrics
Halstead metrics are derived from four fundamental values: $\eta_1$ (distinct operators), $N_1$ (total operators), $\eta_2$ (distinct operands), and $N_2$ (total operands).
| Metric | Formula / Description | Implementation |
|---|---|---|
| Program Length | $N_1 + N_2$ | length() |
| Vocabulary | $\eta_1 + \eta_2$ | vocabulary() |
| Volume | $Length \times \log_2(Vocabulary)$ | volume() |
| Difficulty | $(\eta_1 / 2) \times (N_2 / \eta_2)$ | difficulty() |
| Effort | $Difficulty \times Volume$ | effort() |
| Time | $Effort / 18$ (Seconds) | time() |
| Bugs | $Effort^{2/3} / 3000$ | bugs() |
Sources: src/metrics/halstead.rs:125-212
Maintainability Index (MI)
The Maintainability Index is a composite metric used to evaluate how easy it is to maintain a piece of software. It integrates results from Halstead Volume, Cyclomatic complexity, and SlOC (Source Lines of Code).
MI Formula Variations
The library implements three distinct versions of the Maintainability Index formula:
- Original Formula: The baseline calculation involving Halstead Volume and SLOC.
- SEI Formula: A derivative used by the Software Engineering Institute that includes a Sinusoidal component based on the percentage of comments.
- Visual Studio Formula: A normalized version (0-100) used by Microsoft's IDE.
This flowchart shows the data flow from primitive metrics into the final MI calculations.
Sources: src/metrics/mi.rs:17-30, src/metrics/mi.rs:55-83
Integration Logic
The compute function in the Mi trait bridges different metric suites. It extracts the necessary data from loc::Stats, cyclomatic::Stats, and halstead::Stats to populate the mi::Stats structure.
pub trait Mi where Self: Checker {
fn compute(
loc: &loc::Stats,
cyclomatic: &cyclomatic::Stats,
halstead: &halstead::Stats,
stats: &mut Stats,
) {
stats.halstead_length = halstead.length();
stats.halstead_vocabulary = halstead.vocabulary();
stats.halstead_volume = halstead.volume();
stats.cyclomatic = cyclomatic.cyclomatic_sum();
stats.sloc = loc.sloc();
stats.comments_percentage = loc.cloc() / stats.sloc;
}
}
Sources: src/metrics/mi.rs:86-101
Metric Extraction Process
The extraction of Halstead and MI metrics is part of a larger AST traversal orchestrated in src/spaces.rs.
Traversal and Aggregation
As the library traverses the AST, it identifies nodes as either operators or operands based on the language-specific Getter implementation.
- Node Identification:
get_op_typedetermines if a node is anOperator,Operand, orUnknown. - Map Update:
HalsteadMapsentries are incremented. - Finalization: Once a "Space" (function, class, or unit) is fully traversed, the maps are finalized into
Stats. - MI Derivation: The finalized Halstead Volume is passed to the MI compute function.
Output and Serialization
Metrics are serialized into JSON format for CLI or Web tool consumers. The dump_metrics.rs module handles the human-readable console output, formatting the data into a tree structure.
| Field | JSON Key | Data Source |
|---|---|---|
| Distinct Operators | n1 | halstead::Stats::u_operators |
| Total Operators | N1 | halstead::Stats::operators |
| Original MI | mi_original | mi::Stats::mi_original |
| VS Maintainability | mi_visual_studio | mi::Stats::mi_visual_studio |
Sources: src/output/dump_metrics.rs:163-195, src/metrics/mi.rs:32-41
Conclusion
The Halstead and Maintainability Index modules provide an objective, mathematical approach to assessing code quality. By quantifying maintenance effort and technical debt through established formulas, rust-code-analysis enables developers to identify problematic areas in their codebase across multiple programming languages.