mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Add dateTimeModify return type provider
This commit is contained in:
parent
95bb71f8a2
commit
32aedbac58
@ -7,6 +7,7 @@ use PhpParser;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\Provider\ReturnTypeProvider\ClosureFromCallableReturnTypeProvider;
|
||||
use Psalm\Internal\Provider\ReturnTypeProvider\DateTimeModifyReturnTypeProvider;
|
||||
use Psalm\Internal\Provider\ReturnTypeProvider\DomNodeAppendChild;
|
||||
use Psalm\Internal\Provider\ReturnTypeProvider\ImagickPixelColorReturnTypeProvider;
|
||||
use Psalm\Internal\Provider\ReturnTypeProvider\PdoStatementReturnTypeProvider;
|
||||
@ -58,6 +59,7 @@ class MethodReturnTypeProvider
|
||||
$this->registerClass(SimpleXmlElementAsXml::class);
|
||||
$this->registerClass(PdoStatementReturnTypeProvider::class);
|
||||
$this->registerClass(ClosureFromCallableReturnTypeProvider::class);
|
||||
$this->registerClass(DateTimeModifyReturnTypeProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Internal\Provider\ReturnTypeProvider;
|
||||
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
|
||||
use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
class DateTimeModifyReturnTypeProvider implements MethodReturnTypeProviderInterface
|
||||
{
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return ['DateTime', 'DateTimeImmutable'];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union
|
||||
{
|
||||
$statements_source = $event->getSource();
|
||||
$call_args = $event->getCallArgs();
|
||||
$method_name_lowercase = $event->getMethodNameLowercase();
|
||||
if (
|
||||
!$statements_source instanceof StatementsAnalyzer
|
||||
|| $method_name_lowercase !== 'modify'
|
||||
|| !isset($call_args[0])
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$first_arg = $call_args[0]->value;
|
||||
$first_arg_type = $statements_source->node_data->getType($first_arg);
|
||||
if (!$first_arg_type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$has_date_time = false;
|
||||
$has_false = false;
|
||||
foreach ($first_arg_type->getAtomicTypes() as $type_part) {
|
||||
if (!$type_part instanceof TLiteralString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (@(new \DateTime())->modify($type_part->value) === false) {
|
||||
$has_false = true;
|
||||
} else {
|
||||
$has_date_time = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_false && !$has_date_time) {
|
||||
return Type::getFalse();
|
||||
}
|
||||
if ($has_date_time && !$has_false) {
|
||||
return Type::parseString($event->getFqClasslikeName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
96
tests/DateTimeTest.php
Normal file
96
tests/DateTimeTest.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Tests;
|
||||
|
||||
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
|
||||
|
||||
class DateTimeTest extends TestCase
|
||||
{
|
||||
use ValidCodeAnalysisTestTrait;
|
||||
|
||||
/**
|
||||
* @return iterable<string,array{string,assertions?:array<string,string>,error_levels?:string[]}>
|
||||
*/
|
||||
public function providerValidCodeParse(): iterable
|
||||
{
|
||||
return [
|
||||
'modify' => [
|
||||
'<?php
|
||||
function getString(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$datetime = new DateTime();
|
||||
$dateTimeImmutable = new DateTimeImmutable();
|
||||
$a = $datetime->modify(getString());
|
||||
$b = $dateTimeImmutable->modify(getString());
|
||||
',
|
||||
'assertions' => [
|
||||
'$a' => 'DateTime|false',
|
||||
'$b' => 'DateTimeImmutable|false',
|
||||
],
|
||||
],
|
||||
'modifyWithValidConstant' => [
|
||||
'<?php
|
||||
/**
|
||||
* @return "+1 day"|"+2 day"
|
||||
*/
|
||||
function getString(): string
|
||||
{
|
||||
return "+1 day";
|
||||
}
|
||||
|
||||
$datetime = new DateTime();
|
||||
$dateTimeImmutable = new DateTimeImmutable();
|
||||
$a = $datetime->modify(getString());
|
||||
$b = $dateTimeImmutable->modify(getString());
|
||||
',
|
||||
'assertions' => [
|
||||
'$a' => 'DateTime',
|
||||
'$b' => 'DateTimeImmutable',
|
||||
],
|
||||
],
|
||||
'modifyWithInvalidConstant' => [
|
||||
'<?php
|
||||
/**
|
||||
* @return "foo"|"bar"
|
||||
*/
|
||||
function getString(): string
|
||||
{
|
||||
return "foo";
|
||||
}
|
||||
|
||||
$datetime = new DateTime();
|
||||
$dateTimeImmutable = new DateTimeImmutable();
|
||||
$a = $datetime->modify(getString());
|
||||
$b = $dateTimeImmutable->modify(getString());
|
||||
',
|
||||
'assertions' => [
|
||||
'$a' => 'false',
|
||||
'$b' => 'false',
|
||||
],
|
||||
],
|
||||
'modifyWithBothConstant' => [
|
||||
'<?php
|
||||
/**
|
||||
* @return "+1 day"|"bar"
|
||||
*/
|
||||
function getString(): string
|
||||
{
|
||||
return "+1 day";
|
||||
}
|
||||
|
||||
$datetime = new DateTime();
|
||||
$dateTimeImmutable = new DateTimeImmutable();
|
||||
$a = $datetime->modify(getString());
|
||||
$b = $dateTimeImmutable->modify(getString());
|
||||
',
|
||||
'assertions' => [
|
||||
'$a' => 'DateTime|false',
|
||||
'$b' => 'DateTimeImmutable|false',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -272,7 +272,7 @@ class MethodCallTest extends TestCase
|
||||
$b = (new DateTimeImmutable())->modify("+3 hours");',
|
||||
'assertions' => [
|
||||
'$yesterday' => 'MyDate|false',
|
||||
'$b' => 'DateTimeImmutable|false',
|
||||
'$b' => 'DateTimeImmutable',
|
||||
],
|
||||
],
|
||||
'magicCall' => [
|
||||
|
Loading…
Reference in New Issue
Block a user