I walk Elixir AST and extract call sites.
I am the AST-walking subsystem of GtBridge.Analysis: given a
parsed quoted form I collect remote and local call entries, and
given source text I extract the alias map needed to resolve them
to fully qualified module names.
Public API
collect_calls/2: walk an AST and return raw call entriesalias_map/1: fold alias directive statements into a lookup mapimport_map/1: fold import directive statements into a lookup mapresolve_call_aliases/2: rewrite call entries through an alias mapresolve_import_targets/2: rewrite local entries through an import map
Summary
Functions
I fold alias directives (as AST statements) into a map from the
short name to the fully qualified module string.
I walk ast and return raw call entries.
I fold import directives into a map from {function_name, arity}
to the full module string. only: lists narrow the set; every other
form imports the module's full export list.
I rewrite each call entry's :target_module through aliases and
return the list sorted by {line, column}.
I rewrite local entries (call.local == true) whose
{function, arity} is in imports, setting :target_module to
the imported module and clearing :local. Remote entries pass
through unchanged.
Types
@type call_entry() :: %{ target_module: String.t(), function: String.t(), arity: non_neg_integer(), line: pos_integer() | nil, column: pos_integer() | nil, local: boolean() }
Functions
I fold alias directives (as AST statements) into a map from the
short name to the fully qualified module string.
@spec collect_calls(Macro.t(), module() | nil) :: [call_entry()]
I walk ast and return raw call entries.
When context_module is non-nil, local calls inside that module
are emitted with :target_module set to the module's inspect form;
otherwise only remote calls are emitted.
@spec import_map([Macro.t()]) :: %{ required({String.t(), non_neg_integer()}) => String.t() }
I fold import directives into a map from {function_name, arity}
to the full module string. only: lists narrow the set; every other
form imports the module's full export list.
@spec resolve_call_aliases([call_entry()], %{required(String.t()) => String.t()}) :: [ call_entry() ]
I rewrite each call entry's :target_module through aliases and
return the list sorted by {line, column}.
@spec resolve_import_targets([call_entry()], %{ required({String.t(), non_neg_integer()}) => String.t() }) :: [call_entry()]
I rewrite local entries (call.local == true) whose
{function, arity} is in imports, setting :target_module to
the imported module and clearing :local. Remote entries pass
through unchanged.