Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 49 additions & 15 deletions src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -76,41 +80,42 @@ 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,
'CURLINFO_SSL_VERIFYRESULT' => $integerType,
'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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -181,14 +198,31 @@ 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,
'http_version' => $integerType,
'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);
Expand Down
29 changes: 16 additions & 13 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<array<string, string>>, 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<int, array<string, string>>, 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<int, array<string, string>>, 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<int, array<string, string>>, 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
Expand All @@ -29,38 +31,39 @@ 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));
assertType('int', curl_getinfo($handle, CURLINFO_SSL_VERIFYRESULT));
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<int, string>', curl_getinfo($handle, CURLINFO_SSL_ENGINES));
assertType('array<int, string>', curl_getinfo($handle, CURLINFO_COOKIELIST));
assertType('list<string>', curl_getinfo($handle, CURLINFO_SSL_ENGINES));
assertType('list<string>', 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<int, array<string, string>>', curl_getinfo($handle, CURLINFO_CERTINFO));
assertType('list<array<string, string>>', 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));
}
}
5 changes: 3 additions & 2 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo_7.3.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
18 changes: 18 additions & 0 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo_8.2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php // lint >= 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));
}
}
16 changes: 16 additions & 0 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo_8.3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php // lint >= 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));
}
}
15 changes: 15 additions & 0 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo_8.4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php // lint >= 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));
}
}
19 changes: 19 additions & 0 deletions tests/PHPStan/Analyser/nsrt/curl_getinfo_8.5.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php // lint >= 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));
}
}
Loading