Skip to content

Commit

Permalink
Correct hash function stub return type
Browse files Browse the repository at this point in the history
  • Loading branch information
Synchro committed Oct 14, 2020
1 parent 5f2d42c commit 41c4e02
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 1 deletion.
5 changes: 5 additions & 0 deletions conf/config.neon
Expand Up @@ -895,6 +895,11 @@ services:
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension

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

-
class: PHPStan\Type\Php\SimpleXMLElementClassPropertyReflectionExtension
tags:
Expand Down
2 changes: 1 addition & 1 deletion resources/functionMap.php
Expand Up @@ -3906,7 +3906,7 @@
'HaruPage::stroke' => ['bool', 'close_path='=>'bool'],
'HaruPage::textOut' => ['bool', 'x'=>'float', 'y'=>'float', 'text'=>'string'],
'HaruPage::textRect' => ['bool', 'left'=>'float', 'top'=>'float', 'right'=>'float', 'bottom'=>'float', 'text'=>'string', 'align='=>'int'],
'hash' => ['string', 'algo'=>'string', 'data'=>'string', 'raw_output='=>'bool'],
'hash' => ['string|false', 'algo'=>'string', 'data'=>'string', 'raw_output='=>'bool'],
'hash_algos' => ['array'],
'hash_copy' => ['HashContext', 'context'=>'HashContext'],
'hash_equals' => ['bool', 'known_string'=>'string', 'user_string'=>'string'],
Expand Down
46 changes: 46 additions & 0 deletions src/Type/Php/HashFunctionsReturnTypeExtension.php
@@ -0,0 +1,46 @@
<?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\Constant\ConstantBooleanType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\MixedType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;

final class HashFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{

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

public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
{
$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();

if (!isset($functionCall->args[0])) {
return $defaultReturnType;
}

$argType = $scope->getType($functionCall->args[0]->value);
if ($argType instanceof MixedType) {
return TypeUtils::toBenevolentUnion($defaultReturnType);
}

$values = TypeUtils::getConstantStrings($argType);
if (count($values) !== 1) {
return TypeUtils::toBenevolentUnion($defaultReturnType);
}
$string = $values[0];

return in_array($string->getValue(), hash_algos(), true) ? new StringType() : new ConstantBooleanType(false);
}

}
16 changes: 16 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -5954,6 +5954,22 @@ public function dataFunctions(): array
'(string|false)',
'$hashHmacFileVariable',
],
[
'string',
'$hash',
],
[
'string',
'$hashRaw',
],
[
'false',
'$hashRandom',
],
[
'string',
'$hashMixed',
],
];
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/data/functions.php
Expand Up @@ -135,4 +135,10 @@
$hashHmacFileRandom = hash_hmac_file('random', 'data', 'key');
$hashHmacFileVariable = hash_hmac_file($string, 'data', 'key');

$hash = hash('sha256', 'data', false);
$hashRaw = hash('sha256', 'data', true);
$hashRandom = hash('random', 'data', false);
/** @var mixed $mixed */
$mixed = doFoo();
$hashMixed = hash('md5', $mixed, false);
die;

0 comments on commit 41c4e02

Please sign in to comment.