From 2171be01065d3aaae948cd281f0d81affc8e6976 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 22 Aug 2024 12:45:16 +0200 Subject: [PATCH 1/4] Narrow to non-falsy-string from strlen() on integer-range --- .../Analyser/nsrt/strlen-int-range.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/strlen-int-range.php diff --git a/tests/PHPStan/Analyser/nsrt/strlen-int-range.php b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php new file mode 100644 index 0000000000..c9513a1d4e --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php @@ -0,0 +1,34 @@ + $zeroToThree + * @param int<2, 3> $twoOrThree + * @param int<2, max> $twoOrMore + * @param int $maxThree + * @param int<10, 11> $tenOrEleven + */ +function doFoo(string $s, $zeroToThree, $twoOrThree, $twoOrMore, int $maxThree, $tenOrEleven): void +{ + if (strlen($s) >= $zeroToThree) { + assertType('string', $s); + } + if (strlen($s) > $zeroToThree) { + assertType('non-empty-string', $s); + } + if (strlen($s) > $twoOrThree) { + assertType('non-falsy-string', $s); + } + if (strlen($s) > $twoOrMore) { + assertType('non-falsy-string', $s); + } + if (strlen($s) > $maxThree) { + assertType('string', $s); + } + if (strlen($s) > $tenOrEleven) { + assertType('non-falsy-string', $s); + } +} From 4a5bf2454c2504d3ec339f93bb8f2a05b0d973b3 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 22 Aug 2024 12:46:18 +0200 Subject: [PATCH 2/4] fix --- src/Analyser/TypeSpecifier.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 1c1732089d..49057143fe 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -323,7 +323,7 @@ public function specifyTypesInCondition( $argType = $scope->getType($expr->right->getArgs()[0]->value); if ($argType->isString()->yes()) { $accessory = new AccessoryNonEmptyStringType(); - if ($leftType instanceof ConstantIntegerType && $leftType->getValue() >= 2) { + if (IntegerRangeType::createAllGreaterThanOrEqualTo(2)->isSuperTypeOf($leftType)->yes()) { $accessory = new AccessoryNonFalsyStringType(); } From 6f14967193735452f1db4007da41452c4273f689 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 22 Aug 2024 12:48:59 +0200 Subject: [PATCH 3/4] Update strlen-int-range.php --- tests/PHPStan/Analyser/nsrt/strlen-int-range.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/strlen-int-range.php b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php index c9513a1d4e..bbd3abba74 100644 --- a/tests/PHPStan/Analyser/nsrt/strlen-int-range.php +++ b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php @@ -17,7 +17,7 @@ function doFoo(string $s, $zeroToThree, $twoOrThree, $twoOrMore, int $maxThree, assertType('string', $s); } if (strlen($s) > $zeroToThree) { - assertType('non-empty-string', $s); + assertType('non-empty-string', $s); // could be non-falsy-string } if (strlen($s) > $twoOrThree) { assertType('non-falsy-string', $s); From 1d030495144dc4351c545a8cc9e475205a4eeca9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 22 Aug 2024 17:54:28 +0200 Subject: [PATCH 4/4] more tests --- src/Analyser/TypeSpecifier.php | 3 ++- tests/PHPStan/Analyser/nsrt/bug-10952b.php | 4 ++-- .../Analyser/nsrt/strlen-int-range.php | 24 +++++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 49057143fe..ec28f7009d 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -323,7 +323,8 @@ public function specifyTypesInCondition( $argType = $scope->getType($expr->right->getArgs()[0]->value); if ($argType->isString()->yes()) { $accessory = new AccessoryNonEmptyStringType(); - if (IntegerRangeType::createAllGreaterThanOrEqualTo(2)->isSuperTypeOf($leftType)->yes()) { + + if (IntegerRangeType::createAllGreaterThanOrEqualTo(2 - $offset)->isSuperTypeOf($leftType)->yes()) { $accessory = new AccessoryNonFalsyStringType(); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-10952b.php b/tests/PHPStan/Analyser/nsrt/bug-10952b.php index b02b89ac50..f8f70e07d0 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10952b.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10952b.php @@ -16,13 +16,13 @@ public function test(): void $string = $this->getString(); if (1 < mb_strlen($string)) { - assertType('non-empty-string', $string); + assertType('non-falsy-string', $string); } else { assertType("string", $string); } if (mb_strlen($string) > 1) { - assertType('non-empty-string', $string); + assertType('non-falsy-string', $string); } else { assertType("string", $string); } diff --git a/tests/PHPStan/Analyser/nsrt/strlen-int-range.php b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php index bbd3abba74..540b932531 100644 --- a/tests/PHPStan/Analyser/nsrt/strlen-int-range.php +++ b/tests/PHPStan/Analyser/nsrt/strlen-int-range.php @@ -1,4 +1,4 @@ -= 7.2 namespace StrlenIntRange; @@ -17,17 +17,37 @@ function doFoo(string $s, $zeroToThree, $twoOrThree, $twoOrMore, int $maxThree, assertType('string', $s); } if (strlen($s) > $zeroToThree) { - assertType('non-empty-string', $s); // could be non-falsy-string + assertType('non-empty-string', $s); + } + + if (strlen($s) >= $twoOrThree) { + assertType('non-falsy-string', $s); } if (strlen($s) > $twoOrThree) { assertType('non-falsy-string', $s); } + if (strlen($s) > $twoOrMore) { assertType('non-falsy-string', $s); } + + $oneOrMore = $twoOrMore-1; + if (strlen($s) > $oneOrMore) { + assertType('non-falsy-string', $s); + } + if (strlen($s) >= $oneOrMore) { + assertType('non-empty-string', $s); + } + if (strlen($s) <= $oneOrMore) { + assertType('string', $s); + } else { + assertType('non-falsy-string', $s); + } + if (strlen($s) > $maxThree) { assertType('string', $s); } + if (strlen($s) > $tenOrEleven) { assertType('non-falsy-string', $s); }