mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
parent
19ee843d6c
commit
b54fb06552
@ -12,6 +12,9 @@ use Psalm\IssueBuffer;
|
||||
|
||||
class AlgebraChecker
|
||||
{
|
||||
/** @var array<string, array<int, string>> */
|
||||
private static $broken_paths = [];
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Expr $conditional
|
||||
* @param string|null $this_class_name
|
||||
@ -88,7 +91,7 @@ class AlgebraChecker
|
||||
|
||||
foreach ($assertions as $var => $type) {
|
||||
if ($type === 'isset' || $type === '!empty') {
|
||||
$key_parts = preg_split('/(->|\[|\])/', $var, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$key_parts = self::breakUpPathIntoParts($var);
|
||||
|
||||
$base_key = array_shift($key_parts);
|
||||
|
||||
@ -144,6 +147,83 @@ class AlgebraChecker
|
||||
return [new Clause([], true)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function breakUpPathIntoParts($path)
|
||||
{
|
||||
if (isset(self::$broken_paths[$path])) {
|
||||
return self::$broken_paths[$path];
|
||||
}
|
||||
|
||||
$chars = str_split($path);
|
||||
|
||||
$string_char = null;
|
||||
$escape_char = false;
|
||||
|
||||
$parts = [''];
|
||||
$parts_offset = 0;
|
||||
|
||||
for ($i = 0, $char_count = count($chars); $i < $char_count; ++$i) {
|
||||
$char = $chars[$i];
|
||||
|
||||
if ($string_char) {
|
||||
if ($char === $string_char && !$escape_char) {
|
||||
$string_char = null;
|
||||
}
|
||||
|
||||
if ($char === '\\') {
|
||||
$escape_char = !$escape_char;
|
||||
}
|
||||
|
||||
$parts[$parts_offset] .= $char;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($char) {
|
||||
case '[':
|
||||
case ']':
|
||||
$parts_offset++;
|
||||
$parts[$parts_offset] = $char;
|
||||
$parts_offset++;
|
||||
continue;
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
if (!isset($parts[$parts_offset])) {
|
||||
$parts[$parts_offset] = '';
|
||||
}
|
||||
$parts[$parts_offset] .= $char;
|
||||
$string_char = $char;
|
||||
|
||||
continue;
|
||||
|
||||
case '-':
|
||||
if ($i < $char_count - 1 && $chars[$i + 1] === '>') {
|
||||
++$i;
|
||||
|
||||
$parts_offset++;
|
||||
$parts[$parts_offset] = '->';
|
||||
$parts_offset++;
|
||||
continue;
|
||||
}
|
||||
// fall through
|
||||
|
||||
default:
|
||||
if (!isset($parts[$parts_offset])) {
|
||||
$parts[$parts_offset] = '';
|
||||
}
|
||||
$parts[$parts_offset] .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
self::$broken_paths[$path] = $parts;
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates a set of clauses
|
||||
* negateClauses([$a || $b]) => !$a && !$b
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Type;
|
||||
|
||||
use Psalm\Checker\AlgebraChecker;
|
||||
use Psalm\Checker\ProjectChecker;
|
||||
use Psalm\Checker\StatementsChecker;
|
||||
use Psalm\Checker\TraitChecker;
|
||||
@ -913,7 +914,7 @@ class Reconciler
|
||||
*/
|
||||
private static function getValueForKey(ProjectChecker $project_checker, $key, array &$existing_keys)
|
||||
{
|
||||
$key_parts = preg_split('/(->|\[|\])/', $key, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$key_parts = AlgebraChecker::breakUpPathIntoParts($key);
|
||||
|
||||
if (count($key_parts) === 1) {
|
||||
return isset($existing_keys[$key_parts[0]]) ? clone $existing_keys[$key_parts[0]] : null;
|
||||
|
@ -177,6 +177,10 @@ class IssetTest extends TestCase
|
||||
return $arr[$b];
|
||||
}',
|
||||
],
|
||||
'noExceptionOnBracketString' => [
|
||||
'<?php
|
||||
if (isset($foo["bar[]"])) {}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user