Skip to main content

AnalysisContext

Struct AnalysisContext 

Source
pub struct AnalysisContext {
    pub workspace_root: Arc<Path>,
    pub registry: SymbolRegistry,
    pub code_graph: CodeGraphV2,
    pub typeflow_graph: TypeFlowGraphV2,
    pub dataflow_graph: DataFlowGraphV2,
    pub detail_store: DetailStore,
    pub ast_registry: ASTRegistry,
    pub files: HashMap<WorkspaceFilePath, Arc<PureFile>>,
    pub original: HashMap<WorkspaceFilePath, String>,
    pub use_resolver: UseResolver,
    pub derive_index: DeriveIndex,
}
Expand description

Unified context containing all analysis structures.

This is the recommended way to initialize code analysis from source files. Executor receives this context and works with SymbolId-based Intent.

§Fork-on-Write Pattern

AnalysisContext supports fork-on-write for speculative execution:

let forked = ctx.fork();  // O(log n) structural sharing
// Mutations on forked don't affect original

Uses im::HashMap<FileId, Arc<PureFile>> for efficient cloning:

  • Clone is O(log n) via structural sharing
  • Modifications only copy affected nodes
  • Arc ensures PureFile is shared until modified

See docs/parallel-execution-design.md for design details.

Fields§

§workspace_root: Arc<Path>

Workspace root path (shared via Arc for efficient cloning).

§registry: SymbolRegistry

Symbol registry for path ↔ SymbolId mapping.

§code_graph: CodeGraphV2

Code graph for symbol relationships.

§typeflow_graph: TypeFlowGraphV2

Type flow graph for type relationships.

§dataflow_graph: DataFlowGraphV2

Data flow graph for variable-level flow analysis.

§detail_store: DetailStore

Cached symbol details for O(1) access.

§ast_registry: ASTRegistry

Complete AST storage for v2 mutation engine.

Stores full PureItem per symbol, replacing file-based mutation approach. Used by ASTMutationEngine for registry-only execution.

§files: HashMap<WorkspaceFilePath, Arc<PureFile>>

Source files with structural sharing for O(log n) fork. Key: WorkspaceFilePath (self-contained, no external registry needed)

§original: HashMap<WorkspaceFilePath, String>

Original source strings for diff generation.

§use_resolver: UseResolver

Use statement resolver for cross-crate symbol resolution.

§derive_index: DeriveIndex

Derive index for fast derive trait validation (O(1) lookup).

Implementations§

Source§

impl AnalysisContext

Source

pub fn from_workspace_root( path: impl AsRef<Path>, ) -> Result<AnalysisContext, ContextError>

Create context from workspace root path.

This is the recommended API for workspace-aware analysis.

Automatically discovers and loads all Rust files in the workspace, using CargoMetadataProvider for accurate crate name resolution. Also loads UUID mappings from .ryo/uuid-mapping.json if present.

§Example
use ryo_analysis::AnalysisContext;

let ctx = AnalysisContext::from_workspace_root("/path/to/project")?;
let symbol = ctx.registry.lookup(&path);
Source

pub fn from_workspace_root_parallel( path: impl AsRef<Path>, ) -> Result<AnalysisContext, ContextError>

Create context from workspace root with parallel processing.

Source

pub fn from_im_files( files: HashMap<WorkspaceFilePath, Arc<PureFile>>, ) -> AnalysisContext

Create a minimal context from WorkspaceFilePath-keyed files.

This is useful for speculative execution where you want to work with a snapshot of files without full re-analysis.

Note: This creates a partial context with empty symbol registry and code graph. Suitable for mutation execution but not for symbol-based queries.

§Panics

Panics if files is empty (cannot infer workspace_root).

Source

pub fn registry(&self) -> &SymbolRegistry

Get the registry.

Source

pub fn registry_mut(&mut self) -> &mut SymbolRegistry

Get mutable registry.

Source

pub fn code_graph(&self) -> &CodeGraphV2

Get the code graph.

Source

pub fn code_graph_mut(&mut self) -> &mut CodeGraphV2

Get mutable code graph.

Source

pub fn typeflow_graph(&self) -> &TypeFlowGraphV2

Get the TypeFlow graph.

Source

pub fn workspace_root(&self) -> &Path

Get the workspace root path.

Source

pub fn file(&self, path: &WorkspaceFilePath) -> Option<&PureFile>

Get a file by path.

Source

pub fn file_mut(&mut self, path: &WorkspaceFilePath) -> Option<&mut PureFile>

Get mutable file by path (copy-on-write).

Uses Arc::make_mut for copy-on-write semantics:

  • If Arc is uniquely owned, returns mutable reference directly
  • If Arc is shared, clones the PureFile first
Source

pub fn files(&self) -> &HashMap<WorkspaceFilePath, Arc<PureFile>>

Get all files.

Source

pub fn files_mut(&mut self) -> &mut HashMap<WorkspaceFilePath, Arc<PureFile>>

Get mutable files map.

Source

pub fn original(&self, path: &WorkspaceFilePath) -> Option<&String>

Get original source for a file (for diff generation).

Source

pub fn file_count(&self) -> usize

Get file count.

Source

pub fn is_empty(&self) -> bool

Check if context is empty.

Source

pub fn detail_store(&self) -> &DetailStore

Get the detail store.

Source

pub fn detail_store_mut(&mut self) -> &mut DetailStore

Get mutable detail store.

Source

pub fn commit_changes(&mut self, updates: &RegistryUpdateBatch)

Commit changes at Tick boundary.

