Skip to content

Commit 8cee183

Browse files
committed
Array shapes regression tests
1 parent bfe2003 commit 8cee183

File tree

6 files changed

+312
-8
lines changed

6 files changed

+312
-8
lines changed

src/Type/Constant/ConstantArrayType.php

+20-8
Original file line numberDiff line numberDiff line change
@@ -442,14 +442,26 @@ public function unsetOffset(Type $offsetType): Type
442442
if ($offsetType instanceof ConstantIntegerType || $offsetType instanceof ConstantStringType) {
443443
foreach ($this->keyTypes as $i => $keyType) {
444444
if ($keyType->getValue() === $offsetType->getValue()) {
445-
$newKeyTypes = $this->keyTypes;
446-
unset($newKeyTypes[$i]);
447-
$newValueTypes = $this->valueTypes;
448-
unset($newValueTypes[$i]);
449-
$optionalKeys = $this->optionalKeys;
450-
unset($optionalKeys[$i]);
451-
452-
return new self(array_values($newKeyTypes), array_values($newValueTypes), $this->nextAutoIndex, array_values($optionalKeys));
445+
$keyTypes = $this->keyTypes;
446+
unset($keyTypes[$i]);
447+
$valueTypes = $this->valueTypes;
448+
unset($valueTypes[$i]);
449+
450+
$newKeyTypes = [];
451+
$newValueTypes = [];
452+
$newOptionalKeys = [];
453+
454+
$k = 0;
455+
foreach ($keyTypes as $j => $newKeyType) {
456+
$newKeyTypes[] = $newKeyType;
457+
$newValueTypes[] = $valueTypes[$j];
458+
if (in_array($j, $this->optionalKeys, true)) {
459+
$newOptionalKeys[] = $k;
460+
}
461+
$k++;
462+
}
463+
464+
return new self($newKeyTypes, $newValueTypes, $this->nextAutoIndex, $newOptionalKeys);
453465
}
454466
}
455467
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+18
Original file line numberDiff line numberDiff line change
@@ -9853,6 +9853,21 @@ public function dataBug3226(): array
98539853
return $this->gatherAssertTypes(__DIR__ . '/data/bug-3226.php');
98549854
}
98559855

