Skip to content

Commit f438f28

Browse files
committed
BCFile/FunctionDeclarations::get[Method]Parameters(): sync with upstream / PHP 8.4 asym visibility support
Includes tests. Ref: PHPCSStandards/PHP_CodeSniffer 1116
1 parent 1f9c1a9 commit f438f28

File tree

5 files changed

+239
-68
lines changed

5 files changed

+239
-68
lines changed

PHPCSUtils/BackCompat/BCFile.php

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr)
185185
* // This index will only be set if the property is readonly.
186186
* ```
187187
*
188+
* ... and if the promoted property uses asymmetric visibility, these additional array indexes will also be available:
189+
* ```php
190+
* 'set_visibility' => string, // The property set-visibility as declared.
191+
* 'set_visibility_token' => integer, // The stack pointer to the set-visibility modifier token.
192+
* ```
193+
*
188194
* PHPCS cross-version compatible version of the `File::getMethodParameters()` method.
189195
*
190196
* Changelog for the PHPCS native function:
@@ -196,6 +202,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr)
196202
*
197203
* @since 1.0.0
198204
* @since 1.0.6 Sync with PHPCS 3.8.0, support for readonly properties without explicit visibility. PHPCS#3801.
205+
* @since 1.1.0 Sync with PHPCS 3.13.1, support for asymmetric properties. PHPCS(new)#851
199206
*
200207
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
201208
* @param int $stackPtr The position in the stack of the function token
@@ -242,23 +249,24 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
242249

243250
$closer = $tokens[$opener]['parenthesis_closer'];
244251

245-
$vars = [];
246-
$currVar = null;
247-
$paramStart = ($opener + 1);
248-
$defaultStart = null;
249-
$equalToken = null;
250-
$paramCount = 0;
251-
$hasAttributes = false;
252-
$passByReference = false;
253-
$referenceToken = false;
254-
$variableLength = false;
255-
$variadicToken = false;
256-
$typeHint = '';
257-
$typeHintToken = false;
258-
$typeHintEndToken = false;
259-
$nullableType = false;
260-
$visibilityToken = null;
261-
$readonlyToken = null;
252+
$vars = [];
253+
$currVar = null;
254+
$paramStart = ($opener + 1);
255+
$defaultStart = null;
256+
$equalToken = null;
257+
$paramCount = 0;
258+
$hasAttributes = false;
259+
$passByReference = false;
260+
$referenceToken = false;
261+
$variableLength = false;
262+
$variadicToken = false;
263+
$typeHint = '';
264+
$typeHintToken = false;
265+
$typeHintEndToken = false;
266+
$nullableType = false;
267+
$visibilityToken = null;
268+
$setVisibilityToken = null;
269+
$readonlyToken = null;
262270

263271
for ($i = $paramStart; $i <= $closer; $i++) {
264272
// Check to see if this token has a parenthesis or bracket opener. If it does
@@ -392,6 +400,13 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
392400
$visibilityToken = $i;
393401
}
394402
break;
403+
case T_PUBLIC_SET:
404+
case T_PROTECTED_SET:
405+
case T_PRIVATE_SET:
406+
if ($defaultStart === null) {
407+
$setVisibilityToken = $i;
408+
}
409+
break;
395410
case T_READONLY:
396411
if ($defaultStart === null) {
397412
$readonlyToken = $i;
@@ -426,16 +441,21 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
426441
$vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken;
427442
$vars[$paramCount]['nullable_type'] = $nullableType;
428443

429-
if ($visibilityToken !== null || $readonlyToken !== null) {
444+
if ($visibilityToken !== null || $setVisibilityToken !== null || $readonlyToken !== null) {
430445
$vars[$paramCount]['property_visibility'] = 'public';
431446
$vars[$paramCount]['visibility_token'] = false;
432-
$vars[$paramCount]['property_readonly'] = false;
433447

434448
if ($visibilityToken !== null) {
435449
$vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content'];
436450
$vars[$paramCount]['visibility_token'] = $visibilityToken;
437451
}
438452

453+
if ($setVisibilityToken !== null) {
454+
$vars[$paramCount]['set_visibility'] = $tokens[$setVisibilityToken]['content'];
455+
$vars[$paramCount]['set_visibility_token'] = $setVisibilityToken;
456+
}
457+
458+
$vars[$paramCount]['property_readonly'] = false;
439459
if ($readonlyToken !== null) {
440460
$vars[$paramCount]['property_readonly'] = true;
441461
$vars[$paramCount]['readonly_token'] = $readonlyToken;
@@ -449,21 +469,22 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
449469
}
450470

451471
// Reset the vars, as we are about to process the next parameter.
452-
$currVar = null;
453-
$paramStart = ($i + 1);
454-
$defaultStart = null;
455-
$equalToken = null;
456-
$hasAttributes = false;
457-
$passByReference = false;
458-
$referenceToken = false;
459-
$variableLength = false;
460-
$variadicToken = false;
461-
$typeHint = '';
462-
$typeHintToken = false;
463-
$typeHintEndToken = false;
464-
$nullableType = false;
465-
$visibilityToken = null;
466-
$readonlyToken = null;
472+
$currVar = null;
473+
$paramStart = ($i + 1);
474+
$defaultStart = null;
475+
$equalToken = null;
476+
$hasAttributes = false;
477+
$passByReference = false;
478+
$referenceToken = false;
479+
$variableLength = false;
480+
$variadicToken = false;
481+
$typeHint = '';
482+
$typeHintToken = false;
483+
$typeHintEndToken = false;
484+
$nullableType = false;
485+
$visibilityToken = null;
486+
$setVisibilityToken = null;
487+
$readonlyToken = null;
467488

468489
++$paramCount;
469490
break;

PHPCSUtils/Utils/FunctionDeclarations.php

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,12 @@ public static function getProperties(File $phpcsFile, $stackPtr)
384384
* // This index will only be set if the property is readonly.
385385
* ```
386386
*
387+
* ... and if the promoted property uses asymmetric visibility, these additional array indexes will also be available:
388+
* ```php
389+
* 'set_visibility' => string, // The property set-visibility as declared.
390+
* 'set_visibility_token' => int, // The stack pointer to the set-visibility modifier token.
391+
* ```
392+
*
387393
* Main differences with the PHPCS version:
388394
* - Defensive coding against incorrect calls to this method.
389395
* - More efficient and more stable checking whether a `T_USE` token is a closure use.
@@ -457,23 +463,24 @@ public static function getParameters(File $phpcsFile, $stackPtr)
457463

