Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$this type inside object creation #2620

Merged
merged 6 commits into from Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 11 additions & 8 deletions lib/WorseReflection/Core/Inference/Walker/FunctionLikeWalker.php
Expand Up @@ -68,13 +68,16 @@ public function exit(FrameResolver $resolver, Frame $frame, Node $node): Frame
private function walkFunctionLike(FrameResolver $resolver, Frame $frame, FunctionLike $node): void
{
$namespace = $node->getNamespaceDefinition();
$classNode = $node->getFirstAncestor(
ClassDeclaration::class,
InterfaceDeclaration::class,
TraitDeclaration::class,
EnumDeclaration::class,
ObjectCreationExpression::class, // For Inline classes
);
do {
// If we are here we found a normal ObjectCreationExpression like: new A(); and this is not useful and we continue traversing
$classNode = ($classNode ?? $node)->getFirstAncestor(
ClassDeclaration::class,
InterfaceDeclaration::class,
TraitDeclaration::class,
EnumDeclaration::class,
ObjectCreationExpression::class, // For Inline classes
);
} while ($classNode instanceof ObjectCreationExpression && $classNode->classTypeDesignator instanceof Node);

if ($node instanceof AnonymousFunctionCreationExpression) {
$this->addAnonymousImports($frame, $node);
Expand All @@ -87,7 +90,7 @@ private function walkFunctionLike(FrameResolver $resolver, Frame $frame, Functio
}

// works for both closure and class method (we currently ignore binding)
if ($classNode) {
if ($classNode !== null) {
$classType = $resolver->resolveNode($frame, $classNode)->type();
$this->addClassContext($node, $classType, $frame);
}
Expand Down
Expand Up @@ -34,6 +34,29 @@ public function hello()
$this->assertEquals(false, $frame->locals()->byName('this')->first()->isProperty());
}];

yield 'It returns this with correct type in an anonymous function' => [
<<<'EOT'
<?php

namespace Foobar\Barfoo;

use Acme\Factory;

class Foobar
{
public function hello()
{
new \ReflectionFunction(function() { <> });
}
}

EOT
, function (Frame $frame): void {
$this->assertCount(1, $frame->locals()->byName('this'));
$this->assertEquals('Foobar\Barfoo\Foobar', $frame->locals()->byName('this')->first()->type()->__toString());
$this->assertEquals(false, $frame->locals()->byName('this')->first()->isProperty());
}];

yield 'It returns method arguments' => [
<<<'EOT'
<?php
Expand Down