Skip to content

Commit

Permalink
Restore src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Jan 20, 2023
1 parent 4c383b7 commit e84aa7b
Showing 1 changed file with 47 additions and 12 deletions.
59 changes: 47 additions & 12 deletions src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\ShouldNotHappenException;
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 function sprintf;

class PathinfoFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{

public function __construct(private ReflectionProvider $reflectionProvider)
{
}

public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'pathinfo';
Expand All @@ -25,24 +33,51 @@ 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);
return null;
}

$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;
} else {
$flagsType = $scope->getType($functionCall->getArgs()[1]->value);
if ($flagsType instanceof ConstantIntegerType) {
if ($flagsType->getValue() === $this->getConstant('PATHINFO_ALL')) {
return $arrayType;
}

$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 new StringType();
}
}

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

private function getConstant(string $constantName): ?int
{
if (!$this->reflectionProvider->hasConstant(new Node\Name($constantName), null)) {
return null;
}

return $builder->getArray();
$constant = $this->reflectionProvider->getConstant(new Node\Name($constantName), null);
$valueType = $constant->getValueType();
if (!$valueType instanceof ConstantIntegerType) {
throw new ShouldNotHappenException(sprintf('Constant %s does not have integer type.', $constantName));
}

return new StringType();
return $valueType->getValue();
}

}

0 comments on commit e84aa7b

Please sign in to comment.