diff --git a/src/Reflection/ClassConstantReflection.php b/src/Reflection/ClassConstantReflection.php index f54fc37ba4..00874b9081 100644 --- a/src/Reflection/ClassConstantReflection.php +++ b/src/Reflection/ClassConstantReflection.php @@ -28,6 +28,7 @@ public function __construct( private ?string $deprecatedDescription, private bool $isDeprecated, private bool $isInternal, + private bool $isFinal, ) { } @@ -124,7 +125,7 @@ public function isPublic(): bool public function isFinal(): bool { - return $this->reflection->isFinal(); + return $this->isFinal || $this->reflection->isFinal(); } public function isDeprecated(): TrinaryLogic diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index ff45172fd8..02705f32cd 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -1080,6 +1080,7 @@ public function getConstant(string $name): ClassConstantReflection $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; $isDeprecated = $resolvedPhpDoc->isDeprecated(); $isInternal = $resolvedPhpDoc->isInternal(); + $isFinal = $resolvedPhpDoc->isFinal(); $varTags = $resolvedPhpDoc->getVarTags(); if (isset($varTags[0]) && count($varTags) === 1) { $phpDocType = $varTags[0]->getType(); @@ -1101,6 +1102,7 @@ public function getConstant(string $name): ClassConstantReflection $deprecatedDescription, $isDeprecated, $isInternal, + $isFinal, ); } return $this->constants[$name]; diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 178c16b4a8..8cedcd1272 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -1987,6 +1987,7 @@ function (Type $type, callable $traverse): Type { $constantReflection = $constantClassReflection->getConstant($constantName); if ( !$constantClassReflection->isFinal() + && !$constantReflection->isFinal() && !$constantReflection->hasPhpDocType() && !$constantReflection->hasNativeType() ) { diff --git a/tests/PHPStan/Analyser/nsrt/class-constant-types.php b/tests/PHPStan/Analyser/nsrt/class-constant-types.php index 9d60af25c5..8f19f7659e 100644 --- a/tests/PHPStan/Analyser/nsrt/class-constant-types.php +++ b/tests/PHPStan/Analyser/nsrt/class-constant-types.php @@ -15,6 +15,9 @@ class Foo /** @var string */ private const PRIVATE_TYPE = 'foo'; + /** @final */ + const FINAL_TYPE = 'zoo'; + public function doFoo() { assertType('1', self::NO_TYPE); @@ -28,6 +31,10 @@ public function doFoo() assertType('\'foo\'', self::PRIVATE_TYPE); assertType('string', static::PRIVATE_TYPE); assertType('string', $this::PRIVATE_TYPE); + + assertType('\'zoo\'', self::FINAL_TYPE); + assertType('\'zoo\'', static::FINAL_TYPE); + assertType('\'zoo\'', $this::FINAL_TYPE); } }