458464
$closer = $tokens[$opener]['parenthesis_closer'];
459465

460-
$vars = [];
461-
$currVar = null;
462-
$paramStart = ($opener + 1);
463-
$defaultStart = null;
464-
$equalToken = null;
465-
$paramCount = 0;
466-
$hasAttributes = false;
467-
$passByReference = false;
468-
$referenceToken = false;
469-
$variableLength = false;
470-
$variadicToken = false;
471-
$typeHint = '';
472-
$typeHintToken = false;
473-
$typeHintEndToken = false;
474-
$nullableType = false;
475-
$visibilityToken = null;
476-
$readonlyToken = null;
466+
$vars = [];
467+
$currVar = null;
468+
$paramStart = ($opener + 1);
469+
$defaultStart = null;
470+
$equalToken = null;
471+
$paramCount = 0;
472+
$hasAttributes = false;
473+
$passByReference = false;
474+
$referenceToken = false;
475+
$variableLength = false;
476+
$variadicToken = false;
477+
$typeHint = '';
478+
$typeHintToken = false;
479+
$typeHintEndToken = false;
480+
$nullableType = false;
481+
$visibilityToken = null;
482+
$setVisibilityToken = null;
483+
$readonlyToken = null;
477484

478485
$parameterTypeTokens = Collections::parameterTypeTokens();
479486

