Skip to content

Commit

Permalink
Fix pathinfo($s, PATHINFO_ALL) return type
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Nov 20, 2022
1 parent 85ac37b commit dc25cfc
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 13 deletions.
40 changes: 27 additions & 13 deletions src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php
Expand Up @@ -5,13 +5,15 @@
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;
use const PATHINFO_ALL;

class PathinfoFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{
Expand All @@ -25,24 +27,36 @@ public function getTypeFromFunctionCall(
FunctionReflection $functionReflection,
Node\Expr\FuncCall $functionCall,
Scope $scope,
): Type
): ?Type
{
$argsCount = count($functionCall->getArgs());
if ($argsCount === 0) {
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
} elseif ($argsCount === 1) {
$pathType = $scope->getType($functionCall->getArgs()[0]->value);

$builder = ConstantArrayTypeBuilder::createEmpty();
$builder->setOffsetValueType(new ConstantStringType('dirname'), new StringType(), !$pathType->isNonEmptyString()->yes());
$builder->setOffsetValueType(new ConstantStringType('basename'), new StringType());
$builder->setOffsetValueType(new ConstantStringType('extension'), new StringType(), true);
$builder->setOffsetValueType(new ConstantStringType('filename'), new StringType());
return null;
}

return $builder->getArray();
$pathType = $scope->getType($functionCall->getArgs()[0]->value);

$builder = ConstantArrayTypeBuilder::createEmpty();
$builder->setOffsetValueType(new ConstantStringType('dirname'), new StringType(), !$pathType->isNonEmptyString()->yes());
$builder->setOffsetValueType(new ConstantStringType('basename'), new StringType());
$builder->setOffsetValueType(new ConstantStringType('extension'), new StringType(), true);
$builder->setOffsetValueType(new ConstantStringType('filename'), new StringType());
$arrayType = $builder->getArray();

if ($argsCount === 1) {
return $arrayType;
} elseif ($argsCount >= 2) {
$flagsType = $scope->getType($functionCall->getArgs()[1]->value);
if ($flagsType instanceof ConstantIntegerType) {
if ($flagsType->getValue() === PATHINFO_ALL) {
return $arrayType;
}

return new StringType();
}
}

return new StringType();
return TypeCombinator::union($arrayType, new StringType());
}

}
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -1132,6 +1132,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8361.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8373.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Functions/data/bug-8389.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/pathinfo.php');
}

/**
Expand Down
17 changes: 17 additions & 0 deletions tests/PHPStan/Analyser/data/pathinfo.php
@@ -0,0 +1,17 @@
<?php

namespace pathinfo;

use function PHPStan\Testing\assertType;

function doFoo(string $s, int $i) {
assertType('array{dirname?: string, basename: string, extension?: string, filename: string}|string', pathinfo($s, $i));

assertType('array{dirname?: string, basename: string, extension?: string, filename: string}', pathinfo($s));
assertType('array{dirname?: string, basename: string, extension?: string, filename: string}', pathinfo($s, PATHINFO_ALL));

assertType('string', pathinfo($s, PATHINFO_DIRNAME));
assertType('string', pathinfo($s, PATHINFO_BASENAME));
assertType('string', pathinfo($s, PATHINFO_EXTENSION));
assertType('string', pathinfo($s, PATHINFO_FILENAME));
}

0 comments on commit dc25cfc

Please sign in to comment.