From f93d23899de79beebd8f9d86561081c3583d2f59 Mon Sep 17 00:00:00 2001 From: Yannick Gottschalk Date: Wed, 21 Jun 2023 13:54:56 +0200 Subject: [PATCH] Fix glob CallMap and stub to prevent crash on alpine (and possibly other systems) --- dictionaries/CallMap.php | 2 +- dictionaries/CallMap_historical.php | 2 +- .../Reflector/ExpressionResolver.php | 16 ++++ stubs/CoreGenericFunctions.phpstub | 80 ++++++++++++------- tests/CoreStubsTest.php | 6 ++ 5 files changed, 77 insertions(+), 29 deletions(-) diff --git a/dictionaries/CallMap.php b/dictionaries/CallMap.php index 5d6c352de82..0f17d1917c8 100644 --- a/dictionaries/CallMap.php +++ b/dictionaries/CallMap.php @@ -3330,7 +3330,7 @@ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], -'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int-mask'], +'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'], 'GlobIterator::count' => ['int'], 'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'], diff --git a/dictionaries/CallMap_historical.php b/dictionaries/CallMap_historical.php index 395f271be5a..62a59df5487 100644 --- a/dictionaries/CallMap_historical.php +++ b/dictionaries/CallMap_historical.php @@ -10764,7 +10764,7 @@ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], - 'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int-mask'], + 'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'gmmktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], diff --git a/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php b/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php index 116a8a29559..93a0ddcecd4 100644 --- a/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php +++ b/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php @@ -32,9 +32,12 @@ use ReflectionClass; use ReflectionFunction; +use function array_merge; +use function array_values; use function assert; use function class_exists; use function function_exists; +use function get_defined_constants; use function implode; use function in_array; use function interface_exists; @@ -514,6 +517,19 @@ private static function functionEvaluatesToTrue( return false; } + if ($function->name->parts === ['defined'] + && isset($function->getArgs()[0]) + && $function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_ + ) { + $predefined_constants = get_defined_constants(true); + if (isset($predefined_constants['user'])) { + unset($predefined_constants['user']); + } + $predefined_constants = array_merge(...array_values($predefined_constants)); + + return isset($predefined_constants[$function->getArgs()[0]->value->value]); + } + return null; } } diff --git a/stubs/CoreGenericFunctions.phpstub b/stubs/CoreGenericFunctions.phpstub index 38cdb31b331..d5d669beaef 100644 --- a/stubs/CoreGenericFunctions.phpstub +++ b/stubs/CoreGenericFunctions.phpstub @@ -1717,31 +1717,57 @@ function pg_escape_literal($string1, $string2 = null) {} */ function pg_escape_string($string1, $string2 = null) {} -/** - * @psalm-template P of string - * @psalm-template F of int-mask - * @psalm-param P $pattern - * @psalm-param F $flags - * @psalm-return ( - * P is '' - * ? (F is int-mask - * ? false|list - * : (F is int-mask - * ? false|list{0:''} - * : false|list - * ) - * ) - * : (F is int-mask - * ? false|list - * : (F is int-mask - * ? false|list{0:non-empty-string, ...} - * : false|list - * ) - * ) - * ) - * @psalm-ignore-falsable-return - */ -function glob (string $pattern, int $flags = 0): array|false {} - - +if (defined('GLOB_BRACE')) { + /** + * @psalm-template P of string + * @psalm-template F of int-mask + * @psalm-param P $pattern + * @psalm-param F $flags + * @psalm-return ( + * P is '' + * ? (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:''} + * : false|list + * ) + * ) + * : (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:non-empty-string, ...} + * : false|list + * ) + * ) + * ) + * @psalm-ignore-falsable-return + */ + function glob (string $pattern, int $flags = 0): array|false {} +} else { + /** + * @psalm-template P of string + * @psalm-template F of int-mask + * @psalm-param P $pattern + * @psalm-param F $flags + * @psalm-return ( + * P is '' + * ? (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:''} + * : false|list + * ) + * ) + * : (F is int-mask + * ? false|list + * : (F is int-mask + * ? false|list{0:non-empty-string, ...} + * : false|list + * ) + * ) + * ) + * @psalm-ignore-falsable-return + */ + function glob (string $pattern, int $flags = 0): array|false {} +} diff --git a/tests/CoreStubsTest.php b/tests/CoreStubsTest.php index d3d2e2faf22..ed3d0b76327 100644 --- a/tests/CoreStubsTest.php +++ b/tests/CoreStubsTest.php @@ -406,6 +406,12 @@ function takesList(array $list): void {} takesList(glob( '' )); PHP, ]; + yield 'glob accepts GLOB_BRACE' => [ + 'code' => <<<'PHP' +