Skip to main content

MagellanBridge

Struct MagellanBridge 

Source
pub struct MagellanBridge { /* private fields */ }
Expand description

Bridge to Magellan’s inter-procedural graph algorithms

Wraps CodeGraph to provide access to call graph algorithms including:

  • Reachability analysis (forward/reverse)
  • Dead code detection
  • Cycle detection (mutual recursion)
  • Program slicing
  • Path enumeration

§Example

use mirage_analyzer::analysis::MagellanBridge;

// Open existing Magellan database
let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find all functions reachable from main
let reachable = bridge.reachable_symbols("main")?;
println!("Found {} reachable functions", reachable.len());

// Find dead code unreachable from entry points
let dead = bridge.graph().dead_symbols("main")?;
println!("Found {} dead symbols", dead.len());

Implementations§

Source§

impl MagellanBridge

Source

pub fn open(db_path: &str) -> Result<Self>

Open a Magellan database for inter-procedural analysis

§Arguments
  • db_path - Path to the Magellan database file (typically codemcp/mirage.db)
§Returns

A MagellanBridge instance ready for analysis

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;
Source

pub fn graph(&self) -> &CodeGraph

Get a reference to the underlying Magellan CodeGraph

Provides direct access to all Magellan algorithms for advanced use cases.

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Access full CodeGraph API
let cycles = bridge.graph().detect_cycles()?;
Source

pub fn reachable_symbols(&self, symbol_id: &str) -> Result<Vec<SymbolInfo>>

Find all symbols reachable from a given symbol (forward reachability)

Computes the transitive closure of the call graph starting from the specified symbol. This is useful for:

  • Impact analysis (what does changing this symbol affect?)
  • Test coverage (what code does this test exercise?)
  • Dependency tracing
§Arguments
  • symbol_id - Stable symbol ID (32-char BLAKE3 hash) or FQN
§Returns

Vector of SymbolInfo for reachable symbols, sorted deterministically

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find all functions called from main (directly or indirectly)
let reachable = bridge.reachable_symbols("main")?;
for symbol in reachable {
    println!("  - {}", symbol.fqn.as_deref().unwrap_or("?"));
}
Source

pub fn reverse_reachable_symbols( &self, symbol_id: &str, ) -> Result<Vec<SymbolInfo>>

Find all symbols that can reach a given symbol (reverse reachability)

Computes the reverse transitive closure of the call graph. Returns all symbols from which the specified symbol can be reached (i.e., all callers). This is useful for:

  • Bug isolation (what code affects this symbol?)
  • Refactoring safety (what needs to be updated?)
  • Root cause analysis
§Arguments
  • symbol_id - Stable symbol ID (32-char BLAKE3 hash) or FQN
§Returns

Vector of SymbolInfo for symbols that can reach the target

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find all functions that call 'helper_function'
let callers = bridge.reverse_reachable_symbols("helper_function")?;
println!("{} functions call this", callers.len());
Source

pub fn dead_symbols(&self, entry_symbol_id: &str) -> Result<Vec<DeadSymbol>>

Find dead code unreachable from an entry point symbol

Identifies all symbols in the call graph that cannot be reached from the specified entry point (e.g., main, test_main).

§Limitations
  • Only considers the call graph
  • Symbols called via reflection, function pointers, or dynamic dispatch may be incorrectly flagged
  • Test functions and platform-specific code may appear as dead code
§Arguments
  • entry_symbol_id - Stable symbol ID of the entry point (e.g., main function)
§Returns

Vector of DeadSymbol for unreachable symbols

§Example
use mirage_analyzer::analysis::MagellanBridge;
use mirage_analyzer::cli::DeadSymbolJson;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find all functions unreachable from main
let dead = bridge.dead_symbols("main")?;
for dead_symbol in &dead {
    println!("Dead: {} ({})",
        dead_symbol.symbol.fqn.as_deref().unwrap_or("?"),
        dead_symbol.reason);
}

// Convert to JSON-serializable format
let json_symbols: Vec<DeadSymbolJson> = dead.iter().map(|d| d.into()).collect();
Source

pub fn detect_cycles(&self) -> Result<CycleReport>

Detect cycles in the call graph using SCC decomposition

Finds all strongly connected components (SCCs) with more than one member, which indicate cycles or mutual recursion in the call graph.

§Returns

CycleReport containing all detected cycles

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

let report = bridge.detect_cycles()?;
println!("Found {} cycles", report.total_count);
for cycle in &report.cycles {
    println!("Cycle with {} members:", cycle.members.len());
    for member in &cycle.members {
        println!("  - {}", member.fqn.as_deref().unwrap_or("?"));
    }
}
Source

