diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 4b90be1ec3..65af9e9639 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -322,6 +322,10 @@ jobs: - script: | cd e2e/bug-11819 ../../bin/phpstan + - script: | + cd e2e/bug-12629 + ../../bin/phpstan --generate-baseline # should generate without crash + ../../bin/phpstan # should re-analyze without new errors steps: - name: "Checkout" diff --git a/e2e/bug-12629/phpstan-baseline.neon b/e2e/bug-12629/phpstan-baseline.neon new file mode 100644 index 0000000000..9b03d7b91d --- /dev/null +++ b/e2e/bug-12629/phpstan-baseline.neon @@ -0,0 +1,19 @@ +parameters: + ignoreErrors: + - + message: '#^Method Bug12629\\Bug12629\:\:is_macintosh_enc\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: src/bug-12629.php + + - + message: '#^Method Bug12629\\Bug12629\:\:is_macintosh_enc\(\) has parameter \$s with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: src/bug-12629.php + + - + message: '#^Method Bug12629\\Bug12629\:\:is_macintosh_enc\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: src/bug-12629.php diff --git a/e2e/bug-12629/phpstan.neon b/e2e/bug-12629/phpstan.neon new file mode 100644 index 0000000000..ddbf4c2114 --- /dev/null +++ b/e2e/bug-12629/phpstan.neon @@ -0,0 +1,7 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: 8 + paths: + - src diff --git a/e2e/bug-12629/src/bug-12629.php b/e2e/bug-12629/src/bug-12629.php new file mode 100644 index 0000000000..701a78520a --- /dev/null +++ b/e2e/bug-12629/src/bug-12629.php @@ -0,0 +1,17 @@ + 0 && 0 == count($matchesUtf8[0]); + } +} diff --git a/src/Rules/Regexp/RegularExpressionPatternRule.php b/src/Rules/Regexp/RegularExpressionPatternRule.php index e15bdeb13b..4955f66d9c 100644 --- a/src/Rules/Regexp/RegularExpressionPatternRule.php +++ b/src/Rules/Regexp/RegularExpressionPatternRule.php @@ -9,11 +9,15 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use PHPStan\ShouldNotHappenException; use PHPStan\Type\Regex\RegexExpressionHelper; use function in_array; use function sprintf; use function str_starts_with; +use function strlen; +use function strpos; use function strtolower; +use function substr; /** * @implements Rule @@ -123,7 +127,18 @@ private function validatePattern(string $pattern): ?string try { Strings::match('', $pattern); } catch (RegexpException $e) { - return $e->getMessage(); + $invalidPatternMessage = $e->getMessage(); + try { + Strings::match($invalidPatternMessage, '//u'); + return $invalidPatternMessage; + } catch (RegexpException) { + $patternPos = strpos($invalidPatternMessage, 'pattern:'); + if ($patternPos === false) { + throw new ShouldNotHappenException(); + } + // strip invalid utf-8 pattern contents to keep the error message NEON parsable. + return substr($invalidPatternMessage, 0, $patternPos + strlen('pattern:') - 1); + } } return null; diff --git a/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php b/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php index b376382f18..370c007dca 100644 --- a/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php +++ b/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php @@ -332,4 +332,21 @@ public function dataArrayShapePatterns(): iterable ]; } + public function testBug12629(): void + { + $this->analyse( + [__DIR__ . '/data/bug-12629.php'], + [ + [ + 'Regex pattern is invalid: Compilation failed: UTF-8 error: isolated byte with 0x80 bit set at offset 1 in pattern', + 12, + ], + [ + 'Regex pattern is invalid: Compilation failed: UTF-8 error: byte 2 top bits not 0x80 at offset 0 in pattern', + 13, + ], + ], + ); + } + } diff --git a/tests/PHPStan/Rules/Regexp/data/bug-12629.php b/tests/PHPStan/Rules/Regexp/data/bug-12629.php new file mode 100644 index 0000000000..bf72b60e19 --- /dev/null +++ b/tests/PHPStan/Rules/Regexp/data/bug-12629.php @@ -0,0 +1,17 @@ + 0 && 0 == count($matchesUtf8[0]); + } +}