diff --git a/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php b/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php index 89970fad0b..9224db2dbe 100644 --- a/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php @@ -8,6 +8,7 @@ use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\ReflectionProvider; +use PHPStan\Type\Accessory\AccessoryArrayListType; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantArrayTypeBuilder; use PHPStan\Type\Constant\ConstantBooleanType; @@ -16,6 +17,7 @@ use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; +use PHPStan\Type\MixedType; use PHPStan\Type\NullType; use PHPStan\Type\StringType; use PHPStan\Type\Type; @@ -63,8 +65,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $floatType = new FloatType(); $falseType = new ConstantBooleanType(false); $stringFalseType = TypeCombinator::union($stringType, $falseType); - $integerStringArrayType = new ArrayType($integerType, $stringType); - $nestedStringStringArrayType = new ArrayType($integerType, new ArrayType($stringType, $stringType)); + $integerFalseType = TypeCombinator::union($integerType, $falseType); + $stringListType = TypeCombinator::intersect(new ArrayType($integerType, $stringType), new AccessoryArrayListType()); + $nestedArrayInListType = TypeCombinator::intersect(new ArrayType($integerType, new ArrayType($stringType, $stringType)), new AccessoryArrayListType()); + $mixedType = new MixedType(); $componentTypesPairedConstants = [ 'CURLINFO_EFFECTIVE_URL' => $stringType, @@ -76,15 +80,15 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, 'CURLINFO_STARTTRANSFER_TIME' => $floatType, 'CURLINFO_REDIRECT_COUNT' => $integerType, 'CURLINFO_REDIRECT_TIME' => $floatType, - 'CURLINFO_REDIRECT_URL' => $stringType, + 'CURLINFO_REDIRECT_URL' => $stringFalseType, 'CURLINFO_PRIMARY_IP' => $stringType, 'CURLINFO_PRIMARY_PORT' => $integerType, 'CURLINFO_LOCAL_IP' => $stringType, 'CURLINFO_LOCAL_PORT' => $integerType, - 'CURLINFO_SIZE_UPLOAD' => $integerType, - 'CURLINFO_SIZE_DOWNLOAD' => $integerType, - 'CURLINFO_SPEED_DOWNLOAD' => $integerType, - 'CURLINFO_SPEED_UPLOAD' => $integerType, + 'CURLINFO_SIZE_UPLOAD' => $floatType, + 'CURLINFO_SIZE_DOWNLOAD' => $floatType, + 'CURLINFO_SPEED_DOWNLOAD' => $floatType, + 'CURLINFO_SPEED_UPLOAD' => $floatType, 'CURLINFO_HEADER_SIZE' => $integerType, 'CURLINFO_HEADER_OUT' => $stringFalseType, 'CURLINFO_REQUEST_SIZE' => $integerType, @@ -92,25 +96,26 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, 'CURLINFO_CONTENT_LENGTH_DOWNLOAD' => $floatType, 'CURLINFO_CONTENT_LENGTH_UPLOAD' => $floatType, 'CURLINFO_CONTENT_TYPE' => $stringFalseType, - 'CURLINFO_PRIVATE' => $stringFalseType, + 'CURLINFO_PRIVATE' => $mixedType, 'CURLINFO_RESPONSE_CODE' => $integerType, + 'CURLINFO_HTTP_CODE' => $integerType, 'CURLINFO_HTTP_CONNECTCODE' => $integerType, 'CURLINFO_HTTPAUTH_AVAIL' => $integerType, 'CURLINFO_PROXYAUTH_AVAIL' => $integerType, 'CURLINFO_OS_ERRNO' => $integerType, 'CURLINFO_NUM_CONNECTS' => $integerType, - 'CURLINFO_SSL_ENGINES' => $integerStringArrayType, - 'CURLINFO_COOKIELIST' => $integerStringArrayType, + 'CURLINFO_SSL_ENGINES' => $stringListType, + 'CURLINFO_COOKIELIST' => $stringListType, 'CURLINFO_FTP_ENTRY_PATH' => $stringFalseType, 'CURLINFO_APPCONNECT_TIME' => $floatType, - 'CURLINFO_CERTINFO' => $nestedStringStringArrayType, + 'CURLINFO_CERTINFO' => $nestedArrayInListType, 'CURLINFO_CONDITION_UNMET' => $integerType, 'CURLINFO_RTSP_CLIENT_CSEQ' => $integerType, 'CURLINFO_RTSP_CSEQ_RECV' => $integerType, 'CURLINFO_RTSP_SERVER_CSEQ' => $integerType, - 'CURLINFO_RTSP_SESSION_ID' => $integerType, + 'CURLINFO_RTSP_SESSION_ID' => $stringFalseType, 'CURLINFO_HTTP_VERSION' => $integerType, - 'CURLINFO_PROTOCOL' => $stringType, + 'CURLINFO_PROTOCOL' => $integerType, 'CURLINFO_PROXY_SSL_VERIFYRESULT' => $integerType, 'CURLINFO_SCHEME' => $stringType, 'CURLINFO_CONTENT_LENGTH_DOWNLOAD_T' => $integerType, @@ -127,6 +132,18 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, 'CURLINFO_REDIRECT_TIME_T' => $integerType, 'CURLINFO_STARTTRANSFER_TIME_T' => $integerType, 'CURLINFO_TOTAL_TIME_T' => $integerType, + 'CURLINFO_EFFECTIVE_METHOD' => $stringType, + 'CURLINFO_PROXY_ERROR' => $integerType, + 'CURLINFO_REFERER' => $stringFalseType, + 'CURLINFO_RETRY_AFTER' => $integerType, + 'CURLINFO_CAINFO' => $stringFalseType, + 'CURLINFO_CAPATH' => $stringFalseType, + 'CURLINFO_POSTTRANSFER_TIME_T' => $integerFalseType, + 'CURLINFO_QUEUE_TIME_T' => $integerFalseType, + 'CURLINFO_USED_PROXY' => $integerFalseType, + 'CURLINFO_HTTPAUTH_USED' => $integerFalseType, + 'CURLINFO_PROXYAUTH_USED' => $integerFalseType, + 'CURLINFO_CONN_ID' => $integerFalseType, ]; foreach ($componentTypesPairedConstants as $constantName => $type) { @@ -156,7 +173,7 @@ private function createAllComponentsReturnType(): Type $integerType = new IntegerType(); $floatType = new FloatType(); $stringOrNullType = TypeCombinator::union($stringType, new NullType()); - $nestedStringStringArrayType = new ArrayType($integerType, new ArrayType($stringType, $stringType)); + $nestedArrayInListType = TypeCombinator::intersect(new ArrayType($integerType, new ArrayType($stringType, $stringType)), new AccessoryArrayListType()); $componentTypesPairedStrings = [ 'url' => $stringType, @@ -181,7 +198,7 @@ private function createAllComponentsReturnType(): Type 'redirect_time' => $floatType, 'redirect_url' => $stringType, 'primary_ip' => $stringType, - 'certinfo' => $nestedStringStringArrayType, + 'certinfo' => $nestedArrayInListType, 'primary_port' => $integerType, 'local_ip' => $stringType, 'local_port' => $integerType, @@ -189,6 +206,23 @@ private function createAllComponentsReturnType(): Type 'protocol' => $integerType, 'ssl_verifyresult' => $integerType, 'scheme' => $stringType, + 'appconnect_time_us' => $integerType, + 'queue_time_us' => $integerType, + 'connect_time_us' => $integerType, + 'namelookup_time_us' => $integerType, + 'pretransfer_time_us' => $integerType, + 'redirect_time_us' => $integerType, + 'starttransfer_time_us' => $integerType, + 'posttransfer_time_us' => $integerType, + 'total_time_us' => $integerType, + 'request_header' => $stringType, + 'effective_method' => $stringType, + 'capath' => $stringType, + 'cainfo' => $stringType, + 'used_proxy' => $integerType, + 'httpauth_used' => $integerType, + 'proxyauth_used' => $integerType, + 'conn_id' => $integerType, ]; foreach ($componentTypesPairedStrings as $componentName => $componentValueType) { $builder->setOffsetValueType(new ConstantStringType($componentName), $componentValueType); diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo.php index 453b835778..94750ddacc 100644 --- a/tests/PHPStan/Analyser/nsrt/curl_getinfo.php +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo.php @@ -9,15 +9,17 @@ class Foo { public function bar() { + $curlGetInfoType = '(array{url: string, content_type: string|null, http_code: int, header_size: int, request_size: int, filetime: int, ssl_verify_result: int, redirect_count: int, total_time: float, namelookup_time: float, connect_time: float, pretransfer_time: float, size_upload: float, size_download: float, speed_download: float, speed_upload: float, download_content_length: float, upload_content_length: float, starttransfer_time: float, redirect_time: float, redirect_url: string, primary_ip: string, certinfo: list>, primary_port: int, local_ip: string, local_port: int, http_version: int, protocol: int, ssl_verifyresult: int, scheme: string, appconnect_time_us: int, queue_time_us: int, connect_time_us: int, namelookup_time_us: int, pretransfer_time_us: int, redirect_time_us: int, starttransfer_time_us: int, posttransfer_time_us: int, total_time_us: int, request_header: string, effective_method: string, capath: string, cainfo: string, used_proxy: int, httpauth_used: int, proxyauth_used: int, conn_id: int}|false)'; + $handle = new CurlHandle(); assertType('mixed', curl_getinfo()); assertType('mixed', CURL_GETINFO()); assertType('mixed', CuRl_GeTiNfO()); assertType('false', curl_getinfo($handle, 'Invalid Argument')); - assertType('(array{url: string, content_type: string|null, http_code: int, header_size: int, request_size: int, filetime: int, ssl_verify_result: int, redirect_count: int, total_time: float, namelookup_time: float, connect_time: float, pretransfer_time: float, size_upload: float, size_download: float, speed_download: float, speed_upload: float, download_content_length: float, upload_content_length: float, starttransfer_time: float, redirect_time: float, redirect_url: string, primary_ip: string, certinfo: array>, primary_port: int, local_ip: string, local_port: int, http_version: int, protocol: int, ssl_verifyresult: int, scheme: string}|false)', curl_getinfo($handle, PHP_INT_MAX)); + assertType($curlGetInfoType, curl_getinfo($handle, PHP_INT_MAX)); assertType('false', curl_getinfo($handle, PHP_EOL)); - assertType('(array{url: string, content_type: string|null, http_code: int, header_size: int, request_size: int, filetime: int, ssl_verify_result: int, redirect_count: int, total_time: float, namelookup_time: float, connect_time: float, pretransfer_time: float, size_upload: float, size_download: float, speed_download: float, speed_upload: float, download_content_length: float, upload_content_length: float, starttransfer_time: float, redirect_time: float, redirect_url: string, primary_ip: string, certinfo: array>, primary_port: int, local_ip: string, local_port: int, http_version: int, protocol: int, ssl_verifyresult: int, scheme: string}|false)', curl_getinfo($handle)); - assertType('(array{url: string, content_type: string|null, http_code: int, header_size: int, request_size: int, filetime: int, ssl_verify_result: int, redirect_count: int, total_time: float, namelookup_time: float, connect_time: float, pretransfer_time: float, size_upload: float, size_download: float, speed_download: float, speed_upload: float, download_content_length: float, upload_content_length: float, starttransfer_time: float, redirect_time: float, redirect_url: string, primary_ip: string, certinfo: array>, primary_port: int, local_ip: string, local_port: int, http_version: int, protocol: int, ssl_verifyresult: int, scheme: string}|false)', curl_getinfo($handle, null)); + assertType($curlGetInfoType, curl_getinfo($handle)); + assertType($curlGetInfoType, curl_getinfo($handle, null)); assertType('string', curl_getinfo($handle, CURLINFO_EFFECTIVE_URL)); assertType('string', curl_getinfo($handle, 1048577)); // CURLINFO_EFFECTIVE_URL int value without using constant assertType('false', curl_getinfo($handle, 12345678)); // Non constant non CURLINFO_* int value @@ -29,15 +31,15 @@ public function bar() assertType('float', curl_getinfo($handle, CURLINFO_STARTTRANSFER_TIME)); assertType('int', curl_getinfo($handle, CURLINFO_REDIRECT_COUNT)); assertType('float', curl_getinfo($handle, CURLINFO_REDIRECT_TIME)); - assertType('string', curl_getinfo($handle, CURLINFO_REDIRECT_URL)); + assertType('string|false', curl_getinfo($handle, CURLINFO_REDIRECT_URL)); assertType('string', curl_getinfo($handle, CURLINFO_PRIMARY_IP)); assertType('int', curl_getinfo($handle, CURLINFO_PRIMARY_PORT)); assertType('string', curl_getinfo($handle, CURLINFO_LOCAL_IP)); assertType('int', curl_getinfo($handle, CURLINFO_LOCAL_PORT)); - assertType('int', curl_getinfo($handle, CURLINFO_SIZE_UPLOAD)); - assertType('int', curl_getinfo($handle, CURLINFO_SIZE_DOWNLOAD)); - assertType('int', curl_getinfo($handle, CURLINFO_SPEED_DOWNLOAD)); - assertType('int', curl_getinfo($handle, CURLINFO_SPEED_UPLOAD)); + assertType('float', curl_getinfo($handle, CURLINFO_SIZE_UPLOAD)); + assertType('float', curl_getinfo($handle, CURLINFO_SIZE_DOWNLOAD)); + assertType('float', curl_getinfo($handle, CURLINFO_SPEED_DOWNLOAD)); + assertType('float', curl_getinfo($handle, CURLINFO_SPEED_UPLOAD)); assertType('int', curl_getinfo($handle, CURLINFO_HEADER_SIZE)); assertType('string|false', curl_getinfo($handle, CURLINFO_HEADER_OUT)); assertType('int', curl_getinfo($handle, CURLINFO_REQUEST_SIZE)); @@ -45,22 +47,23 @@ public function bar() assertType('float', curl_getinfo($handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD)); assertType('float', curl_getinfo($handle, CURLINFO_CONTENT_LENGTH_UPLOAD)); assertType('string|false', curl_getinfo($handle, CURLINFO_CONTENT_TYPE)); - assertType('string|false', curl_getinfo($handle, CURLINFO_PRIVATE)); + assertType('mixed', curl_getinfo($handle, CURLINFO_PRIVATE)); assertType('int', curl_getinfo($handle, CURLINFO_RESPONSE_CODE)); + assertType('int', curl_getinfo($handle, CURLINFO_HTTP_CODE));; assertType('int', curl_getinfo($handle, CURLINFO_HTTP_CONNECTCODE)); assertType('int', curl_getinfo($handle, CURLINFO_HTTPAUTH_AVAIL)); assertType('int', curl_getinfo($handle, CURLINFO_PROXYAUTH_AVAIL)); assertType('int', curl_getinfo($handle, CURLINFO_OS_ERRNO)); assertType('int', curl_getinfo($handle, CURLINFO_NUM_CONNECTS)); - assertType('array', curl_getinfo($handle, CURLINFO_SSL_ENGINES)); - assertType('array', curl_getinfo($handle, CURLINFO_COOKIELIST)); + assertType('list', curl_getinfo($handle, CURLINFO_SSL_ENGINES)); + assertType('list', curl_getinfo($handle, CURLINFO_COOKIELIST)); assertType('string|false', curl_getinfo($handle, CURLINFO_FTP_ENTRY_PATH)); assertType('float', curl_getinfo($handle, CURLINFO_APPCONNECT_TIME)); - assertType('array>', curl_getinfo($handle, CURLINFO_CERTINFO)); + assertType('list>', curl_getinfo($handle, CURLINFO_CERTINFO)); assertType('int', curl_getinfo($handle, CURLINFO_CONDITION_UNMET)); assertType('int', curl_getinfo($handle, CURLINFO_RTSP_CLIENT_CSEQ)); assertType('int', curl_getinfo($handle, CURLINFO_RTSP_CSEQ_RECV)); assertType('int', curl_getinfo($handle, CURLINFO_RTSP_SERVER_CSEQ)); - assertType('int', curl_getinfo($handle, CURLINFO_RTSP_SESSION_ID)); + assertType('string|false', curl_getinfo($handle, CURLINFO_RTSP_SESSION_ID)); } } diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo_7.3.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo_7.3.php index a42f17ab32..90e7c82e83 100644 --- a/tests/PHPStan/Analyser/nsrt/curl_getinfo_7.3.php +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo_7.3.php @@ -5,14 +5,15 @@ use CurlHandle; use function PHPStan\Testing\assertType; -class Foo { +class Foo +{ public function bar() { $handle = new CurlHandle(); assertType('int', curl_getinfo($handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T)); assertType('int', curl_getinfo($handle, CURLINFO_CONTENT_LENGTH_UPLOAD_T)); assertType('int', curl_getinfo($handle, CURLINFO_HTTP_VERSION)); - assertType('string', curl_getinfo($handle, CURLINFO_PROTOCOL)); + assertType('int', curl_getinfo($handle, CURLINFO_PROTOCOL)); assertType('int', curl_getinfo($handle, CURLINFO_PROXY_SSL_VERIFYRESULT)); assertType('string', curl_getinfo($handle, CURLINFO_SCHEME)); assertType('int', curl_getinfo($handle, CURLINFO_SIZE_DOWNLOAD_T)); diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.2.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.2.php new file mode 100644 index 0000000000..07cd3431da --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.2.php @@ -0,0 +1,18 @@ += 8.2 + +namespace CurlGetinfo82; + +use CurlHandle; +use function PHPStan\Testing\assertType; + +class Foo +{ + public function bar() + { + $handle = new CurlHandle(); + assertType('string', curl_getinfo($handle, CURLINFO_EFFECTIVE_METHOD)); + assertType('int', curl_getinfo($handle, CURLINFO_PROXY_ERROR)); + assertType('string|false', curl_getinfo($handle, CURLINFO_REFERER)); + assertType('int', curl_getinfo($handle, CURLINFO_RETRY_AFTER)); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.3.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.3.php new file mode 100644 index 0000000000..5d9d4258cf --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.3.php @@ -0,0 +1,16 @@ += 8.3 + +namespace CurlGetinfo83; + +use CurlHandle; +use function PHPStan\Testing\assertType; + +class Foo +{ + public function bar() + { + $handle = new CurlHandle(); + assertType('string|false', curl_getinfo($handle, CURLINFO_CAINFO)); + assertType('string|false', curl_getinfo($handle, CURLINFO_CAPATH)); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.4.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.4.php new file mode 100644 index 0000000000..ca896481d0 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.4.php @@ -0,0 +1,15 @@ += 8.4 + +namespace CurlGetinfo84; + +use CurlHandle; +use function PHPStan\Testing\assertType; + +class Foo +{ + public function bar() + { + $handle = new CurlHandle(); + assertType('int|false', curl_getinfo($handle, CURLINFO_POSTTRANSFER_TIME_T)); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.5.php b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.5.php new file mode 100644 index 0000000000..687096022e --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/curl_getinfo_8.5.php @@ -0,0 +1,19 @@ += 8.5 + +namespace CurlGetinfo85; + +use CurlHandle; +use function PHPStan\Testing\assertType; + +class Foo +{ + public function bar() + { + $handle = new CurlHandle(); + assertType('int|false', curl_getinfo($handle, CURLINFO_QUEUE_TIME_T)); + assertType('int|false', curl_getinfo($handle, CURLINFO_USED_PROXY)); + assertType('int|false', curl_getinfo($handle, CURLINFO_HTTPAUTH_USED)); + assertType('int|false', curl_getinfo($handle, CURLINFO_PROXYAUTH_USED)); + assertType('int|false', curl_getinfo($handle, CURLINFO_CONN_ID)); + } +}