mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Merge pull request #7027 from rarila/issue-6914
This commit is contained in:
commit
28c4f86993
@ -10273,7 +10273,7 @@ return [
|
|||||||
'preg_filter' => ['null|string|string[]', 'pattern'=>'mixed', 'replacement'=>'mixed', 'subject'=>'mixed', 'limit='=>'int', '&w_count='=>'int'],
|
'preg_filter' => ['null|string|string[]', 'pattern'=>'mixed', 'replacement'=>'mixed', 'subject'=>'mixed', 'limit='=>'int', '&w_count='=>'int'],
|
||||||
'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'],
|
'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'],
|
||||||
'preg_last_error' => ['int'],
|
'preg_last_error' => ['int'],
|
||||||
'preg_match' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0|', 'offset='=>'int'],
|
'preg_match' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0', 'offset='=>'int'],
|
||||||
'preg_match\'1' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
'preg_match\'1' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
||||||
'preg_match_all' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
'preg_match_all' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
||||||
'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'string'],
|
'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'string'],
|
||||||
|
@ -14454,7 +14454,7 @@ return [
|
|||||||
'preg_filter' => ['null|string|string[]', 'pattern'=>'mixed', 'replacement'=>'mixed', 'subject'=>'mixed', 'limit='=>'int', '&w_count='=>'int'],
|
'preg_filter' => ['null|string|string[]', 'pattern'=>'mixed', 'replacement'=>'mixed', 'subject'=>'mixed', 'limit='=>'int', '&w_count='=>'int'],
|
||||||
'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'],
|
'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'],
|
||||||
'preg_last_error' => ['int'],
|
'preg_last_error' => ['int'],
|
||||||
'preg_match' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0|', 'offset='=>'int'],
|
'preg_match' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0', 'offset='=>'int'],
|
||||||
'preg_match\'1' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
'preg_match\'1' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
||||||
'preg_match_all' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
'preg_match_all' => ['int|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'],
|
||||||
'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'string'],
|
'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'string'],
|
||||||
|
@ -259,14 +259,14 @@ class CodeLocation
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match($regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) {
|
if (preg_match($regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) {
|
||||||
if (!isset($matches[1]) || (int)$matches[1][1] === -1) {
|
if (!isset($matches[1]) || $matches[1][1] === -1) {
|
||||||
throw new \LogicException(
|
throw new \LogicException(
|
||||||
"Failed to match anything to 1st capturing group, "
|
"Failed to match anything to 1st capturing group, "
|
||||||
. "or regex doesn't contain 1st capturing group, regex type " . $this->regex_type
|
. "or regex doesn't contain 1st capturing group, regex type " . $this->regex_type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->selection_start = $this->selection_start + (int)$matches[1][1];
|
$this->selection_start = $this->selection_start + $matches[1][1];
|
||||||
$this->selection_end = $this->selection_start + strlen((string)$matches[1][0]);
|
$this->selection_end = $this->selection_start + strlen($matches[1][0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,7 +635,7 @@ class ArgumentsAnalyzer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($method_id === 'preg_match_all' && count($args) > 3) {
|
if (($method_id === 'preg_match_all' || $method_id === 'preg_match') && count($args) > 3) {
|
||||||
$args = array_reverse($args, true);
|
$args = array_reverse($args, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ class ClassLikeDocblockParser
|
|||||||
$end_of_method_regex = '/(?<!array\()\) ?(\: ?(\??[\\\\a-zA-Z0-9_]+))?/';
|
$end_of_method_regex = '/(?<!array\()\) ?(\: ?(\??[\\\\a-zA-Z0-9_]+))?/';
|
||||||
|
|
||||||
if (preg_match($end_of_method_regex, $method_entry, $matches, PREG_OFFSET_CAPTURE)) {
|
if (preg_match($end_of_method_regex, $method_entry, $matches, PREG_OFFSET_CAPTURE)) {
|
||||||
$method_entry = substr($method_entry, 0, (int) $matches[0][1] + strlen((string) $matches[0][0]));
|
$method_entry = substr($method_entry, 0, $matches[0][1] + strlen($matches[0][0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$method_entry = str_replace([', ', '( '], [',', '('], $method_entry);
|
$method_entry = str_replace([', ', '( '], [',', '('], $method_entry);
|
||||||
|
@ -963,6 +963,24 @@ function preg_replace_callback($pattern, $callback, $subject, int $limit = -1, &
|
|||||||
*/
|
*/
|
||||||
function preg_match_all($pattern, $subject, &$matches = [], int $flags = 1, int $offset = 0) {}
|
function preg_match_all($pattern, $subject, &$matches = [], int $flags = 1, int $offset = 0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @psalm-pure
|
||||||
|
* @template TFlags as int-mask<0, 256, 512>
|
||||||
|
*
|
||||||
|
* @param string $pattern
|
||||||
|
* @param string $subject
|
||||||
|
* @param mixed $matches
|
||||||
|
* @param TFlags $flags
|
||||||
|
* @param-out (TFlags is 256 ? array<array-key, array{string, 0|positive-int}|array{'', -1}> :
|
||||||
|
* TFlags is 512 ? array<array-key, string|null> :
|
||||||
|
* TFlags is 768 ? array<array-key, array{string, 0|positive-int}|array{null, -1}> :
|
||||||
|
* array<array-key, string>
|
||||||
|
* ) $matches
|
||||||
|
* @return 1|0|false
|
||||||
|
* @psalm-ignore-falsable-return
|
||||||
|
*/
|
||||||
|
function preg_match($pattern, $subject, &$matches = [], int $flags = 0, int $offset = 0) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-pure
|
* @psalm-pure
|
||||||
*
|
*
|
||||||
|
@ -1282,6 +1282,13 @@ class FunctionCallTest extends TestCase
|
|||||||
|
|
||||||
takesInt(preg_match("{foo}", "foo"));',
|
takesInt(preg_match("{foo}", "foo"));',
|
||||||
],
|
],
|
||||||
|
'pregMatch2' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo");',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
],
|
||||||
|
],
|
||||||
'pregMatchWithMatches' => [
|
'pregMatchWithMatches' => [
|
||||||
'<?php
|
'<?php
|
||||||
/** @param string[] $matches */
|
/** @param string[] $matches */
|
||||||
@ -1291,6 +1298,14 @@ class FunctionCallTest extends TestCase
|
|||||||
|
|
||||||
takesMatches($matches);',
|
takesMatches($matches);',
|
||||||
],
|
],
|
||||||
|
'pregMatchWithMatches2' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo", $matches);',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
'$matches===' => 'array<array-key, string>',
|
||||||
|
],
|
||||||
|
],
|
||||||
'pregMatchWithOffset' => [
|
'pregMatchWithOffset' => [
|
||||||
'<?php
|
'<?php
|
||||||
/** @param string[] $matches */
|
/** @param string[] $matches */
|
||||||
@ -1300,18 +1315,46 @@ class FunctionCallTest extends TestCase
|
|||||||
|
|
||||||
takesMatches($matches);',
|
takesMatches($matches);',
|
||||||
],
|
],
|
||||||
|
'pregMatchWithOffset2' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo", $matches, 0, 10);',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
'$matches===' => 'array<array-key, string>',
|
||||||
|
],
|
||||||
|
],
|
||||||
'pregMatchWithFlags' => [
|
'pregMatchWithFlags' => [
|
||||||
'<?php
|
'<?php
|
||||||
function takesInt(int $i) : void {}
|
function takesInt(int $i) : void {}
|
||||||
|
|
||||||
if (preg_match("{foo}", "this is foo", $matches, PREG_OFFSET_CAPTURE)) {
|
if (preg_match("{foo}", "this is foo", $matches, PREG_OFFSET_CAPTURE)) {
|
||||||
/**
|
|
||||||
* @psalm-suppress MixedArrayAccess
|
|
||||||
* @psalm-suppress MixedArgument
|
|
||||||
*/
|
|
||||||
takesInt($matches[0][1]);
|
takesInt($matches[0][1]);
|
||||||
}',
|
}',
|
||||||
],
|
],
|
||||||
|
'pregMatchWithFlagOffsetCapture' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo", $matches, PREG_OFFSET_CAPTURE);',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
'$matches===' => 'array<array-key, array{string, int}>',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'PHP72-pregMatchWithFlagUnmatchedAsNull' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo", $matches, PREG_UNMATCHED_AS_NULL);',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
'$matches===' => 'array<array-key, null|string>',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'PHP72-pregMatchWithFlagOffsetCaptureAndUnmatchedAsNull' => [
|
||||||
|
'<?php
|
||||||
|
$r = preg_match("{foo}", "foo", $matches, PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL);',
|
||||||
|
'assertions' => [
|
||||||
|
'$r===' => '0|1|false',
|
||||||
|
'$matches===' => 'array<array-key, array{null|string, int}>',
|
||||||
|
],
|
||||||
|
],
|
||||||
'pregReplaceCallback' => [
|
'pregReplaceCallback' => [
|
||||||
'<?php
|
'<?php
|
||||||
function foo(string $s) : string {
|
function foo(string $s) : string {
|
||||||
@ -1449,7 +1492,10 @@ class FunctionCallTest extends TestCase
|
|||||||
],
|
],
|
||||||
'writeArgsAllowed' => [
|
'writeArgsAllowed' => [
|
||||||
'<?php
|
'<?php
|
||||||
/** @return false|int */
|
/**
|
||||||
|
* @param 0|256|512|768 $flags
|
||||||
|
* @return false|int
|
||||||
|
*/
|
||||||
function safeMatch(string $pattern, string $subject, ?array $matches = null, int $flags = 0) {
|
function safeMatch(string $pattern, string $subject, ?array $matches = null, int $flags = 0) {
|
||||||
return \preg_match($pattern, $subject, $matches, $flags);
|
return \preg_match($pattern, $subject, $matches, $flags);
|
||||||
}
|
}
|
||||||
|
@ -35,14 +35,18 @@ trait ValidCodeAnalysisTestTrait
|
|||||||
string $php_version = '7.3'
|
string $php_version = '7.3'
|
||||||
): void {
|
): void {
|
||||||
$test_name = $this->getTestName();
|
$test_name = $this->getTestName();
|
||||||
if (strpos($test_name, 'PHP73-') !== false) {
|
if (strpos($test_name, 'PHP71-') !== false) {
|
||||||
if (version_compare(PHP_VERSION, '7.3.0', '<')) {
|
|
||||||
$this->markTestSkipped('Test case requires PHP 7.3.');
|
|
||||||
}
|
|
||||||
} elseif (strpos($test_name, 'PHP71-') !== false) {
|
|
||||||
if (version_compare(PHP_VERSION, '7.1.0', '<')) {
|
if (version_compare(PHP_VERSION, '7.1.0', '<')) {
|
||||||
$this->markTestSkipped('Test case requires PHP 7.1.');
|
$this->markTestSkipped('Test case requires PHP 7.1.');
|
||||||
}
|
}
|
||||||
|
} elseif (strpos($test_name, 'PHP72-') !== false) {
|
||||||
|
if (version_compare(PHP_VERSION, '7.2.0', '<')) {
|
||||||
|
$this->markTestSkipped('Test case requires PHP 7.2.');
|
||||||
|
}
|
||||||
|
} elseif (strpos($test_name, 'PHP73-') !== false) {
|
||||||
|
if (version_compare(PHP_VERSION, '7.3.0', '<')) {
|
||||||
|
$this->markTestSkipped('Test case requires PHP 7.3.');
|
||||||
|
}
|
||||||
} elseif (strpos($test_name, 'PHP80-') !== false) {
|
} elseif (strpos($test_name, 'PHP80-') !== false) {
|
||||||
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
|
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
|
||||||
$this->markTestSkipped('Test case requires PHP 8.0.');
|
$this->markTestSkipped('Test case requires PHP 8.0.');
|
||||||
|
Loading…
Reference in New Issue
Block a user