10000 [TypeInfo] Fix handling ConstFetchNode · symfony/symfony@48f648b · GitHub
[go: up one dir, main page]

Skip to content

Commit 48f648b

Browse files
committed
[TypeInfo] Fix handling ConstFetchNode
1 parent fa4d2d8 commit 48f648b

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ public static function unionTypesProvider(): iterable
927927
Type::object(ParentDummy::class),
928928
Type::null(),
929929
)];
930-
yield ['f', null];
930+
yield ['f', Type::union(Type::string(), Type::int(), Type::float(), Type::bool(), Type::null())];
931931
yield ['g', Type::array(Type::union(Type::string(), Type::int()))];
932932
}
933933

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
13+
14+
final class DummyWithConstants
15+
{
16+
public const DUMMY_STRING_A = 'a';
17+
public const DUMMY_INT_A = 1;
18+
public const DUMMY_FLOAT_A = 1.23;
19+
public const DUMMY_TRUE_A = true;
20+
public const DUMMY_FALSE_A = false;
21+
public const DUMMY_NULL_A = null;
22+
public const DUMMY_ARRAY_A = [];
23+
public const DUMMY_ENUM_A = DummyEnum::ONE;
24+
25+
public const DUMMY_MIX_1 = self::DUMMY_STRING_A;
26+
public const DUMMY_MIX_2 = self::DUMMY_INT_A;
27+
public const DUMMY_MIX_3 = self::DUMMY_FLOAT_A;
28+
public const DUMMY_MIX_4 = self::DUMMY_TRUE_A;
29+
public const DUMMY_MIX_5 = self::DUMMY_FALSE_A;
30+
public const DUMMY_MIX_6 = self::DUMMY_NULL_A;
31+
public const DUMMY_MIX_7 = self::DUMMY_ARRAY_A;
32+
public const DUMMY_MIX_8 = self::DUMMY_ENUM_A;
33+
}

src/Symfony/Component/TypeInfo/Tests/TypeResolver/StringTypeResolverTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyBackedEnum;
2020
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyCollection;
2121
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyEnum;
22+
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithConstants;
2223
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithTemplates;
2324
use Symfony\Component\TypeInfo\Type;
2425
use Symfony\Component\TypeInfo\TypeContext\TypeContext;
@@ -90,6 +91,19 @@ public static function resolveDataProvider(): iterable
9091
yield [Type::string(), '"string"'];
9192
yield [Type::true(), 'true'];
9293

94+
// const fetch
95+
yield [Type::string(), DummyWithConstants::class.'::DUMMY_STRING_*'];
96+
yield [Type::string(), DummyWithConstants::class.'::DUMMY_STRING_A'];
97+
yield [Type::int(), DummyWithConstants::class.'::DUMMY_INT_*'];
98+
yield [Type::int(), DummyWithConstants::class.'::DUMMY_INT_A'];
99+
yield [Type::float(), DummyWithConstants::class.'::DUMMY_FLOAT_*'];
100+
yield [Type::bool(), DummyWithConstants::class.'::DUMMY_TRUE_*'];
101+
yield [Type::bool(), DummyWithConstants::class.'::DUMMY_FALSE_*'];
102+
yield [Type::null(), DummyWithConstants::class.'::DUMMY_NULL_*'];
103+
yield [Type::array(), DummyWithConstants::class.'::DUMMY_ARRAY_*'];
104+
yield [Type::enum(DummyEnum::class, Type\BuiltinType::string()), DummyWithConstants::class.'::DUMMY_ENUM_*'];
105+
yield [Type::union(Type::string(), Type::int(), Type::float(), Type::bool(), Type::null(), Type::array(), Type::enum(DummyEnum::class, Type\BuiltinType::string())), DummyWithConstants::class.'::DUMMY_MIX_*'];
106+
93107
// identifiers
94108
yield [Type::bool(), 'bool'];
95109
yield [Type::bool(), 'boolean'];

src/Symfony/Component/TypeInfo/TypeResolver/StringTypeResolver.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode;
1919
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
2020
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprTrueNode;
21+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
2122
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
2223
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
2324
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
@@ -119,6 +120,33 @@ private function getTypeFromNode(TypeNode $node, ?TypeContext $typeContext): Typ
119120
}
120121

121122
if ($node instanceof ConstTypeNode) {
123+
if ($node->constExpr instanceof ConstFetchNode) {
124+
$types = [];
125+
126+
foreach ((new \ReflectionClass($node->constExpr->className))->getReflectionConstants() as $const) {
127+
if (preg_match('/^' . str_replace('\*', '.*', preg_quote($node->constExpr->name, '/')) . '$/', $const->getName())) {
128+
$constValue = $const->getValue();
129+
130+
$types[] = match (true) {
131+
true === $constValue,
132+
false === $constValue => Type::bool(),
133+
null === A48E $constValue => Type::null(),
134+
\is_string($constValue) => Type::string(),
135+
\is_int($constValue) => Type::int(),
136+
\is_float($constValue) => Type::float(),
137+
\is_array($constValue) => Type::array(),
138+
$constValue instanceof \UnitEnum => Type::enum($constValue::class),
139+
};
140+
}
141+
}
142+
143+
if (count($types) > 2) {
144+
return Type::union(...array_unique($types));
145+
}
146+
147+
return $types[0] ?? Type::null();
148+
}
149+
122150
return match ($node->constExpr::class) {
123151
ConstExprArrayNode::class => Type::array(),
124152
ConstExprFalseNode::class => Type::false(),

0 commit comments

Comments
 (0)
0