Skip to content

Commit 4220d69

Browse files
committed
Merge branch 'master' into 4.x
2 parents 18807f2 + 2d4e793 commit 4220d69

11 files changed

+152
-21
lines changed

src/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public function register()
3333
T_MATCH_DEFAULT => T_MATCH_DEFAULT,
3434
T_PARENT => T_PARENT,
3535
T_SELF => T_SELF,
36+
T_PUBLIC_SET => T_PUBLIC_SET,
37+
T_PROTECTED_SET => T_PROTECTED_SET,
38+
T_PRIVATE_SET => T_PRIVATE_SET,
3639
];
3740

3841
return $targets;

src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,17 @@ $c = function() {
6060
FROM fun();
6161
}
6262

63+
class AsymmetricVisibility {
64+
public(set) int $correctPublicSet;
65+
protected(set) int $correctProtectedSet;
66+
private(set) int $correctPrivateSet;
67+
68+
PubliC(SeT) int $wrongCasePublic;
69+
PROTECTED(set) array $wrongCaseProtected;
70+
protected(sEt) int $wrongCaseProtectedSet;
71+
Private(set) int $wrongCasePrivate;
72+
private(SET) readonly ?string $wrongCasePrivateSet;
73+
}
74+
6375
__HALT_COMPILER(); // An exception due to phar support.
6476
function

src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc.fixed

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,17 @@ $c = function() {
6060
from fun();
6161
}
6262

63+
class AsymmetricVisibility {
64+
public(set) int $correctPublicSet;
65+
protected(set) int $correctProtectedSet;
66+
private(set) int $correctPrivateSet;
67+
68+
public(set) int $wrongCasePublic;
69+
protected(set) array $wrongCaseProtected;
70+
protected(set) int $wrongCaseProtectedSet;
71+
private(set) int $wrongCasePrivate;
72+
private(set) readonly ?string $wrongCasePrivateSet;
73+
}
74+
6375
__HALT_COMPILER(); // An exception due to phar support.
6476
function

src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public function getErrorList()
5555
57 => 2,
5656
58 => 1,
5757
60 => 1,
58+
68 => 1,
59+
69 => 1,
60+
70 => 1,
61+
71 => 1,
62+
72 => 1,
5863
];
5964

6065
}//end getErrorList()

src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ protected function processMemberVar(File $phpcsFile, $stackPtr)
5151
$memberName = ltrim($tokens[$stackPtr]['content'], '$');
5252
$scope = $memberProps['scope'];
5353
$scopeSpecified = $memberProps['scope_specified'];
54+
if ($scopeSpecified === false && $memberProps['set_scope'] !== false) {
55+
// Implicit `public` visibility for property with asymmetric visibility.
56+
$scopeSpecified = true;
57+
}
5458

5559
if ($memberProps['scope'] === 'private') {
5660
$isPublic = false;

src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.1.inc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,17 @@ interface PHP84HookedProperty {
104104
public $thisisfine { get; }
105105
public $_underscore { get; }
106106
}
107+
108+
class AsymVisibility {
109+
// The read scope is public, but not specified. Enforce the naming conventions anyway.
110+
private(set) $asymPublicImplied = 'hello';
111+
private(set) $_asymPublicImplied = 'hello';
112+
113+
// The read scope is private, so these properties should be handled as private properties.
114+
private private(set) $asymPrivate = 'hello';
115+
private(set) private $_asymPrivate = 'hello';
116+
117+
// The read scope is public/protected, so these properties should be handled as public properties.
118+
public private(set) $asymPublicPrivate = 'hello';
119+
private(set) protected $_asymPrivateProtected = 'hello';
120+
}

src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public function getErrorList($testFile='')
4343
94 => 1,
4444
99 => 1,
4545
105 => 1,
46+
111 => 1,
47+
114 => 1,
48+
119 => 1,
4649
];
4750

4851
default:

src/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,30 +122,64 @@ protected function processMemberVar(File $phpcsFile, $stackPtr)
122122
}//end if
123123
}//end if
124124

125-
if ($propertyInfo['scope_specified'] === false) {
125+
if ($propertyInfo['scope_specified'] === false && $propertyInfo['set_scope'] === false) {
126126
$error = 'Visibility must be declared on property "%s"';
127127
$data = [$tokens[$stackPtr]['content']];
128128
$phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $data);
129129
}
130130