pub fn backward_slice(&self, symbol_id: &str) -> Result<SliceWrapper>

Compute a backward program slice (what affects this symbol)

Returns all symbols that can affect the target symbol through the call graph. This is useful for bug isolation.

§Note

Current implementation uses call-graph reachability as a fallback. Full CFG-based program slicing will be available in future versions.

§Arguments
  • symbol_id - Stable symbol ID or FQN to slice from
§Returns

SliceResult containing the slice and statistics

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find what affects 'helper_function'
let slice_result = bridge.backward_slice("helper_function")?;
println!("{} symbols affect this function", slice_result.symbol_count);
Source

pub fn forward_slice(&self, symbol_id: &str) -> Result<SliceWrapper>

Compute a forward program slice (what this symbol affects)

Returns all symbols that the target symbol can affect through the call graph. This is useful for refactoring safety.

§Note

Current implementation uses call-graph reachability as a fallback. Full CFG-based program slicing will be available in future versions.

§Arguments
  • symbol_id - Stable symbol ID or FQN to slice from
§Returns

SliceWrapper containing the slice and statistics

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find what 'main_function' affects
let slice_result = bridge.forward_slice("main_function")?;
println!("{} symbols are affected by this function", slice_result.symbol_count);
Source

pub fn enumerate_paths( &self, start_symbol_id: &str, end_symbol_id: Option<&str>, max_depth: usize, max_paths: usize, ) -> Result<PathEnumerationResult>

Enumerate execution paths from a starting symbol

Finds all execution paths from start_symbol_id to end_symbol_id (if provided) or all paths starting from start_symbol_id (if end_symbol_id is None).

Path enumeration uses bounded DFS to prevent infinite traversal in cyclic graphs.

§Arguments
  • start_symbol_id - Starting symbol ID or FQN
  • end_symbol_id - Optional ending symbol ID or FQN
  • max_depth - Maximum path depth (default: 100)
  • max_paths - Maximum number of paths to return (default: 1000)
§Returns

PathEnumerationResult with all discovered paths and statistics

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

// Find all paths from main to any leaf function
let result = bridge.enumerate_paths("main", None, 50, 100)?;

println!("Found {} paths", result.total_enumerated);
println!("Average length: {:.2}", result.statistics.avg_length);
Source

pub fn enumerate_paths_json( &self, start_symbol_id: &str, end_symbol_id: Option<&str>, max_depth: usize, max_paths: usize, ) -> Result<PathEnumerationJson>

Enumerate paths and return JSON-serializable result

Convenience method that wraps PathEnumerationResult in a JSON-serializable format for CLI output.

§Arguments
  • start_symbol_id - Starting symbol ID or FQN
  • end_symbol_id - Optional ending symbol ID or FQN
  • max_depth - Maximum path depth (default: 100)
  • max_paths - Maximum number of paths to return (default: 1000)
§Returns

JSON-serializable path enumeration result

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;
let result = bridge.enumerate_paths_json("main", None, 50, 100)?;
println!("Found {} paths", result.total_enumerated);
Source

pub fn condense_call_graph(&self) -> Result<CondensationResult>

Condense the call graph by collapsing SCCs into supernodes

Creates a condensation DAG by collapsing each strongly connected component into a single “supernode”. The resulting graph is always acyclic.

§Use Cases
  • Topological Sorting: Condensation graph is a DAG
  • Mutual Recursion Detection: Large supernodes indicate tight coupling
  • Impact Analysis: Changing one symbol affects its entire SCC
  • Inter-procedural Dominance: Functions in root supernodes dominate downstream functions
§Returns

CondensationResult with the condensed DAG and symbol-to-supernode mapping

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;

let condensed = bridge.condense_call_graph()?;

println!("Condensed to {} supernodes", condensed.graph.supernodes.len());
println!("Condensed graph has {} edges", condensed.graph.edges.len());
Source

pub fn condense_call_graph_json(&self) -> Result<CondensationJson>

Condense call graph and return JSON-serializable result

Convenience method that wraps CondensationResult in a JSON-serializable format for CLI output.

§Returns

CondensationJson with condensed DAG summary and supernode details

§Example
use mirage_analyzer::analysis::MagellanBridge;

let bridge = MagellanBridge::open("codemcp/mirage.db")?;
let condensed = bridge.condense_call_graph_json()?;
println!("Condensed to {} supernodes", condensed.supernode_count);
println!("Largest SCC has {} functions", condensed.largest_scc_size);

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more