From 0e869371fb3ac56992c5501b2782f0c95e8b7ee7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Oct 2022 00:56:24 +0200 Subject: [PATCH 1/3] PHP 8.1 | Variables::getMemberProperties(): support intersection types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync with upstream PRs 3581 which added support for PHP 8.1 intersection types to the method. Ref: * squizlabs/PHP_CodeSniffer 3581 Co-authored-by: Jaroslav Hanslík --- PHPCSUtils/Tokens/Collections.php | 19 ++++--- PHPCSUtils/Utils/Variables.php | 1 + .../BCFile/GetMemberPropertiesTest.inc | 16 ++++++ .../BCFile/GetMemberPropertiesTest.php | 52 +++++++++++++++++++ .../Collections/PropertyTypeTokensTest.php | 1 + 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 3b221cf4..ed59f8c9 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -523,20 +523,22 @@ class Collections * * @since 1.0.0-alpha1 * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @deprecated 1.0.0-alpha4 Use the {@see Collections::propertyTypeTokens()} method instead. * * @var array => */ public static $propertyTypeTokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_FALSE => \T_FALSE, - \T_NULL => \T_NULL, - \T_STRING => \T_STRING, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, - \T_TYPE_UNION => \T_TYPE_UNION, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, ]; /** @@ -949,6 +951,7 @@ public static function parameterTypeTokensBC() * @since 1.0.0-alpha4 This method replaces the {@see Collections::$propertyTypeTokens} property. * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @return array => */ diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index 14c92e7c..3fe4924b 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -90,6 +90,7 @@ class Variables * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * @since 1.0.0-alpha4 No longer gets confused by PHP 8.0 property attributes. * @since 1.0.0-alpha4 Added support for PHP 8.1 readonly properties. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the `T_VARIABLE` token diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc index 034ff308..48fde8c0 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc @@ -299,3 +299,19 @@ enum Direction implements ArrayAccess /* testEnumMethodParamNotProperty */ public function offsetGet($val) { ... } } + +$anon = class() { + /* testPHP81IntersectionTypes */ + public Foo&Bar $intersectionType; + + /* testPHP81MoreIntersectionTypes */ + public Foo&Bar&Baz $moreIntersectionTypes; + + /* testPHP81IllegalIntersectionTypes */ + // Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method. + public int&string $illegalIntersectionType; + + /* testPHP81NullableIntersectionType */ + // Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method. + public ?Foo&Bar $nullableIntersectionType; +}; diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php index 574248c1..09c68526 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php @@ -965,6 +965,58 @@ public function dataGetMemberProperties() '/* testEnumProperty */', [], ], + 'php8.1-single-intersection-type' => [ + '/* testPHP81IntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'Foo&Bar', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-multi-intersection-type' => [ + '/* testPHP81MoreIntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'Foo&Bar&Baz', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-illegal-intersection-type' => [ + '/* testPHP81IllegalIntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int&string', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-nullable-intersection-type' => [ + '/* testPHP81NullableIntersectionType */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?Foo&Bar', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], ]; } diff --git a/Tests/Tokens/Collections/PropertyTypeTokensTest.php b/Tests/Tokens/Collections/PropertyTypeTokensTest.php index dbd03093..2a247a49 100644 --- a/Tests/Tokens/Collections/PropertyTypeTokensTest.php +++ b/Tests/Tokens/Collections/PropertyTypeTokensTest.php @@ -41,6 +41,7 @@ public function testPropertyTypeTokens() \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, \T_NAMESPACE => \T_NAMESPACE, \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, From b68597849a15b517f120564645c45011e7bfb0fa Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Oct 2022 16:36:10 +0200 Subject: [PATCH 2/3] PHP 8.1 | FunctionDeclarations::getProperties(): add support for intersection types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref: * squizlabs/PHP_CodeSniffer 3581 Co-authored-by: Jaroslav Hanslík --- PHPCSUtils/Tokens/Collections.php | 21 ++-- PHPCSUtils/Utils/FunctionDeclarations.php | 1 + .../BCFile/GetMethodPropertiesTest.inc | 17 +++ .../BCFile/GetMethodPropertiesTest.php | 119 ++++++++++++++++++ .../Collections/ReturnTypeTokensTest.php | 1 + 5 files changed, 150 insertions(+), 9 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index ed59f8c9..4ffde525 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -546,21 +546,23 @@ class Collections * * @since 1.0.0-alpha1 * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @deprecated 1.0.0-alpha4 Use the {@see Collections::returnTypeTokens()} method instead. * * @var array => */ public static $returnTypeTokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_STATIC => \T_STATIC, - \T_FALSE => \T_FALSE, - \T_NULL => \T_NULL, - \T_STRING => \T_STRING, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, - \T_TYPE_UNION => \T_TYPE_UNION, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, + \T_FALSE => \T_FALSE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, ]; /** @@ -991,6 +993,7 @@ public static function propertyTypeTokensBC() * @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property. * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @return array => */ diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 7ad7d1df..d5decc5d 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -156,6 +156,7 @@ public static function getName(File $phpcsFile, $stackPtr) * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. * @since 1.0.0-alpha3 Added support for PHP 8.0 static return type. * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token to diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index b9fe6279..3d149e83 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -141,6 +141,23 @@ function never(): never {} // Intentional fatal error - nullability is not allowed with never, but that's not the concern of the method. function nullableNever(): ?never {} +/* testPHP8IntersectionTypes */ +function intersectionTypes(): Foo&Bar {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(): MyClassA&\Package\MyClassB&\Package\MyClassC {} + +/* testPHP81IntersectionArrowFunction */ +$fn = fn($var): MyClassA&\Package\MyClassB => $var; + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (): string&int {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (): ?Foo&Bar {}; + /* testNotAFunction */ return true; diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index e5e5a34a..ee20479d 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -895,6 +895,125 @@ public function testPHP81NullableNeverType() $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Foo&Bar', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 11 : 17, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration in arrow function. + * + * @return void + */ + public function testPHP81IntersectionArrowFunction() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB', + 'return_type_token' => 6, // Offset from the T_FN token. + 'return_type_end_token' => ($php8Names === true) ? 8 : 11, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'string&int', + 'return_type_token' => 6, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?Foo&Bar', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. * diff --git a/Tests/Tokens/Collections/ReturnTypeTokensTest.php b/Tests/Tokens/Collections/ReturnTypeTokensTest.php index 7b258a2b..c3a1f05d 100644 --- a/Tests/Tokens/Collections/ReturnTypeTokensTest.php +++ b/Tests/Tokens/Collections/ReturnTypeTokensTest.php @@ -42,6 +42,7 @@ public function testReturnTypeTokens() \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, \T_NAMESPACE => \T_NAMESPACE, \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, From a3c3e0e8c582820eb3bfbb5ed897b126045c7217 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 6 Oct 2022 01:23:44 +0200 Subject: [PATCH 3/3] PHP 8.1 | FunctionDeclarations::getParameters(): add support for intersection types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref: * squizlabs/PHP_CodeSniffer 3581 Co-authored-by: Jaroslav Hanslík --- PHPCSUtils/Tokens/Collections.php | 19 +- PHPCSUtils/Utils/FunctionDeclarations.php | 1 + .../BCFile/GetMethodParametersTest.inc | 17 ++ .../BCFile/GetMethodParametersTest.php | 168 ++++++++++++++++++ .../Collections/ParameterTypeTokensTest.php | 1 + 5 files changed, 198 insertions(+), 8 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 4ffde525..7b743dee 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -471,20 +471,22 @@ class Collections * * @since 1.0.0-alpha1 * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @deprecated 1.0.0-alpha4 Use the {@see Collections::parameterTypeTokens()} method instead. * * @var array => */ public static $parameterTypeTokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_FALSE => \T_FALSE, - \T_NULL => \T_NULL, - \T_STRING => \T_STRING, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, - \T_TYPE_UNION => \T_TYPE_UNION, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, ]; /** @@ -914,6 +916,7 @@ public static function parameterPassingTokens() * @since 1.0.0-alpha4 This method replaces the {@see Collections::$parameterTypeTokens} property. * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. * * @return array => */ diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index d5decc5d..a5421d09 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -365,6 +365,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * @since 1.0.0-alpha4 Added support for PHP 8.0 parameter attributes. * @since 1.0.0-alpha4 Added support for PHP 8.1 readonly keyword for constructor property promotion. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index b84f2ddd..e2991b67 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -239,6 +239,23 @@ class ParametersWithAttributes( ) {} } +/* testPHP8IntersectionTypes */ +function intersectionTypes(Foo&Bar $obj1, Boo&Bar $obj2) {} + +/* testPHP81IntersectionTypesWithSpreadOperatorAndReference */ +function globalFunctionWithSpreadAndReference(Boo&Bar &$paramA, Foo&Bar ...$paramB) {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(MyClassA&\Package\MyClassB&\Package\MyClassC $var) {} + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (string&int $numeric_string) {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (?Foo&Bar $object) {}; + /* testPHP81NewInInitializers */ function newInInitializers( TypeA $new = new TypeA(self::CONST_VALUE), diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index d481ff7d..e47336aa 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -2166,6 +2166,174 @@ public function testParameterAttributesInFunctionDeclaration() $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$obj1', + 'content' => 'Foo&Bar $obj1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 15, // Offset from the T_FUNCTION token. + 'name' => '$obj2', + 'content' => 'Boo&Bar $obj2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 11, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 13, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 intersection type declaration when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + { + $expected = []; + $expected[0] = [ + 'token' => 9, // Offset from the T_FUNCTION token. + 'name' => '$paramA', + 'content' => 'Boo&Bar &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$paramB', + 'content' => 'Foo&Bar ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, // Offset from the T_FUNCTION token. + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 12, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 10 : 16, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 8 : 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 7, // Offset from the T_FUNCTION token. + 'name' => '$numeric_string', + 'content' => 'string&int $numeric_string', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string&int', + 'type_hint_token' => 3, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$object', + 'content' => '?Foo&Bar $object', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Foo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1. * diff --git a/Tests/Tokens/Collections/ParameterTypeTokensTest.php b/Tests/Tokens/Collections/ParameterTypeTokensTest.php index de67dc59..c072e9c6 100644 --- a/Tests/Tokens/Collections/ParameterTypeTokensTest.php +++ b/Tests/Tokens/Collections/ParameterTypeTokensTest.php @@ -41,6 +41,7 @@ public function testParameterTypeTokens() \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, \T_NAMESPACE => \T_NAMESPACE, \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED,