Metastatic.Analysis.Complexity.Result (Metastatic v0.10.4)

View Source

Result structure for complexity analysis.

Contains comprehensive code complexity metrics calculated at the MetaAST level, working uniformly across all supported languages.

Fields

  • :cyclomatic - McCabe cyclomatic complexity (decision points + 1)
  • :cognitive - Cognitive complexity score (structural complexity with nesting penalties)
  • :max_nesting - Maximum nesting depth
  • :halstead - Halstead metrics map (volume, difficulty, effort)
  • :loc - Lines of code metrics map (physical, logical, comments)
  • :function_metrics - Function-level metrics map (statements, returns, variables)
  • :warnings - List of threshold violation warnings
  • :summary - Human-readable summary string

Examples

iex> %Metastatic.Analysis.Complexity.Result{
...>   cyclomatic: 5,
...>   cognitive: 7,
...>   max_nesting: 2,
...>   halstead: %{volume: 100.0, difficulty: 5.0, effort: 500.0},
...>   loc: %{logical: 20, physical: 30},
...>   function_metrics: %{statement_count: 20, return_points: 1, variable_count: 5},
...>   warnings: [],
...>   summary: "Code has low complexity"
...> }

Summary

Functions

Adds a warning to the result.

Applies thresholds and generates warnings.

Merges multiple complexity results.

Creates a new complexity result from metrics map.

Types

function_metrics()

@type function_metrics() :: %{
  statement_count: non_neg_integer(),
  return_points: non_neg_integer(),
  variable_count: non_neg_integer(),
  parameter_count: non_neg_integer()
}

halstead_metrics()

@type halstead_metrics() :: %{
  distinct_operators: non_neg_integer(),
  distinct_operands: non_neg_integer(),
  total_operators: non_neg_integer(),
  total_operands: non_neg_integer(),
  vocabulary: non_neg_integer(),
  length: non_neg_integer(),
  volume: float(),
  difficulty: float(),
  effort: float()
}

loc_metrics()

@type loc_metrics() :: %{
  physical: non_neg_integer(),
  logical: non_neg_integer(),
  comments: non_neg_integer(),
  blank: non_neg_integer()
}

per_function_metrics()

@type per_function_metrics() :: %{
  name: String.t(),
  cyclomatic: non_neg_integer(),
  cognitive: non_neg_integer(),
  max_nesting: non_neg_integer(),
  statements: non_neg_integer(),
  variables: non_neg_integer()
}

t()

@type t() :: %Metastatic.Analysis.Complexity.Result{
  cognitive: non_neg_integer(),
  cyclomatic: non_neg_integer(),
  function_metrics: function_metrics(),
  halstead: halstead_metrics(),
  loc: loc_metrics(),
  max_nesting: non_neg_integer(),
  per_function: [per_function_metrics()],
  summary: String.t(),
  warnings: [String.t()]
}

Functions

add_warning(result, warning)

@spec add_warning(t(), String.t()) :: t()

Adds a warning to the result.

Examples

iex> result = Metastatic.Analysis.Complexity.Result.new(%{
...>   cyclomatic: 5,
...>   cognitive: 7,
...>   max_nesting: 2,
...>   halstead: %{},
...>   loc: %{},
...>   function_metrics: %{}
...> })
iex> result = Metastatic.Analysis.Complexity.Result.add_warning(result, "High complexity detected")
iex> result.warnings
["High complexity detected"]

apply_thresholds(result, thresholds \\ %{})

@spec apply_thresholds(t(), map()) :: t()

Applies thresholds and generates warnings.

Thresholds

  • :cyclomatic_warning - Default: 10
  • :cyclomatic_error - Default: 20
  • :cognitive_warning - Default: 15
  • :cognitive_error - Default: 30
  • :nesting_warning - Default: 3
  • :nesting_error - Default: 5
  • :loc_warning - Default: 50 (logical lines)
  • :loc_error - Default: 100 (logical lines)

Examples

iex> result = Metastatic.Analysis.Complexity.Result.new(%{
...>   cyclomatic: 12,
...>   cognitive: 18,
...>   max_nesting: 2,
...>   halstead: %{},
...>   loc: %{logical: 45},
...>   function_metrics: %{}
...> })
iex> result = Metastatic.Analysis.Complexity.Result.apply_thresholds(result, %{})
iex> length(result.warnings)
2
iex> Enum.any?(result.warnings, &String.contains?(&1, "Cyclomatic"))
true
iex> Enum.any?(result.warnings, &String.contains?(&1, "Cognitive"))
true

merge(results)

@spec merge([t()]) :: t()

Merges multiple complexity results.

Uses maximum values for metrics (worst case).

Examples

iex> r1 = Metastatic.Analysis.Complexity.Result.new(%{
...>   cyclomatic: 5,
...>   cognitive: 7,
...>   max_nesting: 2,
...>   halstead: %{volume: 100.0},
...>   loc: %{logical: 20},
...>   function_metrics: %{statement_count: 20}
...> })
iex> r2 = Metastatic.Analysis.Complexity.Result.new(%{
...>   cyclomatic: 8,
...>   cognitive: 10,
...>   max_nesting: 3,
...>   halstead: %{volume: 150.0},
...>   loc: %{logical: 30},
...>   function_metrics: %{statement_count: 30}
...> })
iex> result = Metastatic.Analysis.Complexity.Result.merge([r1, r2])
iex> result.cyclomatic
8
iex> result.cognitive
10
iex> result.max_nesting
3

new(metrics)

@spec new(map()) :: t()

Creates a new complexity result from metrics map.

Examples

iex> Metastatic.Analysis.Complexity.Result.new(%{
...>   cyclomatic: 5,
...>   cognitive: 7,
...>   max_nesting: 2,
...>   halstead: %{volume: 100.0, difficulty: 5.0, effort: 500.0},
...>   loc: %{logical: 20, physical: 30},
...>   function_metrics: %{statement_count: 20}
...> })
%Metastatic.Analysis.Complexity.Result{
  cyclomatic: 5,
  cognitive: 7,
  max_nesting: 2,
  halstead: %{volume: 100.0, difficulty: 5.0, effort: 500.0},
  loc: %{logical: 20, physical: 30},
  function_metrics: %{statement_count: 20},
  warnings: [],
  summary: "Code has low complexity"
}