Skip to content

Commit

Permalink
Fix-GH-12021
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-worman committed Dec 5, 2024
1 parent 28dfac8 commit 620c8b2
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

namespace PHPStan\Type\Php;

use PhpParser\Node\Arg;
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use function count;
use function in_array;
use const ENT_SUBSTITUTE;

final class NonEmptyStringFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{
Expand Down Expand Up @@ -45,6 +48,15 @@ public function getTypeFromFunctionCall(
return null;
}

if (in_array($functionReflection->getName(), [
'htmlspecialchars',
'htmlentities',
], true)) {
if (!$this->isSubstituteFlagSet($args, $scope)) {
return new StringType();
}
}

$argType = $scope->getType($args[0]->value);
if ($argType->isNonFalsyString()->yes()) {
return new IntersectionType([
Expand All @@ -62,4 +74,22 @@ public function getTypeFromFunctionCall(
return new StringType();
}

/**
* @param Arg[] $args
*/
private function isSubstituteFlagSet(
array $args,
Scope $scope,
): bool
{
if (!isset($args[1])) {
return true;
}
$flagsType = $scope->getType($args[1]->value);
if (!$flagsType instanceof ConstantIntegerType) {
return false;
}
return (bool) ($flagsType->getValue() & ENT_SUBSTITUTE);
}

}
9 changes: 9 additions & 0 deletions tests/PHPStan/Analyser/nsrt/non-empty-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use function strtolower;
use function strtoupper;
use function ucfirst;
use const ENT_SUBSTITUTE;

class Foo
{
Expand Down Expand Up @@ -333,9 +334,17 @@ public function doFoo(string $s, string $nonEmpty, string $nonFalsy, int $i, boo
assertType('string', ucwords($s));
assertType('non-empty-string', ucwords($nonEmpty));
assertType('string', htmlspecialchars($s));
assertType('string', htmlspecialchars($s, ENT_SUBSTITUTE));
assertType('string', htmlspecialchars($s, 0));
assertType('non-empty-string', htmlspecialchars($nonEmpty));
assertType('non-empty-string', htmlspecialchars($nonEmpty, ENT_SUBSTITUTE));
assertType('string', htmlspecialchars($nonEmpty, 0));
assertType('string', htmlentities($s));
assertType('string', htmlentities($s, ENT_SUBSTITUTE));
assertType('string', htmlentities($s, 0));
assertType('non-empty-string', htmlentities($nonEmpty));
assertType('non-empty-string', htmlentities($nonEmpty, ENT_SUBSTITUTE));
assertType('string', htmlentities($nonEmpty, 0));

assertType('string', urlencode($s));
assertType('non-empty-string', urlencode($nonEmpty));
Expand Down
5 changes: 5 additions & 0 deletions tests/PHPStan/Analyser/nsrt/non-falsy-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace NonFalseyString;

use function PHPStan\Testing\assertType;
use const ENT_SUBSTITUTE;

class Foo {
/**
Expand Down Expand Up @@ -95,7 +96,11 @@ function stringFunctions(string $s, $nonFalsey, $arrayOfNonFalsey, $nonEmptyArra
assertType('non-falsy-string', ucfirst($nonFalsey));
assertType('non-falsy-string', ucwords($nonFalsey));
assertType('non-falsy-string', htmlspecialchars($nonFalsey));
assertType('non-falsy-string', htmlspecialchars($nonFalsey, ENT_SUBSTITUTE));
assertType('string', htmlspecialchars($nonFalsey, 0));
assertType('non-falsy-string', htmlentities($nonFalsey));
assertType('non-falsy-string', htmlentities($nonFalsey, ENT_SUBSTITUTE));
assertType('string', htmlentities($nonFalsey, 0));

assertType('non-falsy-string', urlencode($nonFalsey));
assertType('non-falsy-string', urldecode($nonFalsey));
Expand Down

0 comments on commit 620c8b2

Please sign in to comment.