From 91373da7dab3e9e53569ec29c4f02b67441e3113 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 07:59:52 +0000 Subject: [PATCH 1/5] GH Actions: Bump peter-evans/create-pull-request from 4 to 5 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/update-phpcs-versionnr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-phpcs-versionnr.yml b/.github/workflows/update-phpcs-versionnr.yml index 7868a62d..fc512d18 100644 --- a/.github/workflows/update-phpcs-versionnr.yml +++ b/.github/workflows/update-phpcs-versionnr.yml @@ -68,7 +68,7 @@ jobs: run: git status -vv --untracked=all - name: Create pull request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v5 with: base: ${{ steps.branches.outputs.BASE }} branch: ${{ steps.branches.outputs.PR_BRANCH }} From d3593e24b58ef27d58786185ac538eba6780040c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 13 Apr 2023 00:32:33 +0200 Subject: [PATCH 2/5] [BackCompat|ObjectDeclarations]::get[Declaration]Name(): add extra tests ... documenting how the OO hierarchy keywords when used as function/method name are handled. * The `ObjectDeclarations::getName()` method handles these correctly. * The PHPCS native `File::getDeclarationName()` and the related `BackCompat::getDeclarationName()` methods do not handle these correctly. --- Tests/BackCompat/BCFile/GetDeclarationNameTest.inc | 3 +++ Tests/BackCompat/BCFile/GetDeclarationNameTest.php | 4 ++++ Tests/Utils/ObjectDeclarations/GetNameDiffTest.inc | 9 +++++++++ Tests/Utils/ObjectDeclarations/GetNameDiffTest.php | 12 ++++++++++++ 4 files changed, 28 insertions(+) diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc index d6d2ea42..eba7b48c 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc @@ -85,6 +85,9 @@ enum Hoo : string /* testBackedEnumNoSpaceBetweenNameAndColon */ enum Suit: int implements Colorful, CardGame {} +/* testFunctionReturnByRefWithReservedKeywordEach */ +function &each() {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. function // Comment. diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php index 43285e3c..11de6a2c 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php @@ -192,6 +192,10 @@ public function dataGetDeclarationName() '/* testBackedEnumNoSpaceBetweenNameAndColon */', 'Suit', ], + 'function-return-by-reference-with-reserved-keyword-each' => [ + '/* testFunctionReturnByRefWithReservedKeywordEach */', + 'each', + ], ]; } } diff --git a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.inc b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.inc index 7a7ae4e5..3e54ed11 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.inc +++ b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.inc @@ -12,6 +12,15 @@ interface switch{ // Intentional parse error. public function someFunction(); } +/* testFunctionReturnByRefWithReservedKeywordParent */ +function &parent() {} + +/* testFunctionReturnByRefWithReservedKeywordSelf */ +function &self() {} + +/* testFunctionReturnByRefWithReservedKeywordStatic */ +function &static() {} + /* testLiveCoding */ // Intentional parse error. Redundancy testing. abstract class diff --git a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php index c23a2b01..b09173a8 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php @@ -117,6 +117,18 @@ public function dataGetName() 'testMarker' => '/* testInvalidInterfaceName */', 'expected' => 'switch', ], + 'function-return-by-reference-with-reserved-keyword-parent' => [ + '/* testFunctionReturnByRefWithReservedKeywordParent */', + 'parent', + ], + 'function-return-by-reference-with-reserved-keyword-self' => [ + '/* testFunctionReturnByRefWithReservedKeywordSelf */', + 'self', + ], + 'function-return-by-reference-with-reserved-keyword-static' => [ + '/* testFunctionReturnByRefWithReservedKeywordStatic */', + 'static', + ], ]; } } From b92cc166f7d70df79f73730f997f47d045da718a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 30 Mar 2023 19:24:38 +0200 Subject: [PATCH 3/5] [BackCompat|FunctionDeclarations]::get[Method]Parameters(): add extra test --- .../BCFile/GetMethodParametersTest.inc | 6 +++ .../BCFile/GetMethodParametersTest.php | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index e2991b67..34263a77 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -206,6 +206,12 @@ class ConstructorPropertyPromotionWithReadOnly { public function __construct(public readonly ?int $promotedProp, ReadOnly private string|bool &$promotedToo) {} } +class ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration { + /* testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration */ + // Intentional fatal error. Readonly properties MUST be typed. + public function __construct(public readonly $promotedProp, ReadOnly private &$promotedToo) {} +} + /* testPHP8ConstructorPropertyPromotionGlobalFunction */ // Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method. function globalFunction(private $x) {} diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index e47336aa..fbad04c7 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -1961,6 +1961,57 @@ public function testPHP81ConstructorPropertyPromotionWithReadOnly() $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword + * without a property type. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$promotedProp', + 'content' => 'public readonly $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => true, + 'readonly_token' => 6, // Offset from the T_FUNCTION token. + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 16, // Offset from the T_FUNCTION token. + 'name' => '$promotedToo', + 'content' => 'ReadOnly private &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, // Offset from the T_FUNCTION token. + 'property_readonly' => true, + 'readonly_token' => 11, // Offset from the T_FUNCTION token. + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. * From 1c47dafc0c4a19b1c44952e8e8d10c80035de807 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 13 Apr 2023 03:43:45 +0200 Subject: [PATCH 4/5] PassedParameters::hasParameters(): allow for self/parent/static as function call PHP allows for declaring global/OO functions called `self` and `parent` and OO functions called `static`. The guard code against handling of the `self`/`parent`/`static` keywords when not used as a function call did not take this into account correctly. Fixed now. Includes additional unit tests. --- PHPCSUtils/Utils/PassedParameters.php | 13 ++++++--- .../PassedParameters/HasParametersTest.inc | 9 ++++++ .../PassedParameters/HasParametersTest.php | 29 +++++++++++++++---- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/PHPCSUtils/Utils/PassedParameters.php b/PHPCSUtils/Utils/PassedParameters.php index a40bc544..f73ee8c4 100644 --- a/PHPCSUtils/Utils/PassedParameters.php +++ b/PHPCSUtils/Utils/PassedParameters.php @@ -47,13 +47,15 @@ final class PassedParameters /** * Checks if any parameters have been passed. * - * - If passed a `T_STRING`, `T_NAME_FULLY_QUALIFIED`, `T_NAME_RELATIVE`, `T_NAME_QUALIFIED` + * - If passed a `T_STRING`, `T_NAME_FULLY_QUALIFIED`, `T_NAME_RELATIVE`, `T_NAME_QUALIFIED`, * or `T_VARIABLE` stack pointer, it will treat it as a function call. * If a `T_STRING` or `T_VARIABLE` which is *not* a function call is passed, the behaviour is * undetermined. * - If passed a `T_ANON_CLASS` stack pointer, it will accept it as a class instantiation. * - If passed a `T_SELF`, `T_STATIC` or `T_PARENT` stack pointer, it will accept it as a - * class instantiation function call when used like `new self()`. + * class instantiation function call when used like `new self()` (with or without parenthesis). + * When these hierarchiecal keywords are not preceded by the `new` keyword, parenthesis + * will be required for the token to be accepted. * - If passed a `T_ARRAY` or `T_OPEN_SHORT_ARRAY` stack pointer, it will detect * whether the array has values or is empty. * For purposes of backward-compatibility with older PHPCS versions, `T_OPEN_SQUARE_BRACKET` @@ -89,9 +91,13 @@ public static function hasParameters(File $phpcsFile, $stackPtr, $isShortArray = ); } + // Only accept self/static/parent if preceded by `new` or followed by an open parenthesis. + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); if (isset(Collections::ooHierarchyKeywords()[$tokens[$stackPtr]['code']]) === true) { $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] !== \T_NEW) { + if ($tokens[$prev]['code'] !== \T_NEW + && ($next !== false && $tokens[$next]['code'] !== \T_OPEN_PARENTHESIS) + ) { throw new RuntimeException( 'The hasParameters() method expects a function call, array, isset or unset token to be passed.' ); @@ -107,7 +113,6 @@ public static function hasParameters(File $phpcsFile, $stackPtr, $isShortArray = ); } - $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); if ($next === false) { return false; } diff --git a/Tests/Utils/PassedParameters/HasParametersTest.inc b/Tests/Utils/PassedParameters/HasParametersTest.inc index cf69b775..5eca6c33 100644 --- a/Tests/Utils/PassedParameters/HasParametersTest.inc +++ b/Tests/Utils/PassedParameters/HasParametersTest.inc @@ -74,6 +74,15 @@ class HierarchyKeywordsAsMethodNames { /* testHasParamsFunctionCall8 */ $a = $this->parent(true); } + + public function callGlobalFunctionsUsingKeywords() { + /* testHasParamsFunctionCall9 */ + $a = self(true); + /* testHasParamsFunctionCall10 */ + $a = static(true); + /* testHasParamsFunctionCall11 */ + $a = parent(true); + } } /* testNoParamsFunctionCallFullyQualified */ diff --git a/Tests/Utils/PassedParameters/HasParametersTest.php b/Tests/Utils/PassedParameters/HasParametersTest.php index 8e25394c..71d6d1fd 100644 --- a/Tests/Utils/PassedParameters/HasParametersTest.php +++ b/Tests/Utils/PassedParameters/HasParametersTest.php @@ -124,11 +124,11 @@ public function testNotAShortArray() * * @dataProvider dataHasParameters * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int|string $targetType The type of token to look for. - * @param bool $expected Whether or not the function/array has parameters/values. - * @param string $targetContent Optional. The content of the target token to find. - * Defaults to null (ignore content). + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The type(s) of token to look for. + * @param bool $expected Whether or not the function/array has parameters/values. + * @param string $targetContent Optional. The content of the target token to find. + * Defaults to null (ignore content). * * @return void */ @@ -231,6 +231,25 @@ public function dataHasParameters() 'expected' => true, 'targetContent' => 'parent', ], + 'has-params-function-call-9-self-as-global-function-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall9 */', + 'targetType' => [\T_STRING, \T_SELF], + 'expected' => true, + 'targetContent' => 'self', + ], + // Parse error in PHP, but not our concern. + 'has-params-function-call-10-static-as-global-function-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall10 */', + 'targetType' => [\T_STRING, \T_STATIC], + 'expected' => true, + 'targetContent' => 'static', + ], + 'has-params-function-call-11-parent-as-global-function-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall11 */', + 'targetType' => [\T_STRING, \T_PARENT], + 'expected' => true, + 'targetContent' => 'parent', + ], 'no-params-function-call-fully-qualified' => [ 'testMarker' => '/* testNoParamsFunctionCallFullyQualified */', From 53d3d5c127b68c5efccd350fff283759fc5edf4b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 13 Apr 2023 04:02:36 +0200 Subject: [PATCH 5/5] Changelog for PHPCSUtils 1.0.3 --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66e1859e..33f42239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,23 @@ This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and use _Nothing yet._ +## [1.0.3] - 2023-04-13 + +### Changed + +#### Other + +* Various small housekeeping and maintenance updates. + +### Fixed + +#### Utils + +* The `PassedParameters` class now allows for function calls to global functions called `self()`, `parent()` or `static()`. [#452] + +[#452]: https://github.com/PHPCSStandards/PHPCSUtils/pull/452 + + ## [1.0.2] - 2023-03-28 ### Changed @@ -805,6 +822,7 @@ This initial alpha release contains the following utility classes: [Unreleased]: https://github.com/PHPCSStandards/PHPCSUtils/compare/stable...HEAD +[1.0.3]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0...1.0.1 [1.0.0]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-rc1...1.0.0