Skip to content

Commit

Permalink
Correctly account for an unknown parameter type.
Browse files Browse the repository at this point in the history
  • Loading branch information
johnbillion committed Feb 1, 2022
1 parent 6765ea4 commit a2c88f4
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 10 deletions.
39 changes: 29 additions & 10 deletions src/Type/Php/RoundFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\NullType;
use PHPStan\Type\Type;
Expand All @@ -31,28 +33,45 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo

public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
{
$defaultReturnType = new FloatType();
if (PHP_VERSION_ID >= 80000) {
// PHP 8 fatals with a missing parameter.
$noArgsReturnType = new NeverType(true);
// PHP 7 can return either a float or fatal.
$defaultReturnType = new BenevolentUnionType([
new FloatType(),
new NeverType(true),
]);
} else {
// PHP 7 returns null with a missing parameter.
$noArgsReturnType = new NullType();
// PHP 7 can return either a float or false.
$defaultReturnType = new BenevolentUnionType([
new FloatType(),
new ConstantBooleanType(false),
]);
}

if (count($functionCall->getArgs()) < 1) {
if (PHP_VERSION_ID >= 80000) {
return new NeverType(true);
} else {
return new NullType();
}
return $noArgsReturnType;
}

$firstArgType = $scope->getType($functionCall->getArgs()[0]->value);

if ($firstArgType instanceof MixedType) {
return $defaultReturnType;
}

if (PHP_VERSION_ID >= 80000) {
if (!($firstArgType instanceof IntegerType) && !($firstArgType instanceof FloatType)) {
// PHP 8 fatals if the parameter is not an integer or float.
return new NeverType(true);
}
}

if ($firstArgType->isArray()->yes()) {
} elseif ($firstArgType->isArray()->yes()) {
// PHP 7 returns false if the parameter is an array.
return new ConstantBooleanType(false);
}

return $defaultReturnType;
return new FloatType();
}

}
3 changes: 3 additions & 0 deletions tests/PHPStan/Analyser/data/round-php8.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
assertType('*NEVER*', round(array()));
assertType('*NEVER*', round(array(123)));
assertType('*NEVER*', round());
assertType('(*NEVER*|float)', round($_GET['foo']));

// Ceil
assertType('float', ceil(123));
Expand All @@ -31,6 +32,7 @@
assertType('*NEVER*', ceil(array()));
assertType('*NEVER*', ceil(array(123)));
assertType('*NEVER*', ceil());
assertType('(*NEVER*|float)', ceil($_GET['foo']));

// Floor
assertType('float', floor(123));
Expand All @@ -45,3 +47,4 @@
assertType('*NEVER*', floor(array()));
assertType('*NEVER*', floor(array(123)));
assertType('*NEVER*', floor());
assertType('(*NEVER*|float)', floor($_GET['foo']));
3 changes: 3 additions & 0 deletions tests/PHPStan/Analyser/data/round.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
assertType('false', round(array()));
assertType('false', round(array(123)));
assertType('null', round());
assertType('(float|false)', round($_GET['foo']));

// Ceil
assertType('float', ceil(123));
Expand All @@ -31,6 +32,7 @@
assertType('false', ceil(array()));
assertType('false', ceil(array(123)));
assertType('null', ceil());
assertType('(float|false)', ceil($_GET['foo']));

// Floor
assertType('float', floor(123));
Expand All @@ -45,3 +47,4 @@
assertType('false', floor(array()));
assertType('false', floor(array(123)));
assertType('null', floor());
assertType('(float|false)', floor($_GET['foo']));

0 comments on commit a2c88f4

Please sign in to comment.