From b9665c302f172e4cf10e211d9b8be97a319f6776 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 30 Aug 2022 09:09:00 +0200 Subject: [PATCH] infer non-falsy-string in string containing functions --- .../StrContainingTypeSpecifyingExtension.php | 8 ++++- .../non-empty-string-str-containing-fns.php | 33 +++++++++++++------ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/Type/Php/StrContainingTypeSpecifyingExtension.php b/src/Type/Php/StrContainingTypeSpecifyingExtension.php index dddbfe73e5..596a1b3dc2 100644 --- a/src/Type/Php/StrContainingTypeSpecifyingExtension.php +++ b/src/Type/Php/StrContainingTypeSpecifyingExtension.php @@ -16,6 +16,7 @@ use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\AccessoryLiteralStringType; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; +use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\FunctionTypeSpecifyingExtension; use PHPStan\Type\IntersectionType; @@ -66,9 +67,14 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n if ($needleType->isNonEmptyString()->yes() && $haystackType->isString()->yes()) { $accessories = [ new StringType(), - new AccessoryNonEmptyStringType(), ]; + if ($needleType->isNonFalsyString()->yes()) { + $accessories[] = new AccessoryNonFalsyStringType(); + } else { + $accessories[] = new AccessoryNonEmptyStringType(); + } + if ($haystackType->isLiteralString()->yes()) { $accessories[] = new AccessoryLiteralStringType(); } diff --git a/tests/PHPStan/Analyser/data/non-empty-string-str-containing-fns.php b/tests/PHPStan/Analyser/data/non-empty-string-str-containing-fns.php index ec0d59d4d2..6b4dce7186 100644 --- a/tests/PHPStan/Analyser/data/non-empty-string-str-containing-fns.php +++ b/tests/PHPStan/Analyser/data/non-empty-string-str-containing-fns.php @@ -7,13 +7,19 @@ class Foo { /** * @param non-empty-string $nonES + * @param non-falsy-string $nonFalsy * @param numeric-string $numS * @param literal-string $literalS * @param non-empty-string&numeric-string $nonEAndNumericS */ - public function strContains(string $s, string $s2, $nonES, $numS, $literalS, $nonEAndNumericS, int $i): void + public function strContains(string $s, string $s2, $nonES, $nonFalsy, $numS, $literalS, $nonEAndNumericS, int $i): void { if (str_contains($s, ':')) { + assertType('non-falsy-string', $s); + } + assertType('string', $s); + + if (str_contains($s, '0')) { assertType('non-empty-string', $s); } assertType('string', $s); @@ -49,26 +55,33 @@ public function strContains(string $s, string $s2, $nonES, $numS, $literalS, $no if (str_contains($i, $s2)) { assertType('int', $i); } + + if (str_contains($s, $nonFalsy)) { + assertType('non-falsy-string', $s); + } + if (str_contains($numS, $nonFalsy)) { + assertType('non-falsy-string&numeric-string', $numS); + } } public function variants(string $s) { if (fnmatch("*gr[ae]y", $s)) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (str_starts_with($s, ':')) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (str_ends_with($s, ':')) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (strpos($s, ':') !== false) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (strpos($s, ':') === false) { @@ -86,17 +99,17 @@ public function variants(string $s) { assertType('string', $s); if (strrpos($s, ':') !== false) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (stripos($s, ':') !== false) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (strripos($s, ':') !== false) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); @@ -109,13 +122,13 @@ public function variants(string $s) { } assertType('string', $s); if (strstr($s, ':', true) !== false) { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); if (strstr($s, ':', true) === false) { assertType('string', $s); } else { - assertType('non-empty-string', $s); + assertType('non-falsy-string', $s); } assertType('string', $s); }