Skip to content

Commit

Permalink
Merge pull request #9375 from jsanahuja/support_sizeof_alias
Browse files Browse the repository at this point in the history
  • Loading branch information
weirdan committed Feb 23, 2023
2 parents b0e1904 + bf56db7 commit 2cf3db6
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 12 deletions.
2 changes: 1 addition & 1 deletion dictionaries/CallMap.php
Expand Up @@ -11334,7 +11334,7 @@
'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false', 'path'=>'string'],
'sin' => ['float', 'num'=>'float'],
'sinh' => ['float', 'num'=>'float'],
'sizeof' => ['int', 'value'=>'Countable|array', 'mode='=>'int'],
'sizeof' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'],
'sleep' => ['int', 'seconds'=>'0|positive-int'],
'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'],
'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'],
Expand Down
4 changes: 4 additions & 0 deletions dictionaries/CallMap_80_delta.php
Expand Up @@ -497,6 +497,10 @@
'old' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'],
'new' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'],
],
'sizeof' => [
'old' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'],
'new' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'],
],
'count_chars' => [
'old' => ['array<int,int>|false', 'input'=>'string', 'mode='=>'0|1|2'],
'new' => ['array<int,int>', 'input'=>'string', 'mode='=>'0|1|2'],
Expand Down
2 changes: 1 addition & 1 deletion dictionaries/CallMap_historical.php
Expand Up @@ -14030,7 +14030,7 @@
'simplexml_load_string' => ['SimpleXMLElement|false', 'data'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'],
'sin' => ['float', 'num'=>'float'],
'sinh' => ['float', 'num'=>'float'],
'sizeof' => ['int', 'value'=>'Countable|array', 'mode='=>'int'],
'sizeof' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'],
'sleep' => ['int|false', 'seconds'=>'0|positive-int'],
'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'],
'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'],
Expand Down
Expand Up @@ -1542,7 +1542,7 @@ protected static function hasNonEmptyCountEqualityCheck(
) {
if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->left->name instanceof PhpParser\Node\Name
&& strtolower($conditional->left->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof'])
&& $conditional->left->getArgs()
&& ($conditional instanceof BinaryOp\Greater || $conditional instanceof BinaryOp\GreaterOrEqual)
) {
Expand All @@ -1551,7 +1551,7 @@ protected static function hasNonEmptyCountEqualityCheck(
$comparison_adjustment = $conditional instanceof BinaryOp\Greater ? 1 : 0;
} elseif ($conditional->right instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->right->name instanceof PhpParser\Node\Name
&& strtolower($conditional->right->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof'])
&& $conditional->right->getArgs()
&& ($conditional instanceof BinaryOp\Smaller || $conditional instanceof BinaryOp\SmallerOrEqual)
) {
Expand Down Expand Up @@ -1584,7 +1584,7 @@ protected static function hasLessThanCountEqualityCheck(
) {
$left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->left->name instanceof PhpParser\Node\Name
&& strtolower($conditional->left->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof'])
&& $conditional->left->getArgs();

$operator_less_than_or_equal =
Expand All @@ -1603,7 +1603,7 @@ protected static function hasLessThanCountEqualityCheck(

$right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->right->name instanceof PhpParser\Node\Name
&& strtolower($conditional->right->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof'])
&& $conditional->right->getArgs();

$operator_greater_than_or_equal =
Expand Down Expand Up @@ -1633,7 +1633,7 @@ protected static function hasCountEqualityCheck(
) {
$left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->left->name instanceof PhpParser\Node\Name
&& strtolower($conditional->left->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof'])
&& $conditional->left->getArgs();

if ($left_count && $conditional->right instanceof PhpParser\Node\Scalar\LNumber) {
Expand All @@ -1644,7 +1644,7 @@ protected static function hasCountEqualityCheck(

$right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->right->name instanceof PhpParser\Node\Name
&& strtolower($conditional->right->name->parts[0]) === 'count'
&& in_array(strtolower($conditional->right->name->parts[0]), ['count', 'sizeof'])
&& $conditional->right->getArgs();

if ($right_count && $conditional->left instanceof PhpParser\Node\Scalar\LNumber) {
Expand Down Expand Up @@ -1785,7 +1785,7 @@ protected static function hasReconcilableNonEmptyCountEqualityCheck(
) {
$left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall
&& $conditional->left->name instanceof PhpParser\Node\Name
&& strtolower($conditional->left->name->parts[0]) === 'count';
&& in_array(strtolower($conditional->left->name->parts[0]), ['count', 'sizeof']);

$right_number = $conditional->right instanceof PhpParser\Node\Scalar\LNumber
&& $conditional->right->value === (
Expand Down Expand Up @@ -2044,7 +2044,8 @@ protected static function hasInArrayCheck(PhpParser\Node\Expr\FuncCall $stmt): b

protected static function hasNonEmptyCountCheck(PhpParser\Node\Expr\FuncCall $stmt): bool
{
return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->parts[0]) === 'count';
return $stmt->name instanceof PhpParser\Node\Name &&
in_array(strtolower($stmt->name->parts[0]), ['count', 'sizeof']);
}

protected static function hasArrayKeyExistsCheck(PhpParser\Node\Expr\FuncCall $stmt): bool
Expand Down
Expand Up @@ -354,6 +354,7 @@ private static function getReturnTypeFromCallMapWithArgs(
} else {
switch ($call_map_key) {
case 'count':
case 'sizeof':
if (($first_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value))) {
$atomic_types = $first_arg_type->getAtomicTypes();

Expand Down
Expand Up @@ -81,7 +81,8 @@ public static function analyze(
&& ($stmt->cond->name->parts === ['get_class']
|| $stmt->cond->name->parts === ['gettype']
|| $stmt->cond->name->parts === ['get_debug_type']
|| $stmt->cond->name->parts === ['count'])
|| $stmt->cond->name->parts === ['count']
|| $stmt->cond->name->parts === ['sizeof'])
&& $stmt->cond->getArgs()
) {
$first_arg = $stmt->cond->getArgs()[0];
Expand Down
2 changes: 1 addition & 1 deletion src/Psalm/Internal/Codebase/Functions.php
Expand Up @@ -555,7 +555,7 @@ public function isCallMapFunctionPure(
return true;
}

if ($function_id === 'count' && isset($args[0]) && $type_provider) {
if (in_array($function_id, ['count', 'sizeof']) && isset($args[0]) && $type_provider) {
$count_type = $type_provider->getType($args[0]->value);

if ($count_type) {
Expand Down
16 changes: 16 additions & 0 deletions tests/ArrayAccessTest.php
Expand Up @@ -145,6 +145,22 @@ function foo(array $arr) : void {
$this->analyzeFile('somefile.php', new Context());
}

public function testNoIssueWhenUsingArrayValuesOnNonEmptyArrayCheckedWithSizeof(): void
{
Config::getInstance()->ensure_array_int_offsets_exist = true;

$this->addFile(
'somefile.php',
'<?php
/** @param string[][] $arr */
function foo(array $arr) : void {
if (sizeof($arr) === 1 && sizeof(array_values($arr)[0]) === 1) {}
}',
);

$this->analyzeFile('somefile.php', new Context());
}

public function testNoIssueAfterManyIssets(): void
{
Config::getInstance()->ensure_array_int_offsets_exist = true;
Expand Down

0 comments on commit 2cf3db6

Please sign in to comment.