From 93aa984c0ddfc2fc3ee5e16ee3c574ce15542241 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 23 Jan 2024 20:57:05 +0900 Subject: [PATCH 1/5] Separated into DateFunctionReturnTypeHelper --- conf/config.neon | 3 + .../Php/DateFunctionReturnTypeExtension.php | 111 ++-------------- src/Type/Php/DateFunctionReturnTypeHelper.php | 120 ++++++++++++++++++ 3 files changed, 133 insertions(+), 101 deletions(-) create mode 100644 src/Type/Php/DateFunctionReturnTypeHelper.php diff --git a/conf/config.neon b/conf/config.neon index 1ff4a23e8b..c4724cb9e6 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -1272,6 +1272,9 @@ services: tags: - phpstan.broker.dynamicFunctionReturnTypeExtension + - + class: PHPStan\Type\Php\DateFunctionReturnTypeHelper + - class: PHPStan\Type\Php\DateFormatFunctionReturnTypeExtension tags: diff --git a/src/Type/Php/DateFunctionReturnTypeExtension.php b/src/Type/Php/DateFunctionReturnTypeExtension.php index 2147fd1b80..81ae452645 100644 --- a/src/Type/Php/DateFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFunctionReturnTypeExtension.php @@ -5,23 +5,17 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; -use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; -use PHPStan\Type\Accessory\AccessoryNumericStringType; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; -use PHPStan\Type\IntersectionType; -use PHPStan\Type\StringType; use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; -use PHPStan\Type\UnionType; use function count; -use function date; -use function sprintf; class DateFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { + public function __construct(private DateFunctionReturnTypeHelper $dateFunctionReturnTypeHelper) + { + } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return $functionReflection->getName() === 'date'; @@ -31,101 +25,16 @@ public function getTypeFromFunctionCall( FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope, - ): Type + ): ?Type { if (count($functionCall->getArgs()) === 0) { - return new StringType(); - } - $argType = $scope->getType($functionCall->getArgs()[0]->value); - $constantStrings = $argType->getConstantStrings(); - - if (count($constantStrings) === 0) { - return new StringType(); - } - - if (count($constantStrings) === 1) { - $constantString = $constantStrings[0]->getValue(); - - // see see https://www.php.net/manual/en/datetime.format.php - switch ($constantString) { - case 'd': - return $this->buildNumericRangeType(1, 31, true); - case 'j': - return $this->buildNumericRangeType(1, 31, false); - case 'N': - return $this->buildNumericRangeType(1, 7, false); - case 'w': - return $this->buildNumericRangeType(0, 6, false); - case 'm': - return $this->buildNumericRangeType(1, 12, true); - case 'n': - return $this->buildNumericRangeType(1, 12, false); - case 't': - return $this->buildNumericRangeType(28, 31, false); - case 'L': - return $this->buildNumericRangeType(0, 1, false); - case 'g': - return $this->buildNumericRangeType(1, 12, false); - case 'G': - return $this->buildNumericRangeType(0, 23, false); - case 'h': - return $this->buildNumericRangeType(1, 12, true); - case 'H': - return $this->buildNumericRangeType(0, 23, true); - case 'I': - return $this->buildNumericRangeType(0, 1, false); - } - } - - $types = []; - foreach ($constantStrings as $constantString) { - $types[] = new ConstantStringType(date($constantString->getValue())); - } - - $type = TypeCombinator::union(...$types); - if ($type->isNumericString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNumericStringType(), - ]); - } - - if ($type->isNonFalsyString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNonFalsyStringType(), - ]); - } - - if ($type->isNonEmptyString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNonEmptyStringType(), - ]); - } - - if ($type->isNonEmptyString()->no()) { - return new ConstantStringType(''); - } - - return new StringType(); - } - - private function buildNumericRangeType(int $min, int $max, bool $zeroPad): Type - { - $types = []; - - for ($i = $min; $i <= $max; $i++) { - $string = (string) $i; - - if ($zeroPad) { - $string = sprintf('%02s', $string); - } - - $types[] = new ConstantStringType($string); + return null; } - return new UnionType($types); + return $this->dateFunctionReturnTypeHelper->getTypeFromFormatType( + formatType: $scope->getType($functionCall->getArgs()[0]->value), + useMicrosec: false, + ); } } diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php new file mode 100644 index 0000000000..db6e92456b --- /dev/null +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -0,0 +1,120 @@ +getConstantStrings(); + + if (count($constantStrings) === 0) { + return new StringType(); + } + + if (count($constantStrings) === 1) { + $constantString = $constantStrings[0]->getValue(); + + // see see https://www.php.net/manual/en/datetime.format.php + switch ($constantString) { + case 'd': + return $this->buildNumericRangeType(1, 31, true); + case 'j': + return $this->buildNumericRangeType(1, 31, false); + case 'N': + return $this->buildNumericRangeType(1, 7, false); + case 'w': + return $this->buildNumericRangeType(0, 6, false); + case 'm': + return $this->buildNumericRangeType(1, 12, true); + case 'n': + return $this->buildNumericRangeType(1, 12, false); + case 't': + return $this->buildNumericRangeType(28, 31, false); + case 'L': + return $this->buildNumericRangeType(0, 1, false); + case 'g': + return $this->buildNumericRangeType(1, 12, false); + case 'G': + return $this->buildNumericRangeType(0, 23, false); + case 'h': + return $this->buildNumericRangeType(1, 12, true); + case 'H': + return $this->buildNumericRangeType(0, 23, true); + case 'I': + return $this->buildNumericRangeType(0, 1, false); + } + } + + $types = []; + foreach ($constantStrings as $constantString) { + $types[] = new ConstantStringType(date($constantString->getValue())); + } + + $type = TypeCombinator::union(...$types); + if ($type->isNumericString()->yes()) { + return new IntersectionType([ + new StringType(), + new AccessoryNumericStringType(), + ]); + } + + if ($type->isNonFalsyString()->yes()) { + return new IntersectionType([ + new StringType(), + new AccessoryNonFalsyStringType(), + ]); + } + + if ($type->isNonEmptyString()->yes()) { + return new IntersectionType([ + new StringType(), + new AccessoryNonEmptyStringType(), + ]); + } + + if ($type->isNonEmptyString()->no()) { + return new ConstantStringType(''); + } + + return new StringType(); + } + + private function buildNumericRangeType(int $min, int $max, bool $zeroPad): Type + { + $types = []; + + for ($i = $min; $i <= $max; $i++) { + $string = (string) $i; + + if ($zeroPad) { + $string = str_pad($string, 2, '0', STR_PAD_LEFT); + } + + $types[] = new ConstantStringType($string); + } + + return new UnionType($types); + } + +} From 690ccf532e6bb8f36c91d36d8a25a32cb73e6a29 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 23 Jan 2024 21:00:33 +0900 Subject: [PATCH 2/5] Refactor and support non-constant format type --- src/Type/Php/DateFunctionReturnTypeHelper.php | 113 ++++++++---------- .../Analyser/NodeScopeResolverTest.php | 1 + tests/PHPStan/Analyser/data/bug-10468.php | 14 +++ 3 files changed, 68 insertions(+), 60 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/bug-10468.php diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php index db6e92456b..c14c8bb429 100644 --- a/src/Type/Php/DateFunctionReturnTypeHelper.php +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -18,7 +18,6 @@ use function date; use function is_numeric; use function str_pad; -use function preg_match; use const STR_PAD_LEFT; class DateFunctionReturnTypeHelper @@ -26,78 +25,72 @@ class DateFunctionReturnTypeHelper public function getTypeFromFormatType(Type $formatType, bool $useMicrosec): ?Type { - $constantStrings = $formatType->getConstantStrings(); - - if (count($constantStrings) === 0) { - return new StringType(); - } - - if (count($constantStrings) === 1) { - $constantString = $constantStrings[0]->getValue(); - - // see see https://www.php.net/manual/en/datetime.format.php - switch ($constantString) { - case 'd': - return $this->buildNumericRangeType(1, 31, true); - case 'j': - return $this->buildNumericRangeType(1, 31, false); - case 'N': - return $this->buildNumericRangeType(1, 7, false); - case 'w': - return $this->buildNumericRangeType(0, 6, false); - case 'm': - return $this->buildNumericRangeType(1, 12, true); - case 'n': - return $this->buildNumericRangeType(1, 12, false); - case 't': - return $this->buildNumericRangeType(28, 31, false); - case 'L': - return $this->buildNumericRangeType(0, 1, false); - case 'g': - return $this->buildNumericRangeType(1, 12, false); - case 'G': - return $this->buildNumericRangeType(0, 23, false); - case 'h': - return $this->buildNumericRangeType(1, 12, true); - case 'H': - return $this->buildNumericRangeType(0, 23, true); - case 'I': - return $this->buildNumericRangeType(0, 1, false); - } + $types = []; + foreach ($formatType->getConstantStrings() as $formatString) { + $types[] = $this->buildReturnTypeFromFormat($formatString->getValue(), $useMicrosec); } - $types = []; - foreach ($constantStrings as $constantString) { - $types[] = new ConstantStringType(date($constantString->getValue())); + if (count($types) === 0) { + $types[] = $formatType->isNonEmptyString()->yes() + ? new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]) + : new StringType(); } $type = TypeCombinator::union(...$types); - if ($type->isNumericString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNumericStringType(), - ]); + + if ($type->isNumericString()->no() && $formatType->isNonEmptyString()->yes()) { + $type = TypeCombinator::union($type, new IntersectionType([ + new StringType(), new AccessoryNonEmptyStringType() + ])); } - if ($type->isNonFalsyString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNonFalsyStringType(), - ]); + return $type; + } + + public function buildReturnTypeFromFormat(string $formatString, bool $useMicrosec): Type + { + // see see https://www.php.net/manual/en/datetime.format.php + switch ($formatString) { + case 'd': + return $this->buildNumericRangeType(1, 31, zeroPad: true); + case 'j': + return $this->buildNumericRangeType(1, 31, zeroPad: false); + case 'N': + return $this->buildNumericRangeType(1, 7, zeroPad: false); + case 'w': + return $this->buildNumericRangeType(0, 6, zeroPad: false); + case 'm': + return $this->buildNumericRangeType(1, 12, zeroPad: true); + case 'n': + return $this->buildNumericRangeType(1, 12, zeroPad: false); + case 't': + return $this->buildNumericRangeType(28, 31, zeroPad: false); + case 'L': + return $this->buildNumericRangeType(0, 1, zeroPad: false); + case 'g': + return $this->buildNumericRangeType(1, 12, zeroPad: false); + case 'G': + return $this->buildNumericRangeType(0, 23, zeroPad: false); + case 'h': + return $this->buildNumericRangeType(1, 12, zeroPad: true); + case 'H': + return $this->buildNumericRangeType(0, 23, zeroPad: true); + case 'I': + return $this->buildNumericRangeType(0, 1, zeroPad: false); } - if ($type->isNonEmptyString()->yes()) { - return new IntersectionType([ - new StringType(), - new AccessoryNonEmptyStringType(), - ]); + $date = date($formatString); + + // If parameter string is not included, returned as ConstantStringType + if ($date === $formatString) { + return new ConstantStringType($date); } - if ($type->isNonEmptyString()->no()) { - return new ConstantStringType(''); + if (is_numeric($date)) { + return new IntersectionType([new StringType(), new AccessoryNumericStringType()]); } - return new StringType(); + return new IntersectionType([new StringType(), new AccessoryNonFalsyStringType()]); } private function buildNumericRangeType(int $min, int $max, bool $zeroPad): Type diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index e42e662738..392f13ab60 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1450,6 +1450,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10037.php'); yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/PhpDoc/data/bug-10594.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/set-type-type-specifying.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10468.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-10468.php b/tests/PHPStan/Analyser/data/bug-10468.php new file mode 100644 index 0000000000..8a3e30e970 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-10468.php @@ -0,0 +1,14 @@ + Date: Tue, 23 Jan 2024 21:36:55 +0900 Subject: [PATCH 3/5] Support 'u' format string for date_format() --- .../Php/DateFormatFunctionReturnTypeExtension.php | 13 ++++++++----- .../Php/DateFormatMethodReturnTypeExtension.php | 13 ++++++++----- src/Type/Php/DateFunctionReturnTypeHelper.php | 4 ++++ tests/PHPStan/Analyser/NodeScopeResolverTest.php | 1 + tests/PHPStan/Analyser/data/bug-6613.php | 11 +++++++++++ 5 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/bug-6613.php diff --git a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php index b926ed181d..3b56edf946 100644 --- a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php @@ -14,6 +14,10 @@ class DateFormatFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { + public function __construct(private DateFunctionReturnTypeHelper $dateFunctionReturnTypeHelper) + { + } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return $functionReflection->getName() === 'date_format'; @@ -23,16 +27,15 @@ public function getTypeFromFunctionCall( FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope, - ): Type + ): ?Type { if (count($functionCall->getArgs()) < 2) { return new StringType(); } - return $scope->getType( - new FuncCall(new FullyQualified('date'), [ - $functionCall->getArgs()[1], - ]), + return $this->dateFunctionReturnTypeHelper->getTypeFromFormatType( + $scope->getType($functionCall->getArgs()[1]->value), + true, ); } diff --git a/src/Type/Php/DateFormatMethodReturnTypeExtension.php b/src/Type/Php/DateFormatMethodReturnTypeExtension.php index f6b71786bc..695f2c07aa 100644 --- a/src/Type/Php/DateFormatMethodReturnTypeExtension.php +++ b/src/Type/Php/DateFormatMethodReturnTypeExtension.php @@ -16,6 +16,10 @@ class DateFormatMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension { + public function __construct(private DateFunctionReturnTypeHelper $dateFunctionReturnTypeHelper) + { + } + public function getClass(): string { return DateTimeInterface::class; @@ -26,16 +30,15 @@ public function isMethodSupported(MethodReflection $methodReflection): bool return $methodReflection->getName() === 'format'; } - public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { if (count($methodCall->getArgs()) === 0) { return new StringType(); } - return $scope->getType( - new FuncCall(new FullyQualified('date'), [ - $methodCall->getArgs()[0], - ]), + return $this->dateFunctionReturnTypeHelper->getTypeFromFormatType( + $scope->getType($methodCall->getArgs()[0]->value), + true, ); } diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php index c14c8bb429..70d1b1b035 100644 --- a/src/Type/Php/DateFunctionReturnTypeHelper.php +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -77,6 +77,10 @@ public function buildReturnTypeFromFormat(string $formatString, bool $useMicrose return $this->buildNumericRangeType(0, 23, zeroPad: true); case 'I': return $this->buildNumericRangeType(0, 1, zeroPad: false); + case 'u': + return $useMicrosec + ? new IntersectionType([new StringType(), new AccessoryNonFalsyStringType()]) + : new ConstantStringType('000000'); } $date = date($formatString); diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 392f13ab60..023f8dbe5d 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1451,6 +1451,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/PhpDoc/data/bug-10594.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/set-type-type-specifying.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10468.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6613.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-6613.php b/tests/PHPStan/Analyser/data/bug-6613.php new file mode 100644 index 0000000000..29898f7532 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-6613.php @@ -0,0 +1,11 @@ +format('u')); +}; From 61ebb690d1e7392860f56482f6eeb5ab21a4e6f3 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 23 Jan 2024 21:42:09 +0900 Subject: [PATCH 4/5] fixup! Separated into DateFunctionReturnTypeHelper --- .../Php/DateFunctionReturnTypeExtension.php | 4 +-- src/Type/Php/DateFunctionReturnTypeHelper.php | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Type/Php/DateFunctionReturnTypeExtension.php b/src/Type/Php/DateFunctionReturnTypeExtension.php index 81ae452645..41432d1c3a 100644 --- a/src/Type/Php/DateFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFunctionReturnTypeExtension.php @@ -32,8 +32,8 @@ public function getTypeFromFunctionCall( } return $this->dateFunctionReturnTypeHelper->getTypeFromFormatType( - formatType: $scope->getType($functionCall->getArgs()[0]->value), - useMicrosec: false, + $scope->getType($functionCall->getArgs()[0]->value), + false, ); } diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php index 70d1b1b035..acc75849e6 100644 --- a/src/Type/Php/DateFunctionReturnTypeHelper.php +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -52,31 +52,31 @@ public function buildReturnTypeFromFormat(string $formatString, bool $useMicrose // see see https://www.php.net/manual/en/datetime.format.php switch ($formatString) { case 'd': - return $this->buildNumericRangeType(1, 31, zeroPad: true); + return $this->buildNumericRangeType(1, 31, true); case 'j': - return $this->buildNumericRangeType(1, 31, zeroPad: false); + return $this->buildNumericRangeType(1, 31, false); case 'N': - return $this->buildNumericRangeType(1, 7, zeroPad: false); + return $this->buildNumericRangeType(1, 7, false); case 'w': - return $this->buildNumericRangeType(0, 6, zeroPad: false); + return $this->buildNumericRangeType(0, 6, false); case 'm': - return $this->buildNumericRangeType(1, 12, zeroPad: true); + return $this->buildNumericRangeType(1, 12, true); case 'n': - return $this->buildNumericRangeType(1, 12, zeroPad: false); + return $this->buildNumericRangeType(1, 12, false); case 't': - return $this->buildNumericRangeType(28, 31, zeroPad: false); + return $this->buildNumericRangeType(28, 31, false); case 'L': - return $this->buildNumericRangeType(0, 1, zeroPad: false); + return $this->buildNumericRangeType(0, 1, false); case 'g': - return $this->buildNumericRangeType(1, 12, zeroPad: false); + return $this->buildNumericRangeType(1, 12, false); case 'G': - return $this->buildNumericRangeType(0, 23, zeroPad: false); + return $this->buildNumericRangeType(0, 23, false); case 'h': - return $this->buildNumericRangeType(1, 12, zeroPad: true); + return $this->buildNumericRangeType(1, 12, true); case 'H': - return $this->buildNumericRangeType(0, 23, zeroPad: true); + return $this->buildNumericRangeType(0, 23, true); case 'I': - return $this->buildNumericRangeType(0, 1, zeroPad: false); + return $this->buildNumericRangeType(0, 1, false); case 'u': return $useMicrosec ? new IntersectionType([new StringType(), new AccessoryNonFalsyStringType()]) From c9bb7b624529dffb68919f464f4e05e518c358b0 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 23 Jan 2024 21:47:15 +0900 Subject: [PATCH 5/5] Fix --- src/Type/Php/DateFormatFunctionReturnTypeExtension.php | 1 - src/Type/Php/DateFormatMethodReturnTypeExtension.php | 2 -- src/Type/Php/DateFunctionReturnTypeHelper.php | 5 +---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php index 3b56edf946..bae299abaa 100644 --- a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php @@ -3,7 +3,6 @@ namespace PHPStan\Type\Php; use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Name\FullyQualified; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\DynamicFunctionReturnTypeExtension; diff --git a/src/Type/Php/DateFormatMethodReturnTypeExtension.php b/src/Type/Php/DateFormatMethodReturnTypeExtension.php index 695f2c07aa..f028fbea7b 100644 --- a/src/Type/Php/DateFormatMethodReturnTypeExtension.php +++ b/src/Type/Php/DateFormatMethodReturnTypeExtension.php @@ -3,9 +3,7 @@ namespace PHPStan\Type\Php; use DateTimeInterface; -use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Name\FullyQualified; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\DynamicMethodReturnTypeExtension; diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php index acc75849e6..d6cadad384 100644 --- a/src/Type/Php/DateFunctionReturnTypeHelper.php +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -2,9 +2,6 @@ namespace PHPStan\Type\Php; -use PhpParser\Node\Expr\FuncCall; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; use PHPStan\Type\Accessory\AccessoryNumericStringType; @@ -40,7 +37,7 @@ public function getTypeFromFormatType(Type $formatType, bool $useMicrosec): ?Typ if ($type->isNumericString()->no() && $formatType->isNonEmptyString()->yes()) { $type = TypeCombinator::union($type, new IntersectionType([ - new StringType(), new AccessoryNonEmptyStringType() + new StringType(), new AccessoryNonEmptyStringType(), ])); }