Skip to content

Commit ebb0a96

Browse files
authored
Squiz/NonExecutableCode: fix false positives when code goes in and out of PHP/HTML (#3770)
Ignore HTML whitespace and PHP re-open tags when determining whether code should be flagged as non executable.
1 parent 7566b4d commit ebb0a96

File tree

5 files changed

+102
-3
lines changed

5 files changed

+102
-3
lines changed

package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -1940,6 +1940,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
19401940
<file baseinstalldir="PHP/CodeSniffer" name="LowercasePHPFunctionsUnitTest.php" role="test" />
19411941
<file baseinstalldir="PHP/CodeSniffer" name="NonExecutableCodeUnitTest.1.inc" role="test" />
19421942
<file baseinstalldir="PHP/CodeSniffer" name="NonExecutableCodeUnitTest.2.inc" role="test" />
1943+
<file baseinstalldir="PHP/CodeSniffer" name="NonExecutableCodeUnitTest.3.inc" role="test" />
19431944
<file baseinstalldir="PHP/CodeSniffer" name="NonExecutableCodeUnitTest.php" role="test" />
19441945
</dir>
19451946
<dir name="Scope">

src/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ public function process(File $phpcsFile, $stackPtr)
241241
$end = ($phpcsFile->numTokens - 1);
242242
}//end if
243243

244-
// Find the semicolon that ends this statement, skipping
245-
// nested statements like FOR loops and closures.
244+
// Find the semicolon or closing PHP tag that ends this statement,
245+
// skipping nested statements like FOR loops and closures.
246246
for ($start = ($stackPtr + 1); $start < $phpcsFile->numTokens; $start++) {
247247
if ($start === $end) {
248248
break;
@@ -262,7 +262,7 @@ public function process(File $phpcsFile, $stackPtr)
262262
continue;
263263
}
264264

265-
if ($tokens[$start]['code'] === T_SEMICOLON) {
265+
if ($tokens[$start]['code'] === T_SEMICOLON || $tokens[$start]['code'] === T_CLOSE_TAG) {
266266
break;
267267
}
268268
}//end for
@@ -295,6 +295,16 @@ public function process(File $phpcsFile, $stackPtr)
295295
continue;
296296
}
297297

298+
// Skip HTML whitespace.
299+
if ($tokens[$i]['code'] === T_INLINE_HTML && \trim($tokens[$i]['content']) === '') {
300+
continue;
301+
}
302+
303+
// Skip PHP re-open tag (eg, after inline HTML).
304+
if ($tokens[$i]['code'] === T_OPEN_TAG) {
305+
continue;
306+
}
307+
298308
$line = $tokens[$i]['line'];
299309
if ($line > $lastLine) {
300310
$type = substr($tokens[$stackPtr]['type'], 2);

src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc

+12
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,16 @@ $a = new class {
5858
}
5959
};
6060

61+
// Multiple statements are still one line of unreachable code, so should get
62+
// only one complaint from this sniff. (Well, technically two here since there
63+
// are two 'exit()' statements above, so one complaint from each of those. So,
64+
// two here, but not six.)
65+
echo 'one'; echo 'two'; echo 'three';
66+
67+
// A single statement split across multiple lines. Here we get complaints for
68+
// each line, even though they're all part of one statement.
69+
echo 'one' . 'two'
70+
. 'three' . 'four'
71+
. 'five' . 'six';
72+
6173
interface MyInterface {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<!-- no problem here -->
2+
<?php if (true): ?>
3+
<?php foreach ([] as $item): ?>
4+
<?php continue; ?>
5+
<?php endforeach; ?>
6+
<?php endif; ?>
7+
8+
<!-- no problem here -->
9+
<?php if (true) { ?>
10+
<?php foreach ([] as $item) { ?>
11+
<?php continue; ?>
12+
<?php } ?>
13+
<?php } ?>
14+
15+
<!-- no problem here -->
16+
<?php if (true) { ?>
17+
<?php foreach ([] as $item) { ?>
18+
<!-- note missing semicolon on next line -->
19+
<?php continue ?>
20+
<?php } ?>
21+
<?php } ?>
22+
23+
<!-- should detect an error here -->
24+
<?php if (true): ?>
25+
<?php foreach ([] as $item): ?>
26+
<?php continue; ?>
27+
<div>non-executable</div>
28+
<?php endforeach; ?>
29+
<?php endif; ?>
30+
31+
<!-- should detect an error here -->
32+
<?php if (true): ?>
33+
<?php foreach ([] as $item): ?>
34+
<!-- note missing semicolon on next line -->
35+
<?php continue ?>
36+
<div>non-executable</div>
37+
<?php endforeach; ?>
38+
<?php endif; ?>
39+
40+
<!-- should detect an error here -->
41+
<?php if (true): ?>
42+
<?php foreach ([] as $item): ?>
43+
<?php continue; ?>
44+
45+
<div>non-executable</div>
46+
47+
<?php endforeach; ?>
48+
<?php endif; ?>
49+
50+
<!-- should detect an error here -->
51+
<?php if (true): ?>
52+
<?php foreach ([] as $item): ?>
53+
<?php continue; ?>
54+
<?= 'unreachable - no semicolon' ?>
55+
<?php endforeach; ?>
56+
<?php endif; ?>
57+
58+
<!-- should detect an error here -->
59+
<?php if (true): ?>
60+
<?php foreach ([] as $item): ?>
61+
<?php continue; ?>
62+
<?= 'unreachable - with semicolon'; ?>
63+
<?php endforeach; ?>
64+
<?php endif; ?>

src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,20 @@ public function getWarningList($testFile='')
9292
10 => 2,
9393
14 => 1,
9494
54 => 2,
95+
65 => 2,
96+
69 => 2,
97+
70 => 2,
98+
71 => 2,
9599
];
96100
break;
101+
case 'NonExecutableCodeUnitTest.3.inc':
102+
return [
103+
27 => 1,
104+
36 => 1,
105+
45 => 1,
106+
54 => 1,
107+
62 => 1,
108+
];
97109
default:
98110
return [];
99111
break;

0 commit comments

Comments
 (0)