Skip to content

Commit

Permalink
Update ArgumentReflectin API to provide named arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
dantleech committed Feb 5, 2024
1 parent b223625 commit c2e2fa3
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 155 deletions.
6 changes: 3 additions & 3 deletions src/Bridge/TolerantParser/Reflection/ReflectionArgument.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ public function guessName(): string

public function type(): Type
{
return $this->info()->type();
return $this->nodeContext()->type();
}

public function value(): mixed
{
return TypeUtil::valueOrNull($this->info()->type());
return TypeUtil::valueOrNull($this->nodeContext()->type());
}

public function position(): ByteOffsetRange
Expand All @@ -83,7 +83,7 @@ public function position(): ByteOffsetRange
);
}

private function info(): NodeContext
public function nodeContext(): NodeContext
{
return $this->services->nodeContextResolver()->resolveNode($this->frame, $this->node);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Phpactor\WorseReflection\Core\Reflection\Collection;

use Microsoft\PhpParser\Node\Expression\ArgumentExpression;
use Phpactor\WorseReflection\Core\Reflection\ReflectionArgument as PhpactorReflectionArgument;
use Phpactor\WorseReflection\Core\ServiceLocator;
use Microsoft\PhpParser\Node\DelimitedList\ArgumentExpressionList;
Expand All @@ -17,6 +18,14 @@ public static function fromArgumentListAndFrame(ServiceLocator $locator, Argumen
{
$arguments = [];
foreach ($list->getElements() as $element) {
if (!$element instanceof ArgumentExpression) {
continue;
}
if ($element->name) {
$key = $element->name->getText($element->getFileContents());
$arguments[$key] = new ReflectionArgument($locator, $frame, $element);
continue;
}
$arguments[] = new ReflectionArgument($locator, $frame, $element);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Core/Reflection/ReflectionArgument.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Phpactor\WorseReflection\Core\Reflection;

use Phpactor\WorseReflection\Core\Inference\NodeContext;
use Phpactor\WorseReflection\Core\Type;
use Phpactor\TextDocument\ByteOffsetRange;

Expand All @@ -14,4 +15,6 @@ public function type(): Type;
public function value(): mixed;

public function position(): ByteOffsetRange;

public function nodeContext(): NodeContext;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Phpactor\WorseReflection\Tests\Integration\Bridge\TolerantParser\Reflection;

use Generator;
use Phpactor\TextDocument\TextDocumentBuilder;
use Phpactor\WorseReflection\Core\Inference\NodeContext;
use Phpactor\WorseReflection\Tests\Integration\IntegrationTestCase;
use Phpactor\WorseReflection\Core\Reflection\Collection\ReflectionArgumentCollection;
use Phpactor\TestUtils\ExtractOffset;
Expand All @@ -15,102 +18,124 @@ class ReflectionArgumentTest extends IntegrationTestCase
public function testReflectMethodCall(string $source, array $frame, Closure $assertion): void
{
[$source, $offset] = ExtractOffset::fromSource($source);
$reflection = self::createReflector($source)->reflectMethodCall($source, $offset);
$reflection = self::createReflector($source)->reflectMethodCall(TextDocumentBuilder::create($source)->build(), $offset);
$assertion($reflection->arguments());
}

public function provideReflectionMethod()
public static function provideReflectionMethod():Generator
{
return [
'It guesses the name from the var name' => [
<<<'EOT'
<?php
yield 'It guesses the name from the var name' => [
<<<'EOT'
<?php
$foo->b<>ar($foo);
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('foo', $arguments->first()->guessName());
},
$foo->b<>ar($foo);
EOT
, [
],
'It guesses the name from return type' => [
<<<'EOT'
<?php
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('foo', $arguments->first()->guessName());
},
];
yield 'It returns a named argument' => [
<<<'EOT'
<?php
class AAA
{
public function bob(): Alice
{
}
}
$foo->b<>ar(foo: 'hello');
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('"hello"', $arguments->get('foo')->type()->__toString());
},
];
yield 'It returns node context' => [
<<<'EOT'
<?php
$foo = new AAA();
$foo->b<>ar($foo->bob());
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('alice', $arguments->first()->guessName());
},
$foo->b<>ar(foo: 'hello');
EOT
, [
],
'It returns a generated name if it cannot be determined' => [
<<<'EOT'
<?php
function (ReflectionArgumentCollection $arguments): void {
self::assertInstanceOf(NodeContext::class, $arguments->get('foo')->nodeContext());
},
];
yield 'It guesses the name from return type' => [
<<<'EOT'
<?php
class AAA
class AAA
{
public function bob(): Alice
{
}
}
$foo = new AAA();
$foo->b<>ar($foo->bob());
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('alice', $arguments->first()->guessName());
},
];
yield 'It returns a generated name if it cannot be determined' => [
<<<'EOT'
<?php
class AAA
{
}
$foo = new AAA();
$foo->b<>ar($foo->bob(), $foo->zed());
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('argument0', $arguments->first()->guessName());
self::assertEquals('argument1', $arguments->last()->guessName());
},
$foo = new AAA();
$foo->b<>ar($foo->bob(), $foo->zed());
EOT
, [
],
'It returns the argument type' => [
<<<'EOT'
<?php
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('argument0', $arguments->first()->guessName());
self::assertEquals('argument1', $arguments->last()->guessName());
},
];
yield 'It returns the argument type' => [
<<<'EOT'
<?php
$integer = 1;
$foo->b<>ar($integer);
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('1', (string) $arguments->first()->type());
},
$integer = 1;
$foo->b<>ar($integer);
EOT
, [
],
'It returns the value' => [
<<<'EOT'
<?php
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals('1', (string) $arguments->first()->type());
},
];
yield 'It returns the value' => [
<<<'EOT'
<?php
$integer = 1;
$foo->b<>ar($integer);
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals(1, $arguments->first()->value());
},
$integer = 1;
$foo->b<>ar($integer);
EOT
, [
],
'It returns the position' => [
<<<'EOT'
<?php
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals(1, $arguments->first()->value());
},
];
yield 'It returns the position' => [
<<<'EOT'
<?php
$foo->b<>ar($integer);
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals(17, $arguments->first()->position()->start()->toInt());
self::assertEquals(25, $arguments->first()->position()->end()->toInt());
},
$foo->b<>ar($integer);
EOT
, [
],
function (ReflectionArgumentCollection $arguments): void {
self::assertEquals(17, $arguments->first()->position()->start()->toInt());
self::assertEquals(25, $arguments->first()->position()->end()->toInt());
},
];
yield 'It infers named parameters' => [
<<<'EOT'
Expand Down
Loading

0 comments on commit c2e2fa3

Please sign in to comment.