From 6a3b638d401d6a0c55d779fafde4f72d9b096969 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 6 Aug 2023 01:10:41 +0200 Subject: [PATCH] Tokenizer/PHP: bug fix for static typed properties with union/intersection types Just like the `var` keyword, the `static` keyword can also be used stand-alone with property declarations. https://3v4l.org/sbaDM In that case, the tokenization of the `|` operator was not changed to `T_TYPE_UNION` and the `&` operator was not changed to `T_TYPE_INTERSECTION` as the `static` keyword can also be used in return type declarations, so was seen as part of the type declaration. Fixed now by removing the `T_STATIC` token from the `$allowed` list before walking backwards from the operator. Includes tests. Note: this does mean that one test for the `File::getMemberProperties()` method needs to be changed, but as that was testing an illegal syntax anyway, I'm not concerned about making this change. --- CHANGELOG.md | 2 ++ src/Tokenizers/PHP.php | 5 +++++ tests/Core/File/GetMemberPropertiesTest.inc | 3 ++- tests/Core/File/GetMemberPropertiesTest.php | 3 +-- tests/Core/Tokenizer/BitwiseOrTest.inc | 3 +++ tests/Core/Tokenizer/BitwiseOrTest.php | 1 + tests/Core/Tokenizer/TypeIntersectionTest.inc | 3 +++ tests/Core/Tokenizer/TypeIntersectionTest.php | 1 + 8 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3571bf28e8..96c1cb84d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,8 @@ The file documents changes to the PHP_CodeSniffer project. - Thanks to Dan Wallis (@fredden) for the patch - Fixed bug #3816 : PSR12/FileHeader: bug fix - false positives on PHP 8.2+ readonly classes - Thanks to Juliette Reinders Folmer (@jrfnl) for the patch +- Fixed bug #3867 : Tokenizer/PHP: union type and intersection type operators were not correctly tokenized for static properties without explicit visibility + - Thanks to Juliette Reinders Folmer (@jrfnl) for the patch - Fixed bug #3877 : Filter names can be case-sensitive. The -h help text will now display the correct case for the available filters - Thanks to @simonsan for the patch - Fixed bug #3906 : Tokenizer/CSS: fixed a bug related to the unsupported slash comment syntax diff --git a/src/Tokenizers/PHP.php b/src/Tokenizers/PHP.php index 68a9ab76ec..5ca178bd04 100644 --- a/src/Tokenizers/PHP.php +++ b/src/Tokenizers/PHP.php @@ -2998,6 +2998,10 @@ protected function processAdditional() continue; } + if ($suspectedType === 'property or parameter') { + unset($allowed[\T_STATIC]); + } + $typeTokenCount = 0; $typeOperators = [$i]; $confirmed = false; @@ -3030,6 +3034,7 @@ protected function processAdditional() if ($suspectedType === 'property or parameter' && (isset(Util\Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_VAR + || $this->tokens[$x]['code'] === T_STATIC || $this->tokens[$x]['code'] === T_READONLY) ) { // This will also confirm constructor property promotion parameters, but that's fine. diff --git a/tests/Core/File/GetMemberPropertiesTest.inc b/tests/Core/File/GetMemberPropertiesTest.inc index 51d11c2f1a..441bd97772 100644 --- a/tests/Core/File/GetMemberPropertiesTest.inc +++ b/tests/Core/File/GetMemberPropertiesTest.inc @@ -210,7 +210,8 @@ $anon = class() { /* testPHP8UnionTypesIllegalTypes */ // Intentional fatal error - types which are not allowed for properties, but that's not the concern of the method. - public callable|static|void $unionTypesIllegalTypes; + // Note: static is also not allowed as a type, but using static for a property type is not supported by the tokenizer. + public callable|void $unionTypesIllegalTypes; /* testPHP8UnionTypesNullable */ // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. diff --git a/tests/Core/File/GetMemberPropertiesTest.php b/tests/Core/File/GetMemberPropertiesTest.php index 4fd5fb755b..272f3b2ef1 100644 --- a/tests/Core/File/GetMemberPropertiesTest.php +++ b/tests/Core/File/GetMemberPropertiesTest.php @@ -587,8 +587,7 @@ public function dataGetMemberProperties() 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, - // Missing static, but that's OK as not an allowed syntax. - 'type' => 'callable||void', + 'type' => 'callable|void', 'nullable_type' => false, ], ], diff --git a/tests/Core/Tokenizer/BitwiseOrTest.inc b/tests/Core/Tokenizer/BitwiseOrTest.inc index 843f6c57d7..b758aba019 100644 --- a/tests/Core/Tokenizer/BitwiseOrTest.inc +++ b/tests/Core/Tokenizer/BitwiseOrTest.inc @@ -48,6 +48,9 @@ class TypeUnion /* testTypeUnionPropertyWithOnlyReadOnlyKeyword */ readonly string|null $nullableString; + /* testTypeUnionPropertyWithOnlyStaticKeyword */ + static Foo|Bar $obj; + public function paramTypes( /* testTypeUnionParam1 */ int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B, diff --git a/tests/Core/Tokenizer/BitwiseOrTest.php b/tests/Core/Tokenizer/BitwiseOrTest.php index aad4474049..81e10e01a9 100644 --- a/tests/Core/Tokenizer/BitwiseOrTest.php +++ b/tests/Core/Tokenizer/BitwiseOrTest.php @@ -110,6 +110,7 @@ public function dataTypeUnion() ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], + ['/* testTypeUnionPropertyWithOnlyStaticKeyword */'], ['/* testTypeUnionParam1 */'], ['/* testTypeUnionParam2 */'], ['/* testTypeUnionParam3 */'], diff --git a/tests/Core/Tokenizer/TypeIntersectionTest.inc b/tests/Core/Tokenizer/TypeIntersectionTest.inc index abf9b85ba8..ad421cba5a 100644 --- a/tests/Core/Tokenizer/TypeIntersectionTest.inc +++ b/tests/Core/Tokenizer/TypeIntersectionTest.inc @@ -36,6 +36,9 @@ class TypeIntersection /* testTypeIntersectionPropertyWithReadOnlyKeyword */ protected readonly Foo&Bar $fooBar; + /* testTypeIntersectionPropertyWithStaticKeyword */ + static Foo&Bar $obj; + public function paramTypes( /* testTypeIntersectionParam1 */ Foo&Bar $paramA /* testBitwiseAndParamDefaultValue */ = CONSTANT_A & CONSTANT_B, diff --git a/tests/Core/Tokenizer/TypeIntersectionTest.php b/tests/Core/Tokenizer/TypeIntersectionTest.php index 4d18485c39..fcfd191acf 100644 --- a/tests/Core/Tokenizer/TypeIntersectionTest.php +++ b/tests/Core/Tokenizer/TypeIntersectionTest.php @@ -109,6 +109,7 @@ public function dataTypeIntersection() ['/* testTypeIntersectionPropertyPartiallyQualified */'], ['/* testTypeIntersectionPropertyFullyQualified */'], ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], + ['/* testTypeIntersectionPropertyWithStaticKeyword */'], ['/* testTypeIntersectionParam1 */'], ['/* testTypeIntersectionParam2 */'], ['/* testTypeIntersectionParam3 */'],