Dead code
dead_code
Dead code detection via AST caller analysis.
Enumerates all symbols in a package and flags those with zero callers
after applying smart exemptions (dunders, tests, decorators, protocols,
overrides, __all__ exports).
Example::
>>> from axm_ast.core.analyzer import analyze_package
>>> from axm_ast.core.dead_code import find_dead_code, format_dead_code
>>> pkg = analyze_package(Path("src/mylib"))
>>> dead = find_dead_code(pkg)
>>> print(format_dead_code(dead))
DeadSymbol
dataclass
An unreferenced symbol detected by dead code analysis.
Source code in packages/axm-ast/src/axm_ast/core/dead_code.py
__post_init__()
Keep the coordination signal derived from documentation metadata.
find_dead_code(pkg, *, include_tests=False)
Detect unreferenced symbols across a package.
Algorithm
- Enumerate all functions and classes across all modules.
- For each symbol, check if it has any callers or references.
- Apply exemptions (dunders, tests, exports, decorators, entry points, etc.).
- For methods, check override chains.
- Also scan a sibling
tests/directory for callers. - Detect lazy imports inside function bodies.
.. warning:: Reference matching is by name only. Liveness is decided
against a single global set[str] of referenced names, so a dead
symbol that shares its name with a live, distinct symbol elsewhere is
wrongly considered referenced and omitted from the result (a false
negative). This is an intrinsic tree-sitter limitation — no type or
scope inference is performed — and mirrors the homonym ambiguity
documented on :func:~axm_ast.core.callers.find_callers. Symbols
reported as dead are therefore high-confidence; truly-dead symbols that
are homonymous with a live one may be silently missed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkg
|
PackageInfo
|
Analyzed package from |
required |
include_tests
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
list[DeadSymbol]
|
List of dead symbols, sorted by module path then line number. |
Source code in packages/axm-ast/src/axm_ast/core/dead_code.py
| Python | |
|---|---|
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | |
find_namespace_modules(pkg)
Find modules that are imported as namespace objects somewhere in pkg.
A module is considered a "namespace import" when it appears as:
- from pkg import mod where mod resolves to a module file
- import pkg.mod (bare module import)
Public symbols in such modules may be accessed via attribute access
(mod.func()) and would not show up in a direct caller search.
Source code in packages/axm-ast/src/axm_ast/core/dead_code.py
format_dead_code(results)
Format dead code results as human-readable grouped output.
Groups results by module path, then lists each dead symbol with its line number and kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
results
|
list[DeadSymbol]
|
List of dead symbols from |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted string suitable for terminal display. |