@@ -529,6 +536,12 @@ public static function getParameters(File $phpcsFile, $stackPtr)
529536
$visibilityToken = $i;
530537
break;
531538

539+
case \T_PUBLIC_SET:
540+
case \T_PROTECTED_SET:
541+
case \T_PRIVATE_SET:
542+
$setVisibilityToken = $i;
543+
break;
544+
532545
case \T_READONLY:
533546
$readonlyToken = $i;
534547
break;
@@ -566,16 +579,21 @@ public static function getParameters(File $phpcsFile, $stackPtr)
566579
$vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken;
567580
$vars[$paramCount]['nullable_type'] = $nullableType;
568581

569-
if ($visibilityToken !== null || $readonlyToken !== null) {
582+
if ($visibilityToken !== null || $setVisibilityToken !== null || $readonlyToken !== null) {
570583
$vars[$paramCount]['property_visibility'] = 'public';
571584
$vars[$paramCount]['visibility_token'] = false;
572-
$vars[$paramCount]['property_readonly'] = false;
573585

574586
if ($visibilityToken !== null) {
575587
$vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content'];
576588
$vars[$paramCount]['visibility_token'] = $visibilityToken;
577589
}
578590

591+
if ($setVisibilityToken !== null) {
592+
$vars[$paramCount]['set_visibility'] = $tokens[$setVisibilityToken]['content'];
593+
$vars[$paramCount]['set_visibility_token'] = $setVisibilityToken;
594+
}
595+
596+
$vars[$paramCount]['property_readonly'] = false;
579597
if ($readonlyToken !== null) {
580598
$vars[$paramCount]['property_readonly'] = true;
581599
$vars[$paramCount]['readonly_token'] = $readonlyToken;
@@ -589,21 +607,22 @@ public static function getParameters(File $phpcsFile, $stackPtr)
589607
}
590608

591609
// Reset the vars, as we are about to process the next parameter.
592-
$currVar = null;
593-
$paramStart = ($i + 1);
594-
$defaultStart = null;
595-
$equalToken = null;
596-
$hasAttributes = false;
597-
$passByReference = false;
598-
$referenceToken = false;
599-
$variableLength = false;
600-
$variadicToken = false;
601-
$typeHint = '';
602-
$typeHintToken = false;
603-
$typeHintEndToken = false;
604-
$nullableType = false;
605-
$visibilityToken = null;
606-
$readonlyToken = null;
610+
$currVar = null;
611+
$paramStart = ($i + 1);
612+
$defaultStart = null;
613+
$equalToken = null;
614+
$hasAttributes = false;
615+
$passByReference = false;
616+
$referenceToken = false;
617+
$variableLength = false;
618+
$variadicToken = false;
619+
$typeHint = '';
620+
$typeHintToken = false;
621+
$typeHintEndToken = false;
622+
$nullableType = false;
623+
$visibilityToken = null;
624+
$setVisibilityToken = null;
625+
$readonlyToken = null;
607626

608627
++$paramCount;
609628
break;

Tests/BackCompat/BCFile/GetMethodParametersTest.inc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,17 @@ class ConstructorPropertyPromotionWithOnlyReadOnly {
217217
public function __construct(readonly Foo&Bar $promotedProp, readonly ?bool $promotedToo,) {}
218218
}
219219

220+
class ConstructorPropertyPromotionWithAsymVisibility {
221+
/* testPHP84ConstructorPropertyPromotionWithAsymVisibility */
222+
public function __construct(
223+
protected(set) string|Book $book,
224+
public private(set) ?Publisher $publisher,
225+
Private(set) PROTECTED Author $author,
226+
readonly public(set) int $pubYear,
227+
protected(set) $illegalMissingType,
228+
) {}
229+
}
230+
220231
/* testPHP8ConstructorPropertyPromotionGlobalFunction */
221232
// Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method.
222233
function globalFunction(private $x) {}

0 commit comments

Comments
 (0)