Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Read parameter default values from JetBrains/phpstorm-stubs
  • Loading branch information
clxmstaab committed Jan 29, 2022
commit 4b2897621c11767899d0475725841995bac213cd
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public function getMethodSignature(string $className, string $methodName, ?Refle
TypehintHelper::decideTypeFromReflection($nativeParameters[$i]->getType()),
$parameter->passedByReference(),
$parameter->isVariadic(),
$parameter->getDefaultValue(),
);
}

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

$phpDocType = null;
if ($phpDoc !== null) {
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 @@ -199,6 +199,7 @@ private function mergeSignatures(FunctionSignature $nativeSignature, FunctionSig
$nativeParameterType,
$nativeParameter->passedByReference()->yes() ? $functionMapParameter->passedByReference() : $nativeParameter->passedByReference(),
$nativeParameter->isVariadic(),
$nativeParameter->getDefaultValue(),
);
}

Expand Down Expand Up @@ -288,13 +289,20 @@ private function getSignature(
throw new ShouldNotHappenException();
}
$parameterType = ParserNodeTypeToPHPStanType::resolve($param->type, null);

$defaultType = null;
if ($param->default !== null) {
$defaultType = ParserNodeTypeToPHPStanType::resolveParameterDefaultType($param->default);
}

$parameters[] = new ParameterSignature(
$name->name,
$param->default !== null || $param->variadic,
TypehintHelper::decideType($parameterType, $phpDocParameterTypes[$name->name] ?? null),
$parameterType,
$param->byRef ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(),
$param->variadic,
$defaultType,
);

$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, // the functionMap does not provide default values
);
}

Expand Down
105 changes: 104 additions & 1 deletion src/Type/ParserNodeTypeToPHPStanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,121 @@
namespace PHPStan\Type;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\BinaryOp\BitwiseAnd;
use PhpParser\Node\Expr\BinaryOp\BitwiseOr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\UnaryMinus;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Scalar\DNumber;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PHPStan\Reflection\ClassReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
use function get_class;
use function in_array;
use function is_numeric;
use function strtolower;

class ParserNodeTypeToPHPStanType
{

public static function resolveParameterDefaultType(?Expr $type): Type
{
if ($type instanceof ConstFetch) {
$constName = (string) $type->name;
$loweredConstName = strtolower($constName);
if ($loweredConstName === 'true') {
return new ConstantBooleanType(true);
} elseif ($loweredConstName === 'false') {
return new ConstantBooleanType(false);
} elseif ($loweredConstName === 'null') {
return new NullType();
}

return self::resolve(new Identifier($type->name->toString()), null);
} elseif ($type instanceof ClassConstFetch) {
if ($type->name instanceof Identifier) {
$constantName = $type->name->name;
if (!($type->class instanceof Name)) {
throw new \PHPStan\ShouldNotHappenException();
}

$constantClass = (string) $type->class;
$constantClassType = new ObjectType($constantClass);

if (!$constantClassType->hasConstant($constantName)->yes()) {
return new ErrorType();
}

return $constantClassType->getConstant($constantName)->getValueType();
}

throw new \PHPStan\ShouldNotHappenException();
} elseif ($type instanceof String_ || $type instanceof LNumber || $type instanceof DNumber) {
return ConstantTypeHelper::getTypeFromValue($type->value);
} elseif ($type instanceof Array_) {
$arrayBuilder = ConstantArrayTypeBuilder::createEmpty();
foreach ($type->items as $item) {
if ($item === null) {
continue;
}

$keyType = null;
if ($item->key !== null) {
$keyType = self::resolveParameterDefaultType($item->key);
}
$arrayBuilder->setOffsetValueType(
$keyType,
self::resolveParameterDefaultType($item->value),
);
}

return $arrayBuilder->getArray();
} elseif ($type instanceof UnaryMinus) {
$expr = $type->expr;

if (!($expr instanceof LNumber || $expr instanceof DNumber)) {
throw new \PHPStan\ShouldNotHappenException();
}

$type = self::resolveParameterDefaultType($expr);

if ($type instanceof ConstantScalarType) {
$value = $type->getValue();

if (is_numeric($value)) {
return ConstantTypeHelper::getTypeFromValue($value * -1);
}
}

throw new \PHPStan\ShouldNotHappenException();
} elseif ($type instanceof BitwiseOr || $type instanceof BitwiseAnd) {

if ($type->left instanceof ClassConstFetch && $type->right instanceof ClassConstFetch) {
$left = self::resolveParameterDefaultType($type->left);
$right = self::resolveParameterDefaultType($type->right);

if ($left instanceof ConstantIntegerType && $right instanceof ConstantIntegerType) {
if ($type instanceof BitwiseOr) {
return new ConstantIntegerType($left->getValue() | $right->getValue());
}
return new ConstantIntegerType($left->getValue() & $right->getValue());
}
}

throw new \PHPStan\ShouldNotHappenException();
}

throw new \PHPStan\ShouldNotHappenException();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there's a lot of ShouldNotHappenException, we need a test that iterates over all symbols and makes sure that none of them throw.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a separte unit test

}

/**
* @param Node\Name|Node\Identifier|Node\ComplexType|null $type
*/
Expand Down Expand Up @@ -61,6 +163,7 @@ public static function resolve($type, ?ClassReflection $classReflection): Type
}

return TypeCombinator::intersect(...$types);

} elseif (!$type instanceof Identifier) {
throw new ShouldNotHappenException(get_class($type));
}
Expand Down
Loading