Skip to content

Commit 9767538

Browse files
committed
Allow mixed type dynamic constants.
Addresses phpstan/phpstan#7520 Revert "Allow mixed type dynamic constants." This reverts commit 1854985. Allow setting types for dynamic constants Unit test fixes Unit test fix 2 Lint fixes Use TypeStringResolver directly Remove old code
1 parent 5878035 commit 9767538

File tree

9 files changed

+64
-8
lines changed

9 files changed

+64
-8
lines changed

src/Analyser/ConstantResolver.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use PhpParser\Node\Name;
66
use PHPStan\DependencyInjection\AutowiredService;
7+
use PHPStan\DependencyInjection\Container;
78
use PHPStan\Php\ComposerPhpVersionFactory;
89
use PHPStan\Php\PhpVersion;
10+
use PHPStan\PhpDoc\TypeStringResolver;
911
use PHPStan\Reflection\NamespaceAnswerer;
1012
use PHPStan\Reflection\ReflectionProvider;
1113
use PHPStan\Reflection\ReflectionProvider\ReflectionProviderProvider;
@@ -50,6 +52,9 @@ public function __construct(
5052
private array $dynamicConstantNames,
5153
private int|array|null $phpVersion,
5254
private ComposerPhpVersionFactory $composerPhpVersionFactory,
55+
private ?PhpVersion $composerMinPhpVersion,
56+
private ?PhpVersion $composerMaxPhpVersion,
57+
private ?Container $container,
5358
)
5459
{
5560
}
@@ -404,8 +409,17 @@ private function getMaxPhpVersion(): ?PhpVersion
404409

