From 03f7c263fedd20febfde984a3554b6df0d7c60aa Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sun, 13 Aug 2023 05:41:08 +0200 Subject: [PATCH] Correct type for `$enum->name` --- .../Fetch/AtomicPropertyFetchAnalyzer.php | 33 ++++++++++++----- tests/EnumTest.php | 36 +++++++++++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php index 663679383..d6289b668 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php @@ -228,7 +228,7 @@ class AtomicPropertyFetchAnalyzer self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage); } elseif ($prop_name === 'name') { $has_valid_fetch_type = true; - self::handleEnumName($statements_analyzer, $stmt, $lhs_type_part); + self::handleEnumName($statements_analyzer, $stmt, $stmt_var_type, $class_storage); } else { self::handleNonExistentProperty( $statements_analyzer, @@ -979,16 +979,31 @@ class AtomicPropertyFetchAnalyzer private static function handleEnumName( StatementsAnalyzer $statements_analyzer, PropertyFetch $stmt, - Atomic $lhs_type_part + Union $stmt_var_type, + ClassLikeStorage $class_storage ): void { - if ($lhs_type_part instanceof TEnumCase) { - $statements_analyzer->node_data->setType( - $stmt, - new Union([Type::getAtomicStringFromLiteral($lhs_type_part->case_name)]), - ); - } else { - $statements_analyzer->node_data->setType($stmt, Type::getNonEmptyString()); + $relevant_enum_cases = array_filter( + $stmt_var_type->getAtomicTypes(), + static fn(Atomic $type): bool => $type instanceof TEnumCase, + ); + $relevant_enum_case_names = array_map( + static fn(TEnumCase $enumCase): string => $enumCase->case_name, + $relevant_enum_cases, + ); + + if (empty($relevant_enum_case_names)) { + $relevant_enum_case_names = array_keys($class_storage->enum_cases); } + + $statements_analyzer->node_data->setType( + $stmt, + empty($relevant_enum_case_names) + ? Type::getNonEmptyString() + : new Union(array_map( + fn(string $name): TString => Type::getAtomicStringFromLiteral($name), + $relevant_enum_case_names, + )), + ); } private static function handleEnumValue( diff --git a/tests/EnumTest.php b/tests/EnumTest.php index 481824c10..1ac88b1c2 100644 --- a/tests/EnumTest.php +++ b/tests/EnumTest.php @@ -574,6 +574,42 @@ class EnumTest extends TestCase 'ignored_issues' => [], 'php_version' => '8.1', ], + 'nameTypeOnKnownCases' => [ + 'code' => <<<'PHP' + name; + PHP, + 'assertions' => [ + '$_name===' => "'BIKE'|'BOAT'|'CAR'", + ], + 'ignored_issues' => [], + 'php_version' => '8.1', + ], + 'nameTypeOnUnknownCases' => [ + 'code' => <<<'PHP' + name; + /** @psalm-check-type-exact $_name='BIKE'|'BOAT'|'CAR' */; + } + PHP, + 'assertions' => [], + 'ignored_issues' => [], + 'php_version' => '8.1', + ], ]; }