Skip to content

Commit f5b9ac7

Browse files
authored
Merge pull request #9802 from ddevsr/kintphp-version-bump
chore: bump `kint-php/kint` to version minimum `^6.1`
2 parents 0e15d04 + 1dbfd69 commit f5b9ac7

31 files changed

+274
-121
lines changed

admin/framework/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"codeigniter/coding-standard": "^1.7",
2121
"fakerphp/faker": "^1.24",
2222
"friendsofphp/php-cs-fixer": "^3.47.1",
23-
"kint-php/kint": "^6.0",
23+
"kint-php/kint": "^6.1",
2424
"mikey179/vfsstream": "^1.6.12",
2525
"nexusphp/cs-config": "^3.6",
2626
"phpunit/phpunit": "^10.5.16 || ^11.2",

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"require-dev": {
2020
"codeigniter/phpstan-codeigniter": "1.x-dev",
2121
"fakerphp/faker": "^1.24",
22-
"kint-php/kint": "^6.0",
22+
"kint-php/kint": "^6.1",
2323
"mikey179/vfsstream": "^1.6.12",
2424
"nexusphp/tachycardia": "^2.0",
2525
"phpstan/extension-installer": "^1.4",

system/ThirdParty/Kint/CallFinder.php

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ class CallFinder
148148
];
149149

150150
/**
151-
* @psalm-param callable-array|callable-string $function
152-
*
153-
* @psalm-return list<array{parameters: list<CallParameter>, modifiers: list<PhpToken>}>
151+
* @psalm-param callable-string|(callable-array&list{class-string, non-empty-string}) $function
154152
*
155153
* @return array List of matching calls on the relevant line
154+
*
155+
* @psalm-return list<array{parameters: list<CallParameter>, modifiers: list<PhpToken>}>
156156
*/
157157
public static function getFunctionCalls(string $source, int $line, $function): array
158158
{
@@ -198,6 +198,11 @@ public static function getFunctionCalls(string $source, int $line, $function): a
198198
self::$operator[T_NEW] = true; // @codeCoverageIgnore
199199
}
200200

201+
if (KINT_PHP85) {
202+
/** @psalm-suppress UndefinedConstant */
203+
self::$operator[T_PIPE] = true;
204+
}
205+
201206
/** @psalm-var list<PhpToken> */
202207
$tokens = \token_get_all($source);
203208
$function_calls = [];
@@ -212,10 +217,6 @@ public static function getFunctionCalls(string $source, int $line, $function): a
212217
$function = \strtolower($function[1]);
213218
} else {
214219
$class = null;
215-
/**
216-
* @psalm-suppress RedundantFunctionCallGivenDocblockType
217-
* Psalm bug #11075
218-
*/
219220
$function = \strtolower($function);
220221
}
221222

@@ -294,6 +295,8 @@ public static function getFunctionCalls(string $source, int $line, $function): a
294295
$params = []; // All our collected parameters
295296
$shortparam = []; // The short version of the parameter
296297
$param_start = $offset; // The distance to the start of the parameter
298+
$quote = null; // Buffer to store quote type for shortparam
299+
$in_ternary = false;
297300

