Skip to content

Offer magic methods when declaring a method - #898

Open
Firehed wants to merge 17 commits into
mainfrom
291/magic-method-completion
Open

Firehed wants to merge 17 commits into
mainfrom
291/magic-method-completion

Conversation

@Firehed

@Firehed Firehed commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Closes #291.

Problem

Typing a method name in a class-like body offered nothing:

class Foo
{
    public function __to| // nothing offered

Change

Where a method's name is being written, completion now offers the magic methods the declaration may still be, inserting each with the signature the PHP manual gives it (__toString(): string).

What is offered follows PHP's rules:

  • An enum may declare only __call, __callStatic, and __invoke.
  • __callStatic and __set_state are static; every other magic method is not. A declaration written static is offered only those two, and one without static only the rest.
  • All but __construct, __destruct, and __clone must be public. A declaration written private or protected is offered only those three. No visibility written means public.
  • A magic method the class-like already declares (method names are case-insensitive) is not offered again.

How it gets there, each piece from an existing route:

  • PositionLocator gives a method's written name its own slot, Slot::MethodName, split out of Slot::DeclaredName; hover and definition answer it as before (nothing).
  • ExpectedAtPosition turns that slot into a new Expected::$declaredMethod (a MethodName), from the written name and Scope::getSelfName().
  • MagicMethodCandidates looks the class-like up through SymbolSourceInterface: its kind, the declaring method's modifiers, and its other methods all come from the ClassInfo the parsed declaration already produces. Name comparison uses MemberKind::Method->normalize.
  • MagicMethod holds the list, the rules above, and each signature.
  • The item is plain text, not a snippet: snippet syntax would read a signature's $name as a variable.

Known limits

  • Nothing is offered until a name is typed (public function |). There, the parsed document cannot yet tell a method being declared from other unfinished members.
  • Nothing is offered in an anonymous class, which has no name to look its declarations up by (Domain classes are unable to model all declarations #867).
  • Where parentheses already follow the name (public function __g|() {}), the full signature is still inserted.
  • A class-like that declares the same method twice keeps only one of them, so the duplicate filter cannot see the other. PHP rejects that code.
  • __construct() and __invoke() insert no parameters: the manual's mixed ...$values = "" is not valid to declare, and what they take is the author's choice.

#37 (offering unimplemented abstract and interface methods) can use the same Expected::$declaredMethod.

🤖 Generated with Claude Code

Firehed and others added 14 commits November 2, 2026 16:26
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.71%. Comparing base (44f6a1f) to head (c8b2794).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff            @@
##               main     #898   +/-   ##
=========================================
  Coverage     99.71%   99.71%           
- Complexity     1970     2007   +37     
=========================================
  Files           147      149    +2     
  Lines          4488     4545   +57     
=========================================
+ Hits           4475     4532   +57     
  Misses           13       13           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Firehed and others added 3 commits November 2, 2026 16:36
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Firehed
Firehed marked this pull request as ready for review November 3, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Completion: offer magic methods

1 participant