Skip to content

Commit 883bdc9

Browse files
committed
Clean up roadmap
1 parent 4b2ead9 commit 883bdc9

11 files changed

Lines changed: 33 additions & 526 deletions

File tree

docs/todo.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ with each step.
2020
| [Diagnostics](todo/diagnostics.md) | `@deprecated` warnings, resolution-failure diagnostics, unused `use` dimming, suppression intelligence |
2121
| [Code Actions](todo/actions.md) | Import class, remove unused imports, implement missing methods, null coalescing simplification, extract function, inline variable, extract variable, inline function/method, switch→match |
2222
| [LSP Features](todo/lsp-features.md) | Find references, document highlighting, document/workspace symbols, rename, code lens, inlay hints, PHPDoc generation, partial result streaming |
23-
| [Hover](todo/hover.md) | Deprecation messages, constant values, member origin indicators, enum case listing, trait method summaries |
2423
| [Signature Help](todo/signature-help.md) | Parameter descriptions, signature-level docs, default values, attribute/closure support |
2524
| [Laravel](todo/laravel.md) | Model property gaps, relationship methods, type narrowing, custom builders |
2625
| [Blade](todo/blade.md) | Preprocessor, component support, cross-file view intelligence |
@@ -33,30 +32,6 @@ with each step.
3332

3433
---
3534