131131
/*
132-
* Note: per PSR-PER section 4.6, the order should be:
132+
* Note: per PSR-PER section 4.6 v 2.1/3.0, the order should be:
133133
* - Inheritance modifier: `abstract` or `final`.
134134
* - Visibility modifier: `public`, `protected`, or `private`.
135+
* - Set-visibility modifier: `public(set)`, `protected(set)`, or `private(set)`
135136
* - Scope modifier: `static`.
136137
* - Mutation modifier: `readonly`.
137138
* - Type declaration.
138139
* - Name.
139140
*
140-
* Ref: https://www.php-fig.org/per/coding-style/#46-modifier-keywords
141+
* Ref:
142+
* - https://www.php-fig.org/per/coding-style/#46-modifier-keywords
143+
* - https://github.com/php-fig/per-coding-style/pull/99
141144
*
142145
* The `static` and `readonly` modifiers are mutually exclusive and cannot be used together.
143146
*
144147
* Based on that, the below modifier keyword order checks are sufficient (for now).
145148
*/
146149

147-
if ($propertyInfo['scope_specified'] === true && $propertyInfo['is_final'] === true) {
148-
$scopePtr = $phpcsFile->findPrevious(Tokens::SCOPE_MODIFIERS, ($stackPtr - 1));
150+
$hasVisibilityModifier = ($propertyInfo['scope_specified'] === true || $propertyInfo['set_scope'] !== false);
151+
$lastVisibilityModifier = $phpcsFile->findPrevious(Tokens::SCOPE_MODIFIERS, ($stackPtr - 1));
152+
$firstVisibilityModifier = $lastVisibilityModifier;
153+
154+
if ($propertyInfo['scope_specified'] === true && $propertyInfo['set_scope'] !== false) {
155+
$scopePtr = $phpcsFile->findPrevious([T_PUBLIC, T_PROTECTED, T_PRIVATE], ($stackPtr - 1));
156+
$setScopePtr = $phpcsFile->findPrevious([T_PUBLIC_SET, T_PROTECTED_SET, T_PRIVATE_SET], ($stackPtr - 1));
157+
if ($scopePtr > $setScopePtr) {
158+
$error = 'The "read"-visibility must come before the "write"-visibility';
159+
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'AvizKeywordOrder');
160+
if ($fix === true) {
161+
$phpcsFile->fixer->beginChangeset();
162+
163+
for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) {
164+
if ($tokens[$i]['code'] !== T_WHITESPACE) {
165+
break;
166+
}
167+
168+
$phpcsFile->fixer->replaceToken($i, '');
169+
}
170+
171+
$phpcsFile->fixer->replaceToken($scopePtr, '');
172+
$phpcsFile->fixer->addContentBefore($setScopePtr, $tokens[$scopePtr]['content'].' ');
173+
174+
$phpcsFile->fixer->endChangeset();
175+
}
176+
}
177+
178+
$firstVisibilityModifier = min($scopePtr, $setScopePtr);
179+
}//end if
180+
181+
if ($hasVisibilityModifier === true && $propertyInfo['is_final'] === true) {
182+
$scopePtr = $firstVisibilityModifier;
149183
$finalPtr = $phpcsFile->findPrevious(T_FINAL, ($stackPtr - 1));
150184
if ($finalPtr > $scopePtr) {
151185
$error = 'The final declaration must come before the visibility declaration';
@@ -169,50 +203,50 @@ protected function processMemberVar(File $phpcsFile, $stackPtr)
169203
}
170204
}//end if
171205

172-
if ($propertyInfo['scope_specified'] === true && $propertyInfo['is_static'] === true) {
173-
$scopePtr = $phpcsFile->findPrevious(Tokens::SCOPE_MODIFIERS, ($stackPtr - 1));
206+
if ($hasVisibilityModifier === true && $propertyInfo['is_static'] === true) {
207+
$scopePtr = $lastVisibilityModifier;
174208
$staticPtr = $phpcsFile->findPrevious(T_STATIC, ($stackPtr - 1));
175209
if ($scopePtr > $staticPtr) {
176210
$error = 'The static declaration must come after the visibility declaration';
177211
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'StaticBeforeVisibility');
178212
if ($fix === true) {
179213
$phpcsFile->fixer->beginChangeset();
180214

181-
for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) {
215+
for ($i = ($staticPtr + 1); $staticPtr < $stackPtr; $i++) {
182216
if ($tokens[$i]['code'] !== T_WHITESPACE) {
183217
break;
184218
}
185219

186220
$phpcsFile->fixer->replaceToken($i, '');
187221
}
188222

189-
$phpcsFile->fixer->replaceToken($scopePtr, '');
190-
$phpcsFile->fixer->addContentBefore($staticPtr, $propertyInfo['scope'].' ');
223+
$phpcsFile->fixer->replaceToken($staticPtr, '');
224+
$phpcsFile->fixer->addContent($scopePtr, ' '.$tokens[$staticPtr]['content']);
191225

192226
$phpcsFile->fixer->endChangeset();
193227
}
194228
}
195229
}//end if
196230

