GtBridge.Analysis.Walker (gt_bridge v0.19.2)

Copy Markdown View Source

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

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

call_entry()

@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

alias_map(directives)

@spec alias_map([Macro.t()]) :: %{required(String.t()) => String.t()}

I fold alias directives (as AST statements) into a map from the short name to the fully qualified module string.

collect_calls(ast, context_module \\ nil)

@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.

import_map(directives)

@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.

resolve_call_aliases(calls, aliases)

@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}.

resolve_import_targets(calls, imports)

@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.