Skip to content

Commit 8ee5e66

Browse files
authored
Merge pull request #1042 from PHPCSStandards/phpcs-4.0/feature/handle-true-false-null-as-namespacednames
Handle `\true`/`\false`/`\null` in the new namespaced names tokenization
2 parents 570ce73 + 87f139a commit 8ee5e66

30 files changed

+309
-40
lines changed

src/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ public function process(File $phpcsFile, $stackPtr)
7777

7878
if (isset(Tokens::EMPTY_TOKENS[$code]) === true) {
7979
continue;
80+
}
81+
82+
if ($code === T_NAME_FULLY_QUALIFIED) {
83+
$compareReadyKeyword = strtolower($tokens[$next]['content']);
84+
if ($compareReadyKeyword !== '\true' && $compareReadyKeyword !== '\false') {
85+
$goodCondition = true;
86+
}
8087
} else if ($code !== T_TRUE && $code !== T_FALSE) {
8188
$goodCondition = true;
8289
}

src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,24 @@ public function process(File $phpcsFile, $stackPtr)
5555
T_LNUMBER,
5656
T_DNUMBER,
5757
T_CONSTANT_ENCAPSED_STRING,
58+
T_NAME_FULLY_QUALIFIED,
5859
];
5960

6061
if (in_array($tokens[$previousIndex]['code'], $relevantTokens, true) === false) {
6162
return;
6263
}
6364

65+
// Special case: T_NAME_FULLY_QUALIFIED is only a "relevant" token when it is for a FQN true/false/null.
66+
if ($tokens[$previousIndex]['code'] === T_NAME_FULLY_QUALIFIED) {
67+
$compareReadyKeyword = strtolower($tokens[$previousIndex]['content']);
68+
if ($compareReadyKeyword !== '\true'
69+
&& $compareReadyKeyword !== '\false'
70+
&& $compareReadyKeyword !== '\null'
71+
) {
72+
return;
73+
}
74+
}
75+
6476
if ($tokens[$previousIndex]['code'] === T_CLOSE_SHORT_ARRAY) {
6577
$previousIndex = $tokens[$previousIndex]['bracket_opener'];
6678
if ($this->isArrayStatic($phpcsFile, $previousIndex) === false) {
@@ -164,6 +176,7 @@ public function isArrayStatic(File $phpcsFile, $arrayToken)
164176
T_COMMA => T_COMMA,
165177
T_TRUE => T_TRUE,
166178
T_FALSE => T_FALSE,
179+
T_NULL => T_NULL,
167180
];
168181

169182
for ($i = ($start + 1); $i < $end; $i++) {
@@ -172,10 +185,21 @@ public function isArrayStatic(File $phpcsFile, $arrayToken)
172185
continue;
173186
}
174187

188+
// Special case: T_NAME_FULLY_QUALIFIED is only a "static" token when it is for a FQN true/false/null.
189+
if ($tokens[$i]['code'] === T_NAME_FULLY_QUALIFIED) {
190+
$compareReadyKeyword = strtolower($tokens[$i]['content']);
191+
if ($compareReadyKeyword === '\true'
192+
|| $compareReadyKeyword === '\false'
193+
|| $compareReadyKeyword === '\null'
194+
) {
195+
continue;
196+
}
197+
}
198+
175199
if (isset($staticTokens[$tokens[$i]['code']]) === false) {
176200
return false;
177201
}
178-
}
202+
}//end for
179203

