Skip to content

Commit 2e1402b

Browse files
committed
Re organize backend
1 parent d8549e0 commit 2e1402b

64 files changed

Lines changed: 2785 additions & 2665 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/todo/refactor.md

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -214,122 +214,10 @@ Each item must include:
214214

215215
# Outstanding items
216216

217-
Recommended order: 3 → 4 → 5. Tasks 4 and 5 both churn the whole crate
218-
(4 renames `Backend` fields, 5 moves the type-engine modules), so they
219-
go last to avoid re-touching code that 3 moves; do 4 before 5 so 5's
220-
module moves don't collide with 4's field renames.
221-
222-
All three remaining tasks are pure internal refactors. None gets a
223-
changelog entry unless the work uncovers and fixes a concrete
224-
user-visible bug. Run the Rust CI checks (`cargo nextest run`, `cargo
225-
clippy -- -D warnings`, `cargo clippy --tests -- -D warnings`, `cargo
226-
fmt`) after each task.
227-
228-
## 3. Move workspace init/indexing out of `server.rs` and `references/mod.rs`
229-
230-
**What to do.** `src/server.rs` (4,007 lines) ends with an
231-
`impl Backend` block of workspace initialization and indexing
232-
(~lines 2696–4007, ~1,300 lines) that has nothing to do with LSP
233-
dispatch, and `src/references/mod.rs` hosts workspace-indexing
234-
functions that have nothing to do with reference finding. Consolidate
235-
both into a new `src/indexing/` module (declare `mod indexing;` in
236-
`lib.rs`). Pure code motion via `impl Backend` blocks in the new
237-
files; approximate current line numbers given for finding things.
238-
239-
- `indexing/init.rs``init_single_project` (~2696),
240-
`init_monorepo` (~2933), `init_no_composer` (~3102).
241-
- `indexing/scan.rs``add_vendor_dir` (~3153),
242-
`rescan_composer_indexes` (~3374), `scan_autoload_files` (~3469),
243-
`scan_phar_archive` (~3686), `build_self_scan_composer` (~3776),
244-
`populate_autoload_indices` (~3877).
245-
- `indexing/preload.rs``preload_autoload_files` (~3608) and
246-
`preload_autoload_files_with_progress` (~3614) from `server.rs`,
247-
plus from `src/references/mod.rs`: `ensure_workspace_indexed`
248-
(~125), `ensure_workspace_indexed_for_request` (~137),
249-
`ensure_workspace_indexed_with_progress` (~166),
250-
`parse_files_parallel_with_progress` (~314), and
251-
`parse_paths_parallel_with_progress` (~430).
252-
- `indexing/watch.rs``apply_watched_file_changes` (~3194).
253-
254-
Two more relocations while in there:
255-
256-
- `warm_laravel_completion_cache` (`server.rs` ~2081) belongs in
257-
`src/virtual_members/laravel/`.
258-
- The pull-diagnostics resultId-cache logic embedded in the
259-
`diagnostic` (~1589) and `workspace_diagnostic` (~1651) handlers
260-
belongs in a new `src/diagnostics/pull.rs`, leaving both handlers
261-
as thin delegations like the rest of `server.rs`.
262-
263-
**Constraint.** Several of these functions spawn threads sized with
264-
`PARSE_WORKER_STACK_SIZE` (see the "Performance Anti-Patterns" §3
265-
note in `CLAUDE.md`). Move that code verbatim — do not "simplify"
266-
thread spawning or stack sizing while relocating it.
267-
268-
**Acceptance.** `cargo nextest run` passes with no test edits (except
269-
import paths); `server.rs` is reduced to protocol handlers and
270-
dispatch (~1,700 lines); behavior is unchanged.
271-
272-
**Why it matters.** Full background indexing has already shipped on
273-
top of init logic scattered across `server.rs` and
274-
`references/mod.rs`; leaving that logic unconsolidated guarantees more
275-
sprawl as the feature continues to grow.
276-
277-
---
278-
279-
## 4. Group `Backend`'s remaining fields into sub-systems
280-
281-
**What to do.** `struct Backend` in `src/lib.rs` (starts at ~line 377)
282-
still has fields that cluster into implicit sub-systems. The four
283-
external-tool fields are already grouped (`ExternalToolWorker`); this
284-
task introduces three more groups. It is a mechanical, crate-wide
285-
field rename — do it as three separate passes (one per group), running
286-
`cargo check` between passes, and run it as the **sole active agent**
287-
(no parallel sub-agents; see "Never run project-wide rewrites in
288-
parallel" in `CLAUDE.md`).
289-
290-
For each group: define the struct with a `fn new()` used by both
291-
`Backend` constructors (~lines 1096 and 1206) and include the group in
292-
the per-request clone (~line 1836); the `Arc`/`Mutex` wrappers move
293-
into the new struct unchanged (clone semantics of a `Backend` clone
294-
must not change).
295-
296-
**Group 1 — `DiagnosticState`** (define it in `src/diagnostics/`,
297-
field name e.g. `diag`): `diag_version`, `diag_notify`,
298-
`diag_pending_uris`, `diag_last_slow`, `diag_last_fast`,
299-
`diag_last_full`, `diag_result_ids`, `diag_suppressed`,
300-
`workspace_diags`, `workspace_diag_pass_started`. Drop the `diag_`
301-
prefix on the struct's fields (`self.diag_version`
302-
`self.diag.version`). Leave `supports_pull_diagnostics` with the other
303-
client-capability flags.
304-
305-
**Group 2 — `SymbolIndex`** (field name e.g. `symbols`):
306-
`uri_classes_index`, `fqn_uri_index`, `fqn_origin_index`,
307-
`fqn_class_index`, `class_not_found_cache`, `gti_index`,
308-
`method_store`, `global_functions`, `global_defines`,
309-
`uri_globals_index`, `autoload_function_index`,
310-
`autoload_function_origin_index`, `autoload_constant_index`,
311-
`autoload_constant_origin_index`, `autoload_file_paths`. Do **not**
312-
pull in the per-file parse artifacts (`symbol_maps`, `resolved_names`,
313-
`file_imports`, `file_namespaces`, `parse_errors`, `parsed_uris`,
314-
`parse_inflight`, `phar_archives`) or the `stub_*` indexes — they have
315-
a different lifecycle and are out of scope here.
316-
317-
**Group 3 — `WorkspaceEnv`** (field name e.g. `workspace` — not
318-
"WorkspaceConfig", to avoid colliding with the existing
319-
`config: Mutex<config::Config>` field, which becomes a member of this
320-
group): `workspace_root`, `psr4_mappings`, `vendor_uri_prefixes`,
321-
`vendor_dir_paths`, `vendor_package_origin_roots`, `php_version`,
322-
`config`.
323-
324-
**Acceptance.** Pure renames: `cargo nextest run` passes with only
325-
mechanical field-path updates in tests; no lock types, wrapper types,
326-
or clone semantics change.
327-
328-
**Why it matters.** Group 1 directly de-risks the scheduled D10 task;
329-
the rest makes the Backend's state graph legible and shrinks the
330-
constructors.
331-
332-
---
217+
One task remains. It is a pure internal refactor and gets no changelog
218+
entry unless the work uncovers and fixes a concrete user-visible bug. Run
219+
the Rust CI checks (`cargo nextest run`, `cargo clippy -- -D warnings`,
220+
`cargo clippy --tests -- -D warnings`, `cargo fmt`) after the task.
333221

