Reach translates source code into an intermediate representation, builds control/data/call relationships, and combines them into a program dependence graph.
Control flow
Control-flow graphs show branch structure inside functions. Reach keeps function CFGs acyclic and uses block-quality checks to ensure rendered blocks cover source lines without duplicates.
Call graph
The call graph connects caller and callee functions. Reach uses it for dependency trees, impact analysis, module coupling, hotspots, and why-path explanations.
Data flow
Data-flow edges track definitions, uses, parameters, returns, and cross-function value movement. Trace commands use these edges for taint and variable workflows.
Effects
Reach classifies calls into effect categories such as pure, IO, read, write, send, receive, exception, NIF, and unknown. Effect evidence powers boundaries, smells, and refactoring candidates.
Smells
Reach detects structural code smells in two layers:
Pattern smells use ExAST's ~p sigil to match source-level AST patterns — pipe anti-patterns, collection idiom misuse, config phase mistakes. These run per-file via Sourceror zipper traversal.
Semantic smells use Reach's own IR with effects, data flow, call graph, and clone evidence — redundant computation, loop anti-patterns, dual key access, fixed-shape maps, behaviour candidates, return-contract drift.
Pattern smells are declared with a DSL:
use Reach.Smell.PatternCheck
smell ~p[Enum.reverse(_) |> hd()], :suboptimal,
"traverses twice; use List.last/1"
smell(
from(~p[Enum.drop(_, amount) |> Enum.take(_)]) |> where(not match?({:-, _, [_]}, ^amount)),
:eager_pattern,
"use Enum.slice/3"
)Semantic smells use the standard use Reach.Smell.Check behaviour with IR helpers like inside_loop?/2, callback_body/1, and statement_pairs/1.
Clone analysis
Optional clone evidence (via ExDNA) enriches semantic smell confidence. Clone families inform structural consistency checks: return-contract drift, side-effect order drift, map-contract drift, validation drift, and behaviour extraction candidates.
Plugins
Plugins extend Reach with framework-specific semantics: effect classification, trace presets, behaviour labels, visualization filtering, and graph edges. Built-in plugins auto-detect Phoenix, Ecto, Oban, Ash, GenStage, Jido, and OpenTelemetry. Language frontends (JavaScript/Gleam) are also plugin-discovered.
OTP analysis
OTP checks identify GenServer state access, GenStatem transitions, missing handlers, dead replies, supervision, process dictionary/ETS coupling, and cross-process resource sharing.