Skip to content

Commit

Permalink
Update PhpStorm stubs
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 7, 2024
1 parent 1245ea7 commit aa7989f
Show file tree
Hide file tree
Showing 20 changed files with 339 additions and 38 deletions.
11 changes: 11 additions & 0 deletions build/datetime-php-83.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^If condition is always false\\.$#"
count: 1
path: ../src/Type/Php/DateTimeModifyReturnTypeExtension.php

-
message: "#^Strict comparison using \\=\\=\\= between DateTime and false will always evaluate to false\\.$#"
count: 1
path: ../src/Type/Php/DateTimeModifyReturnTypeExtension.php
4 changes: 4 additions & 0 deletions build/ignore-by-php-version.neon.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
$includes[] = __DIR__ . '/spl-autoload-functions-php-8.neon';
}

if (PHP_VERSION_ID >= 80300) {
$includes[] = __DIR__ . '/datetime-php-83.neon';
}

$config = [];
$config['includes'] = $includes;

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"hoa/exception": "^1.0",
"hoa/file": "1.17.07.11",
"hoa/regex": "1.17.01.13",
"jetbrains/phpstorm-stubs": "dev-master#cf7e447ddfa7f0cbab0c1dd38392f0cb05f9881c",
"jetbrains/phpstorm-stubs": "dev-master#d5a839645a65f06c008779f42abfb6081353acc8",
"nette/bootstrap": "^3.0",
"nette/di": "^3.1.4",
"nette/neon": "^3.3.1",
Expand Down
10 changes: 5 additions & 5 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,11 @@ services:
tags:
- phpstan.dynamicStaticMethodThrowTypeExtension

-
class: PHPStan\Type\Php\DateTimeModifyMethodThrowTypeExtension
tags:
- phpstan.dynamicMethodThrowTypeExtension

-
class: PHPStan\Type\Php\DateTimeZoneConstructorThrowTypeExtension
tags:
Expand Down
2 changes: 2 additions & 0 deletions resources/functionMap_php83delta.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
*/
return [
'new' => [
'DateTime::modify' => ['static', 'modify'=>'string'],
'DateTimeImmutable::modify' => ['static', 'modify'=>'string'],
'str_decrement' => ['non-empty-string', 'string'=>'non-empty-string'],
'str_increment' => ['non-falsy-string', 'string'=>'non-empty-string'],
'gc_status' => ['array{running:bool,protected:bool,full:bool,runs:int,collected:int,threshold:int,buffer_size:int,roots:int,application_time:float,collector_time:float,destructor_time:float,free_time:float}'],
Expand Down
5 changes: 5 additions & 0 deletions src/Php/PhpVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,9 @@ public function supportsNeverReturnTypeInArrowFunction(): bool
return $this->versionId >= 80200;
}

public function hasDateTimeExceptions(): bool
{
return $this->versionId >= 80300;
}

}
19 changes: 17 additions & 2 deletions src/Type/Php/DateIntervalConstructorThrowTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@
use DateInterval;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodThrowTypeExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;

class DateIntervalConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === '__construct' && $methodReflection->getDeclaringClass()->getName() === DateInterval::class;
Expand All @@ -33,17 +39,26 @@ public function getThrowTypeFromStaticMethodCall(MethodReflection $methodReflect
try {
new DateInterval($constantString->getValue());
} catch (\Exception $e) { // phpcs:ignore
return $methodReflection->getThrowType();
return $this->exceptionType();
}

$valueType = TypeCombinator::remove($valueType, $constantString);
}

if (!$valueType instanceof NeverType) {
return $methodReflection->getThrowType();
return $this->exceptionType();
}

return null;
}

private function exceptionType(): Type
{
if ($this->phpVersion->hasDateTimeExceptions()) {
return new ObjectType('DateMalformedIntervalStringException');
}

return new ObjectType('Exception');
}

}
19 changes: 17 additions & 2 deletions src/Type/Php/DateTimeConstructorThrowTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
use DateTimeImmutable;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodThrowTypeExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;
Expand All @@ -17,6 +19,10 @@
class DateTimeConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === '__construct' && in_array($methodReflection->getDeclaringClass()->getName(), [DateTime::class, DateTimeImmutable::class], true);
Expand All @@ -35,17 +41,26 @@ public function getThrowTypeFromStaticMethodCall(MethodReflection $methodReflect
try {
new DateTime($constantString->getValue());
} catch (\Exception $e) { // phpcs:ignore
return $methodReflection->getThrowType();
return $this->exceptionType();
}

$valueType = TypeCombinator::remove($valueType, $constantString);
}

