Skip to content

Commit ef09fcd

Browse files
Add BrowserKitAssertionTraitReturnTypeExtension
1 parent 60b312d commit ef09fcd

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ services:
193193
factory: PHPStan\Type\Symfony\EnvelopeReturnTypeExtension
194194
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
195195

196+
# BrowserKitAssertionTrait::getClient() return type
197+
-
198+
class: PHPStan\Type\Symfony\BrowserKitAssertionTraitReturnTypeExtension
199+
tags: [phpstan.broker.expressionTypeResolverExtension]
200+
196201
# Messenger HandleTrait::handle() return type
197202
-
198203
class: PHPStan\Type\Symfony\MessengerHandleTraitReturnTypeExtension
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PhpParser\Node\Expr;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PhpParser\Node\Identifier;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Type\ExpressionTypeResolverExtension;
10+
use PHPStan\Type\ObjectType;
11+
use PHPStan\Type\Type;
12+
use function count;
13+
14+
final class BrowserKitAssertionTraitReturnTypeExtension implements ExpressionTypeResolverExtension
15+
{
16+
17+
private const TRAIT_NAME = 'Symfony\Bundle\FrameworkBundle\Test\BrowserKitAssertionsTrait';
18+
private const TRAIT_METHOD_NAME = 'getClient';
19+
20+
public function getType(Expr $expr, Scope $scope): ?Type
21+
{
22+
if ($this->isSupported($expr, $scope)) {
23+
$args = $expr->getArgs();
24+
if (count($args) > 0) {
25+
return $scope->getType($args[0]->value);
26+
}
27+
28+
return new ObjectType('Symfony\Component\BrowserKit\AbstractBrowser');
29+
}
30+
31+
return null;
32+
}
33+
34+
/**
35+
* @phpstan-assert-if-true =MethodCall $expr
36+
*/
37+
private function isSupported(Expr $expr, Scope $scope): bool
38+
{
39+
if (!($expr instanceof MethodCall) || !($expr->name instanceof Identifier) || $expr->name->name !== self::TRAIT_METHOD_NAME) {
40+
return false;
41+
}
42+
43+
if (!$scope->isInClass()) {
44+
return false;
45+
}
46+
47+
$reflectionClass = $scope->getClassReflection()->getNativeReflection();
48+
49+
if (!$reflectionClass->hasMethod(self::TRAIT_METHOD_NAME)) {
50+
return false;
51+
}
52+
53+
$methodReflection = $reflectionClass->getMethod(self::TRAIT_METHOD_NAME);
54+
$declaringClassReflection = $methodReflection->getBetterReflection()->getDeclaringClass();
55+
56+
return $declaringClassReflection->getName() === self::TRAIT_NAME;
57+
}
58+
59+
}

tests/Type/Symfony/ExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ExtensionTest extends TypeInferenceTestCase
1414
/** @return mixed[] */
1515
public function dataFileAsserts(): iterable
1616
{
17+
yield from $this->gatherAssertTypes(__DIR__ . '/data/browserkit_assertion_trait.php');
1718
yield from $this->gatherAssertTypes(__DIR__ . '/data/messenger_handle_trait.php');
1819
yield from $this->gatherAssertTypes(__DIR__ . '/data/envelope_all.php');
1920
yield from $this->gatherAssertTypes(__DIR__ . '/data/header_bag_get.php');
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace BrowserKitAssertionTrait;
4+
5+
use Symfony\Bundle\FrameworkBundle\Test\BrowserKitAssertionsTrait;
6+
use Symfony\Component\BrowserKit\AbstractBrowser;
7+
use function PHPStan\Testing\assertType;
8+
9+
class Foo {
10+
use BrowserKitAssertionsTrait;
11+
12+
public function test(AbstractBrowser $browser, ?AbstractBrowser $nullableBrowser)
13+
{
14+
assertType('Symfony\Component\BrowserKit\AbstractBrowser', $this->getClient());
15+
assertType('null', $this->getClient(null));
16+
assertType('Symfony\Component\BrowserKit\AbstractBrowser', $this->getClient($browser));
17+
assertType('Symfony\Component\BrowserKit\AbstractBrowser|null', $this->getClient($nullableBrowser));
18+
}
19+
}

0 commit comments

Comments
 (0)