36-
## Sprint 2.5 — Parallel file processing (0.5.0)
37-
38-
This sprint delivers parallel file processing for workspace-wide
39-
operations (find references, go-to-implementation, self-scan,
40-
diagnostics). The prerequisite items replace shared data structures
41-
with reference-counted wrappers so that parallel threads share data
42-
cheaply instead of deep-cloning.
43-
44-
| # | Item | Effort | Domain | Doc Link | Status |
45-
|---|---|---|---|---|---|
46-
| 85 | `Arc<String>` for file content in `open_files` | Low | Performance | [performance.md §5](todo/performance.md#5-arcstring-for-file-content-in-open_files) | ✅ Done |
47-
| 86 | `Arc<SymbolMap>` to avoid snapshot cloning | Low | Performance | [performance.md §6](todo/performance.md#6-arcsymbolmap-to-avoid-snapshot-cloning) | ✅ Done |
48-
| 95 | Parallel file processing | Medium | Indexing | [indexing.md §3](todo/indexing.md#phase-3-parallel-file-processing) | ✅ Done (initial) |
49-
| 14 | Signature help fires on function definition sites | Low | Bug Fix | [bugs.md §14](todo/bugs.md#14-signature-help-fires-on-function-definition-sites) | ✅ Done |
50-
51-
**After Sprint 2.5:** `ensure_workspace_indexed` parses files across
52-
multiple cores using `std::thread::scope`. File content and symbol
53-
maps are shared by reference instead of deep-cloned. Transient entry
54-
eviction after GTI and find references has been removed; parsed files
55-
stay cached for faster repeat queries. Priority-aware scheduling
56-
(preempting batch work for interactive requests) is deferred.
57-
58-
---
59-
6035
## Sprint 3 — Refactoring & deferred performance
6136

6237
Extract Function is the remaining refactoring pillar. Inline Variable,

docs/todo/bugs.md

Lines changed: 1 addition & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -14,137 +14,4 @@ Items are ordered by **impact** (descending), then **effort** (ascending).
1414

1515
---
1616

17-
## 1. Short-name collisions in `find_implementors`
18-
**Impact: Low · Effort: Low (fixed)**
19-
20-
**Status:** Fixed. `class_implements_or_extends` now compares
21-
fully-qualified names when a namespace is available. The short-name
22-
fallback is only used when FQN information is absent. `seen_fqns` in
23-
`find_implementors` deduplicates by FQN (built from `name` +
24-
`file_namespace`) instead of by short name.
25-
26-
---
27-
28-
## 2. GTD fires on parameter variable names and class declaration names
29-
**Impact: Medium · Effort: Low (fixed)**
30-
31-
**Status:** Fixed. Three layers suppress self-referential jumps:
32-
33-
1. `resolve_from_symbol` returns `None` for `ClassDeclaration` and
34-
`MemberDeclaration` symbol kinds (the cursor is at the definition).
35-
2. `lookup_var_def_kind_at` detects when the cursor is on a variable
36-
at its definition site (parameter, assignment LHS, foreach binding,
37-
catch binding) and returns `None` before `find_var_definition` runs.
38-
3. A self-reference guard in `resolve_definition` suppresses jumps
39-
when the resolved location points back to the cursor position.
40-
41-
Tested with `test_goto_definition_parameter_at_definition_returns_none`
42-
and related tests in `definition_variables.rs`.
43-
44-
---
45-
46-
## 3. Relationship classification matches short name only
47-
**Impact: Low · Effort: Low (fixed)**
48-
49-
**Status:** Fixed. `classify_relationship` now checks whether a
50-
namespace-qualified return type lives under
51-
`Illuminate\Database\Eloquent\Relations\` before classifying.
52-
Unqualified short names (the common case for body-inferred types and
53-
use-imported docblock annotations) still match by short name only.
54-
A custom `App\Relations\HasMany` is no longer misclassified.
55-
56-
---
57-
58-
## 4. Go-to-implementation misses transitive implementors
59-
**Impact: Medium · Effort: Medium (fixed)**
60-
61-
**Status:** Fixed. `class_implements_or_extends` already walks the
62-
parent class chain transitively (up to `MAX_INHERITANCE_DEPTH`) and
63-
checks interface-extends chains recursively. Classes that extend a
64-
concrete class which itself implements the target interface are found
65-
correctly. Tested with `test_implementation_transitive_via_parent`,
66-
`test_implementation_skips_abstract_subclasses`, and deep interface
67-
inheritance chains.
68-
69-
---
70-
71-
## 5. Go-to-implementation Phase 5 should only walk user PSR-4 roots
72-
**Impact: Low · Effort: Low (fixed)**
73-
74-
**Status:** Fixed. PSR-4 mappings now come exclusively from
75-
`composer.json` (user code only). Vendor PSR-4 mappings are no longer
76-
loaded (see §7), so Phase 5 inherently walks only user roots.
77-
78-
---
79-
80-
## 6. Go-to-definition does not check the classmap
81-
**Impact: Medium · Effort: Low (fixed)**
82-
83-
**Status:** Fixed. `resolve_class_reference`, `resolve_self_static_parent`,
84-
and `resolve_type_hint_string_to_location` now check the Composer classmap
85-
(FQN → file path) between the class_index lookup and the PSR-4 fallback.
86-
A cold Ctrl+Click on a vendor class resolves through the classmap without
87-
needing vendor PSR-4 mappings.
88-
89-
---
90-
91-
## 7. Vendor PSR-4 mappings removed
92-
**Impact: Low · Effort: Low (fixed)**
93-
94-
**Status:** Fixed. `parse_vendor_autoload_psr4` has been removed.
95-
`parse_composer_json` no longer reads `vendor/composer/autoload_psr4.php`.
96-
PSR-4 mappings come exclusively from the project's own `composer.json`
97-
(`autoload.psr-4` and `autoload-dev.psr-4`). The `is_vendor` flag on
98-
`Psr4Mapping` has been removed.
99-
100-
All resolution paths that could hit a vendor class now check the classmap
101-
first (§6). If the classmap is missing or stale, vendor classes fail to
102-
resolve visibly (fix: run `composer dump-autoload`). This reduces startup
103-
time and memory for projects with large dependency trees.
104-
105-
**Note for Rename Symbol:** when rename support is implemented, the
106-
handler should reject renames for symbols whose definition lives under
107-
the vendor directory. The user cannot meaningfully rename third-party
108-
code. Use `vendor_uri_prefix` to detect this and return an appropriate
109-
error message.
110-
111-
---
112-
113-
## 13. Evict transiently-loaded files from ast_map after GTI and Find References
114-
**Impact: Low · Effort: Low (fixed → superseded)**
115-
116-
**Status:** Superseded. The original fix added post-scan eviction
117-
(`evict_transient_entries`, `evict_transient_ast_entries`) to remove
118-
`ast_map`, `symbol_maps`, `use_map`, and `namespace_map` entries that
119-
were added during GTI and find-references scans.
120-
121-
The eviction has since been removed. With `Arc<SymbolMap>` and
122-
`Arc<String>` reducing per-entry memory cost, keeping parsed files
123-
cached is a better trade-off: subsequent operations (a second
124-
find-references call, go-to-definition on a cross-file symbol)
125-
benefit from the work already done without re-parsing. The eviction
126-
functions (`evict_transient_entries`, `evict_transient_ast_entries`,
127-
`evict_transient_inner`) and their `pre_scan_uris` snapshots have
128-
been removed.
129-
130-
---
131-
132-
## 14. Signature help fires on function definition sites
133-
**Impact: Low · Effort: Low (fixed)**
134-
135-
**Status:** Fixed. `detect_call_site_text_fallback` now calls
136-
`is_function_definition_paren` before extracting a call expression.
137-
The check walks backward from the open parenthesis through the
138-
function name (if any) and whitespace, looking for the `function` or
139-
`fn` keyword. This suppresses signature help for named functions
140-
(`function foo(`), anonymous functions (`function (`), arrow functions
141-
(`fn(`), and method definitions (`public function bar(`).
142-
143-
The AST-based detection path was already safe because `CallSite`
144-
entries are only emitted for actual call expressions, never for
145-
function/method definitions.
146-
147-
Tested with `suppressed_on_named_function_definition`,
148-
`suppressed_on_anonymous_function`, `suppressed_on_arrow_function`,
149-
`suppressed_on_method_definition`, and
150-
`not_suppressed_on_actual_function_call` in `signature_help_tests.rs`.
17+
No outstanding bugs.

docs/todo/completion.md

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,19 @@ parsing and should feed into the same `return_type` field on
133133
---
134134

135135
## 4. `#[Deprecated]` structured deprecation metadata
136-
**Status: ✅ Implemented**
137-
138-
PHPantom reads the `#[Deprecated]` attribute (FQN:
139-
`JetBrains\PhpStorm\Deprecated`) on classes, interfaces, traits, enums,
140-
methods, properties, constants, and standalone functions. The `reason`
141-
and `since` fields appear in hover, completion strikethrough, and
142-
deprecation diagnostics. When both a docblock `@deprecated` tag and the
143-
attribute are present, the docblock message takes priority.
144-
145-
The `replacement` field is parsed and stored but not yet wired to a
146-
code action. Once the general code-action infrastructure lands, a
147-
"replace deprecated call" quick-fix can use the template (e.g.
148-
`"exif_read_data(%parametersList%)"`) to offer automatic replacement.
149-
150-
**Remaining work:**
151-
- Wire `replacement` to a code action (blocked on code-action infra).
152-
- Use `since` to make deprecation warnings version-aware (suppress when
153-
targeting a PHP version older than the `since` value).
136+
**Impact: Low · Effort: Low**
137+
138+
The `#[Deprecated]` attribute is parsed and wired into hover, completion
139+
strikethrough, and deprecation diagnostics. Two pieces remain:
140+
141+
- **Replacement code action.** The `replacement` field is parsed and
142+
stored but not yet wired to a code action. Once the general
143+
code-action infrastructure lands, a "replace deprecated call"
144+
quick-fix can use the template (e.g.
145+
`"exif_read_data(%parametersList%)"`) to offer automatic replacement.
146+
- **Version-aware suppression.** Use the `since` field to suppress
147+
deprecation warnings when targeting a PHP version older than the
148+
`since` value.
154149

155150
---
156151

docs/todo/config.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,5 @@ Controls which external tools PHPantom proxies for diagnostics.
9898

9999
## Implementation order
100100

101-
1.**Config loading.** Read `.phpantom.toml` from the workspace root on `initialized`. Deserialize with `toml` + `serde`. Missing file means all defaults. *Done — `src/config.rs` module, loaded during `initialized` in `server.rs`. Parse errors are reported as a warning to the user.*
102-
2. **Config writing.** When PHPantom prompts the user and gets an answer, write or update the relevant key. Preserve comments and formatting (use `toml_edit` crate).
103-
3.**PHP version override.** Wire `[php].version` into the existing version detection path. *Done — config override takes precedence over `composer.json` detection.*
104-
4. **Diagnostic proxying.** Wire `[diagnostics]` toggles into the proxy infrastructure as each provider is implemented. *Partially done — `unresolved-member-access` toggle is wired; external tool toggles (`phpstan`, `phpmd`, etc.) await proxy infrastructure.*
101+
1. **Config writing.** When PHPantom prompts the user and gets an answer, write or update the relevant key. Preserve comments and formatting (use `toml_edit` crate).
102+
2. **Diagnostic proxying.** Wire `[diagnostics]` toggles into the proxy infrastructure as each provider is implemented. *Partially done — `unresolved-member-access` toggle is wired; external tool toggles (`phpstan`, `phpmd`, etc.) await proxy infrastructure.*

docs/todo/diagnostics.md

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -11,76 +11,20 @@ within the same impact tier.
1111
---
1212

1313
## 2. Resolution-failure diagnostics
14-
**Impact: Medium · Effort: Medium** *(mostly done — unresolved class/interface, unresolved member access, and unresolvable subject type implemented; unresolved function and unresolved PHPDoc type remain)*
15-
16-
Report diagnostics only for symbols and types that PHPantom's own engine
17-
failed to resolve. This is **not** a general PHP linter — we don't check
18-
argument counts, type compatibility, or missing semicolons. The goal is
19-
twofold:
20-
21-
1. **Surface bugs in our engine.** On well-typed projects, every
22-
diagnostic is a false positive that points at a resolution code path
23-
we need to fix. This gives us a live regression signal.
24-
2. **Guide under-typed projects.** On projects that aren't fully typed,
25-
the diagnostics show exactly where adding annotations would unlock
26-
completion and go-to-definition.
14+
**Impact: Medium · Effort: Medium**
2715

28-
All diagnostics should be published on `textDocument/didOpen` and
29-
`textDocument/didChange` (debounced). Severity is **Warning** for
30-
unresolved types (the code may still run fine) and **Hint** or
31-
**Information** for softer signals.
16+
Unresolved class/interface, unresolved member access, and unresolvable
17+
subject type diagnostics are already implemented. Two diagnostic types
18+
remain:
3219

3320
### Diagnostics to emit
3421

3522
| Diagnostic | Trigger | Severity | Example |
3623
|---|---|---|---|
37-
| ✅ Unresolved class/interface | A type hint, `extends`, `implements`, `new`, or `::` reference that `find_or_load_class` cannot resolve after all phases (ast_map → classmap → PSR-4 → stubs) | Warning | `Class 'App\Foo' not found` | *Done — `diagnostics::unknown_classes` module* |
3824
| Unresolved function | A function call that `find_or_load_function` cannot resolve (global functions, namespaced functions, stubs) | Warning | `Function 'do_thing' not found` |
39-
| ✅ Unresolved member access | `->method()` or `->property` on a type we *did* resolve, but the member doesn't exist after full resolution (inheritance + virtual providers) | Warning | `Method 'frobnicate' not found on class 'App\Bar'` | *Done — `diagnostics::unknown_members` module. PHPactor benchmark fixtures `lots_of_missing_methods` and `method_chain` enabled in `benches/completion.rs`.* |
40-
| ✅ Unresolvable subject type (opt-in) | `->method()`, `?->method()`, or `::method()` where PHPantom cannot resolve the subject type at all (e.g. `mixed`, untyped variable, uninferrable return type) | Hint | `Cannot resolve type of '$x'. Add a type annotation or PHPDoc tag to enable full IDE support.` | *Done — `diagnostics::unresolved_member_access` module. Off by default; enable via `[diagnostics] unresolved-member-access = true` in `.phpantom.toml`.* |
4125
| Unresolved type in PHPDoc | A `@return`, `@param`, `@var`, `@throws`, `@mixin`, or `@extends` tag references a class that cannot be resolved | Information | `Type 'SomeAlias' in @return could not be resolved` |
4226

4327

44-
### What we explicitly do NOT report
45-
46-
- Syntax errors (Mago already handles that; we use error-tolerant parsing)
47-
- Argument count / type mismatches (that's PHPStan's job)
48-
- Unused variables, imports, or dead code
49-
- Missing return types or parameter types
50-
- Code style violations
51-
52-
### Implementation plan
53-
54-
1. **Add `publishDiagnostics` capability** in `initialize` response and
55-
store a handle to the client notification sender.
56-
2. **Collect diagnostics during `update_ast`** — the symbol map walk
57-
already visits every class reference, member access, and function
58-
call. At each site, attempt resolution; on failure, record a
59-
`DiagnosticEntry { range, message, severity }`.
60-
3. **Debounce and publish** — after `update_ast` completes (on open or
61-
change), send `textDocument/publishDiagnostics` with the collected
62-
entries. Debounce changes to ~200 ms so fast typing doesn't spam.
63-
4. **Clear on close** — send an empty diagnostics array when a file is
64-
closed.
65-
5. **User opt-out** — respect a config flag (e.g.
66-
`phpantom.diagnostics.enabled: bool`, default `true`) so users who
67-
rely solely on PHPStan / Psalm can turn ours off.
68-
69-
### Design notes
70-
71-
- **False positive budget:** treat every false positive as a bug. If a
72-
diagnostic fires on valid, well-typed code, the fix goes in the
73-
resolution engine, not in a suppression list. This keeps us honest.
74-
- **No cross-file diagnostics** — only diagnose the file being
75-
edited/opened. We don't scan the whole project.
76-
- **Stubs are authoritative** — if a symbol exists in phpstorm-stubs,
77-
it's resolved. We don't warn about `array_map` not being found
78-
because a stub was missing.
79-
- **Performance** — resolution is already happening for completion and
80-
definition; diagnostics piggyback on the same code paths. The
81-
incremental cost should be small since we're just collecting failures
82-
that currently get silently swallowed.
83-
8428
---
8529

8630
## 3. Diagnostic suppression intelligence

docs/todo/hover.md

Lines changed: 0 additions & 14 deletions
This file was deleted.

docs/todo/indexing.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,8 @@ structures.
429429
go-to-implementation, self-scan, diagnostics) by processing files in
430430
parallel with priority awareness.
431431

432-
**Prerequisites (from [performance.md](performance.md)):**
433-
434-
- **§3 `RwLock` for read-heavy maps.** ✅ Fixed.
435-
- **§5 `Arc<String>` for file content.** ✅ Fixed.
436-
- **§6 `Arc<SymbolMap>` to avoid snapshot cloning.** ✅ Fixed.
432+
All prerequisites (§3 `RwLock`, §5 `Arc<String>`, §6 `Arc<SymbolMap>`)
433+
are complete.
437434

438435
### Current state (partial)
439436

@@ -536,20 +533,20 @@ scanning, and complete completion item detail.
536533

537534
**Prerequisites (from [performance.md](performance.md)):**
538535

539-
- **§1 FQN secondary index.** Done. `fqn_index` provides O(1)
536+
- **§1 FQN secondary index.** Done. `fqn_index` provides O(1)
540537
lookups by fully-qualified name, so the second pass populating
541538
`ast_map` with thousands of entries no longer causes linear scans.
542539
- **§2 `Arc<ClassInfo>`.** Full indexing stores a `ClassInfo` for every
543540
class in the project. Without `Arc`, every resolution clones the
544541
entire struct out of the map. With `Arc`, retrieval is a
545542
reference-count increment. This is the difference between full
546543
indexing using ~200 MB vs. ~500 MB for a large project.
547-
- **§3 `RwLock`.** The second pass writes to `ast_map` at Low priority
544+
- **§3 `RwLock`.** Done. The second pass writes to `ast_map` at Low priority
548545
while High-priority LSP requests read from it. `Mutex` would force
549546
every completion/hover request to wait for the current background
550547
parse to finish its map insertion. `RwLock` lets reads proceed
551548
concurrently with other reads; only the brief write window blocks.
552-
- **§4 `HashSet` dedup.** Done. All member deduplication during
549+
- **§4 `HashSet` dedup.** Done. All member deduplication during
553550
inheritance merging now uses `HashSet` lookups, bringing the
554551
per-resolution cost from O(N²) to O(N).
555552

docs/todo/lsp-features.md

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -329,20 +329,6 @@ visible — well within our per-file performance budget.
329329

330330
---
331331

332-
## 10. Reverse jump: implementation → interface method declaration
333-
**Impact: Medium · Effort: Low (fixed)**
334-
335-
**Status:** Fixed. When go-to-implementation is invoked on a
336-
`MemberDeclaration` symbol in a concrete class, the handler walks the
337-
class's interfaces (including those inherited from parent classes) and
338-
parent abstract classes to find the prototype method declaration and
339-
returns its location. Conversely, invoking go-to-implementation on a
340-
method declaration inside an interface or abstract class finds the
341-
concrete implementations. Tested with same-file and transitive
342-
inheritance scenarios.
343-
344-
---
345-
346332
## 11. No go-to-definition for built-in (stub) functions and constants
347333
**Impact: Medium · Effort: Medium**
348334

0 commit comments

Comments
 (0)