Metastatic.Analysis.Smells (Metastatic v0.10.4)

View Source

Code smell detection at the MetaAST level.

Identifies design and maintainability issues that indicate poor code quality. Works across all supported languages by operating on the unified MetaAST representation and leveraging existing complexity metrics.

Detected Smells

  • Long function - Too many statements (threshold: 50)
  • Deep nesting - Excessive nesting depth (threshold: 4)
  • Magic numbers - Unexplained numeric literals in expressions
  • Complex conditionals - Deeply nested boolean operations
  • Long parameter list - Too many parameters (threshold: 5)

Usage

alias Metastatic.{Document, Analysis.Smells}

# Analyze for code smells
ast = {:block, [], (for i <- 1..100, do: {:literal, [subtype: :integer], i})}
doc = Document.new(ast, :python)
{:ok, result} = Smells.analyze(doc)

result.has_smells?    # => true
result.total_smells   # => 1
result.smells         # => [%{type: :long_function, ...}]

Examples

# No code smells - using common constants 0, 1, -1
iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:literal, [subtype: :integer], 1}, {:literal, [subtype: :integer], 0}]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Smells.analyze(doc)
iex> result.has_smells?
false

# Magic number detected
iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:variable, [], "x"}, {:literal, [subtype: :integer], 42}]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Smells.analyze(doc)
iex> result.has_smells?
true
iex> [smell | _] = result.smells
iex> smell.type
:magic_number

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 code smells.

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

Options

  • :thresholds - Map of threshold overrides (see default thresholds)
  • :detect - List of smell types to detect (default: all)

Examples

iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :elixir)
iex> {:ok, result} = Metastatic.Analysis.Smells.analyze(doc)
iex> result.has_smells?
false

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

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

Analyzes a document for code smells.

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

Options

  • :thresholds - Map of threshold overrides (see default thresholds)
  • :detect - List of smell types to detect (default: all)

Examples

iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :elixir)
iex> {:ok, result} = Metastatic.Analysis.Smells.analyze(doc)
iex> result.has_smells?
false

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