Optimize Find References while preserving alias and workspace refresh behavior#116
Merged
AJenbo merged 2 commits intoMay 10, 2026
Merged
Conversation
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (65.02%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #116 +/- ##
==========================================
- Coverage 86.83% 86.71% -0.13%
==========================================
Files 170 170
Lines 108353 108396 +43
==========================================
- Hits 94091 93995 -96
- Misses 14262 14401 +139 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
eb73bf4 to
78cbe01
Compare
78cbe01 to
1c0c1ca
Compare
Collaborator
|
Nice work, my original intent was to have a byte scanner filter the files for candidates and only parse what could have a match, but this seems to work well enough that that isn't needed and at the same time be an over all boost the the function. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Improves project-wide Find References in two ways: it now avoids reading most
files from disk by filtering on pre-built span metadata before touching content,
and it discovers PHP files that were added to the workspace after the editor
started. A separate fix removes a deadlock in the virtual-member (PHPDoc mixin)
resolution cache.
Changes
loading any file content, each scanner now checks whether the file's symbol
spans contain a name that could plausibly match the target. Files with no
candidate spans are skipped entirely. Applies to class, member, function,
constant, and Laravel string-key reference searches.
a span passes the pre-filter, instead of being loaded upfront for every file
in the workspace.
previous algorithm iterated every known class on each expansion step to find
subclasses. The new algorithm does a breadth-first walk of the precomputed
gti_index(the reverse-inheritance map built by Go-to-Implementation),reducing the traversal from O(depth × total_classes) to O(hierarchy_size).
ensure_workspace_indexednow re-runs the filesystem walk on every call, but only parses files not yet
in
symbol_maps. A newworkspace_indexed: AtomicBoolflag lets the code logwhether it is doing an initial scan or a cheaper refresh walk.
phpdoc.rs, the Mutex guard forthe shared mixin cache was held across an
elsebranch that attempted toacquire a thread-local cache — which could deadlock in some call paths. Fixed
by extracting the
map.get()result withArc::clonebefore releasing theguard.
resolve_class_fully_inner. Thecache.lock()call now immediately chains
.insert()rather than holding the guard across aseparate assignment.
find_class_references. Callslocations.dedup()after the sort to remove any duplicate entries that survived the unique-push
logic.
find_referencesandensure_workspace_indexednow emittracing::info!timing spans, making iteasy to measure performance from LSP logs.
benches/references.rsbenchmark suite.How It Works
Pre-filter + lazy load (class / function / member / constant references):
symbol_map.spanstarget — accounting for aliased imports (
use Foo as Bar) by resolvingthrough
file_imports.continuebefore anyUrl::parseorget_file_content_arccall.file_contentis a lazyOption<Arc<String>>thatis only populated on the first span that actually matches.
Descendant collection via
gti_index:collect_class_hierarchyseeds aHashSetwith the target FQN and itsancestors (unchanged), then does a BFS over
gti_index— aHashMap<String, Vec<String>>that maps each FQN to its direct subclasses.VecDeque; the loop terminates naturallywhen no new entries are found. The old iterative O(N) loop and the helper
methods
class_is_descendant_of/ancestor_in_setare removed.Workspace freshness:
ensure_workspace_indexedis called once perfind_referencesrequest(already behind
tokio::spawnso it does not block the LSP thread).workspace_indexedisfalse; the full disk walk runs andall new files are parsed. The flag is set to
trueafter the walk.phase2_workcontains only fileswhose URIs are absent from
symbol_maps— so only newly created files pay theparse cost.
Tests
New tests in
tests/integration/references.rs:function_references_include_aliased_import_usage— verifies thatuse function Foo\bar as baz; baz()is found when searching forFoo\bar.class_references_include_aliased_import_usage— verifies thatuse App\Models\User as Account; new Account()is found when searching forApp\Models\User.workspace_index_refreshes_after_new_file_is_added— writes a new PHP fileto disk after the initial index, then calls find references again and asserts
the newly created file appears in the results.