Skip to content

Commit

Permalink
Read default values from php-8-stubs and jetbrains/phpstorm-stubs
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed May 11, 2022
1 parent cb52f97 commit 7ce177e
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 50 deletions.
22 changes: 21 additions & 1 deletion src/Reflection/InitializerExprContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,31 @@ public static function fromReflectionParameter(ReflectionParameter $parameter):

$file = $declaringFunction->getFileName();
$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
$classReflection = $reflectionProvider->getClass($declaringFunction->getDeclaringClass()->getName());
$className = $declaringFunction->getDeclaringClass()->getName();
if (!$reflectionProvider->hasClass($className)) {
return new self($file === false ? null : $file, null);
}

$classReflection = $reflectionProvider->getClass($className);

return new self($file === false ? null : $file, $classReflection);
}

public static function fromStubParameter(?string $className, string $stubFile): self
{
if ($className === null) {
return new self($stubFile, null);
}

$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
if (!$reflectionProvider->hasClass($className)) {
return new self($stubFile, null);
}
$classReflection = $reflectionProvider->getClass($className);

return new self($stubFile, $classReflection);
}

public function getFile(): ?string
{
return $this->file;
Expand Down
2 changes: 1 addition & 1 deletion src/Reflection/Php/PhpClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ private function createNativeMethodVariant(
$parameterSignature->getNativeType(),
$parameterSignature->passedByReference(),
$stubPhpDocParameterVariadicity[$parameterSignature->getName()] ?? $parameterSignature->isVariadic(),
null,
$parameterSignature->getDefaultValue(),
);
}

Expand Down
12 changes: 11 additions & 1 deletion src/Reflection/SignatureMap/FunctionSignatureMapProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\InitializerExprContext;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\MixedType;
use PHPStan\Type\TypehintHelper;
Expand All @@ -24,7 +26,11 @@ class FunctionSignatureMapProvider implements SignatureMapProvider
/** @var array<string, array{hasSideEffects: bool}>|null */
private ?array $functionMetadata = null;

public function __construct(private SignatureMapParser $parser, private PhpVersion $phpVersion)
public function __construct(
private SignatureMapParser $parser,
private InitializerExprTypeResolver $initializerExprTypeResolver,
private PhpVersion $phpVersion,
)
{
}

Expand Down Expand Up @@ -64,6 +70,10 @@ public function getMethodSignature(string $className, string $methodName, ?Refle
TypehintHelper::decideTypeFromReflection($nativeParameters[$i]->getType()),
$parameter->passedByReference(),
$parameter->isVariadic(),
$nativeParameters[$i]->isDefaultValueAvailable() ? $this->initializerExprTypeResolver->getType(
$nativeParameters[$i]->getDefaultValueExpr(),
InitializerExprContext::fromReflectionParameter($nativeParameters[$i]),
) : null,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef
null,
array_map(static function (ParameterSignature $parameterSignature) use ($lowerCasedFunctionName, $phpDoc): NativeParameterReflection {
$type = $parameterSignature->getType();
$defaultValue = null;

$phpDocType = null;
if ($phpDoc !== null) {
Expand Down Expand Up @@ -103,20 +102,13 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef
);
}

if (
$lowerCasedFunctionName === 'array_reduce'
&& $parameterSignature->getName() === 'initial'
) {
$defaultValue = new NullType();
}

return new NativeParameterReflection(
$parameterSignature->getName(),
$parameterSignature->isOptional(),
TypehintHelper::decideType($type, $phpDocType),
$parameterSignature->passedByReference(),
$parameterSignature->isVariadic(),
$defaultValue,
$parameterSignature->getDefaultValue(),
);
}, $functionSignature->getParameters()),
$functionSignature->isVariadic(),
Expand Down
6 changes: 6 additions & 0 deletions src/Reflection/SignatureMap/ParameterSignature.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function __construct(
private Type $nativeType,
private PassedByReference $passedByReference,
private bool $variadic,
private ?Type $defaultValue,
)
{
}
Expand Down Expand Up @@ -49,4 +50,9 @@ public function isVariadic(): bool
return $this->variadic;
}

