Skip to content

Commit

Permalink
DateTimeZoneConstructorThrowTypeExtension
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 1, 2022
1 parent 75cef53 commit 0710109
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
5 changes: 5 additions & 0 deletions conf/config.neon
Expand Up @@ -1347,6 +1347,11 @@ services:
tags:
- phpstan.dynamicStaticMethodThrowTypeExtension

-
class: PHPStan\Type\Php\DateTimeZoneConstructorThrowTypeExtension
tags:
- phpstan.dynamicStaticMethodThrowTypeExtension

-
class: PHPStan\Type\Php\DsMapDynamicReturnTypeExtension
tags:
Expand Down
50 changes: 50 additions & 0 deletions src/Type/Php/DateTimeZoneConstructorThrowTypeExtension.php
@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Php;

use DateTimeZone;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodThrowTypeExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
use function count;

class DateTimeZoneConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension
{

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === '__construct' && $methodReflection->getDeclaringClass()->getName() === DateTimeZone::class;
}

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

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

foreach ($constantStrings as $constantString) {
try {
new DateTimeZone($constantString->getValue());
} catch (\Exception $e) { // phpcs:ignore
return $methodReflection->getThrowType();
}

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

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

return null;
}

}
Expand Up @@ -40,6 +40,10 @@ public function testRule(): void
'Method MissingExceptionMethodThrows\Foo::doLorem2() throws checked exception InvalidArgumentException but it\'s missing from the PHPDoc @throws tag.',
34,
],
[
'Method MissingExceptionMethodThrows\Foo::dateTimeZoneDoesThrows() throws checked exception Exception but it\'s missing from the PHPDoc @throws tag.',
95,
],
]);
}

Expand Down
Expand Up @@ -85,4 +85,14 @@ private function throwsInterface(): void

}

public function dateTimeZoneDoesNotThrow(): void
{
new \DateTimeZone('UTC');
}

public function dateTimeZoneDoesThrows(string $tz): void
{
new \DateTimeZone($tz);
}

}

0 comments on commit 0710109

Please sign in to comment.