Skip to content

Commit 44ebe97

Browse files
committed
Update roadmap
1 parent 869aebe commit 44ebe97

5 files changed

Lines changed: 15 additions & 183 deletions

File tree

docs/todo.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ within the same impact tier.
4040
| | Clear [refactoring gate](todo/refactor.md) |||
4141
| A35 | [Convert to arrow function](todo/actions.md#a35-convert-to-arrow-function) (only non-void single-expression closures) | Low-Medium | Low |
4242
| C2 | [`#[ArrayShape]` return shapes on stub functions](todo/completion.md#c2-arrayshape-return-shapes-on-stub-functions) | Medium | Medium |
43-
| T7 | [`key-of<T>` and `value-of<T>` resolution](todo/type-inference.md#t7-key-oft-and-value-oft-resolution) | Medium | Medium |
4443
| A3 | Switch → match conversion | Low-Medium | Medium |
4544
| A10 | [Generate interface from class](todo/actions.md#a10-generate-interface-from-class) | Low-Medium | Medium |
4645

@@ -105,14 +104,12 @@ unlikely to move the needle for most users.
105104
| T10 | [Ternary expression as RHS of list destructuring](todo/type-inference.md#t10-ternary-expression-as-rhs-of-list-destructuring) | Low | Low-Medium |
106105
| T11 | [Nested list destructuring](todo/type-inference.md#t11-nested-list-destructuring) | Low | Low-Medium |
107106
| | **[Diagnostics](todo/diagnostics.md)** | | |
108-
| D5 | Diagnostic suppression intelligence | Medium | Medium |
107+
| D5 | [External tool diagnostic suppression actions](todo/diagnostics.md#d5-external-tool-diagnostic-suppression-actions) | Low | Low |
109108
| D6 | [Unreachable code diagnostic](todo/diagnostics.md#d6-unreachable-code-diagnostic) | Low-Medium | Low |
110109
| | **[Bug Fixes](todo/bugs.md)** | | |
111110
| | **[Code Actions](todo/actions.md)** | | |
112111
| A40 | [Generate method from call](todo/actions.md#a40-generate-method-from-call) | Medium-High | Medium |
113112
| A41 | [Create class from non-existing name](todo/actions.md#a41-create-class-from-non-existing-name) | Medium | Medium |
114-
| A42 | [Replace qualifier with import](todo/actions.md#a42-replace-qualifier-with-import) | Medium | Low |
115-
| A8 | [Update docblock to match signature](todo/actions.md#a8-update-docblock-to-match-signature) | Medium | Medium |
116113
| A16 | [Snippet placeholder for extracted method name](todo/actions.md#a16-snippet-placeholder-for-extracted-method-name) (lets the user type over the generated name immediately) | Medium | Low-Medium |
117114
| A25 | [`strpos``str_contains`](todo/actions.md#a25-strpos--str_contains-php-80) (PHP 8.0+) | Medium | Low |
118115
| A28 | [Explicit nullable parameter type](todo/actions.md#a28-explicit-nullable-parameter-type-php-84-deprecation) (PHP 8.4 deprecation) | Medium | Low |
@@ -156,7 +153,6 @@ unlikely to move the needle for most users.
156153
| S5 | Language construct signature help and hover | Low | Low |
157154
| | **[Laravel](todo/laravel.md)** | | |
158155
| L4 | Custom Eloquent builders (`HasBuilder` / `#[UseEloquentBuilder]`) | Medium | Medium |
159-
| L2 | [`morphedByMany` missing from relationship method map](todo/laravel.md#l2-morphedbymany-missing-from-relationship-method-map) | Low-Medium | Low |
160156
| L3 | `$dates` array (deprecated) | Low-Medium | Low |
161157
| L6 | Factory `has*`/`for*` relationship methods | Low-Medium | Medium |
162158
| L7 | `$pivot` property on BelongsToMany | Medium | Medium-High |
@@ -196,4 +192,3 @@ unlikely to move the needle for most users.
196192
| N1 | Template engine (type-aware snippets) | Medium | High |
197193
| N2 | N-gram prediction from PHP corpus | Medium | Very High |
198194
| N3 | Fine-tuned GGUF sidecar model | Medium | Very High |
199-

docs/todo/actions.md

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -95,77 +95,6 @@ but bounded in scope.
9595

9696

9797

98-
## A8. Update Docblock to Match Signature
99-
100-
**Impact: Medium · Effort: Medium**
101-
102-
When a function or method signature changes (parameters added, removed,
103-
reordered, or type hints updated), the docblock often falls out of sync.
104-
This code action regenerates or patches the `@param`, `@return`, and
105-
`@throws` tags to match the current signature.
106-
107-
### Behaviour
108-
109-
- **Trigger:** Cursor is on a function/method declaration that has an
110-
existing docblock. The code action appears when the docblock's `@param`
111-
tags don't match the signature's parameters (by name, count, or order),
112-
or when the `@return` tag contradicts the return type hint.
113-
- **Code action kind:** `quickfix` (when tags are clearly wrong) or
114-
`source.fixAll.docblock` for a broader sweep.
115-
116-
### What gets updated
117-
118-
1. **`@param` tags:**
119-
- Add missing `@param` for parameters present in the signature but
120-
absent from the docblock.
121-
- Remove `@param` for parameters no longer in the signature.
122-
- Reorder `@param` tags to match signature order.
123-
- Update the type if the signature has a type hint and the docblock
124-
type contradicts it (e.g. docblock says `string`, signature says
125-
`int`). If the docblock type is _more specific_ than the signature
126-
(e.g. docblock says `non-empty-string`, signature says `string`),
127-
keep the docblock type (it's a refinement, not a contradiction).
128-
- Preserve existing descriptions after the type and variable name.
129-
130-
2. **`@return` tag:**
131-
- If the signature has a return type hint and the docblock `@return`
132-
contradicts it, update the type. Same refinement rule: keep the
133-
docblock type if it's more specific.
134-
- If the signature has a return type but no `@return` tag exists,
135-
do not add one (the type hint is sufficient). Only update or
136-
remove existing tags.
137-
- Remove `@return void` if redundant with a `: void` return type.
138-
139-
3. **Preserve other tags:** `@throws`, `@template`, `@deprecated`,
140-
`@see`, and any other tags are left untouched.
141-
142-
### Edge cases
143-
144-
- **Promoted constructor parameters:** Treat the same as regular
145-
parameters for `@param` purposes.
146-
- **Variadic parameters:** `...$args` matches `@param type ...$args`.
147-
- **No existing docblock:** This action only patches existing docblocks.
148-
PHPDoc generation on `/**` (F1) handles creating new ones.
149-
150-
### Implementation
151-
152-
- Parse the function signature to extract parameter names, types, and
153-
order, plus the return type.
154-
- Parse the existing docblock to extract `@param` and `@return` tags
155-
with their positions, types, variable names, and descriptions.
156-
- Diff the two lists to determine additions, removals, reorderings,
157-
and type updates.
158-
- Build a `WorkspaceEdit` with targeted `TextEdit`s that modify only
159-
the changed lines within the docblock, preserving formatting,
160-
indentation, and unchanged tags.
161-
162-
### Prerequisites
163-
164-
| Feature | What it contributes |
165-
| ----------------------------------------- | ------------------------------------------------------------------- |
166-
| Docblock tag parsing (`docblock/tags.rs`) | Extracts existing `@param`/`@return` tags with positions |
167-
| Parser (`parser/functions.rs`) | Extracts parameter names, types, and return type from the signature |
168-
16998
---
17099

171100
## A10. Generate Interface from Class
@@ -647,25 +576,6 @@ Phpactor has this.
647576

648577
---
649578

650-
### A42. Replace qualifier with import
651-
652-
**Impact: Medium · Effort: Low**
653-
654-
Convert an inline fully-qualified name like `\Foo\Bar\Baz` to a
655-
`use` import plus the short name. A standalone code action
656-
(auto-import on completion already exists but this covers existing
657-
code). Phpactor has this.
658-
659-
- Detect any fully-qualified class reference under the cursor.
660-
- Add a `use Foo\Bar\Baz;` statement to the file's import block.
661-
- Replace the inline FQN with the short name `Baz`.
662-
- Handle alias conflicts: if `Baz` is already imported with a
663-
different FQN, prompt for an alias or skip.
664-
665-
**Code action kind:** `refactor.rewrite`.
666-
667-
---
668-
669579
### A43. Update docblock generics
670580

671581
**Impact: Medium · Effort: Medium**

docs/todo/diagnostics.md

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,21 @@ The following have been verified and are covered by tests:
5050

5151
---
5252

53-
## D5. Diagnostic suppression intelligence
53+
## D5. External tool diagnostic suppression actions
5454

55-
**Impact: Medium · Effort: Medium**
55+
**Impact: Low · Effort: Low (per tool, after proxy exists)**
5656

57-
When PHPantom proxies diagnostics from external tools, users need a way
58-
to suppress specific warnings. Rather than forcing them to install a
59-
separate extension or memorise each tool's suppression syntax, PHPantom
60-
can offer **code actions to insert the correct suppression comment** for
61-
the tool that produced the diagnostic.
62-
63-
PHPStan suppression is implemented: "Ignore PHPStan error" adds
64-
`// @phpstan-ignore <identifier>` (appending to existing ignores when
65-
present), and "Remove unnecessary @phpstan-ignore" cleans up unmatched
66-
ignores reported by PHPStan. What remains:
67-
68-
### Remaining tools
57+
PHPantom's own inline suppression (`// @phpantom-ignore code`) has
58+
shipped. PHPStan suppression is also implemented ("Ignore PHPStan
59+
error" / "Remove unnecessary @phpstan-ignore"). What remains is
60+
wiring up suppression actions for additional external tool proxies:
6961

7062
- PHPCS: `// phpcs:ignore [Sniff.Name]` or `// phpcs:disable` /
7163
`// phpcs:enable` blocks.
7264
- PHPMD (3.0): `#[SuppressWarnings(RuleName::class)]` as a PHP attribute.
73-
- For PHPantom's own diagnostics: support `@suppress phpantom.*`
74-
in docblocks (matching PHP Tools' convention) and a config flag
75-
`phpantom.diagnostics.enabled: bool` (default `true`).
7665

77-
**Prerequisites:** Each tool needs a diagnostic proxy before its
78-
suppression actions can be wired up.
66+
Each tool needs its diagnostic proxy before its suppression action
67+
can be wired up (D10 for PHPMD; PHPCS proxy is not yet filed).
7968

8069
---
8170

@@ -136,7 +125,7 @@ with `command`, `timeout`, and tool-specific options mirroring the
136125

137126
- PHPMD 3.0 must be released. Current 2.x output formats and rule
138127
naming may change.
139-
- The diagnostic suppression code action (D5) should support PHPMD's
128+
- The diagnostic suppression code action (D5) can add PHPMD's
140129
`@SuppressWarnings(PHPMD.[RuleName])` syntax once the proxy exists.
141130

142131
### Implementation
@@ -258,14 +247,11 @@ narrowed before this call."
258247

259248
Flag function and method parameters that are never read inside the
260249
body. This was intentionally excluded from D4 (unused variable
261-
diagnostic) because without suppression support (D5), false positives
262-
are unavoidable: callbacks, interface implementations, and framework
263-
conventions (e.g. Laravel event listeners) often require specific
264-
parameter signatures even when not all parameters are used.
265-
266-
**Prerequisite:** D5 (diagnostic suppression intelligence) must ship
267-
first so users can silence false positives with `// @phpantom-ignore`
268-
or a configuration-level exclusion.
250+
diagnostic) because false positives are common for callbacks, interface
251+
implementations, and framework conventions (e.g. Laravel event
252+
listeners) that require specific parameter signatures even when not
253+
all parameters are used. Users can now silence false positives with
254+
`// @phpantom-ignore unused_parameter`.
269255

270256
### Scope
271257

docs/todo/laravel.md

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -238,27 +238,6 @@ today and what is still missing.
238238

239239
---
240240

241-
#### L2. `morphedByMany` missing from relationship method map
242-
243-
**Impact: Low-Medium · Effort: Low**
244-
245-
Any model using `morphedByMany` (the inverse of a polymorphic
246-
many-to-many) gets no virtual property or `_count` property for that
247-
relationship. One-line addition to `RELATIONSHIP_METHOD_MAP`.
248-
249-
`morphedByMany` is the inverse side of a polymorphic many-to-many
250-
relationship. It returns a `MorphToMany` instance (the same class as
251-
`morphToMany`), but the method name is not listed in
252-
`RELATIONSHIP_METHOD_MAP`. This means body inference
253-
(`infer_relationship_from_body`) does not recognise
254-
`$this->morphedByMany(Tag::class)` calls, so no virtual property or
255-
`_count` property is synthesized.
256-
257-
**Where to change:** Add `("morphedByMany", "MorphToMany")` to
258-
`RELATIONSHIP_METHOD_MAP` in `src/virtual_members/laravel.rs`.
259-
No other changes needed since `MorphToMany` is already in
260-
`COLLECTION_RELATIONSHIPS`.
261-
262241
#### L4. Custom Eloquent builders (`HasBuilder` / `#[UseEloquentBuilder]`)
263242

264243
**Impact: High · Effort: Medium**

docs/todo/type-inference.md

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -211,44 +211,6 @@ See `ClosureBindDynamicReturnTypeExtension` and
211211

212212
---
213213

214-
## T7. `key-of<T>` and `value-of<T>` resolution
215-
**Impact: Medium · Effort: Medium**
216-
217-
PHPantom already parses `key-of<T>` and `value-of<T>` as type keywords
218-
but does not resolve them to concrete types. When `T` is bound to a
219-
concrete array type, these utility types should resolve:
220-
221-
- `value-of<array{a: string, b: int}>``string|int`
222-
- `key-of<array{a: string, b: int}>``'a'|'b'`
223-
- `value-of<array<string, User>>``User`
224-
- `key-of<array<string, User>>``string`
225-
226-
These types commonly appear in PHPStan-typed libraries and in
227-
`@template` constraints. For example:
228-
229-
```php
230-
/**
231-
* @template T of array
232-
* @param T $array
233-
* @return value-of<T>
234-
*/
235-
function first(array $array): mixed;
236-
```
237-
238-
**Implementation:** plug into the generic substitution pipeline in
239-
`inheritance.rs` / `completion/types/resolution.rs`. After template
240-
parameters are substituted with concrete types, detect `key-of<...>`
241-
and `value-of<...>` wrappers and resolve them by inspecting the inner
242-
type:
243-
244-
- If the inner type is an `array{...}` shape, collect the key or value
245-
types from the shape fields.
246-
- If the inner type is `array<K, V>`, extract `K` or `V` directly.
247-
- If the inner type is still an unresolved template parameter, leave
248-
it as-is (it may resolve later in the chain).
249-
250-
---
251-
252214

253215

254216
## T9. Dead-code elimination after `never`-returning calls

0 commit comments

Comments
 (0)