Summary
Array callable method-name strings like [SortableController::class, 'sort'] currently receive a method semantic token unconditionally, coloring them as methods even when the method name is misspelled (e.g. 'sortaaaa'). The string should only receive method coloring when the member actually exists on the resolved class.
Current behavior
[SortableController::class, 'sort'] // colored as method ✓
[SortableController::class, 'sortaaaa'] // also colored as method ✗ (should be string)
Both strings are colored blue (method token) because semantic_tokens.rs unconditionally emits TT_METHOD for every MemberAccess span. The resolve_member_modifiers stub (line ~502) always returns 0 without checking member existence.
Expected behavior
When the subject is a known class name (from a ::class constant), resolve the class via the class index and check if the member exists. If it doesn't, skip the semantic token so the text reverts to default string coloring.
For variable subjects ($this, $obj), full variable resolution is expensive — these could continue emitting unconditionally, or be resolved cheaply when $this refers to the enclosing class.
Implementation notes
An initial attempt at implementing this in resolve_member_modifiers showed correct behavior on file open (cold start) but stale coloring during editing. The root cause is the async update_ast timing: semantic tokens are requested before the symbol map is rebuilt, and no workspace/semanticTokens/refresh notification is sent after the async rebuild completes. Key areas:
semantic_tokens.rs:272-296 — MemberAccess arm unconditionally returns (tt, mods)
semantic_tokens.rs:502-515 — resolve_member_modifiers is a stub returning 0
server.rs:592-637 — async did_change path: after update_ast completes, schedule_diagnostics is called but no client.semantic_tokens_refresh() is sent
Suggested approach
- Implement
resolve_member_modifiers to return Option<u32> — None means member not found, skip the semantic token
- For non-variable subjects: resolve via use map → namespace → bare name, then check member existence on the fully resolved class (including inheritance/traits)
- Handle
__call/__callStatic/__get magic methods as catch-alls
- Add
client.semantic_tokens_refresh() after async update_ast completes to fix stale tokens during editing
- This would also benefit regular static calls like
Foo::nonExistentMethod(), not just array callables
Related
This builds on the array-callable navigation work in commit 21a0105 and the array-callable completion work.
Summary
Array callable method-name strings like
[SortableController::class, 'sort']currently receive amethodsemantic token unconditionally, coloring them as methods even when the method name is misspelled (e.g.'sortaaaa'). The string should only receive method coloring when the member actually exists on the resolved class.Current behavior
Both strings are colored blue (method token) because
semantic_tokens.rsunconditionally emitsTT_METHODfor everyMemberAccessspan. Theresolve_member_modifiersstub (line ~502) always returns0without checking member existence.Expected behavior
When the subject is a known class name (from a
::classconstant), resolve the class via the class index and check if the member exists. If it doesn't, skip the semantic token so the text reverts to default string coloring.For variable subjects (
$this,$obj), full variable resolution is expensive — these could continue emitting unconditionally, or be resolved cheaply when$thisrefers to the enclosing class.Implementation notes
An initial attempt at implementing this in
resolve_member_modifiersshowed correct behavior on file open (cold start) but stale coloring during editing. The root cause is the asyncupdate_asttiming: semantic tokens are requested before the symbol map is rebuilt, and noworkspace/semanticTokens/refreshnotification is sent after the async rebuild completes. Key areas:semantic_tokens.rs:272-296—MemberAccessarm unconditionally returns(tt, mods)semantic_tokens.rs:502-515—resolve_member_modifiersis a stub returning0server.rs:592-637— asyncdid_changepath: afterupdate_astcompletes,schedule_diagnosticsis called but noclient.semantic_tokens_refresh()is sentSuggested approach
resolve_member_modifiersto returnOption<u32>—Nonemeans member not found, skip the semantic token__call/__callStatic/__getmagic methods as catch-allsclient.semantic_tokens_refresh()after asyncupdate_astcompletes to fix stale tokens during editingFoo::nonExistentMethod(), not just array callablesRelated
This builds on the array-callable navigation work in commit 21a0105 and the array-callable completion work.