Skip to content

Commit 9696f45

Browse files
phpstan-botclaude
andcommitted
Add regression tests for related issues fixed by constant array shape preservation
- Bug 14080: Rule test ensuring no binary operation error on += with preserved array shape - Bug 13623: Rule test for ??= with nested dynamic-key arrays (documents remaining errors) - Bug 8774: Rule test ensuring no sprintf placeholder mismatch with dynamic array keys - Bug 9907: NSRT test for array shape preservation with union key parameter - Bug 11006: Rule test ensuring no constructor parameter type mismatch with union key Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5d9315d commit 9696f45

9 files changed

Lines changed: 189 additions & 0 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug9907;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/**
10+
* @param 'foo'|'bar' $key
11+
*/
12+
public function sayHello(string $key): void
13+
{
14+
$a = ['id' => null, $key => 'string'];
15+
16+
assertType("array{id: null, foo?: 'string', bar?: 'string'}", $a);
17+
}
18+
}

tests/PHPStan/Rules/Classes/InstantiationRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,4 +609,9 @@ public function testBug14251(): void
609609
]);
610610
}
611611

612+
public function testBug11006(): void
613+
{
614+
$this->analyse([__DIR__ . '/data/bug-11006.php'], []);
615+
}
616+
612617
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11006;
4+
5+
class StringOrNullAttributeDto
6+
{
7+
public function __construct(
8+
public ?string $data,
9+
) {
10+
}
11+
}
12+
13+
class StringAttributeDto
14+
{
15+
public function __construct(
16+
public string $data,
17+
) {
18+
}
19+
}
20+
21+
class AkeneoUpdateProductDto
22+
{
23+
/**
24+
* @param array{
25+
* ean?: array<StringOrNullAttributeDto>,
26+
* osa_sizes?: array<StringAttributeDto>,
27+
* size_uk?: array<StringOrNullAttributeDto>,
28+
* size_us?: array<StringOrNullAttributeDto>,
29+
* } $values
30+
*/
31+
public function __construct(
32+
public array $values,
33+
) {
34+
}
35+
}
36+
37+
class ProductParentPayloadDto
38+
{
39+
/**
40+
* @param 'size_uk'|'size_us' $SizeAttributeCode
41+
*/
42+
public function __construct(
43+
public string $SizeAttributeCode,
44+
) {
45+
}
46+
}
47+
48+
class PhpStanProblem
49+
{
50+
public function example(ProductParentPayloadDto $parentPayload): void
51+
{
52+
$values = [
53+
'ean' => [
54+
new StringOrNullAttributeDto(''),
55+
],
56+
$parentPayload->SizeAttributeCode => [
57+
new StringOrNullAttributeDto(''),
58+
],
59+
'osa_sizes' => [
60+
new StringAttributeDto(''),
61+
],
62+
];
63+
64+
new AkeneoUpdateProductDto($values);
65+
}
66+
}

tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,9 @@ public function testBug1889(): void
137137
]);
138138
}
139139

140+
public function testBug8774(): void
141+
{
142+
$this->analyse([__DIR__ . '/data/bug-8774.php'], []);
143+
}
144+
140145
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug8774;
4+
5+
class ModerateCtrl
6+
{
7+
private const DISABLE_KEYS_AND_LABELS = [
8+
'DisablePosting' => 'Posting on forum and comments',
9+
'DisableAvatar' => 'Avatar and Custom Icon',
10+
];
11+
12+
public static function handleModerate(): void
13+
{
14+
$summaryTemplates = [
15+
'PermissionID' => "Class changed from <b>'%s'</b> to <b>'%s'</b>.",
16+
'Reset' => '%s reset.',
17+
];
18+
19+
foreach (self::DISABLE_KEYS_AND_LABELS as $key => $label) {
20+
$summaryTemplates[$key] = "Disable $label status %s.";
21+
}
22+
23+
echo sprintf($summaryTemplates['Reset'], 'foo');
24+
}
25+
}

tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,4 +821,9 @@ public function testBug10595(): void
821821
$this->analyse([__DIR__ . '/data/bug-10595.php'], []);
822822
}
823823

824+
public function testBug14080(): void
825+
{
826+
$this->analyse([__DIR__ . '/data/bug-14080.php'], []);
827+
}
828+
824829
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug14080;
4+
5+
class Foo
6+
{
7+
/**
8+
* @param list<array{sql: string, time: int}> $queries
9+
*/
10+
public function doFoo(array $queries): void
11+
{
12+
$queryTotals = ['all' => 0, 'duplicates' => 0];
13+
$queryTypes = ['select', 'update', 'delete', 'insert'];
14+
15+
$queryTotals['time'] = array_sum(array_column($queries, 'time'));
16+
17+
foreach ($queryTypes as $type) {
18+
$tq = array_filter($queries, fn ($v) => str_starts_with(strtolower($v['sql']), $type));
19+
$queryTotals['all'] += count($tq);
20+
$queryTotals[$type] = [
21+
'count' => count($tq),
22+
];
23+
}
24+
}
25+
}

tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,22 @@ public function testBug13921(): void
372372
]);
373373
}
374374

375+
public function testBug13623(): void
376+
{
377+
$this->analyse([__DIR__ . '/data/bug-13623.php'], [
378+
[
379+
'Offset \'new_invoice\' on array{balance_forward: 0, new_invoice: 0, payments: 0, balance: float} on left side of ??= always exists and is not nullable.',
380+
18,
381+
],
382+
[
383+
'Offset \'payments\' on array{balance_forward: 0, new_invoice: 0, payments: 0, balance: float} on left side of ??= always exists and is not nullable.',
384+
19,
385+
],
386+
[
387+
'Offset \'balance\' on array{balance_forward: 0, new_invoice: 0, payments: 0, balance: float} on left side of ??= always exists and is not nullable.',
388+
20,
389+
],
390+
]);
391+
}
392+
375393
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug13623;
4+
5+
/**
6+
* @param list<array{customer_id: int, order_id: int, order_total: float}> $results
7+
*/
8+
function doFoo(array $results): void
9+
{
10+
$customers = [];
11+
12+
foreach ($results as $row) {
13+
$customers[$row['customer_id']] ??= [];
14+
$customers[$row['customer_id']]['orders'] ??= [];
15+
$customers[$row['customer_id']]['orders'][$row['order_id']] ??= [];
16+
17+
$customers[$row['customer_id']]['orders'][$row['order_id']]['balance_forward'] ??= 0;
18+
$customers[$row['customer_id']]['orders'][$row['order_id']]['new_invoice'] ??= 0;
19+
$customers[$row['customer_id']]['orders'][$row['order_id']]['payments'] ??= 0;
20+
$customers[$row['customer_id']]['orders'][$row['order_id']]['balance'] ??= $row['order_total'];
21+
}
22+
}

0 commit comments

Comments
 (0)