Skip to content

Commit 9463e66

Browse files
staabmondrejmirtes
authored andcommitted
strtok() always returns a non-empty-string when it does not return false
1 parent 38eb365 commit 9463e66

File tree

4 files changed

+13
-10
lines changed

4 files changed

+13
-10
lines changed

resources/functionMap.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12083,8 +12083,8 @@
1208312083
'strrpos' => ['0|positive-int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'],
1208412084
'strspn' => ['int', 'str'=>'string', 'mask'=>'string', 'start='=>'int', 'len='=>'int'],
1208512085
'strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'mixed', 'before_needle='=>'bool'],
12086-
'strtok' => ['string|false', 'str'=>'string', 'token'=>'string'],
12087-
'strtok\'1' => ['string|false', 'token'=>'string'],
12086+
'strtok' => ['non-empty-string|false', 'str'=>'string', 'token'=>'string'],
12087+
'strtok\'1' => ['non-empty-string|false', 'token'=>'string'],
1208812088
'strtolower' => ['string', 'str'=>'string'],
1208912089
'strtotime' => ['int|false', 'time'=>'string', 'now='=>'int'],
1209012090
'strtoupper' => ['string', 'str'=>'string'],

src/Type/Php/StrTokFunctionReturnTypeExtension.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
use PhpParser\Node\Expr\FuncCall;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Reflection\FunctionReflection;
8-
use PHPStan\Reflection\ParametersAcceptorSelector;
8+
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
99
use PHPStan\Type\Constant\ConstantBooleanType;
1010
use PHPStan\Type\Constant\ConstantStringType;
1111
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
12+
use PHPStan\Type\IntersectionType;
1213
use PHPStan\Type\StringType;
1314
use PHPStan\Type\Type;
1415
use function count;
@@ -21,11 +22,11 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo
2122
return $functionReflection->getName() === 'strtok';
2223
}
2324

24-
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
25+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
2526
{
2627
$args = $functionCall->getArgs();
2728
if (count($args) !== 2) {
28-
return ParametersAcceptorSelector::selectFromArgs($scope, $args, $functionReflection->getVariants())->getReturnType();
29+
return null;
2930
}
3031

3132
$delimiterType = $scope->getType($functionCall->getArgs()[0]->value);
@@ -35,10 +36,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3536
}
3637

3738
if ($isEmptyString->no()) {
38-
return new StringType();
39+
return new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]);
3940
}
4041

41-
return ParametersAcceptorSelector::selectFromArgs($scope, $args, $functionReflection->getVariants())->getReturnType();
42+
return null;
4243
}
4344

4445
}

tests/PHPStan/Analyser/data/bug-3981.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ class Foo
1313
*/
1414
public function doFoo(string $s, string $nonEmptyString): void
1515
{
16-
assertType('string|false', strtok($s, ' '));
17-
assertType('string', strtok($nonEmptyString, ' '));
16+
assertType('non-empty-string|false', strtok($s, ' '));
17+
assertType('non-empty-string', strtok($nonEmptyString, ' '));
1818
assertType('false', strtok('', ' '));
1919

2020
assertType('non-empty-string', $nonEmptyString[0]);

tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPStan\Reflection\Native\NativeParameterReflection;
1010
use PHPStan\Reflection\Php\DummyParameter;
1111
use PHPStan\Testing\PHPStanTestCase;
12+
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
1213
use PHPStan\Type\ArrayType;
1314
use PHPStan\Type\Constant\ConstantBooleanType;
1415
use PHPStan\Type\Constant\ConstantIntegerType;
@@ -18,6 +19,7 @@
1819
use PHPStan\Type\Generic\TemplateTypeScope;
1920
use PHPStan\Type\Generic\TemplateTypeVariance;
2021
use PHPStan\Type\IntegerType;
22+
use PHPStan\Type\IntersectionType;
2123
use PHPStan\Type\MixedType;
2224
use PHPStan\Type\NullType;
2325
use PHPStan\Type\ObjectType;
@@ -198,7 +200,7 @@ public function dataSelectFromTypes(): Generator
198200
),
199201
],
200202
false,
201-
new UnionType([new StringType(), new ConstantBooleanType(false)]),
203+
new UnionType([new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]), new ConstantBooleanType(false)]),
202204
),
203205
];
204206
yield [

0 commit comments

Comments
 (0)