diff --git a/lib/extension/RexFunctionsDynamicReturnTypeExtension.php b/lib/extension/RexFunctionsDynamicReturnTypeExtension.php index 19535e484..4986425a7 100644 --- a/lib/extension/RexFunctionsDynamicReturnTypeExtension.php +++ b/lib/extension/RexFunctionsDynamicReturnTypeExtension.php @@ -7,6 +7,7 @@ use PhpParser\Node\Arg; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Scalar\String_; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\MethodReflection; @@ -74,14 +75,17 @@ private function getType(array $args, Scope $scope): ?Type return null; } - $defaultArgType = new ConstantStringType(''); + $results = []; if (count($args) >= 3) { $defaultArgType = $scope->getType($args[2]->value); + $defaultArgTypeStrings = $defaultArgType->getConstantStrings(); + if (count($defaultArgTypeStrings) !== 1 || $defaultArgTypeStrings[0]->getValue() !== '') { + $results[] = $defaultArgType; + } } $typeStrings = $scope->getType($args[1]->value)->getConstantStrings(); if (count($typeStrings) > 0) { - $results = []; foreach ($typeStrings as $typeString) { $resolvedType = $this->resolveTypeFromString($typeString->getValue()); if ($resolvedType === null) { @@ -91,7 +95,7 @@ private function getType(array $args, Scope $scope): ?Type $results[] = $resolvedType; } - return TypeCombinator::union($defaultArgType, ...$results); + return TypeCombinator::union(...$results); } return null; diff --git a/tests/data/rex-sapi.php b/tests/data/rex-sapi.php index 594024b8f..e77c496fc 100644 --- a/tests/data/rex-sapi.php +++ b/tests/data/rex-sapi.php @@ -30,11 +30,19 @@ function doBar() function doFooBar() { assertType('string', rex_get('HTTP_REFERER', 'string', '')); - assertType("''|int", rex_get('HTTP_REFERER', 'int', '')); - assertType("''|int", rex_get('HTTP_REFERER', 'integer', '')); - assertType("''|float", rex_get('HTTP_REFERER', 'float', '')); - assertType("''|float", rex_get('HTTP_REFERER', 'double', '')); - assertType("''|float", rex_get('HTTP_REFERER', 'real', '')); - assertType("''|bool", rex_get('HTTP_REFERER', 'bool', '')); - assertType("''|bool", rex_get('HTTP_REFERER', 'boolean', '')); + assertType('int', rex_get('HTTP_REFERER', 'int', '')); + assertType('int', rex_get('HTTP_REFERER', 'integer', '')); + assertType('float', rex_get('HTTP_REFERER', 'float', '')); + assertType('float', rex_get('HTTP_REFERER', 'double', '')); + assertType('float', rex_get('HTTP_REFERER', 'real', '')); + assertType('bool', rex_get('HTTP_REFERER', 'bool', '')); + assertType('bool', rex_get('HTTP_REFERER', 'boolean', '')); +} + +function doQux() +{ + assertType('int', rex_get('HTTP_REFERER', 'int', 1)); + assertType('int|null', rex_get('HTTP_REFERER', 'int', null)); + assertType("'foo'|int", rex_get('HTTP_REFERER', 'int', 'foo')); + assertType("'foo'|int", rex_get('HTTP_REFERER', 'int', rand(0,1) ? 'foo' : '')); }