Skip to content

Commit

Permalink
strtok() always returns a non-empty-string when it does not return false
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Jan 12, 2024
1 parent 27e5c57 commit bdd5ec9
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 10 deletions.
4 changes: 2 additions & 2 deletions resources/functionMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -12083,8 +12083,8 @@
'strrpos' => ['0|positive-int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'],
'strspn' => ['int', 'str'=>'string', 'mask'=>'string', 'start='=>'int', 'len='=>'int'],
'strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'mixed', 'before_needle='=>'bool'],
'strtok' => ['string|false', 'str'=>'string', 'token'=>'string'],
'strtok\'1' => ['string|false', 'token'=>'string'],
'strtok' => ['non-empty-string|false', 'str'=>'string', 'token'=>'string'],
'strtok\'1' => ['non-empty-string|false', 'token'=>'string'],
'strtolower' => ['string', 'str'=>'string'],
'strtotime' => ['int|false', 'time'=>'string', 'now='=>'int'],
'strtoupper' => ['string', 'str'=>'string'],
Expand Down
11 changes: 6 additions & 5 deletions src/Type/Php/StrTokFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use function count;
Expand All @@ -21,11 +22,11 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo
return $functionReflection->getName() === 'strtok';
}

public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
{
$args = $functionCall->getArgs();
if (count($args) !== 2) {
return ParametersAcceptorSelector::selectFromArgs($scope, $args, $functionReflection->getVariants())->getReturnType();
return null;
}

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

if ($isEmptyString->no()) {
return new StringType();
return new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]);
}

return ParametersAcceptorSelector::selectFromArgs($scope, $args, $functionReflection->getVariants())->getReturnType();
return null;
}

}
4 changes: 2 additions & 2 deletions tests/PHPStan/Analyser/data/bug-3981.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Foo
*/
public function doFoo(string $s, string $nonEmptyString): void
{
assertType('string|false', strtok($s, ' '));
assertType('string', strtok($nonEmptyString, ' '));
assertType('non-empty-string|false', strtok($s, ' '));
assertType('non-empty-string', strtok($nonEmptyString, ' '));
assertType('false', strtok('', ' '));

assertType('non-empty-string', $nonEmptyString[0]);
Expand Down
4 changes: 3 additions & 1 deletion tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\Php\DummyParameter;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
Expand All @@ -18,6 +19,7 @@
use PHPStan\Type\Generic\TemplateTypeScope;
use PHPStan\Type\Generic\TemplateTypeVariance;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
Expand Down Expand Up @@ -198,7 +200,7 @@ public function dataSelectFromTypes(): Generator
),
],
false,
new UnionType([new StringType(), new ConstantBooleanType(false)]),
new UnionType([new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]), new ConstantBooleanType(false)]),
),
];
yield [
Expand Down

0 comments on commit bdd5ec9

Please sign in to comment.