Skip to content

Commit 4875f9f

Browse files
committed
Trigger error on unsafe StrictGroups usages
1 parent 1f78dac commit 4875f9f

File tree

3 files changed

+32
-16
lines changed

3 files changed

+32
-16
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
},
2222
"require-dev": {
2323
"phpunit/phpunit": "^8 || ^9",
24-
"phpstan/phpstan": "^1.11.6",
24+
"phpstan/phpstan": "^1.11.6@dev",
2525
"phpstan/phpstan-strict-rules": "^1.1"
2626
},
2727
"conflict": {

src/PHPStan/PregMatchTypeSpecifyingExtension.php

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,11 @@ public function specifyTypes(MethodReflection $methodReflection, StaticCall $nod
7878
&& count($matchedType->getConstantArrays()) === 1
7979
) {
8080
$matchedType = $matchedType->getConstantArrays()[0];
81-
$matchedType = new ConstantArrayType(
82-
$matchedType->getKeyTypes(),
83-
array_map(static function (Type $valueType): Type {
84-
return TypeCombinator::removeNull($valueType);
85-
}, $matchedType->getValueTypes()),
86-
$matchedType->getNextAutoIndexes(),
87-
[],
88-
$matchedType->isList()
89-
);
81+
foreach ($matchedType as $type) {
82+
if ($type->containsNull()) {
83+
// TODO trigger an error here that $methodReflection->getName() should not be used, or the pattern needs to make sure that $type->?? get key name is not nullable
84+
}
85+
}
9086
}
9187

9288
$overwrite = false;

tests/PHPStanTests/nsrt/preg-match.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,33 @@ function doMatch(string $s): void
1515
assertType('array{}|array{string}', $matches);
1616

1717
if (Preg::match('/Price: (£|€)\d+/', $s, $matches)) {
18-
assertType('array{string, string|null}', $matches);
18+
assertType('array{string, string}', $matches);
1919
} else {
2020
assertType('array{}', $matches);
2121
}
22-
assertType('array{}|array{string, string|null}', $matches);
22+
assertType('array{}|array{string, string}', $matches);
2323

2424
if (Preg::match('/Price: (£|€)?\d+/', $s, $matches)) {
25-
assertType('array{0: string, 1?: string|null}', $matches);
25+
assertType('array{0: string, 1: string|null}', $matches);
2626
} else {
2727
assertType('array{}', $matches);
2828
}
29-
assertType('array{}|array{0: string, 1?: string|null}', $matches);
29+
assertType('array{}|array{0: string, 1: string|null}', $matches);
30+
31+
// passing the PREG_UNMATCHED_AS_NULL should change nothing compared to above as it is always set
32+
if (Preg::match('/Price: (£|€)?\d+/', $s, $matches, PREG_UNMATCHED_AS_NULL)) {
33+
assertType('array{0: string, 1: string|null}', $matches);
34+
} else {
35+
assertType('array{}', $matches);
36+
}
37+
assertType('array{}|array{0: string, 1: string|null}', $matches);
3038

3139
if (Preg::isMatch('/Price: (?<currency>£|€)\d+/', $s, $matches)) {
32-
assertType('array{0: string, currency: string|null, 1: string|null}', $matches);
40+
assertType('array{0: string, currency: string, 1: string}', $matches);
3341
} else {
3442
assertType('array{}', $matches);
3543
}
36-
assertType('array{}|array{0: string, currency: string|null, 1: string|null}', $matches);
44+
assertType('array{}|array{0: string, currency: string, 1: string}', $matches);
3745
}
3846

3947
function doMatchStrictGroups(string $s): void
@@ -60,6 +68,18 @@ function doMatchStrictGroups(string $s): void
6068
assertType('array{}|array{0: string, test: string, 1: string}', $matches);
6169
}
6270

71+
function doMatchStrictGroupsUnsafe(string $s): void
72+
{
73+
if (Preg::isMatchStrictGroups('{Configure Command(?: *</td><td class="v">| *=> *)(.*)(?:</td>|$)}m', $s, $matches)) {
74+
// does not error because the match group might be empty but is not optional
75+
assertType('array{string, string}', $matches);
76+
}
77+
78+
if (Preg::isMatchStrictGroups('{Configure Command(?: *</td><td class="v">| *=> *)(.*)?(?:</td>|$)}m', $s, $matches)) {
79+
// should error as it is unsafe due to the optional group
80+
}
81+
}
82+
6383
// disabled until https://github.com/phpstan/phpstan-src/pull/3185 can be resolved
6484
//
6585
//function identicalMatch(string $s): void

0 commit comments

Comments
 (0)