298301
// Loop through the following tokens until the function call ends
299302
while (isset($tokens[$offset])) {
@@ -341,6 +344,26 @@ public static function getFunctionCalls(string $source, int $line, $function): a
341344
$instring = !$instring;
342345

343346
$shortparam[] = $token;
347+
} elseif (T_START_HEREDOC === $token[0]) {
348+
if (1 === $depth) {
349+
$quote = \ltrim($token[1], " \t<")[0];
350+
if ("'" !== $quote) {
351+
$quote = '"';
352+
}
353+
$shortparam[] = [T_START_HEREDOC, $quote];
354+
$instring = true;
355+
}
356+
357+
++$depth;
358+
} elseif (T_END_HEREDOC === $token[0]) {
359+
--$depth;
360+
361+
if (1 === $depth) {
362+
if ($realtokens) {
363+
$shortparam[] = '...';
364+
}
365+
$shortparam[] = [T_END_HEREDOC, $quote];
366+
}
344367
} elseif (1 === $depth) {
345368
if (',' === $token[0]) {
346369
$params[] = [
@@ -349,6 +372,7 @@ public static function getFunctionCalls(string $source, int $line, $function): a
349372
];
350373
$shortparam = [];
351374
$paramrealtokens = false;
375+
$in_ternary = false;
352376
$param_start = $offset + 1;
353377
} elseif (T_CONSTANT_ENCAPSED_STRING === $token[0]) {
354378
$quote = $token[1][0];
@@ -364,6 +388,15 @@ public static function getFunctionCalls(string $source, int $line, $function): a
364388
}
365389
$shortparam[] = $token;
366390
} else {
391+
// We can't tell the order of named parameters or if they're splatting
392+
// without parsing the called function and that's too much work for this
393+
// edge case so we'll just skip parameters altogether.
394+
if ('?' === $token) {
395+
$in_ternary = true;
396+
} elseif (!$in_ternary && ':' === $token) {
397+
$params = [];
398+
break;
399+
}
367400
$shortparam[] = $token;
368401
}
369402
}
@@ -400,13 +433,26 @@ public static function getFunctionCalls(string $source, int $line, $function): a
400433
$literal = false;
401434
$new_without_parens = false;
402435

403-
foreach ($name as $token) {
436+
foreach ($name as $name_index => $token) {
437+
if (KINT_PHP85 && T_CLONE === $token[0]) {
438+
$nextReal = self::realTokenIndex($name, $name_index + 1);
439+
440+
if (null !== $nextReal && '(' === $name[$nextReal]) {
441+
continue;
442+
}
443+
}
444+
404445
if (self::tokenIsOperator($token)) {
405446
$expression = true;
406447
break;
407448
}
408449
}
409450

451+
if (!$expression && T_START_HEREDOC === $name[0][0]) {
452+
$expression = true;
453+
$literal = true;
454+
}
455+
410456
// As of 8.4 new is only an expression when parentheses are
411457
// omitted. In that case we can cheat and add them ourselves.
412458
//
@@ -593,6 +639,7 @@ private static function tokensTrim(array $tokens): array
593639
return \array_reverse($tokens);
594640
}
595641