405410
public function resolveConstantType(string $constantName, Type $constantType): Type
406411
{
407-
if ($constantType->isConstantValue()->yes() && in_array($constantName, $this->dynamicConstantNames, true)) {
408-
return $constantType->generalize(GeneralizePrecision::lessSpecific());
412+
if ($constantType->isConstantValue()->yes()) {
413+
if (array_key_exists($constantName, $this->dynamicConstantNames)) {
414+
$phpdocTypes = $this->dynamicConstantNames[$constantName];
415+
$typeStringResolver = $this->container?->getByType(TypeStringResolver::class);
416+
if ($typeStringResolver !== null) {
417+
return $typeStringResolver->resolve($phpdocTypes, new NameScope(null, [], null));
418+
}
419+
}
420+
if (in_array($constantName, $this->dynamicConstantNames, true)) {
421+
return $constantType->generalize(GeneralizePrecision::lessSpecific());
422+
}
409423
}
410424

411425
return $constantType;
@@ -414,6 +428,20 @@ public function resolveConstantType(string $constantName, Type $constantType): T
414428
public function resolveClassConstantType(string $className, string $constantName, Type $constantType, ?Type $nativeType): Type
415429
{
416430
$lookupConstantName = sprintf('%s::%s', $className, $constantName);
431+
if (array_key_exists($lookupConstantName, $this->dynamicConstantNames)) {
432+
if ($nativeType !== null) {
433+
return $nativeType;
434+
}
435+
436+
if ($constantType->isConstantValue()->yes()) {
437+
$phpdocTypes = $this->dynamicConstantNames[$lookupConstantName];
438+
$typeStringResolver = $this->container?->getByType(TypeStringResolver::class);
439+
if ($typeStringResolver !== null) {
440+
return $typeStringResolver->resolve($phpdocTypes, new NameScope(null, [], $className));
441+
}
442+
}
443+
}
444+
417445
if (in_array($lookupConstantName, $this->dynamicConstantNames, true)) {
418446
if ($nativeType !== null) {
419447
return $nativeType;

src/Analyser/ConstantResolverFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ public function create(): ConstantResolver
2727
$this->container->getParameter('dynamicConstantNames'),
2828
$this->container->getParameter('phpVersion'),
2929
$composerFactory,
30+
$composerFactory->getMinVersion(),
31+
$composerFactory->getMaxVersion(),
32+
$this->container,
3033
);
3134
}
3235

src/Analyser/MutatingScope.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6191,6 +6191,11 @@ public function getConstantReflection(Type $typeWithConstant, string $constantNa
61916191
return $typeWithConstant->getConstant($constantName);
61926192
}
61936193

6194+
public function getConstantExplicitTypeFromConfig(string $constantName, Type $constantType): Type
6195+
{
6196+
return $this->constantResolver->resolveConstantType($constantName, $constantType);
6197+
}
6198+
61946199
/**
61956200
* @return array<string, ExpressionTypeHolder>
61966201
*/

src/Analyser/Scope.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ public function getMethodReflection(Type $typeWithMethod, string $methodName): ?
8181

8282
public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection;
8383

84+
public function getConstantExplicitTypeFromConfig(string $constantName, Type $constantType): Type;
85+
8486
public function getIterableKeyType(Type $iteratee): Type;
8587

8688
public function getIterableValueType(Type $iteratee): Type;

src/DependencyInjection/ValidateIgnoredErrorsExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function loadConfiguration(): void
6969
ReflectionProviderStaticAccessor::registerInstance($reflectionProvider);
7070
PhpVersionStaticAccessor::registerInstance(new PhpVersion(PHP_VERSION_ID));
7171
$composerPhpVersionFactory = new ComposerPhpVersionFactory([]);
72-
$constantResolver = new ConstantResolver($reflectionProviderProvider, [], null, $composerPhpVersionFactory);
72+
$constantResolver = new ConstantResolver($reflectionProviderProvider, [], null, $composerPhpVersionFactory, null, null, null);
7373

7474
$phpDocParserConfig = new ParserConfig([]);
7575
$ignoredRegexValidator = new IgnoredRegexValidator(

src/Testing/PHPStanTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider
140140

141141
$reflectionProviderProvider = new DirectReflectionProviderProvider($reflectionProvider);
142142
$composerPhpVersionFactory = $container->getByType(ComposerPhpVersionFactory::class);
143-
$constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames, null, $composerPhpVersionFactory);
143+
$constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames, null, $composerPhpVersionFactory, null, null, $container);
144144

145145
$initializerExprTypeResolver = new InitializerExprTypeResolver(
146146
$constantResolver,

src/Type/Php/DefineConstantTypeSpecifyingExtension.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,17 @@ public function specifyTypes(
5252
return new SpecifiedTypes([], []);
5353
}
5454

55+
$valueType = $scope->getType($node->getArgs()[1]->value);
56+
$finalType = $scope->getConstantExplicitTypeFromConfig(
57+
$constantName->getValue(),
58+
$valueType,
59+
);
60+
5561
return $this->typeSpecifier->create(
5662
new Node\Expr\ConstFetch(
5763
new Node\Name\FullyQualified($constantName->getValue()),
5864
),
59-
$scope->getType($node->getArgs()[1]->value),
65+
$finalType,
6066
TypeSpecifierContext::createTruthy(),
6167
$scope,
6268
)->setAlwaysOverwriteTypes();

tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8244,6 +8244,10 @@ public static function dataDynamicConstants(): array
82448244
'string',
82458245
'DynamicConstants\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
82468246
],
8247+
[
8248+
'string|null',
8249+
'DynamicConstants\DynamicConstantClass::DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS',
8250+
],
82478251
[
82488252
"'abc123def'",
82498253
'DynamicConstants\DynamicConstantClass::PURE_CONSTANT_IN_CLASS',
@@ -8253,13 +8257,17 @@ public static function dataDynamicConstants(): array
82538257
'DynamicConstants\NoDynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
82548258
],
82558259
[
8256-
'false',
8260+
'bool',
82578261
'GLOBAL_DYNAMIC_CONSTANT',
82588262
],
82598263
[
82608264
'123',
82618265
'GLOBAL_PURE_CONSTANT',
82628266
],
8267+
[
8268+
'string|null',
8269+
'GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES',
8270+
],
82638271
];
82648272
}
82658273

@@ -8275,8 +8283,10 @@ public function testDynamicConstants(
82758283
$expression,
82768284
'die',
82778285
[
8278-
'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
8279-
'GLOBAL_DYNAMIC_CONSTANT',
8286+
0 => 'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
8287+
1 => 'GLOBAL_DYNAMIC_CONSTANT',
8288+
'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS' => 'string|null',
8289+
'GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES' => 'string|null',
82808290
],
82818291
);
82828292
}

tests/PHPStan/Analyser/data/dynamic-constant.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
define('GLOBAL_PURE_CONSTANT', 123);
66
define('GLOBAL_DYNAMIC_CONSTANT', false);
7+
define('GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES', null);
78

89
class DynamicConstantClass
910
{
1011
const DYNAMIC_CONSTANT_IN_CLASS = 'abcdef';
12+
const DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS = 'xyz';
1113
const PURE_CONSTANT_IN_CLASS = 'abc123def';
1214
}
1315

0 commit comments

Comments
 (0)