Skip to content

Commit

Permalink
fix: add AssertReturnDynamicFunctionReturnTypeExtension
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod committed May 22, 2024
1 parent 00809e5 commit e20f15d
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 12 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"infection/infection": "^0.28.0",
"php-ds/php-ds": "^1.4",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.3",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpunit/phpunit": "^11.0",
"shipmonk/composer-dependency-analyser": "^1.5"
Expand Down
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<rule ref="Cdn77" />

<file>composer-dependency-analyser.php</file>
<file>phpstan/</file>
<file>src/</file>
<file>tests/</file>
</ruleset>
5 changes: 5 additions & 0 deletions phpstan-extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ services:
class: Cdn77\Functions\PHPStan\AssertReturnFunctionTypeSpecifyingExtension
tags:
- phpstan.typeSpecifier.functionTypeSpecifyingExtension

-
class: Cdn77\Functions\PHPStan\AssertReturnDynamicFunctionReturnTypeExtension
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension
52 changes: 52 additions & 0 deletions phpstan/AssertReturnDynamicFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Cdn77\Functions\PHPStan;

use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Analyser\TypeSpecifier;
use PHPStan\Analyser\TypeSpecifierAwareExtension;
use PHPStan\Analyser\TypeSpecifierContext;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\Type;

use function assert;

final class AssertReturnDynamicFunctionReturnTypeExtension implements
DynamicFunctionReturnTypeExtension,
TypeSpecifierAwareExtension
{
private TypeSpecifier $typeSpecifier;

public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'Cdn77\Functions\assert_return';
}

public function getTypeFromFunctionCall(
FunctionReflection $functionReflection,
FuncCall $functionCall,
Scope $scope,
): Type|null {
$arg1 = $functionCall->getArgs()[1]->value;
assert($arg1 instanceof FuncCall, 'Second argument of assert_return must be a function call');

$call = new FuncCall($arg1->name, [$functionCall->getArgs()[0]], $arg1->getAttributes());

$specifiedTypes = $this->typeSpecifier->specifyTypesInCondition(
$scope,
$call,
TypeSpecifierContext::createTruthy(),
);

return $specifiedTypes->getSureTypes()['$value'][1] ?? null;
}

public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
{
$this->typeSpecifier = $typeSpecifier;
}
}
33 changes: 23 additions & 10 deletions phpstan/AssertReturnFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php declare(strict_types = 1);
<?php

declare(strict_types=1);

namespace Cdn77\Functions\PHPStan;

Expand All @@ -11,27 +13,38 @@
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\FunctionTypeSpecifyingExtension;

class AssertReturnFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension
use function assert;

final class AssertReturnFunctionTypeSpecifyingExtension implements
FunctionTypeSpecifyingExtension,
TypeSpecifierAwareExtension
{
private TypeSpecifier $typeSpecifier;

public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool
{
public function isFunctionSupported(
FunctionReflection $functionReflection,
FuncCall $node,
TypeSpecifierContext $context,
): bool {
return $functionReflection->getName() === 'Cdn77\Functions\assert_return';
// && isset($node->getArgs()[0]);
}

public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
{
public function specifyTypes(
FunctionReflection $functionReflection,
FuncCall $node,
Scope $scope,
TypeSpecifierContext $context,
): SpecifiedTypes {
$arg1 = $node->getArgs()[1]->value;
assert($arg1 instanceof FuncCall, 'Second argument of assert_return must be a function call');
$new = new \PhpParser\Node\Expr\FuncCall($arg1->name, [$node->getArgs()[0]], $arg1->getAttributes());
return $this->typeSpecifier->specifyTypesInCondition($scope, $new, TypeSpecifierContext::createTruthy());

$call = new FuncCall($arg1->name, [$node->getArgs()[0]], $arg1->getAttributes());

return $this->typeSpecifier->specifyTypesInCondition($scope, $call, TypeSpecifierContext::createTruthy());
}

public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
{
$this->typeSpecifier = $typeSpecifier;
}

}
3 changes: 2 additions & 1 deletion tests/AssertTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ public function testAssertReturn(): void

public function phpstanType(mixed $value): void
{
$_ = assert_return($value, is_int(...));
$return = assert_return($value, is_int(...));

assertType('int', $value);
assertType('int', $return);
}
}

0 comments on commit e20f15d

Please sign in to comment.