Skip to content

Commit

Permalink
Merge tag '5.26.1' into fix-core-function-flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mmcev106 committed Oct 11, 2024
2 parents 31c40f7 + d747f65 commit 9fdb081
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 41 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"felixfbecker/language-server-protocol": "^1.5.2",
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
"nikic/php-parser": "^4.16",
"nikic/php-parser": "^4.17",
"sebastian/diff": "^4.0 || ^5.0 || ^6.0",
"spatie/array-to-xml": "^2.17.0 || ^3.0",
"symfony/console": "^4.1.6 || ^5.0 || ^6.0 || ^7.0",
Expand Down
16 changes: 8 additions & 8 deletions dictionaries/CallMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -7906,9 +7906,9 @@
'mysqli_fetch_array\'2' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result', 'mode='=>'2'],
'mysqli_fetch_assoc' => ['array<string,null|int|float|string>|false|null', 'result'=>'mysqli_result'],
'mysqli_fetch_column' => ['null|int|float|string|false', 'result'=>'mysqli_result', 'column='=>'int'],
'mysqli_fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result'],
'mysqli_fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result', 'index'=>'int'],
'mysqli_fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>', 'result'=>'mysqli_result'],
'mysqli_fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'],
'mysqli_fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'],
'mysqli_fetch_fields' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>', 'result'=>'mysqli_result'],
'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'],
'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_fetch_row' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result'],
Expand All @@ -7920,7 +7920,7 @@
'mysqli_get_charset' => ['?object', 'mysql'=>'mysqli'],
'mysqli_get_client_info' => ['string', 'mysql='=>'?mysqli'],
'mysqli_get_client_stats' => ['array'],
'mysqli_get_client_version' => ['int', 'link'=>'mysqli'],
'mysqli_get_client_version' => ['int'],
'mysqli_get_connection_stats' => ['array', 'mysql'=>'mysqli'],
'mysqli_get_host_info' => ['string', 'mysql'=>'mysqli'],
'mysqli_get_links_stats' => ['array'],
Expand Down Expand Up @@ -7962,9 +7962,9 @@
'mysqli_result::fetch_array\'2' => ['list<null|int|float|string>|false|null', 'mode='=>'2'],
'mysqli_result::fetch_assoc' => ['array<string,null|int|float|string>|false|null'],
'mysqli_result::fetch_column' => ['null|int|float|string|false', 'column='=>'int'],
'mysqli_result::fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false'],
'mysqli_result::fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'index'=>'int'],
'mysqli_result::fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>'],
'mysqli_result::fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'],
'mysqli_result::fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'],
'mysqli_result::fetch_fields' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>'],
'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_result::fetch_row' => ['list<null|int|float|string>|false|null'],
'mysqli_result::field_seek' => ['true', 'index'=>'int'],
Expand Down Expand Up @@ -10630,7 +10630,7 @@
'ReflectionParameter::getDeclaringFunction' => ['ReflectionFunctionAbstract'],
'ReflectionParameter::getDefaultValue' => ['mixed'],
'ReflectionParameter::getDefaultValueConstantName' => ['?string'],
'ReflectionParameter::getName' => ['string'],
'ReflectionParameter::getName' => ['non-empty-string'],
'ReflectionParameter::getPosition' => ['int<0, max>'],
'ReflectionParameter::getType' => ['?ReflectionType'],
'ReflectionParameter::hasType' => ['bool'],
Expand Down
24 changes: 24 additions & 0 deletions dictionaries/CallMap_81_delta.php
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,30 @@
'old' => ['bool', 'statement' => 'mysqli_stmt'],
'new' => ['bool', 'statement' => 'mysqli_stmt', 'params=' => 'list<mixed>|null'],
],
'mysqli_fetch_field' => [
'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'],
'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'],
],
'mysqli_fetch_field_direct' => [
'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'],
'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'],
],
'mysqli_fetch_fields' => [
'old' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>', 'result'=>'mysqli_result'],
'new' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>', 'result'=>'mysqli_result'],
],
'mysqli_result::fetch_field' => [
'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'],
'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'],
],
'mysqli_result::fetch_field_direct' => [
'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'],
'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'],
],
'mysqli_result::fetch_fields' => [
'old' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>'],
'new' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>'],
],
'mysqli_stmt_execute' => [
'old' => ['bool', 'statement' => 'mysqli_stmt'],
'new' => ['bool', 'statement' => 'mysqli_stmt', 'params=' => 'list<mixed>|null'],
Expand Down
16 changes: 8 additions & 8 deletions dictionaries/CallMap_historical.php
Original file line number Diff line number Diff line change
Expand Up @@ -5968,7 +5968,7 @@
'ReflectionParameter::getDeclaringFunction' => ['ReflectionFunctionAbstract'],
'ReflectionParameter::getDefaultValue' => ['mixed'],
'ReflectionParameter::getDefaultValueConstantName' => ['?string'],
'ReflectionParameter::getName' => ['string'],
'ReflectionParameter::getName' => ['non-empty-string'],
'ReflectionParameter::getPosition' => ['int<0, max>'],
'ReflectionParameter::getType' => ['?ReflectionType'],
'ReflectionParameter::hasType' => ['bool'],
Expand Down Expand Up @@ -12728,9 +12728,9 @@
'mysqli_fetch_array\'1' => ['array<string,null|int|float|string>|false|null', 'result'=>'mysqli_result', 'mode='=>'1'],
'mysqli_fetch_array\'2' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result', 'mode='=>'2'],
'mysqli_fetch_assoc' => ['array<string,null|int|float|string>|false|null', 'result'=>'mysqli_result'],
'mysqli_fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result'],
'mysqli_fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result', 'index'=>'int'],
'mysqli_fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>', 'result'=>'mysqli_result'],
'mysqli_fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'],
'mysqli_fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'],
'mysqli_fetch_fields' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>', 'result'=>'mysqli_result'],
'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'],
'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_fetch_row' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result'],
Expand All @@ -12742,7 +12742,7 @@
'mysqli_get_charset' => ['?object', 'mysql'=>'mysqli'],
'mysqli_get_client_info' => ['string', 'mysql='=>'?mysqli'],
'mysqli_get_client_stats' => ['array'],
'mysqli_get_client_version' => ['int', 'link'=>'mysqli'],
'mysqli_get_client_version' => ['int'],
'mysqli_get_connection_stats' => ['array', 'mysql'=>'mysqli'],
'mysqli_get_host_info' => ['string', 'mysql'=>'mysqli'],
'mysqli_get_links_stats' => ['array'],
Expand Down Expand Up @@ -12783,9 +12783,9 @@
'mysqli_result::fetch_array\'1' => ['array<string,null|int|float|string>|false|null', 'mode='=>'1'],
'mysqli_result::fetch_array\'2' => ['list<null|int|float|string>|false|null', 'mode='=>'2'],
'mysqli_result::fetch_assoc' => ['array<string,null|int|float|string>|false|null'],
'mysqli_result::fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false'],
'mysqli_result::fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'index'=>'int'],
'mysqli_result::fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>'],
'mysqli_result::fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'],
'mysqli_result::fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'],
'mysqli_result::fetch_fields' => ['list<object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}>'],
'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_result::fetch_row' => ['list<null|int|float|string>|false|null'],
'mysqli_result::field_seek' => ['bool', 'index'=>'int'],
Expand Down
14 changes: 9 additions & 5 deletions src/Psalm/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@
*/
class Config
{
private const DEFAULT_FILE_NAME = 'psalm.xml';
private const DEFAULT_FILE_NAMES = [
'psalm.xml',
'psalm.xml.dist',
'psalm.dist.xml',
];
public const CONFIG_NAMESPACE = 'https://getpsalm.org/schema/config';
public const REPORT_INFO = 'info';
public const REPORT_ERROR = 'error';
Expand Down Expand Up @@ -773,10 +777,10 @@ public static function locateConfigFile(string $path): ?string
}