180204
return true;
181205

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ class LowerCaseConstantSniff implements Sniff
4343
T_NAME_QUALIFIED => T_NAME_QUALIFIED,
4444
T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED,
4545
T_NAME_RELATIVE => T_NAME_RELATIVE,
46-
T_NS_SEPARATOR => T_NS_SEPARATOR,
47-
T_NAMESPACE => T_NAMESPACE,
4846
T_TYPE_UNION => T_TYPE_UNION,
4947
T_TYPE_INTERSECTION => T_TYPE_INTERSECTION,
5048
T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS,
@@ -62,6 +60,9 @@ public function register()
6260
{
6361
$targets = $this->targets;
6462

63+
// Allow for "fully qualified" true/false/null.
64+
$targets[] = T_NAME_FULLY_QUALIFIED;
65+
6566
// Register scope modifiers to filter out property type declarations.
6667
$targets += Tokens::SCOPE_MODIFIERS;
6768
$targets[] = T_VAR;
@@ -97,6 +98,13 @@ public function process(File $phpcsFile, $stackPtr)
9798
{
9899
$tokens = $phpcsFile->getTokens();
99100

101+
// If this is a fully qualified name, check if it is FQN true/false/null.
102+
if ($tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED
103+
&& $this->isFQNTrueFalseNull($phpcsFile, $stackPtr) === false
104+
) {
105+
return;
106+
}
107+
100108
// Skip over potential type declarations for constants.
101109
if ($tokens[$stackPtr]['code'] === T_CONST) {
102110
// Constant must always have a value assigned to it, so we can just look for the assignment
@@ -180,7 +188,10 @@ public function process(File $phpcsFile, $stackPtr)
180188
}
181189

182190
for ($i = $param['default_token']; $i < $paramEnd; $i++) {
183-
if (isset($this->targets[$tokens[$i]['code']]) === true) {
191+
if (isset($this->targets[$tokens[$i]['code']]) === true
192+
|| ($tokens[$i]['code'] === T_NAME_FULLY_QUALIFIED
193+
&& $this->isFQNTrueFalseNull($phpcsFile, $i) === true)
194+
) {
184195
$this->processConstant($phpcsFile, $i);
185196
}
186197
}
@@ -196,6 +207,28 @@ public function process(File $phpcsFile, $stackPtr)
196207
}//end process()
197208

198209

210+
/**
211+
* Check if a fully qualified name is a fully qualified true/false/null.
212+
*
213+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
214+
* @param int $stackPtr The position of the T_NAME_FULLY_QUALIFIED token in the
215+
* stack passed in $tokens.
216+
*
217+
* @return bool
218+
*/
219+
protected function isFQNTrueFalseNull(File $phpcsFile, $stackPtr)
220+
{
221+
$tokens = $phpcsFile->getTokens();
222+
223+
// Check for fully qualified true/false/null only.
224+
$compareReadyKeyword = strtolower($tokens[$stackPtr]['content']);
225+
return ($compareReadyKeyword === '\true'
226+
|| $compareReadyKeyword === '\false'
227+
|| $compareReadyKeyword === '\null');
228+
229+
}//end isFQNTrueFalseNull()
230+
231+
199232
/**
200233
* Processes a non-type declaration constant.
201234
*

src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ if (true) {
1111
if (file_exists(__FILE__) === true) {
1212

1313
}
14+
15+
// Check handling of case and FQN state.
16+
if (\true) {
17+
} else if (\FALSE) {
18+
}

src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ public function getWarningList($testFile='')
5050
switch ($testFile) {
5151
case 'UnconditionalIfStatementUnitTest.1.inc':
5252
return [
53-
3 => 1,
54-
5 => 1,
55-
7 => 1,
53+
3 => 1,
54+
5 => 1,
55+
7 => 1,
56+
16 => 1,
57+
17 => 1,
5658
];
5759

5860
default:

src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.inc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ if ($value == true) {}
77
if (true === $value) {}
88
if (true == $value) {}
99

10-
if($value === true){}
11-
if($value == true){}
10+
if($value === false){}
11+
if($value == false){}
1212
if(false === $value){}
1313
if(!false == $value || true !== $value){}
1414

@@ -139,8 +139,8 @@ if (is_array($val)
139139
&& array('foo', 'bar') === array($foo, $bar)
140140
&& ['foo', 'bar'] === [$foo, $bar]
141141
&& array('foo' => true, 'bar' => false) === array(getContents())
142-
&& ['foo' => true, 'bar' => false] === array(getContents())
143-
&& array(getContents()) === ['foo' => true, 'bar' => false]
142+
&& ['foo' => true, 'bar' => \false, 'baz' => null] === array(getContents())
143+
&& array(getContents()) === ['foo' => \true, 'bar' => false, 'baz' => \null]
144144
) {
145145
}
146146

@@ -192,3 +192,14 @@ if(Partially\qualified('foo') === 10){}
192192
if(1.5 === Partially\qualified(true)){}
193193
if(namespace\relative(false) === null){}
194194
if('string' === namespace\relative(null)){}
195+
196+
// Handle FQN true/false/null the same as plain true/false/null.
197+
if ($value === \true) {}
198+
if (\true === $value) {}
199+
200+
if($value == \FALSE){}
201+
if(\FALSE === $value){}
202+
if(!\false == $value || true !== $value){}
203+
204+
if($value === \Null){}
205+
if(\Null == $value){}

src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ public function getErrorList()
7575
190 => 1,
7676
192 => 1,
7777
194 => 1,
78+
198 => 1,
79+
201 => 1,
80+
202 => 2,
81+
205 => 1,
7882
];
7983

8084
}//end getErrorList()

src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,7 @@ class SkipOverPHP84FinalProperties {
160160
final MyType|FALSE $propA;
161161
private static final NULL|MyClass $propB;
162162
}
163+
164+
$a = \NULL;
165+
$a = \falSe;
166+
$a = \True;

src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,7 @@ class SkipOverPHP84FinalProperties {
160160
final MyType|FALSE $propA;
161161
private static final NULL|MyClass $propB;
162162
}
163+
164+
$a = \null;
165+
$a = \false;
166+
$a = \true;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public function getErrorList($testFile='')
6666
129 => 1,
6767
149 => 1,
6868
153 => 1,
69+
164 => 1,
70+
165 => 1,
71+
166 => 1,
6972
];
7073

7174
default:

0 commit comments

Comments
 (0)