From 0f6720e59f3b0a121d0b1af24e5e3cd256ae483d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 23 Mar 2022 10:15:58 +0100 Subject: [PATCH] Support non-empty-array in InArrayFunctionTypeSpecifyingExtension --- ...InArrayFunctionTypeSpecifyingExtension.php | 24 +++++++++++++++---- .../Analyser/NodeScopeResolverTest.php | 5 ++++ .../Analyser/data/in-array-non-empty-php8.php | 20 ++++++++++++++++ .../Analyser/data/in-array-non-empty.php | 20 ++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/in-array-non-empty-php8.php create mode 100644 tests/PHPStan/Analyser/data/in-array-non-empty.php diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php index 98576400ef2..f7421e05f19 100644 --- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php @@ -9,8 +9,10 @@ use PHPStan\Analyser\TypeSpecifierAwareExtension; use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\FunctionReflection; +use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\FunctionTypeSpecifyingExtension; +use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeUtils; use function count; use function strtolower; @@ -41,22 +43,36 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes([], []); } - $arrayValueType = $scope->getType($node->getArgs()[1]->value)->getIterableValueType(); + $arrayType = $scope->getType($node->getArgs()[1]->value); + $arrayValueType = $arrayType->getIterableValueType(); + + $specifiedTypes = new SpecifiedTypes([], []); + if ($context->true()) { + $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); + + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + $node->getArgs()[1]->value, + $arrayType, + $context, + false, + $scope, + )); + } if ( $context->truthy() || count(TypeUtils::getConstantScalars($arrayValueType)) > 0 ) { - return $this->typeSpecifier->create( + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( $node->getArgs()[0]->value, $arrayValueType, $context, false, $scope, - ); + )); } - return new SpecifiedTypes([], []); + return $specifiedTypes; } } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index de5a6ea9241..3545faad297 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -810,6 +810,11 @@ public function dataFileAsserts(): iterable if (PHP_VERSION_ID >= 80100) { yield from $this->gatherAssertTypes(__DIR__ . '/data/value-of-enum.php'); } + + yield from $this->gatherAssertTypes(__DIR__ . '/data/in-array-non-empty.php'); + if (PHP_VERSION_ID >= 80000) { + yield from $this->gatherAssertTypes(__DIR__ . '/data/in-array-non-empty-php8.php'); + } yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6584.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6439.php'); diff --git a/tests/PHPStan/Analyser/data/in-array-non-empty-php8.php b/tests/PHPStan/Analyser/data/in-array-non-empty-php8.php new file mode 100644 index 00000000000..31840243a7b --- /dev/null +++ b/tests/PHPStan/Analyser/data/in-array-non-empty-php8.php @@ -0,0 +1,20 @@ += 8.0 + +declare(strict_types = 1); + +namespace InArrayNonEmptyPhp8; + +use function PHPStan\Testing\assertType; + +class HelloWorld +{ + /** + * @phpstan-param list $array + */ + public function sayHello(array $array): void + { + if(in_array(haystack: $array, needle: "thing", strict: true)){ + assertType('non-empty-array', $array); + } + } +} diff --git a/tests/PHPStan/Analyser/data/in-array-non-empty.php b/tests/PHPStan/Analyser/data/in-array-non-empty.php new file mode 100644 index 00000000000..abedc545385 --- /dev/null +++ b/tests/PHPStan/Analyser/data/in-array-non-empty.php @@ -0,0 +1,20 @@ + $array + */ + public function sayHello(array $array): void + { + if(in_array("thing", $array, true)){ + assertType('non-empty-array', $array); + } + } +}