From 50acf416c7b17a3df4b3f8a5eea31cb5518ef296 Mon Sep 17 00:00:00 2001 From: Jonathan Vollebregt Date: Thu, 3 Oct 2024 17:11:30 +0200 Subject: [PATCH] Property async visibility --- build/kint.phar | Bin 513234 -> 513970 bytes src/Parser/Parser.php | 7 ++++ src/Zval/Value.php | 23 ++++++++++--- tests/CallFinderTest.php | 2 +- tests/Fixtures/Php84TestClass.php | 6 ++++ tests/Parser/ParserTest.php | 52 +++++++++++++++++++++++++++++- tests/Zval/ValueTest.php | 38 +++++++++++++++++++++- 7 files changed, 121 insertions(+), 7 deletions(-) diff --git a/build/kint.phar b/build/kint.phar index cd7b9ee002e12c3196f2a2eba239d6906393b07e..c71a8cf9d1d172ed8ff2c6a64dac145a11cf5b11 100644 GIT binary patch delta 601 zcmcb#Qhw8V`3?Vg1orzdFf{Dbkpa=Kqio-9=Hu-Z66jWjh=S-EerNUO)$;ADz!ifVns5+A&ONPY&@5GL1|J> zX0p09*Yrkac8TeGPO@`O=R3tNiLih)2ZQb6RlsyL+)j`RUbt;m(_^Nx3Qb=yiA{0) z-c#&nIXz^fjkf$e^;;-#>zi%Y{PwG}FqHCh3!A*O4%AJVTlHY&s@7d^Cg0qBFKJ!< j1J=E_eV8tL^SIf7rmS+TF zrtPccnT^u7-)LuUVVs`wo>_FdK{qq|^jTfZ0_~lh%s|Wn#H>Kfw!O2HeYMf{&OPis zeADetv$IXNJIk&!ea$&`{^v|!(DVam*afFAJjX5tlHiywdYWAv zB*w{Fnv|27JYCV5Rdag$WHyQI3(m5i;`Eq4Z^?woGsWKq+@G`V%U-_^=M+9&{&vBG zd*A-0#`Zq{`p;P&*PN=#5U#gOJ8$0O&(CB%Wm6t2FK6dE`{~B*>VL~v7#JAboqU}D D1G8*H diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index 8222180d6..3cbce7b3b 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -506,6 +506,12 @@ private function parseObject(&$var, Value $o): Value $child->depth = $object->depth + 1; if (KINT_PHP84 && $rprop->isDefault()) { + if ($rprop->isProtectedSet()) { + $child->access_set |= Value::ACCESS_PROTECTED; + } elseif ($rprop->isPrivateSet()) { + $child->access_set |= Value::ACCESS_PRIVATE; + } + $hooks = $rprop->getHooks(); if (isset($hooks['get'])) { $child->hooks |= Value::HOOK_GET; @@ -515,6 +521,7 @@ private function parseObject(&$var, Value $o): Value } if (isset($hooks['set'])) { $child->hooks |= Value::HOOK_SET; + $child->hook_set_type = (string) $rprop->getSettableType(); if ($child->hook_set_type !== (string) $rprop->getType()) { $child->hooks |= Value::HOOK_SET_TYPE; diff --git a/src/Zval/Value.php b/src/Zval/Value.php index 11de0f02f..e35ca5dd7 100644 --- a/src/Zval/Value.php +++ b/src/Zval/Value.php @@ -58,6 +58,8 @@ class Value public bool $const = false; /** @psalm-var self::ACCESS_* */ public int $access = self::ACCESS_NONE; + /** @psalm-var self::ACCESS_* */ + public int $access_set = self::ACCESS_NONE; /** @psalm-var ?class-string */ public ?string $owner_class = null; public ?string $access_path = null; @@ -199,12 +201,25 @@ public function getModifiers(): ?string public function getAccess(): ?string { switch ($this->access) { - case self::ACCESS_PRIVATE: - return 'private'; - case self::ACCESS_PROTECTED: - return 'protected'; case self::ACCESS_PUBLIC: + if (self::ACCESS_PRIVATE === $this->access_set) { + return 'private(set)'; + } + if (self::ACCESS_PROTECTED === $this->access_set) { + return 'protected(set)'; + } + return 'public'; + + case self::ACCESS_PROTECTED: + if (self::ACCESS_PRIVATE === $this->access_set) { + return 'protected private(set)'; + } + + return 'protected'; + + case self::ACCESS_PRIVATE: + return 'private'; } return null; diff --git a/tests/CallFinderTest.php b/tests/CallFinderTest.php index b6de8e683..5914d8d39 100644 --- a/tests/CallFinderTest.php +++ b/tests/CallFinderTest.php @@ -1242,7 +1242,7 @@ public function sourceProvider() 'test_property = $value; diff --git a/tests/Fixtures/Php84TestClass.php b/tests/Fixtures/Php84TestClass.php index 8cb4c142a..e860eb220 100644 --- a/tests/Fixtures/Php84TestClass.php +++ b/tests/Fixtures/Php84TestClass.php @@ -38,4 +38,10 @@ class Php84TestClass $this->b = $value - 1; } } + + public private(set) int $g; + public protected(set) int $h; + private(set) int $i; + protected(set) int $j; + protected private(set) int $k; } diff --git a/tests/Parser/ParserTest.php b/tests/Parser/ParserTest.php index f63270038..5d1969342 100644 --- a/tests/Parser/ParserTest.php +++ b/tests/Parser/ParserTest.php @@ -375,32 +375,44 @@ public function testParseObject() $this->assertSame('pub', $props[0]->name); $this->assertSame('array', $props[0]->type); + $this->assertSame(Value::ACCESS_PUBLIC, $props[0]->access); + $this->assertSame(Value::ACCESS_NONE, $props[0]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[0]->operator); $this->assertSame(TestClass::class, $props[0]->owner_class); $this->assertSame('$v->pub', $props[0]->access_path); $this->assertSame('pro', $props[1]->name); $this->assertSame('array', $props[1]->type); - $this->assertSame(ChildTestClass::class, $props[1]->owner_class); + $this->assertSame(Value::ACCESS_PROTECTED, $props[1]->access); + $this->assertSame(Value::ACCESS_NONE, $props[1]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[1]->operator); + $this->assertSame(ChildTestClass::class, $props[1]->owner_class); $this->assertSame('$v->pro', $props[1]->access_path); $this->assertSame('pri', $props[2]->name); $this->assertSame('array', $props[2]->type); + $this->assertSame(Value::ACCESS_PRIVATE, $props[2]->access); + $this->assertSame(Value::ACCESS_NONE, $props[2]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[2]->operator); $this->assertSame(TestClass::class, $props[2]->owner_class); $this->assertSame('$v->pri', $props[2]->access_path); $this->assertSame('pub2', $props[3]->name); $this->assertSame('null', $props[3]->type); + $this->assertSame(Value::ACCESS_PUBLIC, $props[3]->access); + $this->assertSame(Value::ACCESS_NONE, $props[3]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[3]->operator); $this->assertSame(ChildTestClass::class, $props[3]->owner_class); $this->assertSame('$v->pub2', $props[3]->access_path); $this->assertSame('pro2', $props[4]->name); $this->assertSame('null', $props[4]->type); + $this->assertSame(Value::ACCESS_PROTECTED, $props[4]->access); + $this->assertSame(Value::ACCESS_NONE, $props[4]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[4]->operator); $this->assertSame(ChildTestClass::class, $props[4]->owner_class); $this->assertSame('$v->pro2', $props[4]->access_path); $this->assertSame('pri2', $props[5]->name); $this->assertSame('null', $props[5]->type); + $this->assertSame(Value::ACCESS_PRIVATE, $props[5]->access); + $this->assertSame(Value::ACCESS_NONE, $props[5]->access_set); $this->assertSame(Value::OPERATOR_OBJECT, $props[5]->operator); $this->assertSame(ChildTestClass::class, $props[5]->owner_class); $this->assertNull($props[5]->access_path); @@ -986,6 +998,44 @@ public function testParseHooks() $this->assertSame('virtual', $props[5]->type); } + /** + * @covers \Kint\Parser\Parser::parseObject + */ + public function testParseAsymmetricVisibility() + { + if (!KINT_PHP84) { + $this->markTestSkipped('Not testing asymmetric property visilibity below 8.4'); + } + + $b = new Value('$v'); + $b->access_path = '$v'; + $v = new Php84TestClass(); + + $p = new Parser(); + $o = $p->parse($v, clone $b); + $props = $o->value->contents; + + $this->assertSame('g', $props[6]->name); + $this->assertSame(Value::ACCESS_PUBLIC, $props[6]->access); + $this->assertSame(Value::ACCESS_PRIVATE, $props[6]->access_set); + + $this->assertSame('h', $props[7]->name); + $this->assertSame(Value::ACCESS_PUBLIC, $props[7]->access); + $this->assertSame(Value::ACCESS_PROTECTED, $props[7]->access_set); + + $this->assertSame('i', $props[8]->name); + $this->assertSame(Value::ACCESS_PUBLIC, $props[8]->access); + $this->assertSame(Value::ACCESS_PRIVATE, $props[8]->access_set); + + $this->assertSame('j', $props[9]->name); + $this->assertSame(Value::ACCESS_PUBLIC, $props[9]->access); + $this->assertSame(Value::ACCESS_PROTECTED, $props[9]->access_set); + + $this->assertSame('k', $props[10]->name); + $this->assertSame(Value::ACCESS_PROTECTED, $props[10]->access); + $this->assertSame(Value::ACCESS_PRIVATE, $props[10]->access_set); + } + /** * @covers \Kint\Parser\Parser::addPlugin * @covers \Kint\Parser\Parser::applyPlugins diff --git a/tests/Zval/ValueTest.php b/tests/Zval/ValueTest.php index 91106b3bb..2644eb578 100644 --- a/tests/Zval/ValueTest.php +++ b/tests/Zval/ValueTest.php @@ -291,6 +291,7 @@ public function modifierProvider() false, false, Value::ACCESS_PUBLIC, + Value::ACCESS_NONE, 'public', ], 'public const' => [ @@ -298,6 +299,7 @@ public function modifierProvider() false, false, Value::ACCESS_PUBLIC, + Value::ACCESS_NONE, 'public const', ], 'public static' => [ @@ -305,6 +307,7 @@ public function modifierProvider() true, false, Value::ACCESS_PUBLIC, + Value::ACCESS_NONE, 'public static', ], 'protected' => [ @@ -312,6 +315,7 @@ public function modifierProvider() false, false, Value::ACCESS_PROTECTED, + Value::ACCESS_NONE, 'protected', ], 'private' => [ @@ -319,6 +323,7 @@ public function modifierProvider() false, false, Value::ACCESS_PRIVATE, + Value::ACCESS_NONE, 'private', ], 'none' => [ @@ -326,6 +331,7 @@ public function modifierProvider() false, false, Value::ACCESS_NONE, + Value::ACCESS_NONE, null, ], 'private static' => [ @@ -333,6 +339,7 @@ public function modifierProvider() true, false, Value::ACCESS_PRIVATE, + Value::ACCESS_NONE, 'private static', ], 'public const static' => [ @@ -340,6 +347,7 @@ public function modifierProvider() true, false, Value::ACCESS_PUBLIC, + Value::ACCESS_NONE, 'public const static', ], 'const' => [ @@ -347,6 +355,7 @@ public function modifierProvider() false, false, Value::ACCESS_NONE, + Value::ACCESS_NONE, 'const', ], 'public readonly' => [ @@ -354,6 +363,7 @@ public function modifierProvider() false, true, Value::ACCESS_PUBLIC, + Value::ACCESS_NONE, 'public readonly', ], 'private readonly' => [ @@ -361,8 +371,33 @@ public function modifierProvider() false, true, Value::ACCESS_PRIVATE, + Value::ACCESS_NONE, 'private readonly', ], + 'private(set) set hook' => [ + false, + false, + false, + Value::ACCESS_PUBLIC, + Value::ACCESS_PRIVATE, + 'private(set)', + ], + 'protected(set) set hook' => [ + false, + false, + false, + Value::ACCESS_PUBLIC, + Value::ACCESS_PROTECTED, + 'protected(set)', + ], + 'protected private(set) set hook' => [ + false, + false, + false, + Value::ACCESS_PROTECTED, + Value::ACCESS_PRIVATE, + 'protected private(set)', + ], ]; } @@ -371,13 +406,14 @@ public function modifierProvider() * * @covers \Kint\Zval\Value::getModifiers */ - public function testGetModifiers(bool $const, bool $static, bool $readonly, int $access, ?string $expect) + public function testGetModifiers(bool $const, bool $static, bool $readonly, int $access, int $access_set, ?string $expect) { $o = new Value('base'); $o->readonly = $readonly; $o->const = $const; $o->static = $static; $o->access = $access; + $o->access_set = $access_set; $this->assertSame($expect, $o->getModifiers()); }