642+
/** @psalm-return list<PhpToken> */
596643
private static function tokensFormatted(array $tokens): array
597644
{
598645
$tokens = self::tokensTrim($tokens);

system/ThirdParty/Kint/Kint.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,24 @@
3636
use Kint\Renderer\TextRenderer;
3737
use Kint\Value\Context\BaseContext;
3838
use Kint\Value\Context\ContextInterface;
39+
use Kint\Value\TraceFrameValue;
3940
use Kint\Value\UninitializedValue;
4041

4142
/**
4243
* @psalm-consistent-constructor
4344
* Psalm bug #8523
4445
*
4546
* @psalm-import-type CallParameter from CallFinder
47+
* @psalm-import-type TraceFrame from TraceFrameValue
4648
*
47-
* @psalm-type KintMode = Kint::MODE_*|bool
49+
* @psalm-type KintMode = array-key|bool
50+
* @psalm-type KintCallInfo = array{
51+
* params: ?list<CallParameter>,
52+
* modifiers: array,
53+
* callee: ?callable,
54+
* caller: ?callable,
55+
* trace: TraceFrame[],
56+
* }
4857
*
4958
* @psalm-api
5059
*/
@@ -396,9 +405,9 @@ public static function getBasesFromParamInfo(array $params, int $argc): array
396405
* @param array[] $trace Backtrace
397406
* @param array $args Arguments
398407
*
399-
* @return array Call info
400-
*
401408
* @psalm-param list<non-empty-array> $trace
409+
*
410+
* @return KintCallInfo Call info
402411
*/
403412
public static function getCallInfo(array $aliases, array $trace, array $args): array
404413
{
@@ -622,8 +631,8 @@ protected static function getSingleCall(array $frame, array $args): ?array
622631

623632
foreach ($keys as $key) {
624633
$call['parameters'][] = [
625-
'name' => \substr($param['name'], 3).'['.\var_export($key, true).']',
626-
'path' => \substr($param['path'], 3).'['.\var_export($key, true).']',
634+
'name' => ((string) \substr($param['name'], 3)).'['.\var_export($key, true).']',
635+
'path' => ((string) \substr($param['path'], 3)).'['.\var_export($key, true).']',
627636
'expression' => false,
628637
'literal' => false,
629638
'new_without_parens' => false,
@@ -634,8 +643,8 @@ protected static function getSingleCall(array $frame, array $args): ?array
634643
// through array_values so we can't access them directly at all
635644
for ($j = 0; $j + $i < $argc; ++$j) {
636645
$call['parameters'][] = [
637-
'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']',
638-
'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']',
646+
'name' => 'array_values('.((string) \substr($param['name'], 3)).')['.$j.']',
647+
'path' => 'array_values('.((string) \substr($param['path'], 3)).')['.$j.']',
639648
'expression' => false,
640649
'literal' => false,
641650
'new_without_parens' => false,

system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ private function buildStaticValue(ReflectionProperty $pr, int $depth): AbstractV
136136
$context->access_path = '\\'.$context->owner_class.'::$'.$context->name;
137137
}
138138

139-
$pr->setAccessible(true);
139+
if (KINT_PHP81 === false) {
140+
$pr->setAccessible(true);
141+
}
140142

141143
/**
142144
* @psalm-suppress TooFewArguments

system/ThirdParty/Kint/Parser/ColorPlugin.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractVa
5757

5858
$trimmed = \strtolower(\trim($var));
5959

60-
if (!isset(ColorRepresentation::$color_map[$trimmed]) && !\preg_match('/^(?:(?:rgb|hsl)[^\\)]{6,}\\)|#[0-9a-fA-F]{3,8})$/', $trimmed)) {
60+
if (!isset(ColorRepresentation::$color_map[$trimmed]) && !\preg_match('/^(?:(?:rgb|hsl)a?[^\\)]{6,}\\)|#[0-9a-f]{3,8})$/', $trimmed)) {
6161
return $v;
6262
}
6363

system/ThirdParty/Kint/Parser/DomPlugin.php

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@
5555
use Kint\Value\Representation\ContainerRepresentation;
5656
use Kint\Value\StringValue;
5757
use LogicException;
58+
use ReflectionClass;
5859

5960
class DomPlugin extends AbstractPlugin implements PluginBeginInterface
6061
{
6162
/**
62-
* Reflection doesn't work below 8.1, also it won't show readonly status.
63+
* Reflection doesn't show readonly status.
6364
*
6465
* In order to ensure this is stable enough we're only going to provide
6566
* properties for element and node. If subclasses like attr or document
@@ -102,12 +103,9 @@ class DomPlugin extends AbstractPlugin implements PluginBeginInterface
102103
'previousElementSibling' => true,
103104
'nextElementSibling' => true,
104105
'innerHTML' => false,
105-
'outerHTML' => false,
106+
'outerHTML' => true,
106107
'substitutedNodeValue' => false,
107-
];
108-
109-
public const DOM_NS_VERSIONS = [
110-
'outerHTML' => KINT_PHP85,
108+
'children' => true,
111109
];
112110

113111
/**
@@ -208,6 +206,9 @@ class DomPlugin extends AbstractPlugin implements PluginBeginInterface
208206
*/
209207
public static bool $verbose = false;
210208

209+
/** @psalm-var array<class-string, array<string, bool>> cache of properties for getKnownProperties */
210+
protected static array $property_cache = [];
211+
211212
protected ClassMethodsPlugin $methods_plugin;
212213
protected ClassStaticsPlugin $statics_plugin;
213214

@@ -259,12 +260,14 @@ public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
259260
/** @psalm-param Node|DOMNode $var */
260261
private function parseProperty(object $var, string $prop, ContextInterface $c): AbstractValue
261262
{
262-
if (!isset($var->{$prop})) {
263+
// Suppress deprecation message
264+
if (@!isset($var->{$prop})) {
263265
return new FixedWidthValue($c, null);
264266
}
265267

266268
$parser = $this->getParser();
267-
$value = $var->{$prop};
269+
// Suppress deprecation message
270+
@$value = $var->{$prop};
268271

269272
if (\is_scalar($value)) {
270273
return $parser->parse($value, $c);
@@ -450,40 +453,49 @@ private function parseNode(object $var, ContextInterface $c): DomNodeValue
450453
*/
451454
public static function getKnownProperties(object $var): array
452455
{
453-
if ($var instanceof Node) {
454-
$known_properties = self::NODE_PROPS;
455-
if ($var instanceof Element) {
456-
$known_properties += self::ELEMENT_PROPS;
457-
}
458-
459-
if ($var instanceof Document) {
460-
$known_properties['textContent'] = true;
461-
}
456+
if (KINT_PHP81) {
457+
$r = new ReflectionClass($var);
458+
$classname = $r->getName();
459+
460+
if (!isset(self::$property_cache[$classname])) {
461+
self::$property_cache[$classname] = [];
462+
463+
foreach ($r->getProperties() as $prop) {
464+
if ($prop->isStatic()) {
465+
continue;
466+
}
467+
468+
$declaring = $prop->getDeclaringClass()->getName();
469+
$name = $prop->name;
470+
471+
if (\in_array($declaring, [Node::class, Element::class], true)) {
472+
$readonly = self::NODE_PROPS[$name] ?? self::ELEMENT_PROPS[$name];
473+
} elseif (\in_array($declaring, [DOMNode::class, DOMElement::class], true)) {
474+
$readonly = self::DOMNODE_PROPS[$name] ?? self::DOMELEMENT_PROPS[$name];
475+
} else {
476+
continue;
477+
}
478+
479+
self::$property_cache[$classname][$prop->name] = $readonly;
480+
}
462481

463-
if ($var instanceof Attr || $var instanceof CharacterData) {
464-
$known_properties['nodeValue'] = false;
465-
}
482+
if ($var instanceof Document) {
483+
self::$property_cache[$classname]['textContent'] = true;
484+
}
466485

467-
foreach (self::DOM_NS_VERSIONS as $key => $val) {
468-
/**
469-
* @psalm-var bool $val
470-
* Psalm bug #4509
471-
*/
472-
if (false === $val) {
473-
unset($known_properties[$key]); // @codeCoverageIgnore
486+
if ($var instanceof Attr || $var instanceof CharacterData) {
487+
self::$property_cache[$classname]['nodeValue'] = false;
474488
}
475489
}
490+
491+
$known_properties = self::$property_cache[$classname];
476492
} else {
477493
$known_properties = self::DOMNODE_PROPS;
478494
if ($var instanceof DOMElement) {
479495
$known_properties += self::DOMELEMENT_PROPS;
480496
}
481497

482498
foreach (self::DOM_VERSIONS as $key => $val) {
483-
/**
484-
* @psalm-var bool $val
485-
* Psalm bug #4509
486-
*/
487499
if (false === $val) {
488500
unset($known_properties[$key]); // @codeCoverageIgnore
489501
}

system/ThirdParty/Kint/Parser/HtmlPlugin.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function getTriggers(): int
5252

5353
public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
5454
{
55-
if ('<!doctype html>' !== \strtolower(\substr($var, 0, 15))) {
55+
if ('<!doctype html>' !== \strtolower((string) \substr($var, 0, 15))) {
5656
return $v;
5757
}
5858

system/ThirdParty/Kint/Parser/IteratorPlugin.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractVa
8686
$c = $v->getContext();
8787

8888
foreach (self::$blacklist as $class) {
89-
/**
90-
* @psalm-suppress RedundantCondition
91-
* Psalm bug #11076
92-
*/
9389
if ($var instanceof $class) {
9490
$base = new BaseContext($class.' Iterator Contents');
9591
$base->depth = $c->getDepth() + 1;

0 commit comments

Comments
 (0)