Skip to content

Commit

Permalink
Fixed preserving non-empty array in array_reverse()
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 20, 2021
1 parent 0f72505 commit 3ccc152
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 7 deletions.
5 changes: 5 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,11 @@ services:
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension

-
class: PHPStan\Type\Php\ArrayReverseFunctionReturnTypeExtension
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension

-
class: PHPStan\Type\Php\ArrayShiftFunctionReturnTypeExtension
tags:
Expand Down
1 change: 0 additions & 1 deletion src/Type/Php/ArgumentBasedFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class ArgumentBasedFunctionReturnTypeExtension implements \PHPStan\Type\DynamicF
/** @var int[] */
private array $functionNames = [
'array_unique' => 0,
'array_reverse' => 0,
'array_change_key_case' => 0,
'array_diff_assoc' => 0,
'array_diff_key' => 0,
Expand Down
29 changes: 29 additions & 0 deletions src/Type/Php/ArrayReverseFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Php;

use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\Type;

class ArrayReverseFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{

public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'array_reverse';
}

public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
{
if (!isset($functionCall->args[0])) {
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
}

return $scope->getType($functionCall->args[0]->value);
}

}
10 changes: 6 additions & 4 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4983,10 +4983,6 @@ public function dataArrayFunctions(): array
'1',
'$reducedToInt',
],
[
'1|2|3',
'$reversedIntegers[0]',
],
[
'array<0|1|2, 1|2|3>',
'array_change_key_case($integers)',
Expand Down Expand Up @@ -10725,6 +10721,11 @@ public function dataClosureReturnType(): array
return $this->gatherAssertTypes(__DIR__ . '/data/closure-return-type.php');
}

public function dataBug4398(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4398.php');
}

/**
* @param string $file
* @return array<string, mixed[]>
Expand Down Expand Up @@ -10935,6 +10936,7 @@ private function gatherAssertTypes(string $file): array
* @dataProvider dataVarAboveUse
* @dataProvider dataVarAboveDeclare
* @dataProvider dataClosureReturnType
* @dataProvider dataBug4398
* @param string $assertType
* @param string $file
* @param mixed ...$args
Expand Down
2 changes: 0 additions & 2 deletions tests/PHPStan/Analyser/data/array-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@

}, 1);

$reversedIntegers = array_reverse($integers);

$filledIntegers = array_fill(0, 5, 1);
$filledIntegersWithKeys = array_fill_keys([0], 1);

Expand Down
18 changes: 18 additions & 0 deletions tests/PHPStan/Analyser/data/bug-4398.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Bug4398;

use function PHPStan\Analyser\assertType;

function (array $meters): void {
assertType('array', $meters);
if (empty($meters)) {
throw new \Exception('NO_METERS_FOUND');
}

assertType('array&nonEmpty', $meters);
assertType('array', array_reverse());
assertType('array&nonEmpty', array_reverse($meters));
assertType('array<int, (int|string)>&nonEmpty', array_keys($meters));
assertType('array<int, mixed>&nonEmpty', array_values($meters));
};

0 comments on commit 3ccc152

Please sign in to comment.