do {
$maybe_path = $dir_path . DIRECTORY_SEPARATOR . self::DEFAULT_FILE_NAME;

if (file_exists($maybe_path) || file_exists($maybe_path .= '.dist')) {
return $maybe_path;
foreach (self::DEFAULT_FILE_NAMES as $defaultFileName) {
if (file_exists($maybe_path = $dir_path . DIRECTORY_SEPARATOR . $defaultFileName)) {
return $maybe_path;
}
}

$dir_path = dirname($dir_path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ private static function analyzeAtomicAssignment(
* If we have an explicit list of all allowed magic properties on the class, and we're
* not in that list, fall through
*/
if (!$var_id || !$class_storage->hasSealedProperties($codebase->config)) {
if (!$class_storage->hasSealedProperties($codebase->config)) {
if (!$context->collect_initializations && !$context->collect_mutations) {
self::taintProperty(
$statements_analyzer,
Expand Down
60 changes: 58 additions & 2 deletions src/Psalm/Internal/Json/Json.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

use RuntimeException;

use function array_walk_recursive;
use function bin2hex;
use function is_string;
use function json_encode;
use function json_last_error_msg;
use function preg_replace_callback;

use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
Expand All @@ -19,28 +23,80 @@
final class Json
{
public const PRETTY = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
// from https://stackoverflow.com/a/11709412
private const INVALID_UTF_REGEXP = <<<'EOF'
/(
[\xC0-\xC1] # Invalid UTF-8 Bytes
| [\xF5-\xFF] # Invalid UTF-8 Bytes
| \xE0[\x80-\x9F] # Overlong encoding of prior code point
| \xF0[\x80-\x8F] # Overlong encoding of prior code point
| [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
| [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
| [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
| (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
| (?<!
[\xC2-\xDF]
|[\xE0-\xEF]
|[\xE0-\xEF][\x80-\xBF]
|[\xF0-\xF4]
|[\xF0-\xF4][\x80-\xBF]
|[\xF0-\xF4][\x80-\xBF]{2}
)[\x80-\xBF] # Overlong Sequence
| (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
| (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
| (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
)/x
EOF;

/**
* @var int
*/
public const DEFAULT = 0;

/**
* @param mixed $data
* @param array<array-key, mixed> $data
* @psalm-pure
*/
public static function encode($data, ?int $options = null): string
public static function encode(array $data, ?int $options = null): string
{
if ($options === null) {
$options = self::DEFAULT;
}

$result = json_encode($data, $options);

if ($result == false) {
$result = json_encode(self::scrub($data), $options);
}

if ($result === false) {
/** @psalm-suppress ImpureFunctionCall */
throw new RuntimeException('Cannot create JSON string: '.json_last_error_msg());
}

return $result;
}

/** @psalm-pure */
private static function scrub(array $data): array
{
/** @psalm-suppress ImpureFunctionCall */
array_walk_recursive(
$data,
/**
* @psalm-pure
* @param mixed $value
*/
function (&$value): void {
if (is_string($value)) {
$value = preg_replace_callback(
self::INVALID_UTF_REGEXP,
static fn(array $matches): string => '<Invalid UTF-8: 0x' . bin2hex($matches[0] ?? '') . '>',
$value,
);
}
},
);
return $data;
}
}
20 changes: 14 additions & 6 deletions src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,21 @@ public static function isContainedBy(
return false;
}

if ($input_type_part instanceof TCallableString
&& (get_class($container_type_part) === TSingleLetter::class
|| get_class($container_type_part) === TNonEmptyString::class
if ($input_type_part instanceof TCallableString) {
if (get_class($container_type_part) === TNonEmptyString::class
|| get_class($container_type_part) === TNonFalsyString::class
|| get_class($container_type_part) === TLowercaseString::class)
) {
return true;
) {
return true;
}

if (get_class($container_type_part) === TLowercaseString::class
|| get_class($container_type_part) === TSingleLetter::class
) {
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
}
return false;
}
}

if (($container_type_part instanceof TLowercaseString
Expand Down
Loading

0 comments on commit 9fdb081

Please sign in to comment.