if (!$valueType instanceof NeverType) {
return $methodReflection->getThrowType();
return $this->exceptionType();
}

return null;
}

private function exceptionType(): Type
{
if ($this->phpVersion->hasDateTimeExceptions()) {
return new ObjectType('DateMalformedStringException');
}

return new ObjectType('Exception');
}

}
71 changes: 71 additions & 0 deletions src/Type/Php/DateTimeModifyMethodThrowTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Php;

use DateTime;
use DateTimeImmutable;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicMethodThrowTypeExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;
use function in_array;

final class DateTimeModifyMethodThrowTypeExtension implements DynamicMethodThrowTypeExtension
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'modify' && in_array($methodReflection->getDeclaringClass()->getName(), [DateTime::class, DateTimeImmutable::class], true);
}

public function getThrowTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type
{
if (count($methodCall->getArgs()) === 0) {
return null;
}

if (!$this->phpVersion->hasDateTimeExceptions()) {
return null;
}

$valueType = $scope->getType($methodCall->getArgs()[0]->value);
$constantStrings = $valueType->getConstantStrings();

foreach ($constantStrings as $constantString) {
try {
$dateTime = new DateTime();
$dateTime->modify($constantString->getValue());
} catch (\Exception $e) { // phpcs:ignore
return $this->exceptionType();
}

$valueType = TypeCombinator::remove($valueType, $constantString);
}

if (!$valueType instanceof NeverType) {
return $this->exceptionType();
}

return null;
}

private function exceptionType(): Type
{
if ($this->phpVersion->hasDateTimeExceptions()) {
return new ObjectType('DateMalformedStringException');
}

return new ObjectType('Exception');
}

}
26 changes: 16 additions & 10 deletions src/Type/Php/DateTimeModifyReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use DateTimeInterface;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
Expand All @@ -18,13 +19,12 @@
class DateTimeModifyReturnTypeExtension implements DynamicMethodReturnTypeExtension
{

/** @var class-string<DateTimeInterface> */
private $dateTimeClass;

/** @param class-string<DateTimeInterface> $dateTimeClass */
public function __construct(string $dateTimeClass = DateTime::class)
public function __construct(
private PhpVersion $phpVersion,
private string $dateTimeClass = DateTime::class,
)
{
$this->dateTimeClass = $dateTimeClass;
}

public function getClass(): string
Expand Down Expand Up @@ -53,7 +53,6 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
try {
$result = @(new DateTime())->modify($constantString->getValue());
} catch (Throwable) {
$hasFalse = true;
$valueType = TypeCombinator::remove($valueType, $constantString);
continue;
}
Expand All @@ -71,13 +70,20 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
return null;
}

if ($hasFalse && !$hasDateTime) {
return new ConstantBooleanType(false);
}
if ($hasDateTime && !$hasFalse) {
if ($hasFalse) {
if (!$hasDateTime) {
return new ConstantBooleanType(false);
}

return null;
} elseif ($hasDateTime) {
return $scope->getType($methodCall->var);
}

if ($this->phpVersion->hasDateTimeExceptions()) {
return new NeverType();
}

return null;
}

Expand Down
19 changes: 17 additions & 2 deletions src/Type/Php/DateTimeZoneConstructorThrowTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@
use DateTimeZone;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodThrowTypeExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;

class DateTimeZoneConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === '__construct' && $methodReflection->getDeclaringClass()->getName() === DateTimeZone::class;
Expand All @@ -33,17 +39,26 @@ public function getThrowTypeFromStaticMethodCall(MethodReflection $methodReflect
try {
new DateTimeZone($constantString->getValue());
} catch (\Exception $e) { // phpcs:ignore
return $methodReflection->getThrowType();
return $this->exceptionType();
}

$valueType = TypeCombinator::remove($valueType, $constantString);
}

if (!$valueType instanceof NeverType) {
return $methodReflection->getThrowType();
return $this->exceptionType();
}

return null;
}

private function exceptionType(): Type
{
if ($this->phpVersion->hasDateTimeExceptions()) {
return new ObjectType('DateInvalidTimeZoneException');
}

return new ObjectType('Exception');
}

}
4 changes: 3 additions & 1 deletion tests/PHPStan/Analyser/nsrt/DateTimeModifyReturnTypes.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php declare(strict_types = 1);
<?php // lint < 8.3

declare(strict_types = 1);

namespace DateTimeModifyReturnTypes;

Expand Down
Loading

0 comments on commit aa7989f

Please sign in to comment.