diff --git a/build/kint.phar b/build/kint.phar
index 26240a3f8..b261192ff 100644
Binary files a/build/kint.phar and b/build/kint.phar differ
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index fdc31772c..da359b18f 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -27,8 +27,8 @@
-
+
diff --git a/src/Parser/ClassStaticsPlugin.php b/src/Parser/ClassStaticsPlugin.php
index 17fa84ff3..8a18a00ae 100644
--- a/src/Parser/ClassStaticsPlugin.php
+++ b/src/Parser/ClassStaticsPlugin.php
@@ -30,7 +30,6 @@
use Kint\Value\AbstractValue;
use Kint\Value\Context\ClassConstContext;
use Kint\Value\Context\ClassDeclaredContext;
-use Kint\Value\Context\ClassOwnedContext;
use Kint\Value\Context\StaticPropertyContext;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
@@ -42,7 +41,7 @@
class ClassStaticsPlugin extends AbstractPlugin implements PluginCompleteInterface
{
- /** @psalm-var array>> */
+ /** @psalm-var array>> */
private array $cache = [];
public function getTypes(): array
@@ -69,162 +68,163 @@ public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractVa
return $v;
}
- $class = $v->getClassName();
- $parser = $this->getParser();
- $r = new ReflectionClass($class);
+ $deep = 0 === $this->getParser()->getDepthLimit();
- $statics_full_name = false;
- $statics = [];
- $props = $r->getProperties(ReflectionProperty::IS_STATIC);
- foreach ($props as $prop) {
- $statics[$prop->name] = $prop;
- }
+ $r = new ReflectionClass($v->getClassName());
- $parent = $r;
- while ($parent = $parent->getParentClass()) {
- foreach ($parent->getProperties(ReflectionProperty::IS_STATIC) as $static) {
- if (isset($statics[$static->name]) && $statics[$static->name]->getDeclaringClass()->name === $static->getDeclaringClass()->name) {
- continue;
- }
- $statics[] = $static;
- }
+ if ($statics = $this->getStatics($r, $v->getContext()->getDepth() + 1)) {
+ $v->addRepresentation(new ContainerRepresentation('Static properties', \array_values($statics), 'statics'));
}
- $statics_parsed = [];
- $found_statics = [];
+ if ($consts = $this->getCachedConstants($r, $deep)) {
+ $v->addRepresentation(new ContainerRepresentation('Class constants', \array_values($consts), 'constants'));
+ }
- $cdepth = $v->getContext()->getDepth();
+ return $v;
+ }
- foreach ($statics as $static) {
- $prop = new StaticPropertyContext(
- '$'.$static->getName(),
- $static->getDeclaringClass()->name,
- ClassDeclaredContext::ACCESS_PUBLIC
- );
- $prop->depth = $cdepth + 1;
- $prop->final = KINT_PHP84 && $static->isFinal();
+ /** @psalm-return array */
+ private function getStatics(ReflectionClass $r, int $depth): array
+ {
+ $cdepth = $depth ?: 1;
+ $class = $r->getName();
+ $parent = $r->getParentClass();
- if ($static->isProtected()) {
- $prop->access = ClassDeclaredContext::ACCESS_PROTECTED;
- } elseif ($static->isPrivate()) {
- $prop->access = ClassDeclaredContext::ACCESS_PRIVATE;
- }
+ $parent_statics = $parent ? $this->getStatics($parent, $depth) : [];
+ $statics = [];
- if ($prop->isAccessible($parser->getCallerClass())) {
- $prop->access_path = '\\'.$prop->owner_class.'::'.$prop->name;
- }
+ foreach ($r->getProperties(ReflectionProperty::IS_STATIC) as $pr) {
+ $canon_name = \strtolower($pr->getDeclaringClass()->name.'::'.$pr->name);
- if (isset($found_statics[$prop->name])) {
- $statics_full_name = true;
+ if ($pr->getDeclaringClass()->name === $class) {
+ $statics[$canon_name] = $this->buildStaticValue($pr, $cdepth);
+ } elseif (isset($parent_statics[$canon_name])) {
+ $statics[$canon_name] = $parent_statics[$canon_name];
+ unset($parent_statics[$canon_name]);
} else {
- $found_statics[$prop->name] = true;
-
- if ($prop->owner_class !== $class && ClassDeclaredContext::ACCESS_PRIVATE === $prop->access) {
- $statics_full_name = true;
- }
+ // This should never happen since abstract static properties can't exist
+ $statics[$canon_name] = $this->buildStaticValue($pr, $cdepth); // @codeCoverageIgnore
}
+ }
- if ($statics_full_name) {
- $prop->name = $prop->owner_class.'::'.$prop->name;
- }
+ foreach ($parent_statics as $canon_name => $value) {
+ $statics[$canon_name] = $value;
+ }
- $static->setAccessible(true);
+ return $statics;
+ }
- /**
- * @psalm-suppress TooFewArguments
- * Appears to have been fixed in master
- */
- if (!$static->isInitialized()) {
- $statics_parsed[] = new UninitializedValue($prop);
- } else {
- $static = $static->getValue();
- $statics_parsed[] = $parser->parse($static, $prop);
- }
+ private function buildStaticValue(ReflectionProperty $pr, int $depth): AbstractValue
+ {
+ $context = new StaticPropertyContext(
+ $pr->name,
+ $pr->getDeclaringClass()->name,
+ ClassDeclaredContext::ACCESS_PUBLIC
+ );
+ $context->depth = $depth;
+ $context->final = KINT_PHP84 && $pr->isFinal();
+
+ if ($pr->isProtected()) {
+ $context->access = ClassDeclaredContext::ACCESS_PROTECTED;
+ } elseif ($pr->isPrivate()) {
+ $context->access = ClassDeclaredContext::ACCESS_PRIVATE;
}
- if ($statics_parsed) {
- $v->addRepresentation(new ContainerRepresentation('Static properties', $statics_parsed, 'statics'));
+ $parser = $this->getParser();
+
+ if ($context->isAccessible($parser->getCallerClass())) {
+ $context->access_path = '\\'.$context->owner_class.'::$'.$context->name;
}
- if ($consts = $this->getCachedConstants($r)) {
- $v->addRepresentation(new ContainerRepresentation('Class constants', $consts, 'constants'));
+ $pr->setAccessible(true);
+
+ /**
+ * @psalm-suppress TooFewArguments
+ * Appears to have been fixed in master.
+ */
+ if (!$pr->isInitialized()) {
+ $context->access_path = null;
+
+ return new UninitializedValue($context);
}
- return $v;
+ $val = $pr->getValue();
+
+ $out = $this->getParser()->parse($val, $context);
+ $context->access_path = null;
+
+ return $out;
}
- /** @psalm-return list */
- private function getCachedConstants(ReflectionClass $r): array
+ /** @psalm-return array */
+ private function getCachedConstants(ReflectionClass $r, bool $deep): array
{
$parser = $this->getParser();
- $pdepth = $parser->getDepthLimit();
- $pdepth_enabled = (int) ($pdepth > 0);
+ $cdepth = $parser->getDepthLimit() ?: 1;
+ $deepkey = (int) $deep;
$class = $r->getName();
// Separate cache for dumping with/without depth limit
// This means we can do immediate depth limit on normal dumps
- if (!isset($this->cache[$class][$pdepth_enabled])) {
+ if (!isset($this->cache[$class][$deepkey])) {
$consts = [];
- $reflectors = [];
+ $parent_consts = [];
+ if ($parent = $r->getParentClass()) {
+ $parent_consts = $this->getCachedConstants($parent, $deep);
+ }
foreach ($r->getConstants() as $name => $val) {
$cr = new ReflectionClassConstant($class, $name);
// Skip enum constants
- if (\is_a($cr->class, UnitEnum::class, true) && $val instanceof UnitEnum && $cr->class === \get_class($val)) {
+ if ($cr->class === $class && \is_a($class, UnitEnum::class, true)) {
continue;
}
- $reflectors[$cr->name] = [$cr, $val];
- $consts[$cr->name] = null;
- }
+ $canon_name = \strtolower($cr->getDeclaringClass()->name.'::'.$name);
- if ($r = $r->getParentClass()) {
- $parents = $this->getCachedConstants($r);
-
- foreach ($parents as $value) {
- $c = $value->getContext();
- $cname = $c->getName();
-
- if (isset($reflectors[$cname]) && $c instanceof ClassOwnedContext && $reflectors[$cname][0]->getDeclaringClass()->name === $c->owner_class) {
- $consts[$cname] = $value;
- unset($reflectors[$cname]);
- } else {
- $value = clone $value;
- $c = $value->getContext();
- if ($c instanceof ClassOwnedContext) {
- $c->name = $c->owner_class.'::'.$cname;
- }
- $consts[] = $value;
- }
- }
- }
+ if ($cr->getDeclaringClass()->name === $class) {
+ $context = $this->buildConstContext($cr);
+ $context->depth = $cdepth;
- foreach ($reflectors as [$cr, $val]) {
- $context = new ClassConstContext(
- $cr->name,
- $cr->getDeclaringClass()->name,
- ClassDeclaredContext::ACCESS_PUBLIC
- );
- $context->depth = $pdepth ?: 1;
- $context->final = KINT_PHP81 && $cr->isFinal();
-
- if ($cr->isProtected()) {
- $context->access = ClassDeclaredContext::ACCESS_PROTECTED;
- } elseif ($cr->isPrivate()) {
- $context->access = ClassDeclaredContext::ACCESS_PRIVATE;
+ $consts[$canon_name] = $parser->parse($val, $context);
+ $context->access_path = null;
+ } elseif (isset($parent_consts[$canon_name])) {
+ $consts[$canon_name] = $parent_consts[$canon_name];
} else {
- // No access path for protected/private. Tough shit the cache is worth it
- $context->access_path = '\\'.$context->owner_class.'::'.$context->name;
+ $context = $this->buildConstContext($cr);
+ $context->depth = $cdepth;
+
+ $consts[$canon_name] = $parser->parse($val, $context);
+ $context->access_path = null;
}
- $consts[$cr->name] = $parser->parse($val, $context);
+ unset($parent_consts[$canon_name]);
}
- /** @psalm-var AbstractValue[] $consts */
- $this->cache[$class][$pdepth_enabled] = \array_values($consts);
+ $this->cache[$class][$deepkey] = $consts + $parent_consts;
+ }
+
+ return $this->cache[$class][$deepkey];
+ }
+
+ private function buildConstContext(ReflectionClassConstant $cr): ClassConstContext
+ {
+ $context = new ClassConstContext(
+ $cr->name,
+ $cr->getDeclaringClass()->name,
+ ClassDeclaredContext::ACCESS_PUBLIC
+ );
+ $context->final = KINT_PHP81 && $cr->isFinal();
+
+ if ($cr->isProtected()) {
+ $context->access = ClassDeclaredContext::ACCESS_PROTECTED;
+ } elseif ($cr->isPrivate()) {
+ $context->access = ClassDeclaredContext::ACCESS_PRIVATE;
+ } else {
+ $context->access_path = '\\'.$context->owner_class.'::'.$context->name;
}
- return $this->cache[$class][$pdepth_enabled];
+ return $context;
}
}
diff --git a/src/Value/Context/ClassConstContext.php b/src/Value/Context/ClassConstContext.php
index 41777ecaf..27342f2c7 100644
--- a/src/Value/Context/ClassConstContext.php
+++ b/src/Value/Context/ClassConstContext.php
@@ -31,6 +31,11 @@ class ClassConstContext extends ClassDeclaredContext
{
public bool $final = false;
+ public function getName(): string
+ {
+ return $this->owner_class.'::'.$this->name;
+ }
+
public function getOperator(): string
{
return '::';
diff --git a/src/Value/Context/StaticPropertyContext.php b/src/Value/Context/StaticPropertyContext.php
index 6b89a1075..47b83ddb5 100644
--- a/src/Value/Context/StaticPropertyContext.php
+++ b/src/Value/Context/StaticPropertyContext.php
@@ -31,6 +31,11 @@ class StaticPropertyContext extends DoubleAccessMemberContext
{
public bool $final = false;
+ public function getName(): string
+ {
+ return $this->owner_class.'::$'.$this->name;
+ }
+
public function getOperator(): string
{
return '::';
diff --git a/tests/Fixtures/Php74ChildTestClass.php b/tests/Fixtures/Php74ChildTestClass.php
index 841b366b1..c3676d44e 100644
--- a/tests/Fixtures/Php74ChildTestClass.php
+++ b/tests/Fixtures/Php74ChildTestClass.php
@@ -8,6 +8,7 @@ class Php74ChildTestClass extends Php74TestClass
public const VALUE_5 = 5;
private const VALUE_3 = 'replaced';
private const VALUE_6 = 6;
+ public const VALUE_ARRAY_2 = ['contents' => '{"test":"value"}'];
public static $value_1 = 'replaced';
public static $value_5 = 5;
diff --git a/tests/Fixtures/Php74TestClass.php b/tests/Fixtures/Php74TestClass.php
index f53f9ce84..10d38651a 100644
--- a/tests/Fixtures/Php74TestClass.php
+++ b/tests/Fixtures/Php74TestClass.php
@@ -15,6 +15,9 @@ class Php74TestClass
protected static int $value_uninit;
private static $value_3 = 3;
private static $value_4 = 4;
+ public static $value_a_pub = ['contents' => '{"test":"value"}'];
+ protected static $value_a_pro = ['contents' => '{"test":"value"}'];
+ private static $value_a_pri = ['contents' => '{"test":"value"}'];
public $a = 1;
public string $b = '2';
diff --git a/tests/Fixtures/Php81TestClass.php b/tests/Fixtures/Php81TestClass.php
index 04a21ba3c..5bfae5060 100644
--- a/tests/Fixtures/Php81TestClass.php
+++ b/tests/Fixtures/Php81TestClass.php
@@ -7,6 +7,8 @@
class Php81TestClass
{
+ final public const X = 'Y';
+
public readonly string $a;
protected readonly string $b;
private readonly string $c;
diff --git a/tests/Fixtures/Php84TestClass.php b/tests/Fixtures/Php84TestClass.php
index e860eb220..8000a3c36 100644
--- a/tests/Fixtures/Php84TestClass.php
+++ b/tests/Fixtures/Php84TestClass.php
@@ -44,4 +44,6 @@ class Php84TestClass
private(set) int $i;
protected(set) int $j;
protected private(set) int $k;
+
+ final protected static int $l;
}
diff --git a/tests/Fixtures/TestInterface.php b/tests/Fixtures/TestInterface.php
index c3e565ebc..944570480 100644
--- a/tests/Fixtures/TestInterface.php
+++ b/tests/Fixtures/TestInterface.php
@@ -4,6 +4,8 @@
interface TestInterface
{
+ const VALUE = 'abcd';
+
public function normalMethod();
public static function staticMethod();
}
diff --git a/tests/Parser/ClassStaticsPluginTest.php b/tests/Parser/ClassStaticsPluginTest.php
index f43c70215..2b738b272 100644
--- a/tests/Parser/ClassStaticsPluginTest.php
+++ b/tests/Parser/ClassStaticsPluginTest.php
@@ -32,9 +32,15 @@
use Kint\Test\Fixtures\Php74ChildTestClass;
use Kint\Test\Fixtures\Php74TestClass;
use Kint\Test\Fixtures\Php81TestBackedEnum;
+use Kint\Test\Fixtures\Php81TestClass;
use Kint\Test\Fixtures\Php81TestEnum;
+use Kint\Test\Fixtures\Php84ChildTestClass;
+use Kint\Test\Fixtures\Php84TestClass;
+use Kint\Test\Fixtures\TestClass;
+use Kint\Test\Fixtures\TestInterface;
use Kint\Test\KintTestCase;
use Kint\Value\AbstractValue;
+use Kint\Value\ArrayValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ClassConstContext;
use Kint\Value\Context\StaticPropertyContext;
@@ -61,10 +67,12 @@ public function testHooks()
/**
* @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
+ * @covers \Kint\Parser\ClassStaticsPlugin::getStatics
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildStaticValue
*/
public function testParseStatics()
{
- $p = new Parser(5);
+ $p = new Parser(1);
$b = new BaseContext('$v');
$b->access_path = '$v';
@@ -77,15 +85,18 @@ public function testParseStatics()
$p->addPlugin(new ClassStaticsPlugin($p));
$expected = [
- ['$value_1', 'replaced', '\\'.Php74ChildTestClass::class.'::$value_1'],
- ['$value_5', 5, '\\'.Php74ChildTestClass::class.'::$value_5'],
- ['$value_3', 'replaced', null],
- ['$value_6', 6, null],
- ['$value_2', 2, '\\'.Php74TestClass::class.'::$value_2'],
- ['$value_uninit', null, null],
- [Php74TestClass::class.'::$value_1', 1, '\\'.Php74TestClass::class.'::$value_1'],
- [Php74TestClass::class.'::$value_3', 3, null],
- [Php74TestClass::class.'::$value_4', 4, null],
+ [Php74ChildTestClass::class.'::$value_1', 'replaced'],
+ [Php74ChildTestClass::class.'::$value_5', 5],
+ [Php74ChildTestClass::class.'::$value_3', 'replaced'],
+ [Php74ChildTestClass::class.'::$value_6', 6],
+ [Php74TestClass::class.'::$value_2', 2],
+ ($index_uninit = 5) => [Php74TestClass::class.'::$value_uninit', null],
+ ($index_a_pub = 6) => [Php74TestClass::class.'::$value_a_pub', []],
+ ($index_a_pro = 7) => [Php74TestClass::class.'::$value_a_pro', []],
+ [Php74TestClass::class.'::$value_1', 1],
+ [Php74TestClass::class.'::$value_3', 3],
+ [Php74TestClass::class.'::$value_4', 4],
+ ($index_a_pri = 11) => [Php74TestClass::class.'::$value_a_pri', []],
];
$o = $p->parse($v, clone $b);
@@ -98,19 +109,37 @@ public function testParseStatics()
$this->assertInstanceOf(StaticPropertyContext::class, $value->getContext());
$this->assertSame($expect[0], $value->getDisplayName());
- $this->assertSame($expect[2], $value->getContext()->getAccessPath());
+ $this->assertFalse($value->getContext()->final);
+ $this->assertNull($value->getContext()->getAccessPath());
- if ('$value_uninit' === $expect[0]) {
+ if ($index === $index_uninit) {
$this->assertInstanceOf(UninitializedValue::class, $value);
+ } elseif ([] === $expect[1]) {
+ $this->assertInstanceOf(ArrayValue::class, $value);
+ $this->assertEquals(true, $value->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+ $this->assertCount(0, $value->getContents());
} else {
$this->assertSame($expect[1], $value->getValue());
}
}
- $expected_copy = $expected;
- $expected_copy[2][2] = '\\'.Php74ChildTestClass::class.'::$value_3';
- $expected_copy[3][2] = '\\'.Php74ChildTestClass::class.'::$value_6';
- $expected_copy[5][2] = '\\'.Php74TestClass::class.'::$value_uninit';
+ $p->setDepthLimit(5);
+ $o = $p->parse($v, clone $b);
+ $rep = $o->getRepresentation('statics');
+
+ $this->assertEquals(false, $rep->getContents()[$index_a_pub]->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pub['contents']",
+ $rep->getContents()[$index_a_pub]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertEquals(false, $rep->getContents()[$index_a_pro]->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+ $this->assertNull(
+ $rep->getContents()[$index_a_pro]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertEquals(false, $rep->getContents()[$index_a_pri]->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+ $this->assertNull(
+ $rep->getContents()[$index_a_pri]->getContents()['contents']->getContext()->getAccessPath()
+ );
$p->setCallerClass(Php74ChildTestClass::class);
$o = $p->parse($v, clone $b);
@@ -118,14 +147,24 @@ public function testParseStatics()
$this->assertInstanceOf(ContainerRepresentation::class, $rep);
$this->assertCount(\count($expected), $rep->getContents());
- foreach ($expected_copy as $index => $expect) {
- $this->assertSame($expect[2], $rep->getContents()[$index]->getContext()->getAccessPath());
- }
+ foreach ($expected as $index => $expect) {
+ $value = $rep->getContents()[$index];
- $expected_copy = $expected;
- $expected_copy[5][2] = '\\'.Php74TestClass::class.'::$value_uninit';
- $expected_copy[7][2] = '\\'.Php74TestClass::class.'::$value_3';
- $expected_copy[8][2] = '\\'.Php74TestClass::class.'::$value_4';
+ $this->assertInstanceOf(StaticPropertyContext::class, $value->getContext());
+ $this->assertSame($expect[0], $value->getDisplayName());
+ $this->assertNull($value->getContext()->getAccessPath());
+ }
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pub['contents']",
+ $rep->getContents()[$index_a_pub]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pro['contents']",
+ $rep->getContents()[$index_a_pro]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertNull(
+ $rep->getContents()[$index_a_pri]->getContents()['contents']->getContext()->getAccessPath()
+ );
$p->setCallerClass(Php74TestClass::class);
$o = $p->parse($v, clone $b);
@@ -133,14 +172,57 @@ public function testParseStatics()
$this->assertInstanceOf(ContainerRepresentation::class, $rep);
$this->assertCount(\count($expected), $rep->getContents());
- foreach ($expected_copy as $index => $expect) {
- $this->assertSame($expect[2], $rep->getContents()[$index]->getContext()->getAccessPath());
+ foreach ($expected as $index => $expect) {
+ $value = $rep->getContents()[$index];
+
+ $this->assertInstanceOf(StaticPropertyContext::class, $value->getContext());
+ $this->assertSame($expect[0], $value->getDisplayName());
+ $this->assertNull($value->getContext()->getAccessPath());
+ }
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pub['contents']",
+ $rep->getContents()[$index_a_pub]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pro['contents']",
+ $rep->getContents()[$index_a_pro]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ $this->assertSame(
+ '\\'.Php74TestClass::class."::\$value_a_pri['contents']",
+ $rep->getContents()[$index_a_pri]->getContents()['contents']->getContext()->getAccessPath()
+ );
+ }
+
+ /**
+ * @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
+ * @covers \Kint\Parser\ClassStaticsPlugin::getStatics
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildStaticValue
+ */
+ public function testParseFinalStatic()
+ {
+ if (!KINT_PHP84) {
+ $this->markTestSkipped('Not testing final static properties below PHP 8.4');
}
+
+ $p = new Parser(5);
+ $p->addPlugin(new ClassStaticsPlugin($p));
+
+ $b = new BaseContext('$v');
+ $b->access_path = '$v';
+ $v = new Php84ChildTestClass();
+
+ $o = $p->parse($v, clone $b);
+ $rep = $o->getRepresentation('statics');
+
+ $this->assertInstanceOf(ContainerRepresentation::class, $rep);
+ $this->assertSame(Php84TestClass::class.'::$l', $rep->getContents()[0]->getContext()->getName());
+ $this->assertTrue($rep->getContents()[0]->getContext()->final);
}
/**
* @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
* @covers \Kint\Parser\ClassStaticsPlugin::getCachedConstants
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildConstContext
*/
public function testParseConstants()
{
@@ -157,15 +239,16 @@ public function testParseConstants()
$p->addPlugin(new ClassStaticsPlugin($p));
$expected = [
- ['VALUE_1', 'replaced', '\\'.Php74ChildTestClass::class.'::VALUE_1'],
- ['VALUE_5', 5, '\\'.Php74ChildTestClass::class.'::VALUE_5'],
- ['VALUE_3', 'replaced', null],
- ['VALUE_6', 6, null],
- ['VALUE_2', 2, '\\'.Php74TestClass::class.'::VALUE_2'],
- ['VALUE_ARRAY', [], null],
- [Php74TestClass::class.'::VALUE_1', 1, '\\'.Php74TestClass::class.'::VALUE_1'],
- [Php74TestClass::class.'::VALUE_3', 3, null],
- [Php74TestClass::class.'::VALUE_4', 4, null],
+ [Php74ChildTestClass::class.'::VALUE_1', 'replaced'],
+ [Php74ChildTestClass::class.'::VALUE_5', 5],
+ [Php74ChildTestClass::class.'::VALUE_3', 'replaced'],
+ [Php74ChildTestClass::class.'::VALUE_6', 6],
+ [Php74ChildTestClass::class.'::VALUE_ARRAY_2', []],
+ [Php74TestClass::class.'::VALUE_2', 2],
+ [Php74TestClass::class.'::VALUE_ARRAY', []],
+ [Php74TestClass::class.'::VALUE_1', 1],
+ [Php74TestClass::class.'::VALUE_3', 3],
+ [Php74TestClass::class.'::VALUE_4', 4],
];
$o = $p->parse($v, clone $b);
@@ -181,45 +264,106 @@ public function testParseConstants()
$this->assertInstanceOf(ClassConstContext::class, $value->getContext());
$this->assertSame($expect[0], $value->getDisplayName());
if ([] === $expect[1]) {
+ $this->assertInstanceOf(ArrayValue::class, $value);
$this->assertEquals(true, $value->flags & AbstractValue::FLAG_DEPTH_LIMIT);
- $array_key = $index;
+ $this->assertCount(0, $value->getContents());
+ $array_key ??= $index;
} else {
$this->assertSame($expect[1], $value->getValue());
}
- $this->assertSame($expect[2], $value->getContext()->getAccessPath());
+ $this->assertNull($value->getContext()->getAccessPath());
}
$p->setDepthLimit(0);
$o = $p->parse($v, clone $b);
- $this->assertEquals(false, $o->getRepresentation('constants')->getContents()[$array_key]->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+ $array_value = $o->getRepresentation('constants')->getContents()[$array_key];
+ $this->assertEquals(false, $array_value->flags & AbstractValue::FLAG_DEPTH_LIMIT);
+
+ $this->assertCount(1, $array_value->getContents());
+ $this->assertSame(
+ '\\'.Php74ChildTestClass::class."::VALUE_ARRAY_2['contents']",
+ $array_value->getContents()['contents']->getContext()->getAccessPath()
+ );
}
/**
* @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
* @covers \Kint\Parser\ClassStaticsPlugin::getCachedConstants
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildConstContext
*/
public function testParseEnumConstant()
{
if (!KINT_PHP81) {
- $this->markTestSkipped('Not testing ClassStaticsPlugin on enums below PHP 8.1');
+ $this->markTestSkipped('Not testing final consts below PHP 8.1');
}
$p = new Parser(5);
- $p->addPlugin(new ClassStaticsPlugin($p));
$b = new BaseContext('$v');
$b->access_path = '$v';
$v = Php81TestEnum::Hearts;
$o = $p->parse($v, clone $b);
+ $this->assertNull($o->getRepresentation('constants'));
- $this->assertNull($o->getRepresentation('statics'));
+ $p->addPlugin(new ClassStaticsPlugin($p));
+
+ $o = $p->parse($v, clone $b);
+ $this->assertNull($o->getRepresentation('constants'));
$v = Php81TestBackedEnum::Hearts;
$o = $p->parse($v, clone $b);
+ $this->assertNull($o->getRepresentation('constants'));
+ }
- $this->assertNull($o->getRepresentation('statics'));
+ /**
+ * @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
+ * @covers \Kint\Parser\ClassStaticsPlugin::getCachedConstants
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildConstContext
+ */
+ public function testParseInterfaceConst()
+ {
+ $p = new Parser(5);
+ $p->addPlugin(new ClassStaticsPlugin($p));
+
+ $b = new BaseContext('$v');
+ $b->access_path = '$v';
+ $v = new TestClass();
+
+ $o = $p->parse($v, clone $b);
+
+ $rep = $o->getRepresentation('constants');
+
+ $this->assertInstanceOf(ContainerRepresentation::class, $rep);
+ $this->assertSame(TestInterface::class.'::VALUE', $rep->getContents()[2]->getContext()->getName());
+ }
+
+ /**
+ * @covers \Kint\Parser\ClassStaticsPlugin::parseComplete
+ * @covers \Kint\Parser\ClassStaticsPlugin::getCachedConstants
+ * @covers \Kint\Parser\ClassStaticsPlugin::buildConstContext
+ */
+ public function testParseFinalConst()
+ {
+ if (!KINT_PHP81) {
+ $this->markTestSkipped('Not testing ClassStaticsPlugin on enums below PHP 8.1');
+ }
+
+ $p = new Parser(5);
+ $p->addPlugin(new ClassStaticsPlugin($p));
+
+ $b = new BaseContext('$v');
+ $b->access_path = '$v';
+ $v = new Php81TestClass('');
+
+ $o = $p->parse($v, clone $b);
+
+ $rep = $o->getRepresentation('constants');
+
+ $this->assertInstanceOf(ContainerRepresentation::class, $rep);
+ $this->assertSame(Php81TestClass::class.'::X', $rep->getContents()[0]->getContext()->getName());
+ $this->assertTrue($rep->getContents()[0]->getContext()->final);
}
/**
@@ -234,6 +378,7 @@ public function testParseBadValue()
$b = new FixedWidthValue(new BaseContext('$v'), $v);
$csp->parseComplete($v, $b, Parser::TRIGGER_SUCCESS);
- $this->assertNull($b->getRepresentation('methods'));
+ $this->assertNull($b->getRepresentation('statics'));
+ $this->assertNull($b->getRepresentation('constants'));
}
}
diff --git a/tests/Value/Context/ClassConstContextTest.php b/tests/Value/Context/ClassConstContextTest.php
index 1ed35c8a3..02b09f9a8 100644
--- a/tests/Value/Context/ClassConstContextTest.php
+++ b/tests/Value/Context/ClassConstContextTest.php
@@ -77,6 +77,15 @@ public function testGetModifiers(ClassConstContext $c, string $expect)
$this->assertSame($expect, $c->getModifiers());
}
+ /**
+ * @covers \Kint\Value\Context\ClassConstContext::getName
+ */
+ public function testGetName()
+ {
+ $c = new ClassConstContext('base', 'class', ClassDeclaredContext::ACCESS_PUBLIC);
+ $this->assertSame('class::base', $c->getName());
+ }
+
/**
* @covers \Kint\Value\Context\ClassConstContext::getOperator
*/
diff --git a/tests/Value/Context/StaticPropertyContextTest.php b/tests/Value/Context/StaticPropertyContextTest.php
index 2134e096e..4c84163df 100644
--- a/tests/Value/Context/StaticPropertyContextTest.php
+++ b/tests/Value/Context/StaticPropertyContextTest.php
@@ -77,6 +77,15 @@ public function testGetModifiers(StaticPropertyContext $c, string $expect)
$this->assertSame($expect, $c->getModifiers());
}
+ /**
+ * @covers \Kint\Value\Context\StaticPropertyContext::getName
+ */
+ public function testGetName()
+ {
+ $c = new StaticPropertyContext('base', 'class', ClassDeclaredContext::ACCESS_PUBLIC);
+ $this->assertSame('class::$base', $c->getName());
+ }
+
/**
* @covers \Kint\Value\Context\StaticPropertyContext::getOperator
*/