Skip to content

Commit ed6548c

Browse files
committed
Intersect HasOffsetValue type only with possible arrays
1 parent 2b14bf4 commit ed6548c

File tree

6 files changed

+113
-6
lines changed

6 files changed

+113
-6
lines changed

src/Analyser/MutatingScope.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3527,7 +3527,7 @@ private function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
35273527
$dimType = ArrayType::castToArrayKeyType($this->getType($expr->dim));
35283528
if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) {
35293529
$exprVarType = $this->getType($expr->var);
3530-
if (!$exprVarType instanceof MixedType) {
3530+
if (!$exprVarType instanceof MixedType && !$exprVarType->isArray()->no()) {
35313531
$types = [
35323532
new ArrayType(new MixedType(), new MixedType()),
35333533
new ObjectType(ArrayAccess::class),

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,16 @@ public function testBug7762(): void
904904
$this->assertSame('Function json_encode invoked with 0 parameters, 1-3 required.', $errors[1]->getMessage());
905905
}
906906

907+
public function testPrestashopInfiniteRunXmlLoaderBug(): void
908+
{
909+
$errors = $this->runAnalyse(__DIR__ . '/data/prestashop-xml-loader.php');
910+
$this->assertCount(4, $errors);
911+
$this->assertSame('Property PrestaShopBundleInfiniteRunBug\XmlLoader::$data_path has no type specified.', $errors[0]->getMessage());
912+
$this->assertSame('Method PrestaShopBundleInfiniteRunBug\XmlLoader::getEntityInfo() has no return type specified.', $errors[1]->getMessage());
913+
$this->assertSame('Method PrestaShopBundleInfiniteRunBug\XmlLoader::getEntityInfo() has parameter $entity with no type specified.', $errors[2]->getMessage());
914+
$this->assertSame('Method PrestaShopBundleInfiniteRunBug\XmlLoader::getEntityInfo() has parameter $exists with no type specified.', $errors[3]->getMessage());
915+
}
916+
907917
/**
908918
* @param string[]|null $allAnalysedFiles
909919
* @return Error[]

tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ public function dataArrayDestructuring(): array
11491149
'$intArrayForRewritingFirstElement[1]',
11501150
],
11511151
[
1152-
'ArrayAccess&stdClass&hasOffsetValue(0, \'error\')',
1152+
'ArrayAccess&stdClass',
11531153
'$obj',
11541154
],
11551155
[

tests/PHPStan/Analyser/data/bug-6399.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ public function doFoo(): void
3333

3434
assertType('ArrayObject<int, array<string, mixed>>', self::$threadLocalStorage);
3535
if (isset(self::$threadLocalStorage[1])) {
36-
assertType('ArrayObject<int, array<string, mixed>>&hasOffsetValue(1, array<string, mixed>)', self::$threadLocalStorage);
36+
assertType('ArrayObject<int, array<string, mixed>>&hasOffset(1)', self::$threadLocalStorage);
3737
} else {
3838
assertType('ArrayObject<int, array<string, mixed>>', self::$threadLocalStorage);
3939
}
4040

4141
assertType('ArrayObject<int, array<string, mixed>>', self::$threadLocalStorage);
4242
if (isset(self::$threadLocalStorage[1]) && isset(self::$threadLocalStorage[2])) {
43-
assertType('ArrayObject<int, array<string, mixed>>&hasOffsetValue(1, array<string, mixed>)&hasOffsetValue(2, array<string, mixed>)', self::$threadLocalStorage);
43+
assertType('ArrayObject<int, array<string, mixed>>&hasOffset(1)&hasOffset(2)', self::$threadLocalStorage);
4444
unset(self::$threadLocalStorage[2]);
45-
assertType('ArrayObject<int, array<string, mixed>>&hasOffsetValue(1, array<string, mixed>)', self::$threadLocalStorage);
45+
assertType('ArrayObject<int, array<string, mixed>>&hasOffset(1)', self::$threadLocalStorage);
4646
}
4747
}
4848

tests/PHPStan/Analyser/data/has-offset-type-bug.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function doBar(\SimpleXMLElement $xml)
106106
{
107107
if (isset($xml['foo'])) {
108108
assertType('SimpleXMLElement', $xml['foo']);
109-
assertType("SimpleXMLElement&hasOffsetValue('foo', SimpleXMLElement)", $xml);
109+
assertType("SimpleXMLElement&hasOffset('foo')", $xml);
110110
}
111111
}
112112

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
/**
3+
* Copyright since 2007 PrestaShop SA and Contributors
4+
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
5+
*
6+
* NOTICE OF LICENSE
7+
*
8+
* This source file is subject to the Open Software License (OSL 3.0)
9+
* that is bundled with this package in the file LICENSE.md.
10+
* It is also available through the world-wide-web at this URL:
11+
* https://opensource.org/licenses/OSL-3.0
12+
* If you did not receive a copy of the license and are unable to
13+
* obtain it through the world-wide-web, please send an email
14+
* to license@prestashop.com so we can send you a copy immediately.
15+
*
16+
* DISCLAIMER
17+
*
18+
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
19+
* versions in the future. If you wish to customize PrestaShop for your
20+
* needs please refer to https://devdocs.prestashop.com/ for more information.
21+
*
22+
* @author PrestaShop SA and Contributors <contact@prestashop.com>
23+
* @copyright Since 2007 PrestaShop SA and Contributors
24+
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
25+
*/
26+
27+
namespace PrestaShopBundleInfiniteRunBug;
28+
29+
class XmlLoader
30+
{
31+
32+
protected $data_path;
33+
34+
public function getEntityInfo($entity, $exists)
35+
{
36+
$info = [
37+
'config' => [
38+
'id' => '',
39+
'primary' => '',
40+
'class' => '',
41+
'sql' => '',
42+
'ordersql' => '',
43+
'image' => '',
44+
'null' => '',
45+
],
46+
'fields' => [],
47+
];
48+
49+
if (!$exists) {
50+
return $info;
51+
}
52+
53+
$xml = @simplexml_load_file($this->data_path . $entity . '.xml', 'SimplexmlElement');
54+
if (!$xml) {
55+
return $info;
56+
}
57+
58+
if ($xml->fields['id']) {
59+
$info['config']['id'] = (string) $xml->fields['id'];
60+
}
61+
62+
if ($xml->fields['primary']) {
63+
$info['config']['primary'] = (string) $xml->fields['primary'];
64+
}
65+
66+
if ($xml->fields['class']) {
67+
$info['config']['class'] = (string) $xml->fields['class'];
68+
}
69+
70+
if ($xml->fields['sql']) {
71+
$info['config']['sql'] = (string) $xml->fields['sql'];
72+
}
73+
74+
if ($xml->fields['ordersql']) {
75+
$info['config']['ordersql'] = (string) $xml->fields['ordersql'];
76+
}
77+
78+
if ($xml->fields['null']) {
79+
$info['config']['null'] = (string) $xml->fields['null'];
80+
}
81+
82+
if ($xml->fields['image']) {
83+
$info['config']['image'] = (string) $xml->fields['image'];
84+
}
85+
86+
foreach ($xml->fields->field as $field) {
87+
$column = (string) $field['name'];
88+
$info['fields'][$column] = [];
89+
if (isset($field['relation'])) {
90+
$info['fields'][$column]['relation'] = (string) $field['relation'];
91+
}
92+
}
93+
94+
return $info;
95+
}
96+
97+
}

0 commit comments

Comments
 (0)