2021-08-03 15:50:33 +02:00
< ? php
2021-12-15 04:58:32 +01:00
2021-08-03 15:50:33 +02:00
namespace Psalm\Tests\TypeReconciliation ;
2021-12-03 20:11:20 +01:00
use Psalm\Tests\TestCase ;
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait ;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait ;
2021-08-03 15:50:33 +02:00
use const DIRECTORY_SEPARATOR ;
2021-12-03 20:11:20 +01:00
class InArrayTest extends TestCase
2021-08-03 15:50:33 +02:00
{
2021-12-03 20:11:20 +01:00
use ValidCodeAnalysisTestTrait ;
use InvalidCodeAnalysisTestTrait ;
2021-08-03 15:50:33 +02:00
/**
* @ return iterable < string , array { string , assertions ? : array < string , string > , error_levels ? : string []} >
*/
public function providerValidCodeParse () : iterable
{
return [
'nullTypeRemovedAfterNegatedAssertionAgainstArrayOfInt' => [
' < ? php
/**
* @ param int | null $x
* @ return int
*/
function assertInArray ( $x ) {
if ( ! in_array ( $x , range ( 0 , 5 ), true )) {
throw new \Exception ();
}
return $x ;
} ' ,
],
'nullTypeRemovedAfterAssertionAgainstArrayOfInt' => [
' < ? php
/**
* @ param int | null $x
* @ param non - empty - list < int > $y
2021-08-13 00:27:28 +02:00
* @ return int
2021-08-03 15:50:33 +02:00
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
2021-08-13 00:27:28 +02:00
return $x ;
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
throw new \Exception ();
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
' ,
2021-08-03 15:50:33 +02:00
],
'typeNotChangedAfterAssertionAgainstArrayOfMixed' => [
' < ? php
/**
* @ param int | null $x
* @ param list < mixed > $y
* @ return int | null
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
throw new \Exception ();
}
return $x ;
} ' ,
],
'unionTypeReconciledToUnionTypeOfHaystackValueTypes' => [
' < ? php
/**
* @ param int | string | bool $x
* @ param non - empty - list < int | string > $y
2021-08-13 00:27:28 +02:00
* @ return int | string
2021-08-03 15:50:33 +02:00
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
2021-08-13 00:27:28 +02:00
return $x ;
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
throw new \Exception ();
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
' ,
2021-08-03 15:50:33 +02:00
],
2021-08-03 20:09:59 +02:00
'unionTypesReducedToIntersectionWithinAssertion' => [
' < ? php
/**
* @ param int | bool $x
* @ param non - empty - list < int | string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
return $x ;
}
throw new Exception ();
} ' ,
],
'unionTypesReducedToIntersectionOutsideOfNegatedAssertion' => [
' < ? php
/**
* @ param int | bool $x
* @ param non - empty - list < int | string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
throw new Exception ();
}
return $x ;
} ' ,
],
2021-08-05 15:42:37 +02:00
'assertInArrayOfNotIntersectingTypeReturnsOriginalTypeOutsideOfAssertion' => [
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
throw new \Exception ();
}
return $x ;
} ' ,
'assertions' => [],
2021-12-12 18:00:02 +01:00
'error_level' => [ 'RedundantConditionGivenDocblockType' , 'DocblockTypeContradiction' ],
2021-08-05 15:42:37 +02:00
],
'assertNegatedInArrayOfNotIntersectingTypeReturnsOriginalType' => [
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
return $x ;
}
throw new \Exception ();
} ' ,
'assertions' => [],
'error_level' => [ 'RedundantConditionGivenDocblockType' ],
],
'assertAgainstListOfLiteralsAndScalarUnion' => [
' < ? php
/**
* @ param string | bool $x
2021-08-13 00:27:28 +02:00
* @ param non - empty - list < " a " | " b " | int > $y
* @ return " a " | " b "
2021-08-05 15:42:37 +02:00
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
return $x ;
}
throw new Exception ();
} ' ,
],
'assertAgainstListOfLiteralsAndScalarUnionTypeHint' => [
' < ? php
/**
2021-08-13 00:27:28 +02:00
* @ param non - empty - list < " a " | " b " | int > $y
* @ return " a " | " b "
2021-08-05 15:42:37 +02:00
*/
function assertInArray ( string | bool $x , $y ) {
if ( in_array ( $x , $y , true )) {
return $x ;
}
throw new Exception ();
} ' ,
[],
[],
'8.0'
],
2021-09-04 18:28:34 +02:00
'in_arrayNullOrString' => [
' < ? php
function test ( ? string $x , string $y ) : void {
if ( in_array ( $x , [ null , $y ], true )) {
if ( $x === null ) {
echo " Saw null \n " ;
}
echo " Saw $x\n " ;
}
} ' ,
[],
[],
'8.0'
],
'in_array-mixed-twice' => [
' < ? php
function contains ( array $list1 , array $list2 , mixed $element ) : void
{
if ( in_array ( $element , $list1 , true )) {
} elseif ( in_array ( $element , $list2 , true )) {
}
} ' ,
[],
[],
'8.0'
],
2021-09-06 22:05:56 +02:00
'in_array-string-twice' => [
' < ? php
/**
* @ param string [] $list1
* @ param string [] $list2
*/
function contains ( array $list1 , array $list2 , string $element ) : void
{
if ( in_array ( $element , $list1 , true )) {
} elseif ( in_array ( $element , $list2 , true )) {
}
} ' ,
[],
[],
'8.0'
],
2021-09-07 03:42:56 +02:00
'in_array-keyed-array-string-twice' => [
' < ? php
function contains ( string $a , string $b , mixed $element ) : void
{
if ( in_array ( $element , [ $a ], true )) {
} elseif ( in_array ( $element , [ $b ], true )) {
}
} ' ,
[],
[],
'8.0'
],
2021-08-03 15:50:33 +02:00
];
}
/**
* @ return iterable < string , array { string , error_message : string , 1 ? : string [], 2 ? : bool , 3 ? : string } >
*/
public function providerInvalidCodeParse () : iterable
{
return [
'typeNotChangedAfterNegatedAssertionAgainstUnsealedArrayOfMixed' => [
' < ? php
/**
* @ param int | null $x
* @ param non - empty - list < mixed > $y
2021-08-13 00:27:28 +02:00
* @ return int
2021-08-03 15:50:33 +02:00
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
2021-08-13 00:27:28 +02:00
return $x ;
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
throw new \Exception ();
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
' ,
'error_message' => 'NullableReturnStatement' ,
2021-08-03 15:50:33 +02:00
],
'typeNotChangedAfterNegatedAssertionAgainstUnsealedArrayOfUnionType' => [
' < ? php
/**
* @ param int | null $x
* @ param non - empty - list < int | null > $y
2021-08-13 00:27:28 +02:00
* @ return int
2021-08-03 15:50:33 +02:00
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
2021-08-13 00:27:28 +02:00
return $x ;
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
throw new \Exception ();
2021-08-03 15:50:33 +02:00
}
2021-08-13 00:27:28 +02:00
' ,
'error_message' => 'NullableReturnStatement' ,
2021-08-03 15:50:33 +02:00
],
2021-08-03 20:09:59 +02:00
'initialTypeRemainsOutsideOfAssertion' => [
' < ? php
/**
* @ param int | bool $x
* @ param non - empty - list < int | string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
throw new Exception ();
}
return $x ;
} ' ,
'error_message' => 'InvalidReturnStatement - src' . DIRECTORY_SEPARATOR . 'somefile.php:11:32 - The inferred type \'bool|int\' does not match the declared return type \'int\' for assertInArray' ,
],
'initialTypeRemainsWithinTheNegatedAssertion' => [
' < ? php
/**
* @ param int | bool $x
* @ param non - empty - list < int | string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
return $x ;
}
throw new Exception ();
} ' ,
'error_message' => 'InvalidReturnStatement - src' . DIRECTORY_SEPARATOR . 'somefile.php:9:36 - The inferred type \'bool|int\' does not match the declared return type \'int\' for assertInArray' ,
],
2021-08-05 15:42:37 +02:00
'assertInArrayOfNotIntersectingTypeTriggersTypeContradiction' => [
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
throw new \Exception ();
}
return $x ;
} ' ,
2021-12-12 18:00:02 +01:00
'error_message' => 'DocblockTypeContradiction - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:29 - Operand of type false is always false' ,
2021-08-05 15:42:37 +02:00
],
'assertNegatedInArrayOfNotIntersectingTypeTriggersRedundantCondition' => [
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return int
*/
function assertInArray ( $x , $y ) {
if ( ! in_array ( $x , $y , true )) {
return $x ;
}
throw new \Exception ();
} ' ,
2021-12-12 18:00:02 +01:00
'error_message' => 'RedundantConditionGivenDocblockType - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:29 - Operand of type true is always true' ,
2021-08-05 15:42:37 +02:00
],
2021-12-12 18:00:02 +01:00
'assertInArrayOfNotIntersectingTypeTriggersDocblockTypeContradiction' => [
2021-08-05 15:42:37 +02:00
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return string
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
return $x ;
}
throw new \Exception ();
} ' ,
2021-12-12 18:00:02 +01:00
'error_message' => 'DocblockTypeContradiction - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:29 - Operand of type false is always false' ,
2021-08-05 15:42:37 +02:00
],
2021-12-12 18:00:02 +01:00
'assertInArrayOfNotIntersectingTypeReturnsTriggersDocblockTypeContradiction' => [
2021-08-05 15:42:37 +02:00
' < ? php
/**
* @ param int $x
* @ param list < string > $y
* @ return string
*/
function assertInArray ( $x , $y ) {
if ( in_array ( $x , $y , true )) {
return $x ;
}
throw new \Exception ();
} ' ,
2021-12-12 18:00:02 +01:00
'error_message' => 'DocblockTypeContradiction - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:29 - Operand of type false is always false' ,
2021-08-05 15:42:37 +02:00
'error_levels' => [ 'RedundantConditionGivenDocblockType' ],
],
2021-09-07 03:42:56 +02:00
'inArrayDetectType' => [
' < ? php
function x ( $foo , string $bar ) : void {
if ( ! in_array ( $foo , [ $bar ], true )) {
throw new Exception ();
}
if ( is_string ( $foo )) {}
} ' ,
// foo is always string
'error_message' => 'RedundantCondition' ,
],
'inArrayRemoveInvalid' => [
' < ? php
function x ( ? string $foo , int $bar ) : void {
if ( ! in_array ( $foo , [ $bar ], true )) {
throw new Exception ();
}
} ' ,
// Type null|string is never int
'error_message' => 'RedundantCondition' ,
],
2021-08-03 15:50:33 +02:00
];
}
}