9856+
public function dataBug2001(): array
9857+
{
9858+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-2001.php');
9859+
}
9860+
9861+
public function dataBug2232(): array
9862+
{
9863+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-2232.php');
9864+
}
9865+
9866+
public function dataBug3009(): array
9867+
{
9868+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-3009.php');
9869+
}
9870+
98569871
/**
98579872
* @dataProvider dataBug2574
98589873
* @dataProvider dataBug2577
@@ -9893,6 +9908,9 @@ public function dataBug3226(): array
98939908
* @dataProvider dataBug1216
98949909
* @dataProvider dataConstExprPhpDocType
98959910
* @dataProvider dataBug3226
9911+
* @dataProvider dataBug2001
9912+
* @dataProvider dataBug2232
9913+
* @dataProvider dataBug3009
98969914
* @param ConstantStringType $expectedType
98979915
* @param Type $actualType
98989916
*/
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Bug2001;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
class HelloWorld
8+
{
9+
public function parseUrl(string $url): string
10+
{
11+
$parsedUrl = parse_url(urldecode($url));
12+
assertType('array(?\'scheme\' => string, ?\'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)|false', $parsedUrl);
13+
14+
if (array_key_exists('host', $parsedUrl)) {
15+
assertType('array(?\'scheme\' => string, \'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)', $parsedUrl);
16+
throw new \RuntimeException('Absolute URLs are prohibited for the redirectTo parameter.');
17+
}
18+
19+
assertType('array(?\'scheme\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)|false', $parsedUrl);
20+
21+
$redirectUrl = $parsedUrl['path'];
22+
23+
if (array_key_exists('query', $parsedUrl)) {
24+
assertType('array(?\'scheme\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, \'query\' => string, ?\'fragment\' => string)', $parsedUrl);
25+
$redirectUrl .= '?' . $parsedUrl['query'];
26+
}
27+
28+
if (array_key_exists('fragment', $parsedUrl)) {
29+
assertType('array(?\'scheme\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, \'fragment\' => string)', $parsedUrl);
30+
$redirectUrl .= '#' . $parsedUrl['query'];
31+
}
32+
33+
assertType('array(?\'scheme\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)|false', $parsedUrl);
34+
35+
return $redirectUrl;
36+
}
37+
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Bug2232;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
function () {
8+
$data = [
9+
'a1' => "a",
10+
'a2' => "b",
11+
'a3' => "c",
12+
'a4' => [
13+
'name' => "dsfs",
14+
'version' => "fdsfs",
15+
],
16+
];
17+
18+
if (rand(0, 1)) {
19+
$data['b1'] = "hello";
20+
}
21+
22+
if (rand(0, 1)) {
23+
$data['b2'] = "hello";
24+
}
25+
26+
if (rand(0, 1)) {
27+
$data['b3'] = "hello";
28+
}
29+
30+
if (rand(0, 1)) {
31+
$data['b4'] = "goodbye";
32+
}
33+
34+
if (rand(0, 1)) {
35+
$data['b5'] = "env";
36+
}
37+
38+
assertType('array(\'a1\' => \'a\', \'a2\' => \'b\', \'a3\' => \'c\', \'a4\' => array(\'name\' => \'dsfs\', \'version\' => \'fdsfs\'), ?\'b1\' => \'hello\', ?\'b2\' => \'hello\', ?\'b3\' => \'hello\', ?\'b4\' => \'goodbye\', ?\'b5\' => \'env\')', $data);
39+
};
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Bug3009;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
class HelloWorld
8+
{
9+
10+
public function createRedirectRequest(string $redirectUri): ?string
11+
{
12+
$redirectUrlParts = parse_url($redirectUri);
13+
if (false === is_array($redirectUrlParts) || true === array_key_exists('host', $redirectUrlParts)) {
14+
assertType('array(?\'scheme\' => string, ?\'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)|false', $redirectUrlParts);
15+
return null;
16+
}
17+
18+
assertType('array(?\'scheme\' => string, ?\'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)', $redirectUrlParts);
19+
20+
if (true === array_key_exists('query', $redirectUrlParts)) {
21+
assertType('array(?\'scheme\' => string, ?\'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, \'query\' => string, ?\'fragment\' => string)', $redirectUrlParts);
22+
$redirectServer['QUERY_STRING'] = $redirectUrlParts['query'];
23+
}
24+
25+
assertType('array(?\'scheme\' => string, ?\'host\' => string, ?\'port\' => int, ?\'user\' => string, ?\'pass\' => string, ?\'path\' => string, ?\'query\' => string, ?\'fragment\' => string)', $redirectUrlParts);
26+
27+
return 'foo';
28+
}
29+
30+
}

tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php

+168
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,174 @@ public function dataAccepts(): iterable
170170
]),
171171
TrinaryLogic::createNo(),
172172
];
173+
174+
yield [
175+
new ConstantArrayType([
176+
new ConstantStringType('sorton'),
177+
new ConstantStringType('limit'),
178+
], [
179+
new StringType(),
180+
new IntegerType(),
181+
], 0, [0, 1]),
182+
new ConstantArrayType([
183+
new ConstantStringType('sorton'),
184+
new ConstantStringType('limit'),
185+
], [
186+
new ConstantStringType('test'),
187+
new ConstantStringType('true'),
188+
]),
189+
TrinaryLogic::createNo(),
190+
];
191+
192+
yield [
193+
new ConstantArrayType([
194+
new ConstantStringType('sorton'),
195+
new ConstantStringType('limit'),
196+
], [
197+
new StringType(),
198+
new IntegerType(),
199+
]),
200+
new ConstantArrayType([
201+
new ConstantStringType('sorton'),
202+
new ConstantStringType('limit'),
203+
], [
204+
new ConstantStringType('test'),
205+
new ConstantStringType('true'),
206+
]),
207+
TrinaryLogic::createNo(),
208+
];
209+
210+
yield [
211+
new ConstantArrayType([
212+
new ConstantStringType('sorton'),
213+
new ConstantStringType('limit'),
214+
], [
215+
new StringType(),
216+
new IntegerType(),
217+
], 0, [1]),
218+
new ConstantArrayType([
219+
new ConstantStringType('sorton'),
220+
new ConstantStringType('limit'),
221+
], [
222+
new ConstantStringType('test'),
223+
new ConstantStringType('true'),
224+
]),
225+
TrinaryLogic::createNo(),
226+
];
227+
228+
yield [
229+
new ConstantArrayType([
230+
new ConstantStringType('limit'),
231+
], [
232+
new IntegerType(),
233+
], 0, [0]),
234+
new ConstantArrayType([
235+
new ConstantStringType('limit'),
236+
], [
237+
new ConstantStringType('true'),
238+
]),
239+
TrinaryLogic::createNo(),
240+
];
241+
242+
yield [
243+
new ConstantArrayType([
244+
new ConstantStringType('limit'),
245+
], [
246+
new IntegerType(),
247+
], 0),
248+
new ConstantArrayType([
249+
new ConstantStringType('limit'),
250+
], [
251+
new ConstantStringType('true'),
252+
]),
253+
TrinaryLogic::createNo(),
254+
];
255+
256+
yield [
257+
new ConstantArrayType([
258+
new ConstantStringType('sorton'),
259+
new ConstantStringType('limit'),
260+
], [
261+
new StringType(),
262+
new StringType(),
263+
], 0, [0, 1]),
264+
new ConstantArrayType([
265+
new ConstantStringType('sorton'),
266+
new ConstantStringType('limit'),
267+
], [
268+
new ConstantStringType('test'),
269+
new ConstantStringType('true'),
270+
]),
271+
TrinaryLogic::createYes(),
272+
];
273+
274+
yield [
275+
new ConstantArrayType([
276+
new ConstantStringType('name'),
277+
new ConstantStringType('color'),
278+
], [
279+
new StringType(),
280+
new StringType(),
281+
], 0, [0, 1]),
282+
new ConstantArrayType([
283+
new ConstantStringType('color'),
284+
], [
285+
new ConstantStringType('test'),
286+
]),
287+
TrinaryLogic::createYes(),
288+
];
289+
290+
yield [
291+
new ConstantArrayType([
292+
new ConstantStringType('name'),
293+
new ConstantStringType('color'),
294+
], [
295+
new StringType(),
296+
new StringType(),
297+
], 0, [0, 1]),
298+
new ConstantArrayType([
299+
new ConstantStringType('sound'),
300+
], [
301+
new ConstantStringType('test'),
302+
]),
303+
TrinaryLogic::createYes(),
304+
];
305+
306+
yield [
307+
new ConstantArrayType([
308+
new ConstantStringType('foo'),
309+
new ConstantStringType('bar'),
310+
], [
311+
new StringType(),
312+
new StringType(),
313+
], 0, [0, 1]),
314+
new ConstantArrayType([
315+
new ConstantStringType('foo'),
316+
new ConstantStringType('bar'),
317+
], [
318+
new ConstantStringType('s'),
319+
new ConstantStringType('m'),
320+
], 0, [0, 1]),
321+
TrinaryLogic::createYes(),
322+
];
323+
324+
yield [
325+
new ConstantArrayType([
326+
new ConstantStringType('sorton'),
327+
new ConstantStringType('limit'),
328+
], [
329+
new StringType(),
330+
new IntegerType(),
331+
], 0, [0, 1]),
332+
new ConstantArrayType([
333+
new ConstantStringType('sorton'),
334+
new ConstantStringType('limit'),
335+
], [
336+
new ConstantStringType('test'),
337+
new ConstantStringType('true'),
338+
]),
339+
TrinaryLogic::createNo(),
340+
];
173341
}
174342

175343
/**

0 commit comments

Comments
 (0)