Metastatic.Analysis.Complexity (Metastatic v0.10.4)

View Source

Code complexity analysis at the MetaAST level.

Analyzes code to compute comprehensive complexity metrics that work uniformly across all supported languages by operating on the unified MetaAST representation.

Metrics

  • Cyclomatic Complexity - McCabe metric, decision points + 1
  • Cognitive Complexity - Structural complexity with nesting penalties
  • Nesting Depth - Maximum nesting level
  • Halstead Metrics - Volume, difficulty, effort
  • Lines of Code - Physical, logical, comments
  • Function Metrics - Statements, returns, variables

Usage

alias Metastatic.{Document, Analysis.Complexity}

# Analyze a document
ast = {:conditional, [], [
  {:variable, [], "x"},
  {:literal, [subtype: :integer], 1},
  {:literal, [subtype: :integer], 2}]}
doc = Document.new(ast, :python)
{:ok, result} = Complexity.analyze(doc)

result.cyclomatic       # => 2
result.cognitive        # => 1
result.max_nesting      # => 1
result.warnings         # => []
result.summary          # => "Code has low complexity"

Options

Examples

# Simple arithmetic: complexity = 1
iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:literal, [subtype: :integer], 1}, {:literal, [subtype: :integer], 2}]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(doc)
iex> result.cyclomatic
1

# Conditional: complexity = 2
iex> ast = {:conditional, [], [
...>   {:variable, [], "x"},
...>   {:literal, [subtype: :integer], 1},
...>   {:literal, [subtype: :integer], 2}]}
iex> doc = Metastatic.Document.new(ast, :elixir)
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(doc)
iex> result.cyclomatic
2

Summary

Functions

analyze(language_or_doc, source_or_ast_or_opts \\ [], opts \\ [])

@spec analyze(Metastatic.language(), term(), keyword()) ::
  {:ok, map()} | {:error, term()}

Analyzes a document for complexity.

Accepts either:

Returns {:ok, result} where result is a Metastatic.Analysis.Complexity.Result struct.

Options

  • :thresholds - Threshold map for warnings (default thresholds used if not provided)
  • :metrics - List of metrics to calculate (default: :all)

Examples

# Using Document
iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(doc)
iex> result.cyclomatic
1
iex> result.cognitive
0

# Using {language, native_ast} tuple
iex> python_ast = %{"_type" => "Constant", "value" => 42}
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(:python, python_ast, [])
iex> result.cyclomatic
1

analyze!(language_or_doc, source_or_ast_or_opts \\ [], opts \\ [])

@spec analyze!(Metastatic.language(), term(), keyword()) :: map()

Analyzes a document for complexity.

Accepts either:

Returns {:ok, result} where result is a Metastatic.Analysis.Complexity.Result struct.

Options

  • :thresholds - Threshold map for warnings (default thresholds used if not provided)
  • :metrics - List of metrics to calculate (default: :all)

Examples

# Using Document
iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(doc)
iex> result.cyclomatic
1
iex> result.cognitive
0

# Using {language, native_ast} tuple
iex> python_ast = %{"_type" => "Constant", "value" => 42}
iex> {:ok, result} = Metastatic.Analysis.Complexity.analyze(:python, python_ast, [])
iex> result.cyclomatic
1

Unlike not-banged version, this one either returns a result or raises