From 9d4c6d1ea298a72f49cba8249a83fd6a64512e1f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 18 Dec 2021 07:24:23 +0100 Subject: [PATCH] File::getMemberProperties(): minor tweaks after readonly merge Follow up on 3480 I realized after the merge that I had not published a few follow up comments. Addressing those here. * The new `is_readonly` key still needed to be added to the documentation for the `File::getMemberProperties()` method. * For consistency in how the method is tested, adding the `is_readonly` property to all other test expectations, which makes the `testPHP81NotReadonly` test case redundant. * Adding two additional test cases. In particular I wanted to verify (and safeguard) that the retokenization of the `?` to `T_NULLABLE` after a `readonly` keyword would not be broken (which it partially was, but that has now been fixed in 3513). --- src/Files/File.php | 1 + tests/Core/File/GetMemberPropertiesTest.inc | 8 +- tests/Core/File/GetMemberPropertiesTest.php | 82 +++++++++++++++++++-- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/Files/File.php b/src/Files/File.php index 021949cb67..b0e67cec10 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -1759,6 +1759,7 @@ public function getMethodProperties($stackPtr) * 'scope' => string, // Public, private, or protected. * 'scope_specified' => boolean, // TRUE if the scope was explicitly specified. * 'is_static' => boolean, // TRUE if the static keyword was found. + * 'is_readonly' => boolean, // TRUE if the readonly keyword was found. * 'type' => string, // The type of the var (empty if no type specified). * 'type_token' => integer, // The stack pointer to the start of the type * // or FALSE if there is no type. diff --git a/tests/Core/File/GetMemberPropertiesTest.inc b/tests/Core/File/GetMemberPropertiesTest.inc index 3daf52c998..4533c5ffaf 100644 --- a/tests/Core/File/GetMemberPropertiesTest.inc +++ b/tests/Core/File/GetMemberPropertiesTest.inc @@ -240,10 +240,14 @@ $anon = class() { // Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. public int |string| /*comment*/ INT $duplicateTypeInUnion; - /* testPHP81NotReadonly */ - private string $notReadonly; /* testPHP81Readonly */ public readonly int $readonly; + + /* testPHP81ReadonlyWithNullableType */ + public readonly ?array $array; + + /* testPHP81ReadonlyWithUnionType */ + protected ReadOnly string|null $array; }; $anon = class { diff --git a/tests/Core/File/GetMemberPropertiesTest.php b/tests/Core/File/GetMemberPropertiesTest.php index d05814239d..cc709e69c7 100644 --- a/tests/Core/File/GetMemberPropertiesTest.php +++ b/tests/Core/File/GetMemberPropertiesTest.php @@ -51,6 +51,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -61,6 +62,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '?int', 'nullable_type' => true, ], @@ -71,6 +73,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -81,6 +84,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'string', 'nullable_type' => false, ], @@ -91,6 +95,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -101,6 +106,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'bool', 'nullable_type' => false, ], @@ -111,6 +117,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -121,6 +128,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'array', 'nullable_type' => false, ], @@ -131,6 +139,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -141,6 +150,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'nullable_type' => true, ], @@ -151,6 +161,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -161,6 +172,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -171,6 +183,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -181,6 +194,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -191,6 +205,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -201,6 +216,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -211,6 +227,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -221,6 +238,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -231,6 +249,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'float', 'nullable_type' => false, ], @@ -241,6 +260,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'float', 'nullable_type' => false, ], @@ -251,6 +271,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'nullable_type' => true, ], @@ -261,6 +282,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'nullable_type' => true, ], @@ -271,6 +293,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -281,6 +304,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -291,6 +315,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -301,6 +326,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -311,6 +337,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -321,6 +348,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -331,6 +359,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -341,6 +370,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -351,6 +381,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -361,6 +392,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -371,6 +403,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -381,6 +414,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?array', 'nullable_type' => true, ], @@ -391,6 +425,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '\MyNamespace\MyClass', 'nullable_type' => false, ], @@ -401,6 +436,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?ClassName', 'nullable_type' => true, ], @@ -411,6 +447,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?Folder\ClassName', 'nullable_type' => true, ], @@ -421,6 +458,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '\MyNamespace\MyClass\Foo', 'nullable_type' => false, ], @@ -431,6 +469,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -445,6 +484,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -455,6 +495,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'nullable_type' => false, ], @@ -465,6 +506,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => 'miXed', 'nullable_type' => false, ], @@ -475,6 +517,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?mixed', 'nullable_type' => true, ], @@ -485,6 +528,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?namespace\Name', 'nullable_type' => true, ], @@ -495,6 +539,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'int|float', 'nullable_type' => false, ], @@ -505,6 +550,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'MyClassA|\Package\MyClassB', 'nullable_type' => false, ], @@ -515,6 +561,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'array|bool|int|float|NULL|object|string', 'nullable_type' => false, ], @@ -525,6 +572,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => 'false|mixed|self|parent|iterable|Resource', 'nullable_type' => false, ], @@ -535,6 +583,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, // Missing static, but that's OK as not an allowed syntax. 'type' => 'callable||void', 'nullable_type' => false, @@ -546,6 +595,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?int|float', 'nullable_type' => true, ], @@ -556,6 +606,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'null', 'nullable_type' => false, ], @@ -566,6 +617,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'false', 'nullable_type' => false, ], @@ -576,6 +628,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'bool|FALSE', 'nullable_type' => false, ], @@ -586,6 +639,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'object|ClassName', 'nullable_type' => false, ], @@ -596,6 +650,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'iterable|array|Traversable', 'nullable_type' => false, ], @@ -606,29 +661,41 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'int|string|INT', 'nullable_type' => false, ], ], [ - '/* testPHP81NotReadonly */', + '/* testPHP81Readonly */', [ - 'scope' => 'private', + 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, - 'is_readonly' => false, - 'type' => 'string', + 'is_readonly' => true, + 'type' => 'int', 'nullable_type' => false, ], ], [ - '/* testPHP81Readonly */', + '/* testPHP81ReadonlyWithNullableType */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, - 'type' => 'int', + 'type' => '?array', + 'nullable_type' => true, + ], + ], + [ + '/* testPHP81ReadonlyWithUnionType */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'string|null', 'nullable_type' => false, ], ], @@ -638,6 +705,7 @@ public function dataGetMemberProperties() 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'string', 'nullable_type' => false, ], @@ -648,6 +716,7 @@ public function dataGetMemberProperties() 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?int|float', 'nullable_type' => true, ], @@ -658,6 +727,7 @@ public function dataGetMemberProperties() 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'mixed', 'nullable_type' => false, ],