From 5010ef459465fa27a3b0fe3593bdd445b6dae8f3 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 23 Aug 2021 22:52:47 +0200 Subject: [PATCH] self::CONSTANT can be precise even with PHPDoc type --- src/Analyser/MutatingScope.php | 13 ++++++- tests/PHPStan/Analyser/data/bug-5293.php | 2 +- .../data/class-constant-stub-files.php | 8 +++- .../Analyser/data/class-constant-types.php | 38 ++++++++++++++++--- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index a84eacfa9d..3e76a98ef8 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1992,7 +1992,18 @@ private function resolveType(Expr $node): Type return new MixedType(); } - $constantType = $constantReflection->getValueType(); + if ( + $isObject + && ( + !$constantReflection instanceof ClassConstantReflection + || !$constantClassReflection->isFinal() + ) + ) { + $constantType = $constantReflection->getValueType(); + } else { + $constantType = ConstantTypeHelper::getTypeFromValue($constantReflection->getValue()); + } + if ( $constantType instanceof ConstantType && in_array(sprintf('%s::%s', $constantClassReflection->getName(), $constantName), $this->dynamicConstantNames, true) diff --git a/tests/PHPStan/Analyser/data/bug-5293.php b/tests/PHPStan/Analyser/data/bug-5293.php index 63f30fe000..40d8ca8cc4 100644 --- a/tests/PHPStan/Analyser/data/bug-5293.php +++ b/tests/PHPStan/Analyser/data/bug-5293.php @@ -49,7 +49,7 @@ public static function getAllSupportedCurrencies(): void { array_map( function (string $currencyCode): int { - assertType('non-empty-string', $currencyCode); + assertType('\'AUD\'|\'BGN\'|\'BRL\'|\'CAD\'|\'CHF\'|\'CZK\'|\'DKK\'|\'EUR\'|\'GBP\'|\'HUF\'|\'NOK\'|\'NZD\'|\'PLN\'|\'RON\'|\'SEK\'|\'SGD\'|\'USD\'', $currencyCode); return 1; }, self::SUPPORTED_CURRENCIES diff --git a/tests/PHPStan/Analyser/data/class-constant-stub-files.php b/tests/PHPStan/Analyser/data/class-constant-stub-files.php index 93f25365f3..4777b0ec22 100644 --- a/tests/PHPStan/Analyser/data/class-constant-stub-files.php +++ b/tests/PHPStan/Analyser/data/class-constant-stub-files.php @@ -15,6 +15,10 @@ class Foo } function (): void { - assertType('int', Foo::BAR); - assertType('int', Foo::BAZ); + assertType('1', Foo::BAR); + assertType('1', Foo::BAZ); + + $foo = new Foo(); + assertType('int', $foo::BAR); + assertType('int', $foo::BAZ); }; diff --git a/tests/PHPStan/Analyser/data/class-constant-types.php b/tests/PHPStan/Analyser/data/class-constant-types.php index c5fd3499b2..9d60af25c5 100644 --- a/tests/PHPStan/Analyser/data/class-constant-types.php +++ b/tests/PHPStan/Analyser/data/class-constant-types.php @@ -21,11 +21,11 @@ public function doFoo() assertType('mixed', static::NO_TYPE); assertType('mixed', $this::NO_TYPE); - assertType('string', self::TYPE); + assertType('\'foo\'', self::TYPE); assertType('string', static::TYPE); assertType('string', $this::TYPE); - assertType('string', self::PRIVATE_TYPE); + assertType('\'foo\'', self::PRIVATE_TYPE); assertType('string', static::PRIVATE_TYPE); assertType('string', $this::PRIVATE_TYPE); } @@ -41,7 +41,7 @@ class Bar extends Foo public function doFoo() { - assertType('string', self::TYPE); + assertType('\'bar\'', self::TYPE); assertType('string', static::TYPE); assertType('string', $this::TYPE); @@ -60,7 +60,7 @@ class Baz extends Foo public function doFoo() { - assertType('int', self::TYPE); + assertType('1', self::TYPE); assertType('int', static::TYPE); assertType('int', $this::TYPE); } @@ -75,9 +75,37 @@ class Lorem extends Foo public function doFoo() { - assertType('string', self::TYPE); + assertType('1', self::TYPE); assertType('string', static::TYPE); assertType('string', $this::TYPE); } } + +final class FinalFoo +{ + + const NO_TYPE = 1; + + /** @var string */ + const TYPE = 'foo'; + + /** @var string */ + private const PRIVATE_TYPE = 'foo'; + + public function doFoo() + { + assertType('1', self::NO_TYPE); + assertType('1', static::NO_TYPE); + assertType('1', $this::NO_TYPE); + + assertType('\'foo\'', self::TYPE); + assertType('\'foo\'', static::TYPE); + assertType('\'foo\'', $this::TYPE); + + assertType('\'foo\'', self::PRIVATE_TYPE); + assertType('\'foo\'', static::PRIVATE_TYPE); + assertType('\'foo\'', $this::PRIVATE_TYPE); + } + +}