public function getDefaultValue(): ?Type
{
return $this->defaultValue;
}

}
8 changes: 8 additions & 0 deletions src/Reflection/SignatureMap/Php8SignatureMapProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
use PHPStan\Php8StubsMap;
use PHPStan\PhpDoc\Tag\ParamTag;
use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher;
use PHPStan\Reflection\InitializerExprContext;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\Reflection\PassedByReference;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\FileTypeMapper;
Expand Down Expand Up @@ -42,6 +44,7 @@ public function __construct(
private FileNodesFetcher $fileNodesFetcher,
private FileTypeMapper $fileTypeMapper,
private PhpVersion $phpVersion,
private InitializerExprTypeResolver $initializerExprTypeResolver,
)
{
$this->map = new Php8StubsMap($phpVersion->getVersionId());
Expand Down Expand Up @@ -253,6 +256,7 @@ private function mergeSignatures(FunctionSignature $nativeSignature, FunctionSig
$nativeParameterType,
$nativeParameter->passedByReference()->yes() ? $functionMapParameter->passedByReference() : $nativeParameter->passedByReference(),
$nativeParameter->isVariadic(),
$nativeParameter->getDefaultValue(),
);
}

Expand Down Expand Up @@ -349,6 +353,10 @@ private function getSignature(
$parameterType,
$param->byRef ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(),
$param->variadic,
$param->default !== null ? $this->initializerExprTypeResolver->getType(
$param->default,
InitializerExprContext::fromStubParameter($className, $stubFile),
) : null,
);

$variadic = $variadic || $param->variadic;
Expand Down
1 change: 1 addition & 0 deletions src/Reflection/SignatureMap/SignatureMapParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private function getParameters(array $parameterMap): array
new MixedType(),
$passedByReference,
$isVariadic,
null,
);
}

Expand Down
56 changes: 22 additions & 34 deletions src/Type/Php/DsMapDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,8 @@
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeScope;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use function array_filter;
use function array_values;
use PHPStan\Type\TypeWithClassName;
use function count;

final class DsMapDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
Expand All @@ -37,43 +32,36 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
$methodReflection->getVariants(),
)->getReturnType();

if (count($methodCall->getArgs()) > 1) {
$argsCount = count($methodCall->getArgs());
if ($argsCount > 1) {
return $returnType;
}

if ($returnType instanceof UnionType) {
$types = array_values(
array_filter(
$returnType->getTypes(),
static function (Type $type): bool {
if (
$type instanceof TemplateType
&& $type->getName() === 'TDefault'
&& (
$type->getScope()->equals(TemplateTypeScope::createWithMethod('Ds\Map', 'get'))
|| $type->getScope()->equals(TemplateTypeScope::createWithMethod('Ds\Map', 'remove'))
)
) {
return false;
}
if ($argsCount === 0) {
return $returnType;
}

return true;
},
),
);
$mapType = $scope->getType($methodCall->var);
if (!$mapType instanceof TypeWithClassName) {
return $returnType;
}

if (count($types) === 1) {
return $types[0];
}
$mapAncestor = $mapType->getAncestorWithClassName('Ds\Map');
if ($mapAncestor === null) {
return $returnType;
}

if (count($types) === 0) {
return $returnType;
}
$mapAncestorClass = $mapAncestor->getClassReflection();
if ($mapAncestorClass === null) {
return $returnType;
}

return TypeCombinator::union(...$types);
$valueType = $mapAncestorClass->getActiveTemplateTypeMap()->getType('TValue');
if ($valueType === null) {
return $returnType;
}

return $returnType;
return $valueType;
}

}
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/key-of-generic.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7106.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4950.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/native-reflection-default-values.php');
}

/**
Expand Down
11 changes: 11 additions & 0 deletions tests/PHPStan/Analyser/data/native-reflection-default-values.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace NativeReflectionDefaultValues;

use function PHPStan\Testing\assertType;

function () {
assertType('ArrayObject<*NEVER*, *NEVER*>', new \ArrayObject());
assertType('ArrayObject<*NEVER*, *NEVER*>', new \ArrayObject([]));
assertType('ArrayObject<string, int>', new \ArrayObject(['key' => 1]));
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPStan\Php\PhpVersion;
use PHPStan\Php8StubsMap;
use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\PassedByReference;
use PHPStan\Testing\PHPStanTestCase;
Expand Down Expand Up @@ -146,11 +147,13 @@ private function createProvider(): Php8SignatureMapProvider
return new Php8SignatureMapProvider(
new FunctionSignatureMapProvider(
self::getContainer()->getByType(SignatureMapParser::class),
self::getContainer()->getByType(InitializerExprTypeResolver::class),
$phpVersion,
),
self::getContainer()->getByType(FileNodesFetcher::class),
self::getContainer()->getByType(FileTypeMapper::class),
$phpVersion,
self::getContainer()->getByType(InitializerExprTypeResolver::class),
);
}

Expand Down
Loading

0 comments on commit 7ce177e

Please sign in to comment.