Skip to content

Commit 15afb2f

Browse files
committed
2 parents e73f14b + 46dc37a commit 15afb2f

File tree

5 files changed

+143
-3
lines changed

5 files changed

+143
-3
lines changed

src/Files/File.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,11 @@ public function findStartOfStatement($start, $ignore=null)
23132313
&& $this->tokens[$i]['code'] !== T_CLOSE_PARENTHESIS
23142314
&& $this->tokens[$i]['code'] !== T_END_NOWDOC
23152315
&& $this->tokens[$i]['code'] !== T_END_HEREDOC
2316+
&& $this->tokens[$i]['code'] !== T_BREAK
2317+
&& $this->tokens[$i]['code'] !== T_RETURN
2318+
&& $this->tokens[$i]['code'] !== T_CONTINUE
2319+
&& $this->tokens[$i]['code'] !== T_THROW
2320+
&& $this->tokens[$i]['code'] !== T_EXIT
23162321
) {
23172322
// Found the end of the previous scope block.
23182323
return $lastNotEmpty;

src/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,8 @@ private function findNestedTerminator($phpcsFile, $stackPtr, $end)
251251
$lastToken = $phpcsFile->findPrevious(T_WHITESPACE, ($end - 1), $stackPtr, true);
252252
if ($lastToken !== false) {
253253
if ($tokens[$lastToken]['code'] === T_CLOSE_CURLY_BRACKET) {
254-
// We found a closing curly bracket and want to check if its
255-
// block belongs to an IF, ELSEIF or ELSE clause. If yes, we
254+
// We found a closing curly bracket and want to check if its block
255+
// belongs to a SWITCH or an IF, ELSEIF or ELSE clause. If yes, we
256256
// continue searching for a terminating statement within that
257257
// block. Note that we have to make sure that every block of
258258
// the entire if/else statement has a terminating statement.
@@ -267,7 +267,7 @@ private function findNestedTerminator($phpcsFile, $stackPtr, $end)
267267
return false;
268268
}
269269

270-
// IF and ELSEIF clauses possess a condition we have to account for.
270+
// SWITCH, IF and ELSEIF clauses possess a condition we have to account for.
271271
if ($tokens[$prevToken]['code'] === T_CLOSE_PARENTHESIS) {
272272
$prevToken = $tokens[$prevToken]['parenthesis_owner'];
273273
}
@@ -294,6 +294,39 @@ private function findNestedTerminator($phpcsFile, $stackPtr, $end)
294294
if ($tokens[$prevToken]['code'] === T_ELSE) {
295295
$hasElseBlock = true;
296296
}
297+
} else if ($tokens[$prevToken]['code'] === T_SWITCH) {
298+
$hasDefaultBlock = false;
299+
$endOfSwitch = $tokens[$prevToken]['scope_closer'];
300+
$nextCase = $prevToken;
301+
302+
// We look for a terminating statement within every blocks.
303+
while (($nextCase = $this->findNextCase($phpcsFile, ($nextCase + 1), $endOfSwitch)) !== false) {
304+
if ($tokens[$nextCase]['code'] === T_DEFAULT) {
305+
$hasDefaultBlock = true;
306+
}
307+
308+
$opener = $tokens[$nextCase]['scope_opener'];
309+
310+
$nextCode = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), $endOfSwitch, true);
311+
if ($tokens[$nextCode]['code'] === T_CASE || $tokens[$nextCode]['code'] === T_DEFAULT) {
312+
// This case statement has no content. We skip it.
313+
continue;
314+
}
315+
316+
$nextCode = $this->findNextCase($phpcsFile, ($opener + 1), $endOfSwitch);
317+
if ($nextCode === false) {
318+
$nextCode = $endOfSwitch;
319+
}
320+
321+
$hasTerminator = $this->findNestedTerminator($phpcsFile, ($opener + 1), $nextCode);
322+
if ($hasTerminator === false) {
323+
return false;
324+
}
325+
}//end while
326+
327+
// If we have not encountered a DEFAULT block by now, we cannot
328+
// be sure that the whole statement terminates in every case.
329+
return $hasDefaultBlock;
297330
} else {
298331
return false;
299332
}//end if

src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,53 @@ case Foo::ARRAY:
281281
echo '1';
282282
return self::VALUE;
283283
}
284+
285+
// OK: Every clause terminates
286+
switch ($foo) {
287+
case 1:
288+
switch ($bar) {
289+
case 1:
290+
return 1;
291+
default:
292+
return 3;
293+
}
294+
case 2:
295+
return 2;
296+
}
297+
298+
// KO: Not every clause terminates
299+
switch ($foo) {
300+
case 1:
301+
switch ($bar) {
302+
case 1:
303+
return;
304+
}
305+
case 2:
306+
return 2;
307+
}
308+
309+
// KO: Not every clause terminates
310+
switch ($foo) {
311+
case 1:
312+
switch ($bar) {
313+
case 1:
314+
return;
315+
default:
316+
$a = 1;
317+
}
318+
case 2:
319+
return 2;
320+
}
321+
322+
// OK: Every clause terminates
323+
switch ($foo) {
324+
case 1:
325+
switch ($bar) {
326+
case 1:
327+
return 1;
328+
default:
329+
throw new \Exception();
330+
}
331+
case 2:
332+
return 2;
333+
}

src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,53 @@ case Foo::ARRAY:
284284
echo '1';
285285
return self::VALUE;
286286
}
287+
288+
// OK: Every clause terminates
289+
switch ($foo) {
290+
case 1:
291+
switch ($bar) {
292+
case 1:
293+
return 1;
294+
default:
295+
return 3;
296+
}
297+
case 2:
298+
return 2;
299+
}
300+
301+
// KO: Not every clause terminates
302+
switch ($foo) {
303+
case 1:
304+
switch ($bar) {
305+
case 1:
306+
return;
307+
}
308+
case 2:
309+
return 2;
310+
}
311+
312+
// KO: Not every clause terminates
313+
switch ($foo) {
314+
case 1:
315+
switch ($bar) {
316+
case 1:
317+
return;
318+
default:
319+
$a = 1;
320+
}
321+
case 2:
322+
return 2;
323+
}
324+
325+
// OK: Every clause terminates
326+
switch ($foo) {
327+
case 1:
328+
switch ($bar) {
329+
case 1:
330+
return 1;
331+
default:
332+
throw new \Exception();
333+
}
334+
case 2:
335+
return 2;
336+
}

src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public function getErrorList()
4747
224 => 1,
4848
236 => 1,
4949
260 => 1,
50+
300 => 1,
51+
311 => 1,
5052
];
5153

5254
}//end getErrorList()

0 commit comments

Comments
 (0)