197-
if ($propertyInfo['scope_specified'] === true && $propertyInfo['is_readonly'] === true) {
198-
$scopePtr = $phpcsFile->findPrevious(Tokens::SCOPE_MODIFIERS, ($stackPtr - 1));
231+
if ($hasVisibilityModifier === true && $propertyInfo['is_readonly'] === true) {
232+
$scopePtr = $lastVisibilityModifier;
199233
$readonlyPtr = $phpcsFile->findPrevious(T_READONLY, ($stackPtr - 1));
200234
if ($scopePtr > $readonlyPtr) {
201235
$error = 'The readonly declaration must come after the visibility declaration';
202236
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'ReadonlyBeforeVisibility');
203237
if ($fix === true) {
204238
$phpcsFile->fixer->beginChangeset();
205239

206-
for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) {
240+
for ($i = ($readonlyPtr + 1); $readonlyPtr < $stackPtr; $i++) {
207241
if ($tokens[$i]['code'] !== T_WHITESPACE) {
208242
break;
209243
}
210244

211245
$phpcsFile->fixer->replaceToken($i, '');
212246
}
213247

214-
$phpcsFile->fixer->replaceToken($scopePtr, '');
215-
$phpcsFile->fixer->addContentBefore($readonlyPtr, $propertyInfo['scope'].' ');
248+
$phpcsFile->fixer->replaceToken($readonlyPtr, '');
249+
$phpcsFile->fixer->addContent($scopePtr, ' '.$tokens[$readonlyPtr]['content']);
216250

217251
$phpcsFile->fixer->endChangeset();
218252
}

src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.1.inc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,20 @@ class AsymmetricVisibility {
114114
protected(set) public int $wrongOrder1;
115115

116116
private(set) protected ?string $wrongOrder2;
117+
118+
final protected private(set) static bool $correctOrder;
119+
120+
private(set) static final protected bool $wrongOrder3;
121+
private(set) static protected final bool $wrongOrder4;
122+
final protected(set) static public bool $wrongOrder5;
123+
static public(set) final public bool $wrongOrder6;
124+
125+
protected private(set) static final bool $wrongOrder7;
126+
protected final private(set) static bool $wrongOrder8;
127+
static public final protected(set) bool $wrongOrder9;
128+
public static public(set) final bool $wrongOrder10;
129+
130+
private(set) static final bool $wrongOrder11;
131+
final static protected(set) bool $wrongOrder12;
132+
static public(set) final bool $wrongOrder13;
117133
}

src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.1.inc.fixed

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class ABC {
3737
private static $propC;
3838
public static $propD;
3939
protected static
40-
$propE;
41-
private static /*comment*/ $propF;
40+
$propE;
41+
private static /*comment*/ $propF;
4242
}
4343

4444
class MyClass
@@ -108,7 +108,23 @@ class AsymmetricVisibility {
108108

109109
protected(set) array $unfixed;
110110

111-
protected(set) public int $wrongOrder1;
111+
public protected(set) int $wrongOrder1;
112112

113-
private(set) protected ?string $wrongOrder2;
113+
protected private(set) ?string $wrongOrder2;
114+
115+
final protected private(set) static bool $correctOrder;
116+
117+
final protected private(set) static bool $wrongOrder3;
118+
final protected private(set) static bool $wrongOrder4;
119+
final public protected(set) static bool $wrongOrder5;
120+
final public public(set) static bool $wrongOrder6;
121+
122+
final protected private(set) static bool $wrongOrder7;
123+
final protected private(set) static bool $wrongOrder8;
124+
final public protected(set) static bool $wrongOrder9;
125+
final public public(set) static bool $wrongOrder10;
126+
127+
final private(set) static bool $wrongOrder11;
128+
final protected(set) static bool $wrongOrder12;
129+
final public(set) static bool $wrongOrder13;
114130
}

0 commit comments

Comments
 (0)