Ragex.Analysis.DeadCode
(Ragex v0.11.0)
View Source
Dead code detection for identifying unused functions and code.
Provides two complementary approaches:
Interprocedural Analysis (Graph-based)
Analyzes the knowledge graph to find:
- Unused public functions (exported but never called externally)
- Unused private functions (never called within module)
- Functions with low confidence of being dead (potential entry points, callbacks)
Intraprocedural Analysis (AST-based via Metastatic)
Analyzes individual files for:
- Unreachable code after early returns
- Constant conditionals with unreachable branches
- Other dead code patterns within function bodies
Provides confidence scores to help distinguish between truly dead code and potential entry points (callbacks, GenServer handlers, etc.).
Summary
Functions
Analyzes a file for intraprocedural dead code patterns.
Analyzes multiple files for intraprocedural dead code patterns.
Calculates a confidence score for dead code detection.
Finds all unused functions (both public and private).
Finds all dead code in the knowledge graph.
Finds unused functions within a specific module.
Finds unused public (exported) functions.
Finds unused modules (modules with no external references).
Finds unused private functions.
Generates removal suggestions based on dead code analysis.
Types
@type confidence() :: float()
@type dead_function() :: %{ function: function_ref(), confidence: confidence(), reason: String.t(), visibility: :public | :private, module: module(), metadata: map() }
@type function_ref() :: {:function, module(), atom(), non_neg_integer()} | %{type: :function, module: module(), name: atom(), arity: non_neg_integer()}
@type suggestion() :: %{ type: :remove_function | :review_function | :potential_callback, confidence: confidence(), target: function_ref(), description: String.t(), metadata: map() }
Functions
@spec analyze_file( String.t(), keyword() ) :: {:ok, Metastatic.Analysis.DeadCode.Result.t()} | {:error, term()}
Analyzes a file for intraprocedural dead code patterns.
Uses Metastatic's AST-level analysis to detect:
- Unreachable code after early returns
- Constant conditionals (if true/false) with unreachable branches
- Other dead code patterns within function bodies
This is complementary to the interprocedural analysis (find_unused_exports/1, etc.)
which detects unused functions based on the call graph.
Parameters
file_path- Path to the file to analyzeopts- Keyword list of options:min_confidence- Minimum confidence level (:high,:medium,:low, default::low)
Returns
{:ok, result}- Metastatic.Analysis.DeadCode.Result struct{:error, reason}- Error if analysis fails
Examples
iex> {:ok, result} = analyze_file("lib/my_module.ex")
iex> result.has_dead_code?
true
@spec analyze_files( [String.t()], keyword() ) :: {:ok, %{required(String.t()) => any()}} | {:error, term()}
Analyzes multiple files for intraprocedural dead code patterns.
Batch version of analyze_file/2 that processes multiple files in parallel.
Parameters
file_paths- List of file paths to analyzeopts- Keyword list of options (same asanalyze_file/2)
Returns
{:ok, results_map}- Map of file_path => result{:error, reason}- Error if analysis fails
Examples
iex> {:ok, results} = analyze_files(["lib/a.ex", "lib/b.ex"])
iex> is_map(results)
true
@spec confidence_score(function_ref(), map()) :: confidence()
Calculates a confidence score for dead code detection.
Takes into account:
- Function name patterns (callbacks, entry points)
- Visibility (public vs private)
- Number of callers
- Module characteristics (test, Mix task, etc.)
Returns
- Float between 0.0 (definitely not dead) and 1.0 (definitely dead)
@spec find_all_unused(keyword()) :: {:ok, [dead_function()]} | {:error, term()}
Finds all unused functions (both public and private).
Combines results from find_unused_exports/1 and find_unused_private/1.
Parameters
opts: Keyword list of options (same as individual functions)
Returns
{:ok, [dead_function]}- Combined list of unused functions
Examples
{:ok, all_dead} = find_all_unused(min_confidence: 0.6)
Finds all dead code in the knowledge graph.
Convenience function combining unused exports and private functions.
Examples
{:ok, dead_functions} = DeadCode.find_dead_code()
@spec find_in_module( module(), keyword() ) :: {:ok, [dead_function()]} | {:error, term()}
Finds unused functions within a specific module.
Analyzes all functions (public and private) in the specified module to identify potentially dead code. This is useful for focused refactoring of a single module.
Parameters
module: Module name atomopts: Keyword list of options:min_confidence- Minimum confidence threshold (default: 0.5):include_callbacks- Include potential callbacks (default: false):visibility- Filter by:public,:private, or:all(default::all)
Returns
{:ok, [dead_function]}- List of unused functions in the module{:error, reason}- Error if module not found or analysis fails
Examples
# Find all dead code in MyModule
{:ok, dead} = find_in_module(MyModule)
# Find only dead private functions with high confidence
{:ok, dead_private} = find_in_module(MyModule, visibility: :private, min_confidence: 0.8)
# Include potential callbacks
{:ok, all} = find_in_module(MyModule, include_callbacks: true, min_confidence: 0.3)
@spec find_unused_exports(keyword()) :: {:ok, [dead_function()]} | {:error, term()}
Finds unused public (exported) functions.
Public functions with no callers are potentially dead code, but may be:
- Entry points (main, CLI commands)
- Callbacks (GenServer, Supervisor, Phoenix)
- API functions not yet used
- Test helpers
Returns functions with confidence scores indicating likelihood of being dead.
Parameters
opts: Keyword list of options:min_confidence- Minimum confidence threshold (0.0-1.0, default: 0.5):exclude_tests- Exclude test modules (default: true):include_callbacks- Include potential callbacks (default: false):ai_refine- Use AI to refine confidence scores (default: from config)
Returns
{:ok, [dead_function]}- List of potentially unused functions with confidence scores{:error, reason}- Error if analysis fails
Examples
# Find unused exports with high confidence
{:ok, dead} = find_unused_exports(min_confidence: 0.8)
# Include potential callbacks
{:ok, all} = find_unused_exports(include_callbacks: true, min_confidence: 0.3)
Finds unused modules (modules with no external references).
Delegates to DependencyGraph.find_unused/1 for consistency.
Parameters
opts: Keyword list of options (passed to DependencyGraph)
Returns
{:ok, [module_name]}- List of unused modules{:error, reason}- Error if analysis fails
@spec find_unused_private(keyword()) :: {:ok, [dead_function()]} | {:error, term()}
Finds unused private functions.
Private functions with no callers within their module are likely dead code. Higher confidence than public functions since private functions are not part of the API.
Parameters
opts: Keyword list of options:min_confidence- Minimum confidence threshold (default: 0.7):exclude_tests- Exclude test modules (default: true):ai_refine- Use AI to refine confidence scores (default: from config)
Returns
{:ok, [dead_function]}- List of unused private functions{:error, reason}- Error if analysis fails
Examples
{:ok, dead} = find_unused_private()
@spec removal_suggestions(keyword()) :: {:ok, [suggestion()]} | {:error, term()}
Generates removal suggestions based on dead code analysis.
Categorizes dead code into:
- Safe to remove (high confidence)
- Review recommended (medium confidence)
- Potential callbacks (low confidence, may be entry points)
Parameters
opts: Keyword list of options:min_confidence- Minimum confidence for suggestions (default: 0.5):group_by_module- Group suggestions by module (default: true)
Returns
{:ok, [suggestion]}- List of removal suggestions{:error, reason}- Error if analysis fails
Examples
{:ok, suggestions} = removal_suggestions()
# Process suggestions...