Skip to content

Commit

Permalink
Add readonly constructor promotion support (#294)
Browse files Browse the repository at this point in the history
* Add test for readonly constructor promotion

* Add support for readonly

* Adjust formatting
  • Loading branch information
sirbrillig committed Mar 30, 2023
1 parent d8a00fb commit 11b9433
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 7 deletions.
12 changes: 12 additions & 0 deletions Tests/VariableAnalysisSniff/fixtures/ClassWithMembersFixture.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,15 @@ public static function createStatic($value) {
}

}

class ClassWithReadonlyConstructorPromotion {
public function __construct(
private readonly string $message,
private readonly $name,
public readonly bool $key
) {}

public function getMessage(): string {
return $this->message;
}
}
28 changes: 21 additions & 7 deletions VariableAnalysis/Lib/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -1445,24 +1445,38 @@ public static function isConstructorPromotion(File $phpcsFile, $stackPtr)

// If the previous token is a visibility keyword, this is constructor
// promotion. eg: `public $foobar`.
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), $functionIndex, true);
if (! is_int($prev)) {
$prevIndex = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), $functionIndex, true);
if (! is_int($prevIndex)) {
return false;
}
$prevToken = $tokens[$prev];
$prevToken = $tokens[$prevIndex];
if (in_array($prevToken['code'], Tokens::$scopeModifiers, true)) {
return true;
}

// If the previous token is not a visibility keyword, but the one before it
// is, the previous token was probably a typehint and this is constructor
// promotion. eg: `public boolean $foobar`.
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), $functionIndex, true);
if (! is_int($prev)) {
$prev2Index = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prevIndex - 1), $functionIndex, true);
if (! is_int($prev2Index)) {
return false;
}
$prevToken = $tokens[$prev];
if (in_array($prevToken['code'], Tokens::$scopeModifiers, true)) {
$prev2Token = $tokens[$prev2Index];
if (in_array($prev2Token['code'], Tokens::$scopeModifiers, true)) {
return true;
}

// If the previous token is not a visibility keyword, but the one two
// before it is, and one of the tokens is `readonly`, the previous token
// was probably a typehint and this is constructor promotion. eg: `public
// readonly boolean $foobar`.
$prev3Index = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev2Index - 1), $functionIndex, true);
if (! is_int($prev3Index)) {
return false;
}
$prev3Token = $tokens[$prev3Index];
$wasPreviousReadonly = $prevToken['content'] === 'readonly' || $prev2Token['content'] === 'readonly';
if (in_array($prev3Token['code'], Tokens::$scopeModifiers, true) && $wasPreviousReadonly) {
return true;
}

Expand Down

0 comments on commit 11b9433

Please sign in to comment.