From 2302d6998ff0014081acab96281cc20e6f579c7b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 16:05:30 +0200 Subject: [PATCH 01/12] Collections::propertyTypeTokensBC(): uncouple from the parameterTypeTokensBC() method --- PHPCSUtils/Tokens/Collections.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 04924c34..27fedf2b 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -660,7 +660,14 @@ public static function parameterTypeTokensBC() */ public static function propertyTypeTokensBC() { - return self::parameterTypeTokensBC(); + $tokens = self::$propertyTypeTokens; + + // PHPCS < 4.0; Needed for support of PHPCS < 3.3.0. For PHPCS 3.3.0+ the constant is no longer used. + if (\defined('T_ARRAY_HINT') === true) { + $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; + } + + return $tokens; } /** From 8fa856b60418c6c4b03f823a5addd3f9022f34aa Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 11:39:08 +0200 Subject: [PATCH 02/12] Collections: deprecate $parameterTypeTokens in favour of parameterTypeTokens() Deprecate the `$parameterTypeTokens` property in favour of a new `Collections::parameterTypeTokens()` method. PHPCS is expected to introduce a new `T_TYPE_UNION` token. As that token would not always be available, a property can't handle this. In anticipation of the introduction of the new token, I'm deprecating the `Collections::$parameterTypeTokens` property straight away to prevent BC breaks at a later point. Includes adding unit tests for the new method. --- PHPCSUtils/Tokens/Collections.php | 67 +++++++++++++------ .../Collections/ParameterTypeTokensBCTest.php | 2 +- .../Collections/ParameterTypeTokensTest.php | 45 +++++++++++++ 3 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 Tests/Tokens/Collections/ParameterTypeTokensTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 27fedf2b..9205282c 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -333,23 +333,14 @@ class Collections ]; /** - * Token types which can be encountered in a parameter type declaration. - * - * Sister-property to the {@see Collections::parameterTypeTokensBC()} method. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. - * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. - * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). + * DEPRECATED: Token types which can be encountered in a parameter type declaration. * * @since 1.0.0 * + * @deprecated 1.0.0-alpha4 Use the {@see \PHPCSUtils\Tokens\Collections::parameterTypeTokens()} + * or {@see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC()} + * method instead. + * * @var array => */ public static $parameterTypeTokens = [ @@ -606,21 +597,53 @@ public static function functionDeclarationTokensBC() return $tokens; } + /** + * Token types which can be encountered in a parameter type declaration. + * + * Sister-method to the {@see Collections::parameterTypeTokensBC()} method. + * This method supports PHPCS 3.3.0 and up. + * The {@see Collections::parameterTypeTokensBC()} method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * - The {@see Collections::parameterTypeTokensBC()} method will include the `T_ARRAY_HINT` token + * when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use this method instead of the {@see Collections::parameterTypeTokensBC()} + * method if a standard does not need to support PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$parameterTypeTokens} property. + * + * @return array => + */ + public static function parameterTypeTokens() + { + return [ + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + } + /** * Token types which can be encountered in a parameter type declaration (cross-version). * - * Sister-method to the {@see Collections::$parameterTypeTokens} property. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * Sister-method to the {@see Collections::parameterTypeTokens()} method. + * The {@see Collections::parameterTypeTokens()} method supports PHPCS 3.3.0 and up. + * This method supports PHPCS 2.6.0 and up. * * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * - This method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. * This token constant will no longer exist in PHPCS 4.x. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. + * It is recommended to use {@see Collections::parameterTypeTokens()} method instead of + * this method if a standard does not need to support PHPCS < 3.3.0. * - * @see \PHPCSUtils\Tokens\Collections::$parameterTypeTokens Related property (PHPCS 3.3.0+). + * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 * @@ -628,7 +651,7 @@ public static function functionDeclarationTokensBC() */ public static function parameterTypeTokensBC() { - $tokens = self::$parameterTypeTokens; + $tokens = self::parameterTypeTokens(); // PHPCS < 4.0; Needed for support of PHPCS < 3.3.0. For PHPCS 3.3.0+ the constant is no longer used. if (\defined('T_ARRAY_HINT') === true) { diff --git a/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php index 0fcb7cf1..f618f28d 100644 --- a/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php @@ -34,7 +34,7 @@ class ParameterTypeTokensBCTest extends TestCase public function testParameterTypeTokensBC() { $version = Helper::getVersion(); - $expected = Collections::$parameterTypeTokens; + $expected = Collections::parameterTypeTokens(); if (\version_compare($version, '3.99.99', '<=') === true) { $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; diff --git a/Tests/Tokens/Collections/ParameterTypeTokensTest.php b/Tests/Tokens/Collections/ParameterTypeTokensTest.php new file mode 100644 index 00000000..e443de6b --- /dev/null +++ b/Tests/Tokens/Collections/ParameterTypeTokensTest.php @@ -0,0 +1,45 @@ + \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + + $this->assertSame($expected, Collections::parameterTypeTokens()); + } +} From ea706342b06a219d0c3a7415eb97c7f76a4e6260 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 12:03:18 +0200 Subject: [PATCH 03/12] PHP 8.0 | Collection::parameterTypeTokens[BC](): add support for union types Includes adjusted unit test. --- PHPCSUtils/Tokens/Collections.php | 5 +++++ Tests/Tokens/Collections/ParameterTypeTokensTest.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 9205282c..e44e394c 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -615,6 +615,7 @@ public static function functionDeclarationTokensBC() * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). * * @since 1.0.0-alpha4 This method replaces the {@see Collections::$parameterTypeTokens} property. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ @@ -624,8 +625,11 @@ public static function parameterTypeTokens() \T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, // Union types only. + \T_NULL => \T_NULL, // Union types only. \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_BITWISE_OR => \T_BITWISE_OR, // Union types. ]; } @@ -646,6 +650,7 @@ public static function parameterTypeTokens() * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ diff --git a/Tests/Tokens/Collections/ParameterTypeTokensTest.php b/Tests/Tokens/Collections/ParameterTypeTokensTest.php index e443de6b..d4874cb5 100644 --- a/Tests/Tokens/Collections/ParameterTypeTokensTest.php +++ b/Tests/Tokens/Collections/ParameterTypeTokensTest.php @@ -36,8 +36,11 @@ public function testParameterTypeTokens() \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_BITWISE_OR => \T_BITWISE_OR, ]; $this->assertSame($expected, Collections::parameterTypeTokens()); From b3f7e68d757fc2b7c61cb5ee6976f31c2a49febc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 16:00:55 +0200 Subject: [PATCH 04/12] Collections: deprecate $propertyTypeTokens in favour of propertyTypeTokens() Deprecate the `$propertyTypeTokens` property in favour of a new `Collections::propertyTypeTokens()` method. PHPCS is expected to introduce a new `T_TYPE_UNION` token. As that token would not always be available, a property can't handle this. In anticipation of the introduction of the new token, I'm deprecating the `Collections::$propertyTypeTokens` property straight away to prevent BC breaks at a later point. Includes adding unit tests for the new method. --- PHPCSUtils/Tokens/Collections.php | 67 +++++++++++++------ .../Collections/PropertyTypeTokensBCTest.php | 2 +- .../Collections/PropertyTypeTokensTest.php | 45 +++++++++++++ 3 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 Tests/Tokens/Collections/PropertyTypeTokensTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index e44e394c..ef7632a3 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -367,23 +367,14 @@ class Collections ]; /** - * Token types which can be encountered in a property type declaration. - * - * Sister-property to the {@see Collections::propertyTypeTokensBC()} method. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. - * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. - * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() Related method (cross-version). + * DEPRECATED: Token types which can be encountered in a property type declaration. * * @since 1.0.0 * + * @deprecated 1.0.0-alpha4 Use the {@see \PHPCSUtils\Tokens\Collections::propertyTypeTokens()} + * or {@see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC()} + * method instead. + * * @var array => */ public static $propertyTypeTokens = [ @@ -666,21 +657,53 @@ public static function parameterTypeTokensBC() return $tokens; } + /** + * Token types which can be encountered in a property type declaration. + * + * Sister-method to the {@see Collections::propertyTypeTokensBC()} method. + * This method supports PHPCS 3.3.0 and up. + * The {@see Collections::propertyTypeTokensBC()} method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * - The {@see Collections::propertyTypeTokensBC()} method will include the `T_ARRAY_HINT` token + * when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use this method instead of the {@see Collections::propertyTypeTokensBC()} + * method if a standard does not need to support PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() Related method (cross-version). + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$propertyTypeTokens} property. + * + * @return array => + */ + public static function propertyTypeTokens() + { + return [ + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + } + /** * Token types which can be encountered in a property type declaration (cross-version). * - * Sister-method to the {@see Collections::$propertyTypeTokens} property. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * Sister-method to the {@see Collections::propertyTypeTokens()} method. + * The {@see Collections::propertyTypeTokens()} method supports PHPCS 3.3.0 and up. + * This method supports PHPCS 2.6.0 and up. * * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * - This method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. * This token constant will no longer exist in PHPCS 4.x. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. + * It is recommended to use the {@see Collections::propertyTypeTokens()} method instead of + * this method if a standard does not need to support PHPCS < 3.3.0. * - * @see \PHPCSUtils\Tokens\Collections::$propertyTypeTokens Related property (PHPCS 3.3.0+). + * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 * @@ -688,7 +711,7 @@ public static function parameterTypeTokensBC() */ public static function propertyTypeTokensBC() { - $tokens = self::$propertyTypeTokens; + $tokens = self::propertyTypeTokens(); // PHPCS < 4.0; Needed for support of PHPCS < 3.3.0. For PHPCS 3.3.0+ the constant is no longer used. if (\defined('T_ARRAY_HINT') === true) { diff --git a/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php index b743eaad..cc9a68c8 100644 --- a/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php @@ -34,7 +34,7 @@ class PropertyTypeTokensBCTest extends TestCase public function testPropertyTypeTokensBC() { $version = Helper::getVersion(); - $expected = Collections::$propertyTypeTokens; + $expected = Collections::propertyTypeTokens(); if (\version_compare($version, '3.99.99', '<=') === true) { $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; diff --git a/Tests/Tokens/Collections/PropertyTypeTokensTest.php b/Tests/Tokens/Collections/PropertyTypeTokensTest.php new file mode 100644 index 00000000..b104c544 --- /dev/null +++ b/Tests/Tokens/Collections/PropertyTypeTokensTest.php @@ -0,0 +1,45 @@ + \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + + $this->assertSame($expected, Collections::propertyTypeTokens()); + } +} From 27d5bedc9c84d851a7f12857f6cf2bacea51f7d0 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 16:10:15 +0200 Subject: [PATCH 05/12] PHP 8.0 | Collection::propertyTypeTokens[BC](): add support for union types Includes adjusted unit test. --- PHPCSUtils/Tokens/Collections.php | 5 +++++ Tests/Tokens/Collections/PropertyTypeTokensTest.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index ef7632a3..e482a03a 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -675,6 +675,7 @@ public static function parameterTypeTokensBC() * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() Related method (cross-version). * * @since 1.0.0-alpha4 This method replaces the {@see Collections::$propertyTypeTokens} property. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ @@ -684,8 +685,11 @@ public static function propertyTypeTokens() \T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, // Union types only. + \T_NULL => \T_NULL, // Union types only. \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_BITWISE_OR => \T_BITWISE_OR, // Union types. ]; } @@ -706,6 +710,7 @@ public static function propertyTypeTokens() * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ diff --git a/Tests/Tokens/Collections/PropertyTypeTokensTest.php b/Tests/Tokens/Collections/PropertyTypeTokensTest.php index b104c544..920915aa 100644 --- a/Tests/Tokens/Collections/PropertyTypeTokensTest.php +++ b/Tests/Tokens/Collections/PropertyTypeTokensTest.php @@ -36,8 +36,11 @@ public function testPropertyTypeTokens() \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_BITWISE_OR => \T_BITWISE_OR, ]; $this->assertSame($expected, Collections::propertyTypeTokens()); From 311a2d5ba2ddad7b0b9770595bdfd9cf223331de Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 16:15:50 +0200 Subject: [PATCH 06/12] Collections: deprecate $returnTypeTokens in favour of returnTypeTokens() Deprecate the `$returnTypeTokens` property in favour of a new `Collections::returnTypeTokens()` method. PHPCS is expected to introduce a new `T_TYPE_UNION` token. As that token would not always be available, a property can't handle this. In anticipation of the introduction of the new token, I'm deprecating the `Collections::$returnTypeTokens` property straight away to prevent BC breaks at a later point. Includes adding unit tests for the new method. --- PHPCSUtils/Tokens/Collections.php | 75 +++++++++++++------ .../Collections/ReturnTypeTokensBCTest.php | 2 +- .../Collections/ReturnTypeTokensTest.php | 46 ++++++++++++ 3 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 Tests/Tokens/Collections/ReturnTypeTokensTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index e482a03a..da82ebc7 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -386,24 +386,14 @@ class Collections ]; /** - * Token types which can be encountered in a return type declaration. - * - * Sister-property to the {@see Collections::returnTypeTokensBC()} method. - * The property supports PHPCS 3.5.4 and up. - * The method supports PHPCS 2.6.0 and up. - * - * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. - * These token constants will no longer exist in PHPCS 4.x. - * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. - * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.5.4. - * - * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). + * DEPRECATED: Token types which can be encountered in a return type declaration. * * @since 1.0.0 * + * @deprecated 1.0.0-alpha4 Use the {@see \PHPCSUtils\Tokens\Collections::returnTypeTokens()} + * or {@see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC()} + * method instead. + * * @var array => */ public static $returnTypeTokens = [ @@ -726,22 +716,59 @@ public static function propertyTypeTokensBC() return $tokens; } + /** + * Token types which can be encountered in a return type declaration. + * + * Sister-method to the {@see Collections::returnTypeTokensBC()} method. + * This method supports PHPCS 3.5.4 and up. + * The {@see Collections::returnTypeTokensBC()} method supports PHPCS 2.6.0 and up. + * + * Notable differences: + * - The {@see Collections::returnTypeTokensBC()} method will include the `T_ARRAY_HINT` + * and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. + * These token constants will no longer exist in PHPCS 4.x. + * - The {@see Collections::returnTypeTokensBC()} method will include the `T_ARRAY` token + * which is needed for select arrow functions in PHPCS < 3.5.4. + * + * It is recommended to use this method instead of the {@see Collections::returnTypeTokensBC()} + * method if a standard does not need to support PHPCS < 3.5.4. + * + * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property. + * + * @return array => + */ + public static function returnTypeTokens() + { + return [ + \T_STRING => \T_STRING, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + } + /** * Token types which can be encountered in a return type declaration (cross-version). * - * Sister-property to the {@see Collections::returnTypeTokensBC()} method. - * The property supports PHPCS 3.5.4 and up. - * The method supports PHPCS 2.6.0 and up. + * Sister-method to the {@see Collections::returnTypeTokens()} method. + * The {@see Collections::returnTypeTokens()} method supports PHPCS 3.5.4 and up. + * This method supports PHPCS 2.6.0 and up. * * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. + * - This method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when + * used with PHPCS 2.x and 3.x. * These token constants will no longer exist in PHPCS 4.x. - * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. + * - This method will include the `T_ARRAY` token which is needed for select arrow + * functions in PHPCS < 3.5.4. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.5.4. + * It is recommended to use the {@see Collections::returnTypeTokens()} method instead of + * this method if a standard does not need to support PHPCS < 3.5.4. * - * @see \PHPCSUtils\Tokens\Collections::$returnTypeTokens Related property (PHPCS 3.5.4+). + * @see \PHPCSUtils\Tokens\Collections::returnTypeTokens() Related method (PHPCS 3.5.4+). * * @since 1.0.0-alpha3 * @@ -749,7 +776,7 @@ public static function propertyTypeTokensBC() */ public static function returnTypeTokensBC() { - $tokens = self::$returnTypeTokens; + $tokens = self::returnTypeTokens(); /* * PHPCS < 4.0. Needed for support of PHPCS 2.4.0 < 3.3.0. diff --git a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php index 347ca673..8e01f06e 100644 --- a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php @@ -34,7 +34,7 @@ class ReturnTypeTokensBCTest extends TestCase public function testReturnTypeTokensBC() { $version = Helper::getVersion(); - $expected = Collections::$returnTypeTokens; + $expected = Collections::returnTypeTokens(); if (\version_compare($version, '3.99.99', '<=') === true) { $expected[\T_RETURN_TYPE] = \T_RETURN_TYPE; diff --git a/Tests/Tokens/Collections/ReturnTypeTokensTest.php b/Tests/Tokens/Collections/ReturnTypeTokensTest.php new file mode 100644 index 00000000..747e5780 --- /dev/null +++ b/Tests/Tokens/Collections/ReturnTypeTokensTest.php @@ -0,0 +1,46 @@ + \T_STRING, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ]; + + $this->assertSame($expected, Collections::returnTypeTokens()); + } +} From 9158cc7c36aa9a30ecd23ae191693988a94cb2ff Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 15 Jul 2020 16:22:59 +0200 Subject: [PATCH 07/12] PHP 8.0 | Collection::returnTypeTokens[BC](): add support for union types In addition to the other tokens needed to support union types, the `returnTypeTokens[BC]()` methods also needs the `T_ARRAY` token as the `array` keyword in union type return types is not always correctly re-tokenized to `T_STRING`. A change to the PHPCS tokenizer to mitigate this will be pulled upstream, but until that PR has been merged, `T_ARRAY` will continue to be needed. This changes the versions supported by the `returnTypeTokens()` method from "minimum PHPCS 3.5.4" to "minimum 3.3.0", which also brings the method more in line with the `parameterTypeTokens()` and the `propertyTypeTokens()` methods. Includes adjusted unit tests. --- PHPCSUtils/Tokens/Collections.php | 30 +++++++------------ .../Collections/ReturnTypeTokensBCTest.php | 4 --- .../Collections/ReturnTypeTokensTest.php | 4 +++ 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index da82ebc7..dc2fcb19 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -10,8 +10,6 @@ namespace PHPCSUtils\Tokens; -use PHPCSUtils\BackCompat\Helper; - /** * Collections of related tokens as often used and needed for sniffs. * @@ -720,22 +718,21 @@ public static function propertyTypeTokensBC() * Token types which can be encountered in a return type declaration. * * Sister-method to the {@see Collections::returnTypeTokensBC()} method. - * This method supports PHPCS 3.5.4 and up. + * This method supports PHPCS 3.3.0 and up. * The {@see Collections::returnTypeTokensBC()} method supports PHPCS 2.6.0 and up. * * Notable differences: * - The {@see Collections::returnTypeTokensBC()} method will include the `T_ARRAY_HINT` * and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. * These token constants will no longer exist in PHPCS 4.x. - * - The {@see Collections::returnTypeTokensBC()} method will include the `T_ARRAY` token - * which is needed for select arrow functions in PHPCS < 3.5.4. * * It is recommended to use this method instead of the {@see Collections::returnTypeTokensBC()} - * method if a standard does not need to support PHPCS < 3.5.4. + * method if a standard does not need to support PHPCS < 3.3.0. * * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). * * @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ @@ -747,7 +744,11 @@ public static function returnTypeTokens() \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_STATIC => \T_STATIC, + \T_FALSE => \T_FALSE, // Union types only. + \T_NULL => \T_NULL, // Union types only. + \T_ARRAY => \T_ARRAY, // Arrow functions PHPCS < 3.5.4 + union types. \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_BITWISE_OR => \T_BITWISE_OR, // Union types. ]; } @@ -755,22 +756,21 @@ public static function returnTypeTokens() * Token types which can be encountered in a return type declaration (cross-version). * * Sister-method to the {@see Collections::returnTypeTokens()} method. - * The {@see Collections::returnTypeTokens()} method supports PHPCS 3.5.4 and up. + * The {@see Collections::returnTypeTokens()} method supports PHPCS 3.3.0 and up. * This method supports PHPCS 2.6.0 and up. * * Notable differences: * - This method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when * used with PHPCS 2.x and 3.x. * These token constants will no longer exist in PHPCS 4.x. - * - This method will include the `T_ARRAY` token which is needed for select arrow - * functions in PHPCS < 3.5.4. * * It is recommended to use the {@see Collections::returnTypeTokens()} method instead of - * this method if a standard does not need to support PHPCS < 3.5.4. + * this method if a standard does not need to support PHPCS < 3.3.0. * - * @see \PHPCSUtils\Tokens\Collections::returnTypeTokens() Related method (PHPCS 3.5.4+). + * @see \PHPCSUtils\Tokens\Collections::returnTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @return array => */ @@ -794,14 +794,6 @@ public static function returnTypeTokensBC() $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; } - /* - * PHPCS < 3.5.4. Needed for support of PHPCS < 3.5.4 for select arrow functions. - * For PHPCS 3.5.4+ the constant is no longer used in return type tokenization. - */ - if (\version_compare(Helper::getVersion(), '3.5.4', '<')) { - $tokens[\T_ARRAY] = \T_ARRAY; - } - return $tokens; } } diff --git a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php index 8e01f06e..c1955f1b 100644 --- a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php @@ -41,10 +41,6 @@ public function testReturnTypeTokensBC() $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; } - if (\version_compare($version, '3.5.3', '<=') === true) { - $expected[\T_ARRAY] = \T_ARRAY; - } - $this->assertSame($expected, Collections::returnTypeTokensBC()); } } diff --git a/Tests/Tokens/Collections/ReturnTypeTokensTest.php b/Tests/Tokens/Collections/ReturnTypeTokensTest.php index 747e5780..12155a2f 100644 --- a/Tests/Tokens/Collections/ReturnTypeTokensTest.php +++ b/Tests/Tokens/Collections/ReturnTypeTokensTest.php @@ -38,7 +38,11 @@ public function testReturnTypeTokens() \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_STATIC => \T_STATIC, + \T_FALSE => \T_FALSE, + \T_NULL => \T_NULL, + \T_ARRAY => \T_ARRAY, \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_BITWISE_OR => \T_BITWISE_OR, ]; $this->assertSame($expected, Collections::returnTypeTokens()); From fb18be6c46e52aa5dc40e0acc97865b8b9fdfe86 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 16 Jul 2020 08:46:22 +0200 Subject: [PATCH 08/12] FunctionDeclarations::getParameters(): add support for PHP 8 "union" types This commit adds support for union types to the `FunctionDeclarations::getParameters()` method. Changes along the same lines as included in this PR will also be pulled upstream to PHPCS itself. Once the upstream PR has been merged, those changes will also be applied to the `BCFile::getMethodParameters()` method. Includes extensive unit tests. Ref: https://wiki.php.net/rfc/union_types_v2 --- PHPCSUtils/Utils/FunctionDeclarations.php | 5 + .../GetParametersDiffTest.inc | 44 +- .../GetParametersDiffTest.php | 387 ++++++++++++++++++ 3 files changed, 435 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 54eab74f..deaf536c 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -379,12 +379,14 @@ public static function getProperties(File $phpcsFile, $stackPtr) * - Clearer exception message when a non-closure use token was passed to the function. * - To allow for backward compatible handling of arrow functions, this method will also accept * `T_STRING` tokens and examine them to check if these are arrow functions. + * - Support for PHP 8.0 union types. * * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodParameters() Cross-version compatible version of the original. * * @since 1.0.0 * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -476,8 +478,11 @@ public static function getParameters(File $phpcsFile, $stackPtr) case 'T_SELF': case 'T_PARENT': case 'T_STATIC': // Self and parent are valid, static invalid, but was probably intended as type hint. + case 'T_FALSE': // Union types. + case 'T_NULL': // Union types. case 'T_STRING': case 'T_NS_SEPARATOR': + case 'T_BITWISE_OR': // Union type separator. if ($typeHintToken === false) { $typeHintToken = $i; } diff --git a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc index 0b8c0af4..a10b9089 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc +++ b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc @@ -1,3 +1,45 @@ $var; + +/* testPHP8UnionTypesTwoClasses */ +function unionTypesTwoClasses(MyClassA|\Package\MyClassB $var) {} + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes(array|bool|callable|int|float|null|object|string $var) {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var) {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function (?int|float $number) {}; + +/* testPHP8PseudoTypeNull */ +// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(null $var = null) {} + +/* testPHP8PseudoTypeFalse */ +// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(false $var = false) {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(bool|false $var = false) {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(object|ClassName $var) {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +function pseudoTypeIterableAndArray(iterable|array|Traversable $var) {} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion( int | string /*comment*/ | INT $var) {} diff --git a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php index 66235ace..fc6a14f9 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -39,4 +40,390 @@ public function testNonExistentToken() FunctionDeclarations::getParameters(self::$phpcsFile, 10000); } + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$number', + 'content' => 'int|float $number', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + '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' => 17, // Offset from the T_FUNCTION token. + 'name' => '$obj', + 'content' => 'self|parent &...$obj', + 'pass_by_reference' => true, + 'reference_token' => 15, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'self|parent', + '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->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * + * @return void + */ + public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', + 'default' => 'CONSTANT_A | CONSTANT_B', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 2, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + } + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + $expected = []; + $expected[0] = [ + 'token' => 11, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'MyClassA|\Package\MyClassB $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA|\Package\MyClassB', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 20, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array|bool|callable|int|float|null|object|string', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 18, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types.. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 16, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|mixed|self|parent|iterable|Resource', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$number', + 'content' => '?int|float $number', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int|float', + '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->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'null $var = null', + 'default' => 'null', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'null', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'false $var = false', + 'default' => 'false', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'bool|false $var = false', + 'default' => 'false', + 'default_token' => 12, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool|false', + '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' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'object|ClassName $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object|ClassName', + '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' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + $expected = []; + $expected[0] = [ + 'token' => 10, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'iterable|array|Traversable $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable|array|Traversable', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + $expected = []; + $expected[0] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'int | string /*comment*/ | INT $var', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|string|INT', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 15, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test helper. + * + * @param string $commentString The comment which preceeds the test. + * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $commentString. + * Defaults to the function/closure tokens. + * + * @return void + */ + protected function getParametersTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) + { + $target = $this->getTargetToken($commentString, $targetType); + $found = FunctionDeclarations::getParameters(self::$phpcsFile, $target); + + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $target; + + if ($param['reference_token'] !== false) { + $expected[$key]['reference_token'] += $target; + } + if ($param['variadic_token'] !== false) { + $expected[$key]['variadic_token'] += $target; + } + if ($param['type_hint_token'] !== false) { + $expected[$key]['type_hint_token'] += $target; + } + if ($param['type_hint_end_token'] !== false) { + $expected[$key]['type_hint_end_token'] += $target; + } + if ($param['comma_token'] !== false) { + $expected[$key]['comma_token'] += $target; + } + if (isset($param['default_token'])) { + $expected[$key]['default_token'] += $target; + } + if (isset($param['default_equal_token'])) { + $expected[$key]['default_equal_token'] += $target; + } + } + + $this->assertSame($expected, $found); + } } From 6584ce46606b0ec6a19e00bfea247f31847e4e52 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jul 2020 08:16:41 +0200 Subject: [PATCH 09/12] FunctionDeclarations::getProperties(): add tests verifying support for PHP 8 "union" types The commit which added union type support to the `Collections::returnTypeTokens[BC]()` methods implicitly added support for union types to the `FunctionDeclarations::getProperties()` method. This commit adds extensive unit tests to safeguard this support. The same commit also _silently_ added support for union types to the `BCFile::getMethodProperties()` method. Union types are not supported yet in PHPCS itself and until they are, the fact that the `BCFile::getMethodProperties()` method supports them should be regarded as an artefact and not as official support. --- PHPCSUtils/Utils/FunctionDeclarations.php | 2 + .../GetPropertiesDiffTest.inc | 43 +++ .../GetPropertiesDiffTest.php | 264 +++++++++++++++++- 3 files changed, 307 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index deaf536c..07acf4b9 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -170,6 +170,7 @@ public static function getName(File $phpcsFile, $stackPtr) * - New `"return_type_end_token"` (int|false) array index. * - To allow for backward compatible handling of arrow functions, this method will also accept * `T_STRING` tokens and examine them to check if these are arrow functions. + * - Support for PHP 8.0 union types. * * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodProperties() Cross-version compatible version of the original. @@ -177,6 +178,7 @@ public static function getName(File $phpcsFile, $stackPtr) * @since 1.0.0 * @since 1.0.0-alpha2 Added BC 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. * * @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/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc index 34138d72..d7eb966a 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc @@ -22,3 +22,46 @@ trait FooTrait { function myFunction(): ?\MyNamespace /* comment */ \MyClass // comment \Foo {} + +/* testPHP8UnionTypesSimple */ +function unionTypeSimple($number) : int|float {} + +/* testPHP8UnionTypesTwoClasses */ +$fn = fn($var): MyClassA|\Package\MyClassB => $var; + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes() : array|bool|callable|int|float|null|Object|string {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterable|Resource|void {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function () use($a) :?int|float {}; + +/* testPHP8PseudoTypeNull */ +// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(): null {} + +/* testPHP8PseudoTypeFalse */ +// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(): false {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(): bool|false {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(): object|ClassName {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +interface FooBar { + public function pseudoTypeIterableAndArray(): iterable|array|Traversable; +} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion(): int | /*comment*/ string | INT {} diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php index 8fee9566..e1234bfb 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -109,17 +110,276 @@ public function testReturnTypeEndTokenIndex() $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|float', + 'return_type_token' => 9, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA|\Package\MyClassB', + 'return_type_token' => 6, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + } + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array|bool|callable|int|float|null|Object|string', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 22, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', + 'return_type_token' => 9, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 23, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?int|float', + 'return_type_token' => 12, // Offset from the T_CLOSURE token. + 'return_type_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|false', + '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->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|ClassName', + '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->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'iterable|array|Traversable', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|string|INT', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 17, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Test helper. * * @param string $commentString The comment which preceeds the test. * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $commentString. + * Defaults to the function/closure tokens. * * @return void */ - protected function getPropertiesTestHelper($commentString, $expected) + protected function getPropertiesTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) { - $function = $this->getTargetToken($commentString, [\T_FUNCTION, \T_CLOSURE]); + $function = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { From d00a5b7312fb54f6d9f21f25bd366ec55146cea4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jul 2020 11:49:20 +0200 Subject: [PATCH 10/12] Variables::getMemberProperties(): add tests verifying support for PHP 8 "union" types The commit which added union type support to the `Collections::propertyTypeTokens[BC]()` methods implicitly added support for union types to the `Variables::getMemberProperties()` method. This commit adds extensive unit tests to safeguard this support. The same commit also _silently_ added support for union types to the `BCFile::getMemberProperties()` method. Union types are not supported yet in PHPCS itself and until they are, the fact that the `BCFile::getMemberProperties()` method supports them should be regarded as an artefact and not as official support. --- PHPCSUtils/Utils/Variables.php | 2 + .../Variables/GetMemberPropertiesDiffTest.inc | 47 +++++ .../Variables/GetMemberPropertiesDiffTest.php | 182 ++++++++++++++++++ 3 files changed, 231 insertions(+) diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index e24c0056..0f3abbc3 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -80,11 +80,13 @@ class Variables * This will now throw the same _"$stackPtr is not a class member var"_ runtime exception as * other non-property variables passed to the method. * - Defensive coding against incorrect calls to this method. + * - Support for PHP 8.0 union types. * * @see \PHP_CodeSniffer\Files\File::getMemberProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMemberProperties() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 union 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/Utils/Variables/GetMemberPropertiesDiffTest.inc b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc index 4cfc073d..e161225f 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc +++ b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc @@ -5,3 +5,50 @@ interface Base /* testInterfaceProperty */ protected $anonymous; } + +$anon = class() { + /* testPHP8UnionTypesSimple */ + public int|float $unionTypeSimple; + + /* testPHP8UnionTypesTwoClasses */ + private MyClassA|\Package\MyClassB $unionTypesTwoClasses; + + /* testPHP8UnionTypesAllBaseTypes */ + protected array|bool|int|float|NULL|object|string $unionTypesAllBaseTypes; + + /* testPHP8UnionTypesAllPseudoTypes */ + // Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. + var false|mixed|self|parent|iterable|Resource $unionTypesAllPseudoTypes; + + /* 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; + + /* testPHP8UnionTypesNullable */ + // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. + public ?int|float $unionTypesNullable; + + /* testPHP8PseudoTypeNull */ + // Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. + public null $pseudoTypeNull; + + /* testPHP8PseudoTypeFalse */ + // Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. + public false $pseudoTypeFalse; + + /* testPHP8PseudoTypeFalseAndBool */ + // Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. + public bool|FALSE $pseudoTypeFalseAndBool; + + /* testPHP8ObjectAndClass */ + // Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. + public object|ClassName $objectAndClass; + + /* testPHP8PseudoTypeIterableAndArray */ + // Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. + public iterable|array|Traversable $pseudoTypeIterableAndArray; + + /* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ + // 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; +}; diff --git a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php index 2dfa66bb..eb48efa0 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php +++ b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php @@ -52,4 +52,186 @@ public function testNotClassPropertyException() $variable = $this->getTargetToken('/* testInterfaceProperty */', \T_VARIABLE); Variables::getMemberProperties(self::$phpcsFile, $variable); } + + /** + * Test the getMemberProperties() method. + * + * @dataProvider dataGetMemberProperties + * + * @param string $identifier Comment which precedes the test case. + * @param bool $expected Expected function output. + * + * @return void + */ + public function testGetMemberProperties($identifier, $expected) + { + $variable = $this->getTargetToken($identifier, \T_VARIABLE); + $result = Variables::getMemberProperties(self::$phpcsFile, $variable); + + if (isset($expected['type_token']) && $expected['type_token'] !== false) { + $expected['type_token'] += $variable; + } + if (isset($expected['type_end_token']) && $expected['type_end_token'] !== false) { + $expected['type_end_token'] += $variable; + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetMemberProperties() + * + * @return array + */ + public function dataGetMemberProperties() + { + return [ + [ + '/* testPHP8UnionTypesSimple */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8UnionTypesTwoClasses */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'MyClassA|\Package\MyClassB', + 'type_token' => -7, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8UnionTypesAllBaseTypes */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'array|bool|int|float|NULL|object|string', + 'type_token' => -14, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8UnionTypesAllPseudoTypes */', + [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'type' => 'false|mixed|self|parent|iterable|Resource', + 'type_token' => -12, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8UnionTypesIllegalTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'callable||void', // Missing static, but that's OK as not an allowed syntax. + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8UnionTypesNullable */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => '?int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + [ + '/* testPHP8PseudoTypeNull */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'null', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8PseudoTypeFalse */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'false', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8PseudoTypeFalseAndBool */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'bool|FALSE', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8ObjectAndClass */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'object|ClassName', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8PseudoTypeIterableAndArray */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'iterable|array|Traversable', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + [ + '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'int|string|INT', + 'type_token' => -10, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + ]; + } } From 6b3bbef5a8a051cdf635dc6a2dac566cabdba7c9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 16 Jul 2020 12:03:41 +0200 Subject: [PATCH 11/12] FunctionDeclarations::isArrowFunction(): add tests verifying support for union types Adds tests, same as wil be pulled upstream, to the tests for the `FunctionDeclarations::isArrowFunction()` and the `FunctionDeclarations::getArrowFunctionOpenClose()` methods to verify and safeguard support for arrow functions using union type declarations. --- .../IsArrowFunctionTest.inc | 9 ++++++ .../IsArrowFunctionTest.php | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc index bd813de1..342649ac 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc @@ -79,6 +79,12 @@ $fn = fn(array $a) : array => $a; /* testReturnTypeStatic */ $fn = fn(array $a) : static => $a; +/* testUnionParamType */ +$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param); + +/* testUnionReturnType */ +$arrowWithUnionReturn = fn($param) : int|float => $param | 10; + /* testReturnTypeArrayBug2773 */ $fn = fn(): array => [a($a, $b)]; @@ -147,6 +153,9 @@ $a = MyNS\Sub\Fn($param); /* testNonArrowNamespaceOperatorFunctionCall */ $a = namespace\fn($param); +/* testNonArrowFunctionNameWithUnionTypes */ +function &fn(int|float $param) : string|null {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. $fn = fn diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php index 672da290..9e49f781 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -408,6 +408,31 @@ public function dataArrowFunction() ], ], ], + + 'arrow-function-with-union-param-type' => [ + '/* testUnionParamType */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 7, + 'scope_opener' => 13, + 'scope_closer' => 21, + ], + ], + ], + 'arrow-function-with-union-return-type' => [ + '/* testUnionReturnType */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 11, + 'scope_closer' => 18, + ], + ], + ], 'arrow-function-with-return-type-array-bug-2773' => [ '/* testReturnTypeArrayBug2773 */', [ @@ -598,6 +623,13 @@ public function dataArrowFunction() 'get' => false, ], ], + 'non-arrow-function-declaration-with-union-types' => [ + '/* testNonArrowFunctionNameWithUnionTypes */', + [ + 'is' => false, + 'get' => false, + ], + ], 'live-coding' => [ '/* testLiveCoding */', From 38ad2b050c8ebf4f6402d269e72d6d8a484be8e1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 7 Jul 2020 22:13:57 +0200 Subject: [PATCH 12/12] Docs: update "nullable_type" comments to clarify meaning --- PHPCSUtils/BackCompat/BCFile.php | 9 ++++++--- PHPCSUtils/Utils/FunctionDeclarations.php | 6 ++++-- PHPCSUtils/Utils/Variables.php | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index e8225518..39a3170c 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -204,7 +204,8 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * // or FALSE if there is no type hint. * 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint * // or FALSE if there is no type hint. - * 'nullable_type' => boolean, // TRUE if the var type is nullable. + * 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + * // operator. * 'comma_token' => integer, // The stack pointer to the comma after the param * // or FALSE if this is the last param. * ) @@ -503,7 +504,8 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * 'return_type' => '', // The return type of the method. * 'return_type_token' => integer, // The stack pointer to the start of the return type * // or FALSE if there is no return type. - * 'nullable_return_type' => false, // TRUE if the return type is nullable. + * 'nullable_return_type' => false, // TRUE if the return type is preceded by + * // the nullability operator. * 'is_abstract' => false, // TRUE if the abstract keyword was found. * 'is_final' => false, // TRUE if the final keyword was found. * 'is_static' => false, // TRUE if the static keyword was found. @@ -712,7 +714,8 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) * // or FALSE if there is no type. * 'type_end_token' => integer, // The stack pointer to the end of the type * // or FALSE if there is no type. - * 'nullable_type' => boolean, // TRUE if the type is nullable. + * 'nullable_type' => boolean, // TRUE if the type is preceded by the + * // nullability operator. * ); * ``` * diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 07acf4b9..0d64c26d 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -195,7 +195,8 @@ public static function getName(File $phpcsFile, $stackPtr) * // or FALSE if there is no return type. * 'return_type_end_token' => integer, // The stack pointer to the end of the return type * // or FALSE if there is no return type. - * 'nullable_return_type' => false, // TRUE if the return type is nullable. + * 'nullable_return_type' => false, // TRUE if the return type is preceded + * // by the nullability operator. * 'is_abstract' => false, // TRUE if the abstract keyword was found. * 'is_final' => false, // TRUE if the final keyword was found. * 'is_static' => false, // TRUE if the static keyword was found. @@ -361,7 +362,8 @@ public static function getProperties(File $phpcsFile, $stackPtr) * // or FALSE if there is no type hint. * 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint * // or FALSE if there is no type hint. - * 'nullable_type' => boolean, // TRUE if the var type is nullable. + * 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + * // operator. * 'comma_token' => integer, // The stack pointer to the comma after the param * // or FALSE if this is the last param. * ) diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index 0f3abbc3..b4dd078e 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -104,7 +104,8 @@ class Variables * // or FALSE if there is no type. * 'type_end_token' => integer, // The stack pointer to the end of the type * // or FALSE if there is no type. - * 'nullable_type' => boolean, // TRUE if the type is nullable. + * 'nullable_type' => boolean, // TRUE if the type is preceded by the + * // nullability operator. * ); * ``` *