Skip to content

Commit

Permalink
Introduce AccessoryNumericStringType
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Aug 25, 2020
1 parent 7f04f75 commit 1d27c61
Show file tree
Hide file tree
Showing 34 changed files with 384 additions and 31 deletions.
17 changes: 17 additions & 0 deletions src/PhpDoc/TypeNodeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\PassedByReference;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Accessory\AccessoryNumericStringType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
Expand Down Expand Up @@ -145,6 +146,22 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
case 'number':
return new UnionType([new IntegerType(), new FloatType()]);

case 'numeric':
return new UnionType([
new IntegerType(),
new FloatType(),
new IntersectionType([
new StringType(),
new AccessoryNumericStringType(),
]),
]);

case 'numeric-string':
return new IntersectionType([
new StringType(),
new AccessoryNumericStringType(),
]);

case 'bool':
case 'boolean':
return new BooleanType();
Expand Down
9 changes: 0 additions & 9 deletions src/Rules/Comparison/ImpossibleCheckTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectType;
Expand Down Expand Up @@ -75,14 +74,6 @@ public function findSpecifiedType(
}
if ($functionName === 'count') {
return null;
} elseif ($functionName === 'is_numeric') {
$argType = $scope->getType($node->args[0]->value);
if (count(TypeUtils::getConstantScalars($argType)) > 0) {
return !$argType->toNumber() instanceof ErrorType;
}
if (TypeUtils::containsGeneralString($argType)) {
return null;
}
} elseif ($functionName === 'defined') {
return null;
} elseif (
Expand Down
156 changes: 156 additions & 0 deletions src/Type/Accessory/AccessoryNumericStringType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Accessory;

use PHPStan\TrinaryLogic;
use PHPStan\Type\CompoundType;
use PHPStan\Type\CompoundTypeHelper;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
use PHPStan\Type\Traits\NonCallableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

class AccessoryNumericStringType implements CompoundType, AccessoryType
{

use NonCallableTypeTrait;
use NonObjectTypeTrait;
use NonIterableTypeTrait;
use UndecidedBooleanTypeTrait;
use NonGenericTypeTrait;

public function getReferencedClasses(): array
{
return [];
}

public function accepts(Type $type, bool $strictTypes): TrinaryLogic
{
if ($type instanceof CompoundType) {
return CompoundTypeHelper::accepts($type, $this, $strictTypes);
}

return $type->isNumericString();
}

public function isSuperTypeOf(Type $type): TrinaryLogic
{
if ($this->equals($type)) {
return TrinaryLogic::createYes();
}

return $type->isNumericString();
}

public function isSubTypeOf(Type $otherType): TrinaryLogic
{
if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
return $otherType->isSuperTypeOf($this);
}

return $otherType->isNumericString()
->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe());
}

public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
{
return $this->isSubTypeOf($acceptingType);
}

public function equals(Type $type): bool
{
return $type instanceof self;
}

public function describe(\PHPStan\Type\VerbosityLevel $level): string
{
return 'numeric';
}

public function isOffsetAccessible(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return (new IntegerType())->isSuperTypeOf($offsetType)->and(TrinaryLogic::createMaybe());
}

public function getOffsetValueType(Type $offsetType): Type
{
if ($this->hasOffsetValueType($offsetType)->no()) {
return new ErrorType();
}

return new StringType();
}

public function setOffsetValueType(?Type $offsetType, Type $valueType): Type
{
return $this;
}

public function isArray(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function toNumber(): Type
{
return new UnionType([
$this->toInteger(),
$this->toFloat(),
]);
}

public function toInteger(): Type
{
return new IntegerType();
}

public function toFloat(): Type
{
return new FloatType();
}

public function toString(): Type
{
return $this;
}

public function toArray(): Type
{
return new ConstantArrayType(
[new ConstantIntegerType(0)],
[$this],
1
);
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function traverse(callable $cb): Type
{
return $this;
}

public static function __set_state(array $properties): Type
{
return new self();
}

}
5 changes: 5 additions & 0 deletions src/Type/Accessory/HasOffsetType.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

public function toNumber(): Type
{
return new ErrorType();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Accessory/NonEmptyArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function toNumber(): Type
{
return new ErrorType();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function isOffsetAccessible(): TrinaryLogic
{
return TrinaryLogic::createYes();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/CallableType.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

/**
* @param mixed[] $properties
* @return Type
Expand Down
5 changes: 5 additions & 0 deletions src/Type/ClosureType.php
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

/**
* @param mixed[] $properties
* @return Type
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Constant/ConstantStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ public function toFloat(): Type
return $type->toFloat();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createFromBoolean(is_numeric($this->getValue()));
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
if ($offsetType instanceof ConstantIntegerType) {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/FloatType.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function traverse(callable $cb): Type
{
return $this;
Expand Down
7 changes: 7 additions & 0 deletions src/Type/IntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ public function isArray(): TrinaryLogic
});
}

public function isNumericString(): TrinaryLogic
{
return $this->intersectResults(static function (Type $type): TrinaryLogic {
return $type->isNumericString();
});
}

public function isOffsetAccessible(): TrinaryLogic
{
return $this->intersectResults(static function (Type $type): TrinaryLogic {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/IterableType.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
{
if ($receivedType instanceof UnionType || $receivedType instanceof IntersectionType) {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/JustNullableTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

}
5 changes: 5 additions & 0 deletions src/Type/MixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

/**
* @param mixed[] $properties
* @return Type
Expand Down
5 changes: 5 additions & 0 deletions src/Type/NeverType.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

/**
* @param mixed[] $properties
* @return Type
Expand Down
5 changes: 5 additions & 0 deletions src/Type/NullType.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

/**
* @param mixed[] $properties
* @return Type
Expand Down
5 changes: 5 additions & 0 deletions src/Type/ObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isNumericString(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

private function isExtraOffsetAccessibleClass(): TrinaryLogic
{
$classReflection = $this->getClassReflection();
Expand Down
4 changes: 2 additions & 2 deletions src/Type/Php/IsNumericFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
use PHPStan\Analyser\TypeSpecifierAwareExtension;
use PHPStan\Analyser\TypeSpecifierContext;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\Accessory\AccessoryNumericStringType;
use PHPStan\Type\FloatType;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use PHPStan\Type\IntegerType;
use PHPStan\Type\StringType;
use PHPStan\Type\UnionType;

class IsNumericFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension
Expand All @@ -39,7 +39,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
];

if ($context->truthy()) {
$numericTypes[] = new StringType();
$numericTypes[] = new AccessoryNumericStringType();
}

return $this->typeSpecifier->create($node->args[0]->value, new UnionType($numericTypes), $context);
Expand Down
Loading

0 comments on commit 1d27c61

Please sign in to comment.