8000 bug #44578 [PropertyInfo] Fix phpstan extractor issues (ostrolucky) · symfony/symfony@d6a29ae · GitHub
[go: up one dir, main page]

Skip to content

Commit d6a29ae

Browse files
bug #44578 [PropertyInfo] Fix phpstan extractor issues (ostrolucky)
This PR was squashed before being merged into the 5.4 branch. Discussion ---------- [PropertyInfo] Fix phpstan extractor issues | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #44491 | License | MIT | Doc PR | Since this crashes denormalization for codebase that was upgraded from 5.3 to 5.4, I am classifying this as a bugfix. This PR fixes 2 issues. One is with docblocks like `/** `@var` Foo::*|null */`, where Extractor returns `null` only and afterwards Serializer fails to accept anything else. Second is `/** `@var` non-empty-array<...> */` where extractor doesn't recognize that `non-empty-array` is still an array and afterwards Serializer fails complaining that `array` is not an `non-empty-array` Commits ------- 0302128 [PropertyInfo] Fix phpstan extractor issues
2 parents d17ae34 + 0302128 commit d6a29ae

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed

src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ public function constructorTypesProvider()
355355
/**
356356
* @dataProvider unionTypesProvider
357357
*/
358-
public function testExtractorUnionTypes(string $property, array $types)
358+
public function testExtractorUnionTypes(string $property, ?array $types)
359359
{
360360
$this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DummyUnionType', $property));
361361
}
@@ -368,6 +368,8 @@ public function unionTypesProvider(): array
368368
['c', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
369369
['d', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])])]],
370370
['e', [new Type(Type::BUILTIN_TYPE_OBJECT, true, Dummy::class, true, [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])], [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_STRING, false, null, true, [], [new Type(Type::BUILTIN_TYPE_OBJECT, false, DefaultValue::class)])])]), new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
371+
['f', null],
372+
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
371373
];
372374
}
373375

src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyUnionType.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
*/
1717
class DummyUnionType
1818
{
19+
private const TYPE_A = 'a';
20+
private const TYPE_B = 'b';
21+
1922
/**
2023
* @var string|int
2124
*/
@@ -40,4 +43,14 @@ class DummyUnionType
4043
* @var (Dummy<array<mixed, string>, (int | (string<DefaultValue>)[])> | ParentDummy | null)
4144
*/
4245
public $e;
46+
47+
/**
48+
* @var self::TYPE_*|null
49+
*/
50+
public $f;
51+
52+
/**
53+
* @var non-empty-array<string|int>
54+
*/
55+
public $g;
4356
}

src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
2020
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
2121
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
22+
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
2223
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
2324
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
2425
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
@@ -102,6 +103,10 @@ private function extractTypes(TypeNode $node, NameScope $nameScope): array
102103
if ($node instanceof UnionTypeNode) {
103104
$types = [];
104105
foreach ($node->types as $type) {
106+
if ($type instanceof ConstTypeNode) {
107+
// It's safer to fall back to other extractors here, as resolving const types correctly is not easy at the moment
108+
return [];
109+
}
105110
foreach ($this->extractTypes($type, $nameScope) as $subType) {
106111
$types[] = $subType;
107112
}
@@ -160,7 +165,10 @@ private function extractTypes(TypeNode $node, NameScope $nameScope): array
160165
case 'integer':
161166
return [new Type(Type::BUILTIN_TYPE_INT)];
162167
case 'list':
168+
case 'non-empty-list':
163169
return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT))];
170+
case 'non-empty-array':
171+
return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)];
164172
case 'mixed':
165173
return []; // mixed seems to be ignored in all other extractors
166174
case 'parent':

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace Symfony\Component\Serializer\Tests\Normalizer;
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
15+
use PHPStan\PhpDocParser\Parser\PhpDocParser;
1516
use PHPUnit\Framework\TestCase;
1617
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
18+
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
1719
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
1820
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
1921
use Symfony\Component\Serializer\Exception\LogicException;
@@ -721,6 +723,22 @@ public function testAcceptJsonNumber()
721723
$this->assertSame(10.0, $serializer->denormalize(['number' => 10], JsonNumber::class, 'jsonld')->number);
722724
}
723725

726+
public function testDoesntHaveIssuesWithUnionConstTypes()
727+
{
728+
if (!class_exists(PhpStanExtractor::class) || !class_exists(PhpDocParser::class)) {
729+
$this->markTestSkipped('phpstan/phpdoc-parser required for this test');
730+
}
731+
732+
$extractor = new PropertyInfoExtractor([], [new PhpStanExtractor(), new PhpDocExtractor(), new ReflectionExtractor()]);
733+
$normalizer = new ObjectNormalizer(null, null, null, $extractor);
734+
$serializer = new Serializer([new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer]);
735+
736+
$this->assertSame('bar', $serializer->denormalize(['foo' => 'bar'], \get_class(new class() {
737+
/** @var self::*|null */
738+
public $foo;
739+
}))->foo);
740+
}
741+
724742
public function testExtractAttributesRespectsFormat()
725743
{
726744
$normalizer = new FormatAndContextAwareNormalizer();

0 commit comments

Comments
 (0)
0