334222
## 5. Extract the shared type engine out of `completion/`
335223

src/analyse/run.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub async fn run(options: AnalyseOptions) -> i32 {
6363
// calls are no-ops.
6464
let backend = Backend::new_headless();
6565
*backend.workspace_root().write() = Some(root.to_path_buf());
66-
*backend.config.lock() = cfg.clone();
66+
*backend.workspace.config.lock() = cfg.clone();
6767

6868
let composer_package = composer::read_composer_package(root);
6969

@@ -199,7 +199,7 @@ pub async fn run(options: AnalyseOptions) -> i32 {
199199
// read lock, then drop the lock before resolving. Resolution may
200200
// call find_or_load_class which takes write locks on uri_classes_index.
201201
let sorted_fqns = {
202-
let uri_classes_index = backend.uri_classes_index.read();
202+
let uri_classes_index = backend.symbols.uri_classes_index.read();
203203
crate::toposort::toposort_from_uri_classes_index(&uri_classes_index)
204204
};
205205
// Run on a dedicated large-stack thread: `resolve_class_fully_inner`
@@ -661,7 +661,7 @@ pub(crate) fn discover_user_files(
661661
source_dirs.sort();
662662
source_dirs.dedup();
663663

664-
let vendor_dirs: Vec<PathBuf> = backend.vendor_dir_paths.lock().clone();
664+
let vendor_dirs: Vec<PathBuf> = backend.workspace.vendor_dir_paths.lock().clone();
665665

666666
// When an explicit path filter points outside all PSR-4 source
667667
// directories (e.g. into vendor/), walk the filter path directly

src/backend/file_access.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Backend {
3636
// For namespace-qualified names the FQN is the normalized name
3737
// itself. For bare names (no backslash) the FQN equals the
3838
// short name, which is also stored in the index.
39-
if let Some(cls) = self.fqn_class_index.read().get(class_name) {
39+
if let Some(cls) = self.symbols.fqn_class_index.read().get(class_name) {
4040
return Some(Arc::clone(cls));
4141
}
4242

@@ -108,7 +108,8 @@ impl Backend {
108108

109109
/// Public helper for tests: get the uri_classes_index entry for a given URI.
110110
pub fn get_classes_for_uri(&self, uri: &str) -> Option<Vec<ClassInfo>> {
111-
self.uri_classes_index
111+
self.symbols
112+
.uri_classes_index
112113
.read()
113114
.get(uri)
114115
.map(|classes| classes.iter().map(|c| ClassInfo::clone(c)).collect())
@@ -124,6 +125,7 @@ impl Backend {
124125
/// extracting the entry for a given URI.
125126
pub(crate) fn file_context(&self, uri: &str) -> FileContext {
126127
let classes = self
128+
.symbols
127129
.uri_classes_index
128130
.read()
129131
.get(uri)
@@ -170,6 +172,7 @@ impl Backend {
170172
/// namespace block for the cursor position.
171173
pub(crate) fn file_context_at(&self, uri: &str, byte_offset: u32) -> FileContext {
172174
let classes = self
175+
.symbols
173176
.uri_classes_index
174177
.read()
175178
.get(uri)
@@ -266,7 +269,7 @@ impl Backend {
266269
// open. uri_classes_index is redundant with fqn_class_index once indexing is
267270
// complete — GTD falls back to fqn_uri_index + parse_and_cache_file
268271
// when the uri_classes_index entry is missing.
269-
self.uri_classes_index.write().remove(uri);
272+
self.symbols.uri_classes_index.write().remove(uri);
270273
self.symbol_maps.write().remove(uri);
271274
self.evict_reference_index_uri(uri);
272275
self.file_imports.write().remove(uri);

src/code_actions/change_visibility.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ impl Backend {
253253
) -> Option<u8> {
254254
// Find the enclosing ClassInfo from the uri_classes_index.
255255
let local_classes: Vec<Arc<ClassInfo>> = self
256+
.symbols
256257
.uri_classes_index
257258
.read()
258259
.get(uri)

src/code_actions/import_class.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ impl Backend {
5151
};
5252

5353
let local_classes: Vec<crate::types::ClassInfo> = self
54+
.symbols
5455
.uri_classes_index
5556
.read()
5657
.get(uri)
@@ -336,7 +337,7 @@ impl Backend {
336337

337338
// ── 1. fqn_uri_index ──────────────────────────────────────────────
338339
{
339-
let idx = self.fqn_uri_index.read();
340+
let idx = self.symbols.fqn_uri_index.read();
340341
for fqn in idx.keys() {
341342
if short_name(fqn).to_lowercase() == name_lower {
342343
candidates.push(fqn.to_owned());
@@ -346,7 +347,7 @@ impl Backend {
346347

347348
// ── 2. Class index ──────────────────────────────────────────────
348349
{
349-
let cmap = self.fqn_uri_index.read();
350+
let cmap = self.symbols.fqn_uri_index.read();
350351
for fqn in cmap.keys() {
351352
if short_name(fqn).to_lowercase() == name_lower
352353
&& !candidates
@@ -360,7 +361,7 @@ impl Backend {
360361

361362
// ── 3. uri_classes_index (already-parsed files) ───────────────────────────
362363
{
363-
let amap = self.uri_classes_index.read();
364+
let amap = self.symbols.uri_classes_index.read();
364365
for classes in amap.values() {
365366
for cls in classes {
366367
if cls.name.to_lowercase() == name_lower {
@@ -554,6 +555,7 @@ impl Backend {
554555
};
555556

556557
let local_classes: Vec<crate::types::ClassInfo> = self
558+
.symbols
557559
.uri_classes_index
558560
.read()
559561
.get(uri)
@@ -758,6 +760,7 @@ impl Backend {
758760
};
759761

760762
let local_classes: Vec<crate::types::ClassInfo> = self
763+
.symbols
761764
.uri_classes_index
762765
.read()
763766
.get(uri)

0 commit comments

Comments
 (0)