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
@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
@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?
falseUnlike not-banged version, this one either returns a result or raises