pub struct DocumentStore { /* private fields */ }Implementations§
Source§impl DocumentStore
impl DocumentStore
pub fn new() -> Self
Sourcepub fn interactive_read_guard(&self) -> InteractiveReadGuard<'_>
pub fn interactive_read_guard(&self) -> InteractiveReadGuard<'_>
Mark an interactive read (a request the user is waiting on) as in
flight for the guard’s lifetime. Background bulk writers poll
Self::yield_to_interactive_reads between files and pause while any
guard is live, giving the read a write-free window to complete.
Sourcepub fn settled_write_rev_guard(&self) -> (InteractiveReadGuard<'_>, u64)
pub fn settled_write_rev_guard(&self) -> (InteractiveReadGuard<'_>, u64)
Take an interactive-read guard, wait (bounded ~50 ms) for in-flight background writes to go quiet, and return the settled write revision.
For user-facing sweeps that abort when Self::write_rev advances:
snapshotting the revision this way ensures only genuine user edits —
not the background scan the guard just paused — void the sweep.
Sleeps; call from a blocking thread only.
Sourcepub fn yield_to_interactive_reads(&self)
pub fn yield_to_interactive_reads(&self)
Pause the calling (background-writer) thread while interactive reads are in flight, up to 500 ms per call. Bounded so a wedged reader can only slow the scan, never stop it; callers invoke this per file, so sustained interactive traffic keeps yielding at each boundary.
Sourcepub fn begin_reanalyze(&self) -> IndexCancel
pub fn begin_reanalyze(&self) -> IndexCancel
Install a fresh cancel token for a dependent-diagnostics sweep,
cancelling whichever sweep was previously in flight. Pass the returned
token to reanalyze_dependents_cancellable; when a newer edit calls
this again the old token flips and that older sweep stops at its next
file boundary instead of racing this one to publish stale diagnostics.
Sourcepub fn begin_warm_sweep(&self) -> IndexCancel
pub fn begin_warm_sweep(&self) -> IndexCancel
Install a fresh cancel token for an analysis warm sweep, cancelling any
sweep previously in flight. Mirrors Self::begin_reanalyze but on a
separate slot: edit-triggered diagnostic sweeps and background warming
must not cancel each other.
Sourcepub fn warm_analysis_sweep(&self, priority: &[Uri], cancel: &IndexCancel)
pub fn warm_analysis_sweep(&self, priority: &[Uri], cancel: &IndexCancel)
Drive every workspace file through mir’s memoized analyze_file query
so later reference/rename requests are memo hits instead of cold
analyses (~20 ms per file on real code — a few hundred candidate files
makes an interactive request take seconds).
priority files (and the files declaring the classes they reference —
the user’s working set) are warmed first, so requests against open
files go warm within the sweep’s first seconds even on workspaces
where the full sweep takes much longer.
Background-priority: processes files in small chunks, yielding to
interactive reads at each boundary, and stops at the next boundary once
cancel flips. Re-running after edits is cheap — unaffected files
revalidate via salsa without re-analysis. Blocking; call from
spawn_blocking.
Sourcepub fn warm_references_phase(
&self,
untrusted: Vec<Arc<str>>,
priority: &[Uri],
ambient: bool,
progress: Option<UnboundedSender<(u32, u32)>>,
)
pub fn warm_references_phase( &self, untrusted: Vec<Arc<str>>, priority: &[Uri], ambient: bool, progress: Option<UnboundedSender<(u32, u32)>>, )
The reference-warm phase: one deduped reanalysis queue holding the
untrusted replay subset first (files whose disk-cache postings
carry an unresolved name, so the first live query to touch one pays a
full synchronous analyze_file), then — when ambient — the project
sweep set with priority files at its front, so a file in both is
analyzed once rather than twice. Flushes the analysis cache and
counts as a completed warm sweep on full completion.
Every caller runs this in the background after publishing
indexReady: it reanalyzes the whole project set, which on a real
workspace costs seconds, and no query needs it to have finished (a
cold file is analyzed on demand). Background-priority: yields to
interactive reads at chunk boundaries, stops at the next boundary
once a newer sweep takes the slot. Blocking; call from
spawn_blocking.
Sourcepub fn flush_analysis_cache(&self)
pub fn flush_analysis_cache(&self)
Persist mir’s staged analysis-cache entries (reference postings) to disk. No-op when nothing changed since the last flush.
Sourcepub fn warm_sweeps_completed(&self) -> u64
pub fn warm_sweeps_completed(&self) -> u64
Warm sweeps that ran to completion. See $/php-lsp/debugStats.
pub fn warm_start_replays_completed(&self) -> u64
Sourcepub fn warm_start_untrusted_reanalyzed(&self) -> u64
pub fn warm_start_untrusted_reanalyzed(&self) -> u64
See the warm_start_untrusted_reanalyzed field’s docs.
Sourcepub fn vendor_warm_sweeps_completed(&self) -> u64
pub fn vendor_warm_sweeps_completed(&self) -> u64
See the vendor_warm_sweeps_completed field’s docs.
Sourcepub fn mark_index_ready(&self)
pub fn mark_index_ready(&self)
Mark the workspace reference index as fully built. Called by the scan
when its final phase completes (alongside $/php-lsp/indexReady).
Sourcepub fn is_index_ready(&self) -> bool
pub fn is_index_ready(&self) -> bool
Whether the workspace reference index has finished building.
Sourcepub fn write_rev(&self) -> u64
pub fn write_rev(&self) -> u64
Snapshot of the write-revision counter. Long-running reads should capture this before starting and pass it to cancellable operations; if the counter advances, those operations abort and return empty rather than looping indefinitely against a newly-invalidated database.
Sourcepub fn set_session_cache_dir(&self, dir: PathBuf) -> bool
pub fn set_session_cache_dir(&self, dir: PathBuf) -> bool
Set the directory used to persist stub-parse and analysis results across
server restarts. Subsequent calls are silently ignored (OnceLock
semantics).
If a session was already built — an early request (e.g. the editor’s
restored-buffer didOpen racing initialized) builds one on demand —
it was pinned in-memory-only: nothing it computes is ever flushed, and
the next launch replays nothing, silently re-paying the whole cold
cost every session. Drop it so the next analysis_session() rebuilds
with the cache attached.
Returns true when a session was dropped — the caller must then
re-mirror every currently open buffer (see drop_session_scoped_state):
the workspace scan won’t do it, since it explicitly skips files that
are already open.
Sourcepub fn set_user_stub_dirs(&self, dirs: Vec<PathBuf>) -> bool
pub fn set_user_stub_dirs(&self, dirs: Vec<PathBuf>) -> bool
Set the user-supplied stub directories (initializationOptions.stubDirs).
Subsequent calls are silently ignored (OnceLock semantics).
Same early-session race as Self::set_session_cache_dir: if a
session was already built without these directories, drop it so the
next analysis_session() rebuilds with with_user_stubs attached.
Returns true when a session was dropped — same re-mirroring
obligation as set_session_cache_dir.
Sourcepub fn set_autoload_uris(&self, uris: Vec<Uri>)
pub fn set_autoload_uris(&self, uris: Vec<Uri>)
Register URIs discovered from composer.json autoload.files entries.
These PHP files define global helper functions (e.g. tap() in Laravel)
that are not class-resolvable via PSR-4. Clears analysis_cache so the
next per-file analysis pre-ingests them into the AnalysisSession before
running mir’s FileAnalyzer.
Sourcepub fn analysis_session(&self, php_version: PhpVersion) -> Arc<AnalysisSession> ⓘ
pub fn analysis_session(&self, php_version: PhpVersion) -> Arc<AnalysisSession> ⓘ
Get or build the AnalysisSession for the given PHP version. Rebuilds
when the version changes (e.g. user flipped config). The session owns
the shared salsa db and AnalysisCache; lazy-loads vendor files via the
shared PSR-4 map. Built-in stubs are not pre-loaded: mir’s
prepare_ast_for_analysis ingests the stubs each analyzed file
references, and [crate::types::stub_members] faults in single stub
files for builtin member/hover lookups. User stub directories (see
Self::set_user_stub_dirs) are configured on the builder here; mir’s
ingest_file — called for every mirrored document — is what actually
registers them (and the built-in stubs) as SourceFile inputs.
Sourcepub fn current_analysis_session(&self) -> Arc<AnalysisSession> ⓘ
pub fn current_analysis_session(&self) -> Arc<AnalysisSession> ⓘ
Get-or-build the AnalysisSession for the current workspace PHP
version — a single lock acquisition on the common (already-built)
path. Replaces self.analysis_session(self.workspace_php_version()),
which took two separate locks per call.
Sourcepub fn workspace_php_version(&self) -> PhpVersion
pub fn workspace_php_version(&self) -> PhpVersion
Current PHP version tracked by the workspace input.
Sourcepub fn class_subtype_urls(&self, class_fqn: &str) -> Vec<Uri>
pub fn class_subtype_urls(&self, class_fqn: &str) -> Vec<Uri>
File URIs of all direct and transitive subclasses of class_fqn,
resolved via mir’s inheritance graph. Returns an empty vec when the mir
session hasn’t ingested the class yet (cold start, excluded paths).
Used by goto_implementation and subtypes to scope their lookups to
the correct files, fixing aliased extends and FQN-qualified forms that
the mention-index-narrowed raw-name fallback (subtypes_of_from_workspace)
misses.
Sourcepub fn psr4_arc(&self) -> Arc<ArcSwap<Psr4Map>> ⓘ
pub fn psr4_arc(&self) -> Arc<ArcSwap<Psr4Map>> ⓘ
Return the Arc<ArcSwap<Psr4Map>> so callers can share it.
Backend clones this arc at construction time so writes
(e.g. loading composer.json on initialized) are immediately visible
to PSR-4 resolution during analysis without extra plumbing.
Sourcepub fn mirror_text(&self, uri: &Uri, text: &str)
pub fn mirror_text(&self, uri: &Uri, text: &str)
Mirror a file’s current text into the salsa layer. Creates the
FileText input on first sight, otherwise updates text on the
existing input (bumping the salsa revision so downstream queries
invalidate).
Sourcepub fn mirror_text_arc(&self, uri: &Uri, text_arc: Arc<str>)
pub fn mirror_text_arc(&self, uri: &Uri, text_arc: Arc<str>)
Like [mirror_text] but takes an already-allocated Arc<str>.
Callers that already hold an Arc<str> (e.g. ingest_from_doc reusing
ParsedDoc::source_arc()) use this to avoid a second allocation and to
ensure text_cache and parsed_cache hold the same Arc pointer —
enabling Arc::ptr_eq validation in get_parsed_cached.
Sourcepub fn seed_cached_index(&self, uri: &Uri, index: Arc<FileIndex>) -> bool
pub fn seed_cached_index(&self, uri: &Uri, index: Arc<FileIndex>) -> bool
Phase K2: pre-seed a FileIndex loaded from the on-disk cache onto
the FileText input for uri. The next file_index call for that
file returns the cached index directly, skipping parse + extract.
Must be called before any file_index(db, sf) call for this file —
otherwise salsa has already memoized the fresh-parse result and setting
cached_index now would only bump the revision without using the cache.
In practice the workspace-scan path seeds immediately after mirror_text
and before any query runs.
Returns false when uri was not mirrored (caller should mirror
first); returns true on success.
Sourcepub fn evict_token_cache(&self, uri: &Uri)
pub fn evict_token_cache(&self, uri: &Uri)
Evict the semantic-tokens cache for uri. Called by Backend when a
file is closed; diff-based tokens computed against the old revision
are no longer meaningful.
Sourcepub fn ingest(&self, uri: Uri, text: &str)
pub fn ingest(&self, uri: Uri, text: &str)
Register a file in the salsa layer without marking it open.
Salsa’s parsed_doc query parses lazily on first read; diagnostics
are populated by did_open when the editor actually opens the file.
Sourcepub fn ingest_from_doc(&self, uri: Uri, doc: &ParsedDoc)
pub fn ingest_from_doc(&self, uri: Uri, doc: &ParsedDoc)
Index a file using an already-parsed ParsedDoc, avoiding a second parse.
Prefer this over [ingest] when the caller already has a ParsedDoc (e.g.
after running DefinitionCollector during workspace scan). Reuses the
Arc<str> already owned by doc so that text_cache and SourceFile::text
share the same pointer — enabling the Arc::ptr_eq fast path in
get_parsed_cached on the first subsequent salsa query, without an extra
Arc::from(source) allocation.
pub fn remove(&self, uri: &Uri)
Sourcepub fn get_doc_salsa(&self, uri: &Uri) -> Option<Arc<ParsedDoc>>
pub fn get_doc_salsa(&self, uri: &Uri) -> Option<Arc<ParsedDoc>>
Salsa-backed parsed document.
Salsa-backed parsed document for any mirrored file (open or
background-indexed). Returns None only when the file is not known
to the store. Callers that want “only if open” should gate on
Backend::open_files at the call site (see Backend::get_doc).
Sourcepub fn get_index_salsa(&self, uri: &Uri) -> Option<Arc<FileIndex>>
pub fn get_index_salsa(&self, uri: &Uri) -> Option<Arc<FileIndex>>
Salsa-backed compact symbol index.
Sourcepub fn get_symbol_map_salsa(&self, uri: &Uri) -> Option<Arc<SymbolMap>>
pub fn get_symbol_map_salsa(&self, uri: &Uri) -> Option<Arc<SymbolMap>>
Salsa-backed pre-computed symbol map (name → Vec
Sourcepub fn other_symbol_maps(
&self,
uri: &Uri,
open_urls: &[Uri],
) -> Vec<(Uri, Arc<SymbolMap>)>
pub fn other_symbol_maps( &self, uri: &Uri, open_urls: &[Uri], ) -> Vec<(Uri, Arc<SymbolMap>)>
Pre-computed symbol maps for every entry in open_urls except uri.
Sourcepub fn get_doc_snapshot_or_stale(&self, uri: &Uri) -> Option<Arc<ParsedDoc>>
pub fn get_doc_snapshot_or_stale(&self, uri: &Uri) -> Option<Arc<ParsedDoc>>
Parsed doc for a cosmetic, cursor-triggered read (e.g. documentHighlight)
that must stay responsive while the user types. Unlike Self::get_doc_salsa
it never spins on the Cancelled retry loop: it tries the lock-free
parsed_cache, then a bounded snapshot parse, and if a concurrent write
stream keeps cancelling it, returns the last-good cached ParsedDoc
(possibly one edit stale — invisible for a highlight, unlike a hang).
None only when the file has never been parsed.
Sourcepub fn sync_workspace_files(&self)
pub fn sync_workspace_files(&self)
Refresh workspace.files to mirror the current active file set.
Skips all work when workspace_files_dirty is false (the common
case after the workspace scan completes — file-set changes are rare).
Sourcepub fn mark_workspace_files_dirty(&self)
pub fn mark_workspace_files_dirty(&self)
Mark the workspace file set as dirty so the next sync_workspace_files
call re-runs the collect/sort/compare path, and invalidate the
workspace_file_paths() cache. Exposed for benchmarks that need to
measure the dirty-path cost in isolation.
Sourcepub fn set_php_version(&self, version: PhpVersion) -> bool
pub fn set_php_version(&self, version: PhpVersion) -> bool
Update the PHP version tracked by the workspace. Salsa will invalidate
all semantic_issues queries so diagnostics are re-evaluated.
Skips the setter when the version hasn’t changed to avoid spurious
query invalidation. Returns true when the version actually changed —
callers that scan the workspace at runtime (not just at init, before
any file is mirrored) must re-scan every root when this is true,
since drop_session_scoped_state below empties lsp_ws_files and
nothing else repopulates it.
Sourcepub fn indexed_references(
&self,
symbol: &Name,
files: &[Arc<str>],
include_declaration: bool,
cancel_rev: Option<u64>,
) -> Vec<(Arc<str>, u32, u32, u32)>
pub fn indexed_references( &self, symbol: &Name, files: &[Arc<str>], include_declaration: bool, cancel_rev: Option<u64>, ) -> Vec<(Arc<str>, u32, u32, u32)>
Inverted-index reference lookup scoped to files (the text-pre-filtered
candidate set): a posting-list read for committed-fresh files plus an
on-demand analyze+commit for stale/uncommitted candidates, so warm
requests are O(results) instead of O(candidates).
Returns LSP-style 0-based line/column.
cancel_rev: when Some(rev), the loop throws salsa::Cancelled and
returns empty if a concurrent write advances the write_revision counter
past rev — preventing unbounded retries against a newly-invalidated db.
Pass None to retain the original indefinite-retry behaviour (fast ops
like single-file reads where a stale result is not a concern).
Sourcepub fn indexed_use_imports(
&self,
symbol: &Name,
files: &[Arc<str>],
) -> Vec<(Arc<str>, u32, u32, u32)>
pub fn indexed_use_imports( &self, symbol: &Name, files: &[Arc<str>], ) -> Vec<(Arc<str>, u32, u32, u32)>
use-import lines referencing symbol, from mir’s use: postings.
Read-only lookup with no freshness pass — run Self::indexed_references
over the same files first so uncommitted candidates are analyzed.
Returns (file_uri, line, col_start, col_end) tuples like
Self::indexed_references; the range covers the whole import item.
Sourcepub fn warm_start_indexes(&self) -> Vec<Arc<str>>
pub fn warm_start_indexes(&self) -> Vec<Arc<str>>
Replay disk-cached reference postings and subtype edges for the whole
mirrored workspace (mir’s warm_start_files) — a no-op per file
without a content-hash-matching cache entry from a previous run. Call
once after the scan mirrors texts, before the reference-warm phase,
so a returning session starts index-warm. Cheap enough to sit on the
pre-indexReady path — it replays cache entries, it does not analyze.
Returns the subset of replayed files that mir flags as untrusted —
their postings carry an unresolved name, so the first live query to
touch one pays a full synchronous analyze_file (mir’s changelog
measured ~1.3-1.5s on a real 15K-file workspace). The caller feeds
this list to the front of Self::warm_references_phase’s queue, so
the cost lands in the background warm phase instead of the user’s
first request — and shares that phase’s cancellation and
interactive-read yielding instead of racing requests on its own
detached thread.
Sourcepub fn workspace_file_paths(&self) -> Arc<Vec<Arc<str>>> ⓘ
pub fn workspace_file_paths(&self) -> Arc<Vec<Arc<str>>> ⓘ
Every active workspace file as a mir path (Arc<str> of the URI).
The candidate scope handed to mir’s queries — mir gates uncommitted
candidates on symbol-name mention internally, so this is always safe.
Cached behind an Arc (invalidated by mark_workspace_files_dirty) so
the ~15K-file walk + Arc<str> allocation per file only happens once
per workspace-file-set change, not once per caller per request.
Sourcepub fn indexed_subtype_classes(
&self,
class_fqn: &str,
include_trait_users: bool,
) -> Vec<SubtypeClassSite>
pub fn indexed_subtype_classes( &self, class_fqn: &str, include_trait_users: bool, ) -> Vec<SubtypeClassSite>
Transitive subtypes of class_fqn from mir’s maintained subtype edge
index, with declaration sites. include_trait_users also counts
use Trait; composition as a subtype edge (trait-usage lenses); leave
it off for goto-implementation semantics (extends/implements only).
Sourcepub fn indexed_method_implementations(
&self,
class_fqn: &str,
method: &str,
) -> Vec<(Arc<str>, Arc<str>, Range)>
pub fn indexed_method_implementations( &self, class_fqn: &str, method: &str, ) -> Vec<(Arc<str>, Arc<str>, Range)>
Concrete implementations of class_fqn::method across its subtypes:
(subtype fqcn, file, name range) from mir’s subtype edge index.
Sourcepub fn method_reference_scope(
&self,
owner_fqn: &str,
method: &str,
) -> Option<Vec<Uri>>
pub fn method_reference_scope( &self, owner_fqn: &str, method: &str, ) -> Option<Vec<Uri>>
The complete set of files a private method’s references can occur in,
or None when the search must stay workspace-wide.
owner_fqn is the enclosing class at the cursor; narrowing applies only
when that class directly declares method (so its MethodDef
visibility is authoritative — inherited/call-site lookups fall through to
None). A reference to Class::method is recorded only where
analyze_file resolves an expression to that key, and analyze_file is
per-source-file, so a private member — resolvable only inside the
declaring class body, which lives in one file — is fully scoped to the
declaring file at any indexing stage.
A protected member is reachable from the declaring class and its
transitive subclasses ($this->m(), parent::m(), self::/static::),
all of which live in the declaring file or a subtype file — never outside
the hierarchy in valid PHP. Its scope is therefore the declaring file plus
the transitive subtype files. The complete subtype set is only known once
the workspace reference index finishes, so this narrowing applies only
when Self::is_index_ready; before then it falls back to None (full
workspace scope) so references are never under-reported.
Classes that compose traits or mixins are excluded — those inline external resolution context, so a reference could surface in another file.
Sourcepub fn fqn_reachable_files(&self, fqns: &[Arc<str>]) -> Option<Vec<Arc<str>>>
pub fn fqn_reachable_files(&self, fqns: &[Arc<str>]) -> Option<Vec<Arc<str>>>
Files that could possibly reference any FQN in fqns, narrowed via
PHP’s own name-resolution rules rather than bare-word text mention:
- Namespace rule — the file’s namespace equals the target’s, or
is a
\-segment prefix of it:namespace Foo;reachesFoo\Bar\Bazthrough the relative-qualifiedBar\Baz. - Import rule — a
useof the target itself, an alias of it, or any namespace prefix of it (use Foo\Bar; Bar\Baz::x()), all matched on the import’s FQN so aliases come for free. - Text rule — the qualified path appears literally in the file
(
\App\Widget::classconfig arrays with nouseline, or a leading-slash-freeApp\Widgetfrom a no-namespace file, where qualified names resolve from the root). Matched ASCII-case-insensitively — PHP class names are case-insensitive.
These are the only ways PHP resolves a class-like or namespaced name, so this is exact narrowing grounded in the language’s own resolution order, not a heuristic — unlike mir’s own gate, which only sees bare short names and can’t distinguish this owner class from an unrelated class sharing its short name elsewhere in the workspace.
Callers must NOT use this for global-namespace functions/constants (unqualified calls fall back to the global namespace from any namespace, so no file can be excluded) or for instance members (a typed receiver can hide the class entirely).
Returns None (full workspace) when the boot scan hasn’t finished —
same conservative discipline as the Protected branch above — so
references are never under-reported at cold start.
Sourcepub fn get_workspace_index_salsa(&self) -> Arc<WorkspaceIndexData> ⓘ
pub fn get_workspace_index_salsa(&self) -> Arc<WorkspaceIndexData> ⓘ
Phase J: salsa-memoized aggregate workspace index.
Returns the shared Arc<WorkspaceIndexData> with the flat
(Uri, Arc<FileIndex>) list plus classes_by_lowercase_name (for
completion’s prefix search). Used by workspace_symbols,
prepare_type_hierarchy, supertypes_of, subtypes_of, and
find_implementations so they don’t each rebuild the aggregate per
request. Invalidates automatically when any file’s file_index
changes. Class/declaration name lookups no longer come from this
aggregate — see Self::resolve_class_ref/class_candidates/
declaration_candidate_files, which query mir’s mention index instead.
Sourcepub fn parse_count(&self) -> u64
pub fn parse_count(&self) -> u64
Total number of real ParsedDoc parses served so far (cache misses).
Surfaced via $/php-lsp/debugStats so tests can assert the references
read path doesn’t parse the whole workspace.
Sourcepub fn ref_index_lock_count(&self) -> u64
pub fn ref_index_lock_count(&self) -> u64
Times mir’s RefIndex was locked on the current session. Reads are
per-key posting lookups and edits commit one file’s postings, so this
grows by a small bounded amount per operation — never per candidate.
Surfaced via $/php-lsp/debugStats for the stress-test guard.
Sourcepub fn mir_ref_query_cache_hits(&self) -> u64
pub fn mir_ref_query_cache_hits(&self) -> u64
Diagnostic: mir’s indexed_references_to memoization hits, surfaced
via $/php-lsp/debugStats so a host-side query can be attributed to
the right layer when diagnosing latency.
Sourcepub fn mir_subtype_query_cache_hits(&self) -> u64
pub fn mir_subtype_query_cache_hits(&self) -> u64
Diagnostic: mir’s indexed_subtype_classes memoization hits.
Sourcepub fn workspace_symbol_index_ready(&self) -> bool
pub fn workspace_symbol_index_ready(&self) -> bool
Whether mir’s workspace symbol index singleton is populated (warm-start
seed or first sweep). See DebugStats::workspace_symbol_index_ready.
Sourcepub fn workspace_index_walks(&self) -> u64
pub fn workspace_index_walks(&self) -> u64
Executions of mir’s tracked O(all-files) symbol-index walk.
Sourcepub fn workspace_file_count(&self) -> u64
pub fn workspace_file_count(&self) -> u64
Number of files mirrored into the salsa workspace (open + background
indexed). Surfaced via $/php-lsp/debugStats as a denominator for the
per-file cache sizes below — e.g. text_cache_len tracking this 1:1
means it’s carrying the workspace’s working set, not leaking.
Sourcepub fn token_cache_len(&self) -> u64
pub fn token_cache_len(&self) -> u64
Entries in the semantic-tokens delta cache. Evicted per-file on
did_close; a value that keeps climbing past the number of files
ever opened in the editor means that eviction isn’t firing.
Sourcepub fn text_cache_len(&self) -> u64
pub fn text_cache_len(&self) -> u64
Entries in the mirrored-source-text cache. Expected to track
Self::workspace_file_count — it shares its Arc<str> with
salsa’s own SourceFile::text, so this is a pointer per file, not a
second copy of the workspace’s source.
Sourcepub fn parsed_cache_len(&self) -> u64
pub fn parsed_cache_len(&self) -> u64
Entries in the read-through ParsedDoc cache. Bounded by
PARSED_CACHE_CAP via LRU shedding.
Sourcepub fn analysis_cache_len(&self) -> u64
pub fn analysis_cache_len(&self) -> u64
Entries in the per-file FileAnalysis cache. Bounded by
ANALYSIS_CACHE_CAP via LRU shedding.
Sourcepub fn owned_program_cache_len(&self) -> u64
pub fn owned_program_cache_len(&self) -> u64
Entries in the owned-Program cache. Bounded by
OWNED_PROGRAM_CACHE_CAP via LRU shedding.
Sourcepub fn decl_fingerprints_len(&self) -> u64
pub fn decl_fingerprints_len(&self) -> u64
Entries in the declaration-fingerprint cache — one per file that
declares something, used to detect cross-file declaration changes.
Expected to track Self::workspace_file_count, not grow past it.
Sourcepub fn vendor_index_cache_len(&self) -> u64
pub fn vendor_index_cache_len(&self) -> u64
Entries in the lazily-loaded vendor FileIndex cache, populated by
PSR-4 “go to definition” navigation into vendor/. Unlike the other
per-file caches above, this one has no LRU cap today — a session with
heavy navigation through a large dependency tree will keep growing
this for the life of the process.
Sourcepub fn source_text(&self, uri: &Uri) -> Option<Arc<str>>
pub fn source_text(&self, uri: &Uri) -> Option<Arc<str>>
Return the raw source text for uri if it has been mirrored into the
salsa workspace. Used by the references handler to pre-filter session
results by checking whether a file mentions the owning class name.
Sourcepub fn store_token_cache(
&self,
uri: &Uri,
result_id: String,
tokens: Arc<Vec<SemanticToken>>,
)
pub fn store_token_cache( &self, uri: &Uri, result_id: String, tokens: Arc<Vec<SemanticToken>>, )
Cache the semantic tokens computed for a delta response.
result_id is an opaque string (a hash of the token data) returned to the client.
Sourcepub fn get_token_cache(
&self,
uri: &Uri,
result_id: &str,
) -> Option<Arc<Vec<SemanticToken>>>
pub fn get_token_cache( &self, uri: &Uri, result_id: &str, ) -> Option<Arc<Vec<SemanticToken>>>
Return the cached tokens if result_id matches the stored one.
Sourcepub fn get_semantic_issues_salsa(&self, uri: &Uri) -> Option<Arc<[Issue]>>
pub fn get_semantic_issues_salsa(&self, uri: &Uri) -> Option<Arc<[Issue]>>
Raw semantic issues for a file, computed via mir’s session-based
FileAnalyzer. The session lazy-loads dependencies via PSR-4 so the
LSP no longer needs to mirror vendor up-front. Callers apply their
own DiagnosticsConfig filter via
crate::semantic_diagnostics::issues_to_diagnostics.
Sourcepub fn mir_name_at(&self, uri: &Uri, offset: u32) -> Option<Name>
pub fn mir_name_at(&self, uri: &Uri, offset: u32) -> Option<Name>
Resolve only the codebase symbol identity at offset in uri.
mir 0.72.1 provides this targeted navigation path so reference queries
do not need php-lsp’s retained whole-file mir_analyzer::FileAnalysis
merely to call symbol_at(...).kind.to_name(). The interactive guard
pauses background writes; the retry covers a write already in flight.
Sourcepub fn cached_analysis_if_fresh(&self, uri: &Uri) -> Option<Arc<FileAnalysis>>
pub fn cached_analysis_if_fresh(&self, uri: &Uri) -> Option<Arc<FileAnalysis>>
Run (or reuse) mir’s per-file body analysis, retaining the full
mir_analyzer::FileAnalysis — issues and resolved symbols — across
requests. Diagnostics read .issues; position features call
.symbol_at(offset) for the resolved type at a cursor.
Cache hit when the entry’s captured source Arc is pointer-equal to the
file’s current doc.source_arc(). A miss recomputes and overwrites, so
the entry self-evicts on any content edit.
Cache-hit-only variant of Self::cached_analysis: returns the cached
analysis when the entry is current for the file’s text, never computes.
Lets async handlers take the warm path synchronously and reserve
spawn_blocking for the cold path (mir Pass 1 + Pass 2 can take
hundreds of ms on large files).
pub fn cached_analysis(&self, uri: &Uri) -> Option<Arc<FileAnalysis>>
Sourcepub fn note_new_file_declarations(&self, uri: &Uri)
pub fn note_new_file_declarations(&self, uri: &Uri)
Register a newly-discovered file’s declarations so a consumer that was analyzed before this file existed doesn’t keep a stale cached analysis forever.
mirror_text/ingest_from_doc alone never bump decl_version —
that only happens inside cached_analysis_cancellable’s own
first-analysis check, which runs when a file undergoes its own full
analysis. A file that is merely scanned or created as someone else’s
dependency (what a workspace scan or a didChangeWatchedFiles
CREATED/CHANGED event does) never goes through that path, so without
this call, a consumer analyzed earlier keeps returning a stale
UndefinedClass (or similar) even after the dependency shows up.
Call this after mirroring a file from one of those discovery paths —
not from every mirror_text call, which would also fire on every
keystroke edit to an already-open file and defeat the whole point of
caching sibling files’ analyses across those edits.
Sourcepub fn cached_analysis_cancellable(
&self,
uri: &Uri,
should_cancel: &(dyn Fn() -> bool + Sync),
) -> Option<Arc<FileAnalysis>>
pub fn cached_analysis_cancellable( &self, uri: &Uri, should_cancel: &(dyn Fn() -> bool + Sync), ) -> Option<Arc<FileAnalysis>>
Self::cached_analysis with an early exit: should_cancel is
polled whenever a concurrent salsa write cancels the analysis attempt.
A handler passes its write-revision staleness probe so a request made
obsolete by newer typing stops burning a blocking-pool thread instead
of retrying until the writer pauses — the editor re-requests anyway.
Sourcepub fn docs_for(&self, open_urls: &[Uri]) -> Vec<(Uri, Arc<ParsedDoc>)>
pub fn docs_for(&self, open_urls: &[Uri]) -> Vec<(Uri, Arc<ParsedDoc>)>
Returns (uri, doc) for files currently open in the editor.
Resolve open_urls (from Backend::open_urls()) to parsed docs.
Files not mirrored in the salsa layer are filtered out silently.
Sourcepub fn other_docs(
&self,
uri: &Uri,
open_urls: &[Uri],
) -> Vec<(Uri, Arc<ParsedDoc>)>
pub fn other_docs( &self, uri: &Uri, open_urls: &[Uri], ) -> Vec<(Uri, Arc<ParsedDoc>)>
Parsed docs for every entry in open_urls except uri.
Sourcepub fn with_all_indexes<R>(
&self,
f: impl FnOnce(&[(Uri, Arc<FileIndex>)]) -> R,
) -> R
pub fn with_all_indexes<R>( &self, f: impl FnOnce(&[(Uri, Arc<FileIndex>)]) -> R, ) -> R
Borrow-scoped access to the aggregate (Uri, Arc<FileIndex>) slice,
avoiding per-call cloning of the workspace-wide vector.
Sourcepub fn cache_vendor_index(&self, uri: Uri, index: Arc<FileIndex>)
pub fn cache_vendor_index(&self, uri: Uri, index: Arc<FileIndex>)
Store a lazily-loaded vendor FileIndex in the session cache.
Only call this for files that are not part of the normal workspace scan
(i.e. vendor files loaded on-demand by PSR-4 navigation).
Sourcepub fn get_vendor_index(&self, uri: &Uri) -> Option<Arc<FileIndex>>
pub fn get_vendor_index(&self, uri: &Uri) -> Option<Arc<FileIndex>>
Retrieve a previously cached vendor FileIndex.
Sourcepub fn all_docs_for_scan(&self) -> Vec<(Uri, Arc<ParsedDoc>)>
pub fn all_docs_for_scan(&self) -> Vec<(Uri, Arc<ParsedDoc>)>
Parsed documents for every mirrored file (open or background-indexed). Suitable for full-scan operations: find-references, rename, call_hierarchy, code_lens.
Sourcepub fn docs_for_scan_mentioning(
&self,
needles: &[String],
) -> Vec<(Uri, Arc<ParsedDoc>)>
pub fn docs_for_scan_mentioning( &self, needles: &[String], ) -> Vec<(Uri, Arc<ParsedDoc>)>
Like Self::all_docs_for_scan, but only parses files whose raw text
mentions at least one of needles as a whole identifier
(ASCII-case-insensitive — PHP class names are case-insensitive). Used
by callers scanning for a class/interface declaration by name (e.g.
“implement missing methods”), where the needle set is small and a miss
guarantees the file declares none of them.
Answered from mir’s persistent per-file ClassMentionIndex — the
same cache the reference/subtype gates and
Self::resolve_reachability_queries populate — so a file scanned
here answers later reference queries for free, and vice versa. Text
comes from this store’s own mirror (source_text), same as before;
class_mention_answer validates cache freshness against it, so a
file whose mirror diverges from mir’s copy is simply rescanned.
Sourcepub fn files_mentioning_short_name(
&self,
files: &[Arc<str>],
short_name: &str,
) -> Vec<Arc<str>>
pub fn files_mentioning_short_name( &self, files: &[Arc<str>], short_name: &str, ) -> Vec<Arc<str>>
Subset of files (mir paths) mentioning short_name as a whole
identifier, ASCII-case-insensitive, via mir’s shared per-file mention
cache (AnalysisSession::files_mentioning_any). A file mir doesn’t
know is omitted — callers use this as a prioritization heuristic, not
an authoritative filter.
Sourcepub fn declaration_candidate_files(
&self,
wi: &WorkspaceIndexData,
name: &str,
) -> Vec<Uri>
pub fn declaration_candidate_files( &self, wi: &WorkspaceIndexData, name: &str, ) -> Vec<Uri>
Candidate files that may declare something named name anywhere in
the workspace (function/class/method/property/constant/enum-case),
narrowed via mir’s persistent per-file mention cache instead of an
eagerly-rebuilt name → [DeclRef] map. A miss means no file’s text
contains name at all, so nothing declares it either — same
necessary-not-sufficient contract as files_mentioning_short_name;
callers must still verify the candidate actually declares name (via
its own FileIndex/AST), same as they always have. Unlike an eagerly
rebuilt map, an edit to file X only invalidates X’s own cached mention
set, not the whole workspace’s.
Sourcepub fn class_candidates_by_short_name(
&self,
wi: &WorkspaceIndexData,
short_name: &str,
) -> Vec<ClassRef>
pub fn class_candidates_by_short_name( &self, wi: &WorkspaceIndexData, short_name: &str, ) -> Vec<ClassRef>
Every class in the workspace whose own (unqualified) name is exactly
short_name, via mir’s classes_named (O(1) short-name bucket,
incrementally maintained — no per-call scan over every workspace
file, unlike the mention-index-based narrowing this used to do).
This is the explicit short-name fallback path. Prefer
Self::resolve_class_ref_by_fqn whenever the caller already has a
resolved FQN; use this only for true ambiguity handling where the
source text is still just a bare short name.
Sourcepub fn class_ref_by_fqn(
&self,
wi: &WorkspaceIndexData,
fqn: &str,
) -> Option<ClassRef>
pub fn class_ref_by_fqn( &self, wi: &WorkspaceIndexData, fqn: &str, ) -> Option<ClassRef>
O(1) resolution of a known FQN to its declaring class, via mir’s own
incrementally-maintained FQN→location index (definition_of_cached,
backed by the same singleton all_classes()/workspace_classes read
from — no rebuild-from-scratch, no per-call scan over every workspace
file). No php-lsp-side duplicate structure involved. Use this whenever
the caller already has a resolved FQN, not just a bare short name
needing disambiguation; falls back to None (never wrong, just not
fast) when mir hasn’t loaded/committed the class yet.
Sourcepub fn resolve_class_ref_by_fqn(
&self,
wi: &WorkspaceIndexData,
fqn: &str,
) -> Option<ClassRef>
pub fn resolve_class_ref_by_fqn( &self, wi: &WorkspaceIndexData, fqn: &str, ) -> Option<ClassRef>
Resolve a known FQN to its declaring class. This is the default lookup path for callers that already resolved imports/aliases or are following a semantic symbol carrying an FQN.
Sourcepub fn resolve_class_ref_by_short_name(
&self,
wi: &WorkspaceIndexData,
short_name: &str,
) -> Option<ClassRef>
pub fn resolve_class_ref_by_short_name( &self, wi: &WorkspaceIndexData, short_name: &str, ) -> Option<ClassRef>
Resolve a bare short name to the first same-named class in the workspace. This is intentionally the explicit fallback path.
Sourcepub fn resolve_class_ref_by_fqn_or_short_name_fallback(
&self,
wi: &WorkspaceIndexData,
fqn: &str,
) -> Option<ClassRef>
pub fn resolve_class_ref_by_fqn_or_short_name_fallback( &self, wi: &WorkspaceIndexData, fqn: &str, ) -> Option<ClassRef>
Resolve a known FQN, falling back to the short-name bucket only when mir’s direct FQN lookup has not loaded/committed the class yet.
Callers should use this only when they already have an FQN but still
want the previous resilience against a cold mir cache. New callers
should prefer Self::resolve_class_ref_by_fqn and reserve this for
compatibility with existing FileIndex-backed behavior.
Sourcepub fn find_declaration(
&self,
wi: &WorkspaceIndexData,
word: &str,
exclude: Option<&Uri>,
) -> Option<Location>
pub fn find_declaration( &self, wi: &WorkspaceIndexData, word: &str, exclude: Option<&Uri>, ) -> Option<Location>
O(candidates) replacement for the old decls_by_name-backed linear
scan: find a declaration named word anywhere in the workspace,
optionally excluding one file (the current document, which the
caller has already searched with accurate AST ranges), via
Self::declaration_candidate_files + the same per-file check
goto_declaration_from_index uses.
Sourcepub fn files_importing(&self, fqn: &str) -> Vec<Uri>
pub fn files_importing(&self, fqn: &str) -> Vec<Uri>
Files whose use imports include the class fqn (leading \ ignored
— PHP names are case-insensitive), from mir’s use: postings. The
candidate scope for use-line rewrites on file rename/delete: only
importers can carry such a line.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for DocumentStore
impl !RefUnwindSafe for DocumentStore
impl !UnwindSafe for DocumentStore
impl Send for DocumentStore
impl Sync for DocumentStore
impl Unpin for DocumentStore
impl UnsafeUnpin for DocumentStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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