From dcc855de95fb29f0fe13491971fa814be495df7a Mon Sep 17 00:00:00 2001 From: Brown Date: Fri, 7 Feb 2020 10:54:57 -0500 Subject: [PATCH] Fix #2739 - specify wildcards in constants --- .../Statements/ExpressionAnalyzer.php | 55 +++++++++++++++---- src/Psalm/Internal/Type/ParseTree.php | 2 +- .../Internal/Visitor/SimpleNameResolver.php | 2 +- tests/ConstantTest.php | 53 ++++++++++++++++++ 4 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php index a7dda5a4f..375f0e916 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php @@ -1311,22 +1311,53 @@ class ExpressionAnalyzer return new Type\Atomic\TLiteralClassString($return_type->fq_classlike_name); } - try { - $class_constant = $codebase->classlikes->getConstantForClass( - $return_type->fq_classlike_name, - $return_type->const_name, - \ReflectionProperty::IS_PRIVATE - ); - } catch (\Psalm\Exception\CircularReferenceException $e) { - $class_constant = null; + if (strpos($return_type->const_name, '*') !== false) { + $class_storage = $codebase->classlike_storage_provider->get($return_type->fq_classlike_name); + + $matching_constants = \array_keys($class_storage->class_constant_locations); + + $const_name_part = \substr($return_type->const_name, 0, -1); + + if ($const_name_part) { + $matching_constants = \array_filter( + $matching_constants, + function ($constant_name) use ($const_name_part) { + return $constant_name !== $const_name_part + && \strpos($constant_name, $const_name_part) === 0; + } + ); + } + } else { + $matching_constants = [$return_type->const_name]; } - if ($class_constant) { - if ($class_constant->isSingle()) { - $class_constant = clone $class_constant; + $matching_constant_types = []; - return array_values($class_constant->getAtomicTypes())[0]; + foreach ($matching_constants as $matching_constant) { + try { + $class_constant = $codebase->classlikes->getConstantForClass( + $return_type->fq_classlike_name, + $matching_constant, + \ReflectionProperty::IS_PRIVATE + ); + } catch (\Psalm\Exception\CircularReferenceException $e) { + $class_constant = null; } + + if ($class_constant) { + if ($class_constant->isSingle()) { + $class_constant = clone $class_constant; + + $matching_constant_types = \array_merge( + \array_values($class_constant->getAtomicTypes()), + $matching_constant_types + ); + } + } + } + + if ($matching_constant_types) { + return $matching_constant_types; } } diff --git a/src/Psalm/Internal/Type/ParseTree.php b/src/Psalm/Internal/Type/ParseTree.php index 6030bd6a6..a300ba216 100644 --- a/src/Psalm/Internal/Type/ParseTree.php +++ b/src/Psalm/Internal/Type/ParseTree.php @@ -547,7 +547,7 @@ class ParseTree $nexter_token = $i + 2 < $c ? $type_tokens[$i + 2] : null; if (!$nexter_token - || (!preg_match('/^[a-zA-Z_][a-zA-Z_0-9]*$/', $nexter_token[0]) + || (!preg_match('/^([a-zA-Z_][a-zA-Z_0-9]*\*?|\*)$/', $nexter_token[0]) && strtolower($nexter_token[0]) !== 'class') ) { throw new TypeParseTreeException( diff --git a/src/Psalm/Internal/Visitor/SimpleNameResolver.php b/src/Psalm/Internal/Visitor/SimpleNameResolver.php index 68f60a512..f3ebec30c 100644 --- a/src/Psalm/Internal/Visitor/SimpleNameResolver.php +++ b/src/Psalm/Internal/Visitor/SimpleNameResolver.php @@ -197,7 +197,7 @@ class SimpleNameResolver extends NodeVisitorAbstract * Resolve name, according to name resolver options. * * @param Name $name Function or constant name to resolve - * @param int $type One of Stmt\Use_::TYPE_* + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* * * @return Name Resolved name, or original name with attribute */ diff --git a/tests/ConstantTest.php b/tests/ConstantTest.php index f5c1aaf31..25e99a2b4 100644 --- a/tests/ConstantTest.php +++ b/tests/ConstantTest.php @@ -622,6 +622,42 @@ class ConstantTest extends TestCase public $foo = "a"; }', ], + 'wildcardEnum' => [ + ' [ + ' 'InvalidArgument', ], + 'wildcardEnumBadValue' => [ + ' 'InvalidArgument' + ], ]; } }