GtBridge.Analysis (gt_bridge v0.17.2)

Copy Markdown View Source

I provide static analysis data for GT visualization.

I use :xref to extract module-level call graphs from compiled BEAM files and Code.fetch_docs/1 for documentation coverage. I return raw data — GT builds the views.

Sibling modules cover related subsystems split out from this one: GtBridge.HotReload (hot_reload + compile dep edges), GtBridge.DepGraph (app dep trees + root_apps), GtBridge.Mnesia (table introspection), GtBridge.Supervision (process tree), and GtBridge.Eval.Preamble (editor session import-loading).

Summary

Functions

I return all function definitions with complete line ranges.

I return all module names across all loaded applications, sorted.

I return per-module doc coverage with function-level detail for an app.

I parse Elixir source and return uniquely resolvable remote call sites.

I return the modules that mod calls.

I return the modules that mod calls within app.

I return the modules within app that call mod.

I return example dependency data for a module that uses ExExample.

I return exported functions for a module (works for both Elixir and Erlang).

I am true when mod defines a function (or macro-generated export) named name. Used by GT-side C-n to decide whether an unqualified reference should be searched in mod (true) or fall back to cross-module implementors search (false).

I return the source for a function or type in mod matching name/arity. Used by the inline |> expander, which attaches both to function calls and to type references in @spec / typedstruct field types. Returns nil when no entry matches.

I return all call sites of mod.name/arity across loaded applications.

I parse source and return the AST function entries (the same shape all_functions/1 returns minus the runtime-export merging, which needs the module to be loaded). Works on disk bytes alone, so safe to call before / after a failed compile.

I return all modules that define a function with the given name and optional arity. Includes def, defp, and macro-generated functions.

I return mod's alias declarations as a list of [short_name, full_name] pairs.

I return per-module metadata for an application.

I return module-level call edges for an application.

I extract the top-level defmodule X.Y name from source. Returns the dotted module string, or nil when the source doesn't define one or doesn't parse.

I check whether each name in names (dotted Elixir module name strings, e.g. "GtBridge.Eval") is a currently-loaded module, and return a %{name => boolean()} map.

I resolve an alias name using a context module's alias declarations.

I return application names matching a substring query.

I return exported functions matching a query within an app.

I return module names matching a substring query, limited to max results.

I return documentation coverage grouped by application.

I return system info for the Overview view.

I return aggregate stats across all loaded applications.

Types

edge()

@type edge() :: {module(), module()}

Functions

all_functions(mod)

@spec all_functions(module()) :: [map()]

I return all function definitions with complete line ranges.

Each entry includes :start (extended back to include @doc/@spec), :end_line, :name, :arity, :kind, :sig, and :source (the source text for that function including annotations).

AST entries are merged with runtime exports from __info__(:functions) so macro-generated functions (e.g. defview, defstruct field accessors, etc.) are visible. Runtime-only entries get default start: 0, end_line: 0, kind: :def, and a placeholder source.

all_module_names()

@spec all_module_names() :: [String.t()]

I return all module names across all loaded applications, sorted.

app_doc_coverage(app)

@spec app_doc_coverage(atom()) :: [map()]

I return per-module doc coverage with function-level detail for an app.

Each entry has :module, :has_mod_doc, and :functions (list of %{name: String.t(), has_doc: boolean()}).

call_sites(source, context_module \\ nil)

@spec call_sites(String.t(), module() | nil) :: [map()]

I parse Elixir source and return uniquely resolvable remote call sites.

Each result has :target_module, :function, :arity, :line, and :column. Only fully qualified and alias-resolved remote calls are returned.

callees(mod)

@spec callees(module()) :: [module()]

I return the modules that mod calls.

callees(mod, app)

@spec callees(module(), atom()) :: [module()]

I return the modules that mod calls within app.

callers(mod, app)

@spec callers(module(), atom()) :: [module()]

I return the modules within app that call mod.

example_deps(mod)

@spec example_deps(module()) :: [{String.t(), [String.t()]}]

I return example dependency data for a module that uses ExExample.

exported_functions(mod)

@spec exported_functions(module()) :: [map()]

I return exported functions for a module (works for both Elixir and Erlang).

function_in_module?(mod, name)

@spec function_in_module?(module(), String.t() | atom()) :: boolean()

