Skip to content

v1.4.0

Choose a tag to compare

@github-actions github-actions released this 31 Aug 20:50
· 35 commits to main since this release
9d51940

This release introduces deterministic, C#-specific Halstead Metrics and continues the project's focus on maintainable, reproducible static-analysis infrastructure.

Halstead analysis complements the existing complexity dimensions by measuring the vocabulary and usage of operators and operands within supported C# executable members.

Rather than attempting to collapse these measurements into another generic maintainability score, ComplexityAnalysis.Analyzers exposes a well-defined internal metric model that can support future diagnostics, reporting, and higher-level analysis while preserving the project's conservative diagnostic philosophy.

Phase 10 — Halstead Metrics

10.1 — C#-specific Halstead Metrics

The analyzer now provides a deterministic C#-specific implementation of Halstead Metrics based on Roslyn syntax rather than generic C-like token heuristics.

The analysis collects the four primitive Halstead measurements:

  • n1 — distinct operators;
  • n2 — distinct operands;
  • N1 — total operators;
  • N2 — total operands.

From these primitive values, the analyzer derives:

  • vocabulary;
  • program length;
  • calculated length;
  • volume;
  • difficulty;
  • effort;
  • estimated implementation time;
  • estimated delivered bugs.

The implementation explicitly protects empty and trivial executable members from invalid floating-point results such as NaN or infinity.

C#-specific classification

The operator and operand model is deliberately defined for modern C# and documented as part of the project's compatibility contract.

Supported syntax includes representative constructs such as:

  • arithmetic, comparison, logical, and assignment operators;
  • compound assignments;
  • null-related operators such as ?., ??, and ??=;
  • lambdas and expression-bodied members using =>;
  • pattern-matching constructs;
  • identifiers and literals;
  • interpolated strings;
  • member access;
  • range and index syntax;
  • collection expressions;
  • supported control-flow and expression constructs.

Comments and trivia do not contribute to the metrics.

Nested executable members such as local functions, lambdas, and anonymous methods retain independent ownership and therefore do not incorrectly inflate their lexical parent's Halstead measurements.

Independent complexity dimensions

Halstead Metrics remain independent from the analyzer's existing measurements:

  • Big-O complexity;
  • Cyclomatic Complexity;
  • Maximum Control-Flow Nesting Depth;
  • NLOC;
  • Statement Count;
  • Token Count;
  • Parameter Count;
  • Cognitive Complexity.

Each metric answers a different question about source code.

Halstead Metrics focus on the vocabulary and frequency of the operators and operands required to express an implementation, while the existing metrics describe computational growth, execution paths, structural depth, source size, API shape, or cognitive control-flow burden.

Keeping these dimensions separate avoids introducing a speculative composite maintainability score.

No Halstead threshold diagnostic

This release intentionally does not introduce a new BIG2xxx diagnostic or public Halstead threshold configuration.

Although Halstead measurements can provide useful information about code characteristics, there is currently no single Halstead-derived value with a sufficiently universal and evidence-backed threshold to justify a maintainability diagnostic across different C# codebases.

This follows the project's established principle that diagnostics should be actionable, deterministic, and defensible rather than being introduced simply because a metric can be calculated.

The Halstead implementation therefore establishes the measurement foundation without prematurely defining policy around acceptable values.

Maintainability hardening

This release also addresses a SonarQube maintainability finding in MethodSizeMetricsAnalyzer.

The affected analysis logic is refactored to reduce its Cognitive Complexity while preserving the existing behavior and contracts of the NLOC, Statement Count, and Token Count metrics.

The change is structural rather than behavioral: existing diagnostic semantics, configuration, executable-member boundaries, and metric calculations remain unchanged.

This keeps the analyzer's own implementation aligned with the maintainability principles it is designed to help enforce.

Documentation

The Halstead classification convention is documented in both English and Brazilian Portuguese.

The documentation defines:

  • operator and operand classification;
  • primitive-count semantics;
  • derived formulas;
  • modern C# syntax handling;
  • nested executable-member ownership;
  • comments and trivia exclusion;
  • numeric stability requirements;
  • the relationship between Halstead and the analyzer's other complexity dimensions.

The goal is to make Halstead values reproducible across future versions rather than dependent on undocumented token-classification behavior.

Validation

The implementation was validated against the engineering baseline established by previous releases, including:

  • primitive Halstead count tests;
  • derived-formula tests;
  • numeric safety and deterministic formatting;
  • modern C# operator and operand classification;
  • null operators;
  • pattern matching;
  • lambdas and expression-bodied members;
  • interpolated strings;
  • range, index, and collection syntax;
  • comments and trivia exclusion;
  • identifier-renaming behavior;
  • nested executable-member isolation;
  • supported executable-member kinds;
  • regression coverage for existing complexity metrics;
  • analyzer performance budgets;
  • Roslyn host compatibility;
  • NuGet package and consumer contracts.

The existing analyzer behavior remains unchanged outside the new Halstead analysis capability and the internal maintainability refactoring.

Why this release matters

Complexity is multidimensional.

Big-O describes how computational cost grows. Cyclomatic Complexity measures independent execution paths. Maximum Nesting Depth describes structural depth. Cognitive Complexity focuses on how difficult control flow is to mentally follow.

Halstead Metrics add another perspective: the vocabulary and operational structure used to express an implementation.

With Phase 10 beginning, ComplexityAnalysis.Analyzers can reason about an increasingly broad set of code characteristics while keeping every measurement deterministic, independently explainable, and free from arbitrary composite scoring.

At the same time, the maintainability refactoring included in this release reinforces an important principle of the project: the analyzer itself should meet the same engineering standards it encourages in the code it evaluates.

See the canonical execution roadmap in #36 — Execution order for analyzer hardening and capability expansion.

What's Changed

  • feat: add C#-specific Halstead Metrics — #60
  • refactor: reduce Cognitive Complexity in MethodSizeMetricsAnalyzer — #61
  • closes #15 — [10.1] Add C#-specific Halstead Metrics
  • closes #61 — [Sonar][HIGH][MAINTAINABILITY] Cognitive Complexity of methods should not be too high

Full Changelog: v1.3.0...v1.4.0