From e8e8f1fbd45e7f97745ffd186a55ef5958bb984a Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:29:05 +0200 Subject: [PATCH] make superglobals more specific --- .../Fetch/VariableFetchAnalyzer.php | 109 ++++++++++++++++-- 1 file changed, 100 insertions(+), 9 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php index 3ecde22a7f9..2695d90f0db 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php @@ -22,7 +22,16 @@ use Psalm\IssueBuffer; use Psalm\Type; use Psalm\Type\Atomic\TArray; +use Psalm\Type\Atomic\TArrayKey; +use Psalm\Type\Atomic\TFloat; +use Psalm\Type\Atomic\TInt; +use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TList; +use Psalm\Type\Atomic\TMixed; +use Psalm\Type\Atomic\TNull; +use Psalm\Type\Atomic\TNonEmptyList; +use Psalm\Type\Atomic\TPositiveInt; +use Psalm\Type\Atomic\TString; use Psalm\Type\TaintKindGroup; use Psalm\Type\Union; @@ -531,29 +540,111 @@ public static function getGlobalType(string $var_id): Union } if ($var_id === '$argv') { + // only in CLI, null otherwise return new Union([ - new TArray([Type::getInt(), Type::getString()]), + new TNonEmptyList([Type::getNonEmptyString()]), + new TNull() ]); } if ($var_id === '$argc') { - return Type::getInt(); + // only in CLI, null otherwise + return new Union([ + new TPositiveInt(), + new TNull() + ]); } if ($var_id === '$http_response_header') { return new Union([ - new TList(Type::getString()) + new TList(Type::getNonEmptyString()) ]); } - if (self::isSuperGlobal($var_id)) { - $type = Type::getArray(); - if ($var_id === '$_SESSION') { - $type->possibly_undefined = true; + if (!self::isSuperGlobal($var_id)) { + return Type::getMixed(); + } + + if ($var_id === '$_COOKIE') { + $type = new TArray( + [ + Type::getNonEmptyString(), + Type::getString(), + ] + ); + + return new Union([$type]); + } + + if (in_array($var_id, array('$_GET', '$_POST', '$_REQUEST'), true)) { + $array = new TArray( + [ + new Union([new TArrayKey]), + new Union([new TMixed]), + ] + ); + + $type = new TArray( + [ + Type::getNonEmptyString(), + new Union([new TString(), $array]), + ] + ); + + return new Union([$type]); + } + + if ($var_id === '$_SERVER' || $var_id === '$_ENV') { + $type = new TArray( + [ + Type::getNonEmptyString(), + new Union([new TFloat(), new TPositiveInt(), new TString(), new TNonEmptyList(Type::getNonEmptyString())]), + ] + ); + + return new Union([$type]); + } + + if ($var_id === '$_FILES') { + $values = [ + 'name' => new Union([ + new TString(), + new TNonEmptyList(Type::getString()), + ]), + 'type' => new Union([ + new TString(), + new TNonEmptyList(Type::getString()), + ]), + 'size' => new Union([ + new TInt(), + new TNonEmptyList(Type::getInt()), + ]), + 'tmp_name' => new Union([ + new TString(), + new TNonEmptyList(Type::getString()), + ]), + 'error' => new Union([ + new TInt(), + new TNonEmptyList(Type::getInt()), + ]), + ]; + + if (version_compare( $config->getPhpVersionFromConfig(), '8.1', '>=')) { + $values['full_path'] = new Union([ + new TString(), + new TNonEmptyList(Type::getString()), + ]); } - return $type; + + $type = new TKeyedArray($values); + + return new Union([$type]); } - return Type::getMixed(); + $type = Type::getArray(); + if ($var_id === '$_SESSION') { + $type->possibly_undefined = true; + } + return $type; } }