Skip to content

Commit 164691d

Browse files
staabmondrejmirtes
authored andcommitted
RegularExpressionPatternRule: fix false positive in preg_quote() handling
1 parent a2a0a51 commit 164691d

File tree

3 files changed

+38
-13
lines changed

3 files changed

+38
-13
lines changed

src/Type/Php/RegexExpressionHelper.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,16 @@ public function __construct(private Scope $scope)
4040

4141
public function resolve(Expr $expr): Type
4242
{
43+
// assume preg_quote() cannot create capturing groups or contain meta characters.
44+
// replace it with a pattern which matches anything, does not affect $matches results
45+
// and does not produce regex errors when followed by a quantifier.
46+
// this allows us to turn string concatenations with preg_quote() into static analyzable strings.
4347
if (
4448
$expr instanceof Expr\FuncCall
4549
&& $expr->name instanceof Name
4650
&& $expr->name->toLowerString() === 'preg_quote'
4751
) {
48-
return new ConstantStringType('.*');
52+
return new ConstantStringType('(?:.*)');
4953
}
5054

5155
if ($expr instanceof Concat) {

tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,27 +119,27 @@ public function testValidRegexPatternBefore73(): void
119119
43,
120120
],
121121
[
122-
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok.*',
122+
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)',
123123
57,
124124
],
125125
[
126-
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok.*',
126+
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)',
127127
58,
128128
],
129129
[
130-
'Regex pattern is invalid: Compilation failed: missing ) at offset 3 in pattern: ~(.*~',
130+
'Regex pattern is invalid: Compilation failed: missing ) at offset 7 in pattern: ~((?:.*)~',
131131
59,
132132
],
133133
[
134-
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok.*nono',
134+
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)nono',
135135
61,
136136
],
137137
[
138-
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok.*nope',
138+
'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)nope',
139139
62,
140140
],
141141
[
142-
'Regex pattern is invalid: Compilation failed: missing ) at offset 3 in pattern: ~(.*~',
142+
'Regex pattern is invalid: Compilation failed: missing ) at offset 7 in pattern: ~((?:.*)~',
143143
63,
144144
],
145145
],
@@ -249,27 +249,27 @@ public function testValidRegexPatternAfter73(): void
249249
43,
250250
],
251251
[
252-
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok.*', $messagePart),
252+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok(?:.*)', $messagePart),
253253
57,
254254
],
255255
[
256-
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok.*', $messagePart),
256+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok(?:.*)', $messagePart),
257257
58,
258258
],
259259
[
260-
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 3 in pattern: ~(.*~',
260+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 7 in pattern: ~((?:.*)~',
261261
59,
262262
],
263263
[
264-
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok.*nono', $messagePart),
264+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok(?:.*)nono', $messagePart),
265265
61,
266266
],
267267
[
268-
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok.*nope', $messagePart),
268+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok(?:.*)nope', $messagePart),
269269
62,
270270
],
271271
[
272-
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 3 in pattern: ~(.*~',
272+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 7 in pattern: ~((?:.*)~',
273273
63,
274274
],
275275
],

tests/PHPStan/Rules/Regexp/data/valid-regex-pattern.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,24 @@ public function sayHello(string $s): void
7070
preg_replace('![' . preg_quote($s) . ']+!u', $s, $s);
7171
}
7272
}
73+
74+
class Bug11432 {
75+
function a(string $str, string $character = ',', bool $trim = false): string
76+
{
77+
$str = preg_replace('#' . preg_quote($character, '#') . '{2,}#', $character, $str);
78+
79+
return ($trim) ? trim($str, $character) : $str;
80+
}
81+
function b(string $str, string $character = ',', bool $trim = false): string
82+
{
83+
$str = preg_replace('#' . preg_quote($character, '#') . '*#', $character, $str);
84+
85+
return ($trim) ? trim($str, $character) : $str;
86+
}
87+
function c(string $str, string $character = ',', bool $trim = false): string
88+
{
89+
$str = preg_replace('#' . preg_quote($character, '#') . '?#', $character, $str);
90+
91+
return ($trim) ? trim($str, $character) : $str;
92+
}
93+
}

0 commit comments

Comments
 (0)