I am true when mod defines a function (or macro-generated export) named name. Used by GT-side C-n to decide whether an unqualified reference should be searched in mod (true) or fall back to cross-module implementors search (false).

function_or_type_source(mod, name, arity)

@spec function_or_type_source(module(), String.t(), non_neg_integer()) ::
  String.t() | nil

I return the source for a function or type in mod matching name/arity. Used by the inline |> expander, which attaches both to function calls and to type references in @spec / typedstruct field types. Returns nil when no entry matches.

function_references(mod, name, arity \\ nil)

@spec function_references(module() | nil, atom(), non_neg_integer() | nil) :: [map()]

I return all call sites of mod.name/arity across loaded applications.

Each result has :module (calling module), :function (calling function), and :arity.

When mod is nil I match callers of name/arity regardless of target module — used by GT-side C-n when the call is a runtime variable (builder.text(...), &1.inserted_at) or an unqualified Kernel/imported function and we can't statically know the target.

functions_in_source(source)

@spec functions_in_source(String.t()) :: [map()]

I parse source and return the AST function entries (the same shape all_functions/1 returns minus the runtime-export merging, which needs the module to be loaded). Works on disk bytes alone, so safe to call before / after a failed compile.

implementors(name, arity \\ nil)

@spec implementors(atom(), non_neg_integer() | nil) :: [map()]

I return all modules that define a function with the given name and optional arity. Includes def, defp, and macro-generated functions.

module_aliases(mod)

@spec module_aliases(module()) :: [[String.t()]]

I return mod's alias declarations as a list of [short_name, full_name] pairs.

GT-side wrench detection in inline function editors (the |> expander, the Meta browser's Functions tab) shows only a function body — the surrounding alias lines aren't visible in source, so bare references like ColumnedList look unresolved even when the enclosing module aliases them. The styler calls me to merge the module's aliases into its local map before classifying.

I return a list (rather than a map) so the Smalltalk side can iterate via asList without needing attributeAt: per name — Maps come back as opaque proxies on the GT side.

module_details(app)

@spec module_details(atom()) :: [map()]

I return per-module metadata for an application.

module_graph(app)

@spec module_graph(atom()) :: [edge()]

I return module-level call edges for an application.

Each edge {from, to} means from contains a call to a function in to. Self-edges are excluded. Only modules whose BEAM files are on the code path are analyzed.

module_in_source(source)

@spec module_in_source(String.t()) :: String.t() | nil

I extract the top-level defmodule X.Y name from source. Returns the dotted module string, or nil when the source doesn't define one or doesn't parse.

modules_loaded?(names)

@spec modules_loaded?([String.t()]) :: %{required(String.t()) => boolean()}

I check whether each name in names (dotted Elixir module name strings, e.g. "GtBridge.Eval") is a currently-loaded module, and return a %{name => boolean()} map.

Backed by the Analysis.LoadedModules ETS-backed set, which is populated initially from :application.get_key/2 and maintained additively by EventBroker %ModuleEvent{} events — so each lookup is O(1) and stays fresh without recompute.

Used by GT-side BeamModuleResolution: the styler walks source locally with the SmaCC ElixirParser, finds module-name candidates, batches the unknowns, and asks me once per source change for their resolution status. After warm-up the GT cache holds answers for every name in the user's workspace and bridge calls go to zero.

resolve_alias(context_module, alias_name)

@spec resolve_alias(module(), String.t()) :: String.t()

I resolve an alias name using a context module's alias declarations.

search_apps(query, max \\ 30)

@spec search_apps(String.t(), pos_integer()) :: [String.t()]

I return application names matching a substring query.

search_functions(app, query, max \\ 30)

@spec search_functions(atom(), String.t(), pos_integer()) :: [map()]

I return exported functions matching a query within an app.

search_modules(query, max \\ 30)

@spec search_modules(String.t(), pos_integer()) :: [String.t()]

I return module names matching a substring query, limited to max results.

system_doc_coverage()

@spec system_doc_coverage() :: [map()]

I return documentation coverage grouped by application.

Each entry has :app (string name) and :modules (list of %{name: String.t(), has_doc: boolean()}). Used by the GT-side doc coverage heatmap.

system_info()

@spec system_info() :: map()

I return system info for the Overview view.

system_stats()

@spec system_stats() :: map()

I return aggregate stats across all loaded applications.

Returns a map with :apps, :modules, :functions, :with_docs, and :with_source counts.