Applies registry updates and incrementally updates CodeGraphV2 indices. This is O(k) where k is the number of updates, not O(n) for full rebuild.

§Arguments
  • updates - Registry updates collected during this Tick
§Performance
OperationBefore (rebuild_indices)After (incremental)
10 updates, 10k symbolsO(10k)O(10)
100 updates, 10k symbolsO(10k)O(100)
Source

pub fn rebuild_edges_for_files(&mut self, file_paths: &[WorkspaceFilePath])

Rebuild edges for symbols in the specified files.

This is used for incremental updates after mutation:

  1. Clear outgoing edges for all symbols in the files
  2. Rebuild edges from the updated AST
§Performance

O(k * m) where k is the number of files and m is symbols per file. Much faster than full rebuild for small changes.

Source

pub fn rebuild_edges_for_symbols(&mut self, affected_ids: &[SymbolId])

Rebuild code_graph edges for the given symbol IDs (Phase 2: Symbol-based).

This method rebuilds edges directly from ASTRegistry without file I/O:

  1. Clear outgoing edges for affected symbols
  2. Get AST from ASTRegistry for each symbol
  3. Rebuild edges from the AST
§Performance

O(S) where S is the number of affected symbols. Much faster than file-based updates for targeted changes.

Source

pub fn get_symbols_in_files( &self, file_paths: &[WorkspaceFilePath], ) -> Vec<SymbolId>

Get all symbols defined in the specified files.

Uses registry.span() to determine which file each symbol belongs to.

§Returns

Vector of SymbolIds for symbols defined in the given files.

Source

pub fn rebuild_after_mutation(&mut self, modified_files: &[WorkspaceFilePath])

Rebuild all analysis graphs after mutation execution.

Converts file paths to symbol IDs and delegates to the Symbol-based rebuild path. All graphs are rebuilt from ASTRegistry (no file I/O).

Note: ast_registry and files are already updated by execute_v2.

Source

pub fn rebuild_after_mutation_by_symbols(&mut self, affected_ids: &[SymbolId])

Rebuild analysis graphs for the given affected symbol IDs.

This is the Symbol-based update path (Phase 2) that rebuilds all graphs directly from ASTRegistry, avoiding file reconstruction overhead.

All graphs are now built from ASTRegistry (no file I/O):

  1. code_graph: Incremental edge rebuild for affected symbols
  2. typeflow_graph: Full rebuild from ASTRegistry
  3. dataflow_graph: Incremental rebuild for affected symbols
  4. detail_store: Incremental rebuild for affected symbols
§Performance
  • code_graph: O(S) where S is affected symbols
  • typeflow_graph: O(N) where N is total symbols (full rebuild, but no file I/O)
  • dataflow_graph: O(S) incremental
  • detail_store: O(S) incremental
Source

pub fn fork(&self) -> ExecutionContext<'_>

Create an ExecutionContext for parallel Mutation execution.

Registry and Graph are shared as read-only references. Files use O(log n) structural sharing via im::HashMap.

§Design

During parallel Mutation execution:

  • Registry: Read-only, shared across all Mutations
  • Graph: Read-only, shared across all Mutations
  • Files: O(log n) clone via structural sharing, copy-on-write
  • Changes to Registry are collected as RegistryUpdate deltas
§Performance

Clone is O(log n) due to im::HashMap structural sharing. Modifications use copy-on-write via Arc::make_mut.

§Example
let ctx = AnalysisContext::from_path_files(files, "my_crate");
let mut exec_ctx = ctx.fork();  // O(log n) clone

// Modify files in exec_ctx - original is unchanged
exec_ctx.file_mut(&path).unwrap().modify(...);  // Copy-on-write

// Registry is read-only
let symbol = exec_ctx.registry.lookup(&path);
Source

pub fn fork_rebuild(&self) -> AnalysisContext

Create a new AnalysisContext with files cloned.

Registry, graph, and detail store are rebuilt from the cloned files. Use this when you need a completely independent context with mutable Registry access.

§Note

This is more expensive than fork() as it rebuilds all indices. Prefer fork() for parallel Mutation execution.

§Panics

Panics if the current context has zero files (cannot infer crate_name during rebuild) or if any file fails source generation during rebuild. Either situation indicates a corrupted internal state that should not occur in normal use.

Source

pub fn fork_clone(&self) -> AnalysisContext

Create an owned clone of AnalysisContext without rebuilding.

This is much faster than fork_rebuild() because it clones the existing graph structures directly instead of rebuilding from files.

§Performance
  • Files: O(log n) structural sharing via im::HashMap
  • All other fields: Direct Clone (no rebuild)

Expected: < 1ms vs ~100ms for fork_rebuild()

§Use Case

Use this for precheck scenarios where you need a mutable owned context but don’t need to rebuild graphs from scratch.

Source

pub fn symbol_count(&self) -> usize

Get the number of registered symbols.

Source

pub fn snapshot_symbols(&self, symbols: &[SymbolId]) -> ContextSnapshot

Take a snapshot of specified symbols before mutation.

This enables efficient speculative execution by only saving the symbols that will be modified, rather than cloning the entire context.

§Usage
let snapshot = ctx.snapshot_symbols(&affected_ids);
// ... apply mutation ...
ctx.rollback(snapshot, &affected_ids);
Source

pub fn rollback(&mut self, snapshot: ContextSnapshot, affected_ids: &[SymbolId])

Rollback to a previous snapshot.

Restores AST items and rebuilds analysis graphs for affected symbols. This is more efficient than fork_clone when processing many mutations sequentially on the same context.

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> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
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