Skip to content

Commit 72cb4f9

Browse files
authored
Allow parsing mixed HTML and PHP (sirbrillig#234)
* Add test for mixed html and php * Consider html and closing tags to be empty tokens * Remove explicit return type to support PHP 5.6 * Add additional test for sniff codes for closing tags fixture
1 parent e76e816 commit 72cb4f9

File tree

3 files changed

+78
-16
lines changed

3 files changed

+78
-16
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
namespace VariableAnalysis\Tests\VariableAnalysisSniff;
3+
4+
use VariableAnalysis\Tests\BaseTestCase;
5+
6+
class ClosingPhpTagsTest extends BaseTestCase {
7+
public function testVariableWarningsWhenClosingTagsAreUsed() {
8+
$fixtureFile = $this->getFixture('ClosingPhpTagsFixture.php');
9+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
10+
$phpcsFile->process();
11+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
12+
$expectedWarnings = [
13+
6,
14+
8,
15+
13,
16+
16,
17+
];
18+
$this->assertEquals($expectedWarnings, $lines);
19+
}
20+
21+
public function testVariableWarningsHaveCorrectSniffCodesWhenClosingTagsAreUsed() {
22+
$fixtureFile = $this->getFixture('ClosingPhpTagsFixture.php');
23+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
24+
$phpcsFile->process();
25+
$warnings = $phpcsFile->getWarnings();
26+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[6][1][0]['source']);
27+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[8][6][0]['source']);
28+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[13][1][0]['source']);
29+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[16][6][0]['source']);
30+
}
31+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<html>
2+
<h1>Page Title</h1>
3+
<?php
4+
$foo = 'hello';
5+
$blue = 'hello';
6+
$bar = 'bye'; // unused variable
7+
echo $foo;
8+
echo $baz; // undefined variable
9+
?>
10+
<p>More stuff</p>
11+
<?php
12+
$foo2 = 'hello';
13+
$bar2 = 'bye'; // unused variable
14+
echo $foo2;
15+
echo $blue;
16+
echo $baz2; // undefined variable
17+
?>
18+
</html>

VariableAnalysis/Lib/Helpers.php

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@
99
use PHP_CodeSniffer\Util\Tokens;
1010

1111
class Helpers {
12+
/**
13+
* return int[]
14+
*/
15+
public static function getEmptyTokens() {
16+
return array_merge(
17+
array_values(Tokens::$emptyTokens),
18+
[
19+
T_INLINE_HTML,
20+
T_CLOSE_TAG,
21+
]
22+
);
23+
}
24+
1225
/**
1326
* @param int|bool $value
1427
*
@@ -146,7 +159,7 @@ public static function getFunctionIndexForFunctionArgument(File $phpcsFile, $sta
146159
return null;
147160
}
148161

149-
$nonFunctionTokenTypes = array_values(Tokens::$emptyTokens);
162+
$nonFunctionTokenTypes = self::getEmptyTokens();
150163
$nonFunctionTokenTypes[] = T_STRING;
151164
$nonFunctionTokenTypes[] = T_BITWISE_AND;
152165
$functionPtr = self::getIntOrNull($phpcsFile->findPrevious($nonFunctionTokenTypes, $startOfArguments - 1, null, true, null, true));
@@ -186,7 +199,7 @@ public static function isTokenInsideFunctionUseImport(File $phpcsFile, $stackPtr
186199
public static function getUseIndexForUseImport(File $phpcsFile, $stackPtr) {
187200
$tokens = $phpcsFile->getTokens();
188201

189-
$nonUseTokenTypes = array_values(Tokens::$emptyTokens);
202+
$nonUseTokenTypes = self::getEmptyTokens();
190203
$nonUseTokenTypes[] = T_VARIABLE;
191204
$nonUseTokenTypes[] = T_ELLIPSIS;
192205
$nonUseTokenTypes[] = T_COMMA;
@@ -215,7 +228,7 @@ public static function findFunctionCall(File $phpcsFile, $stackPtr) {
215228
$openPtr = Helpers::findContainingOpeningBracket($phpcsFile, $stackPtr);
216229
if (is_int($openPtr)) {
217230
// First non-whitespace thing and see if it's a T_STRING function name
218-
$functionPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $openPtr - 1, null, true, null, true);
231+
$functionPtr = $phpcsFile->findPrevious(self::getEmptyTokens(), $openPtr - 1, null, true, null, true);
219232
if (is_int($functionPtr) && $tokens[$functionPtr]['code'] === T_STRING) {
220233
return $functionPtr;
221234
}
@@ -242,7 +255,7 @@ public static function findFunctionCallArguments(File $phpcsFile, $stackPtr) {
242255
}
243256

244257
// $stackPtr is the function name, find our brackets after it
245-
$openPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
258+
$openPtr = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true, null, true);
246259
if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) {
247260
return [];
248261
}
@@ -280,7 +293,7 @@ public static function getNextAssignPointer(File $phpcsFile, $stackPtr) {
280293
$tokens = $phpcsFile->getTokens();
281294

282295
// Is the next non-whitespace an assignment?
283-
$nextPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
296+
$nextPtr = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true, null, true);
284297
if (is_int($nextPtr)
285298
&& isset(Tokens::$assignmentTokens[$tokens[$nextPtr]['code']])
286299
// Ignore double arrow to prevent triggering on `foreach ( $array as $k => $v )`.
@@ -508,14 +521,14 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) {
508521
return false;
509522
}
510523
// Make sure next non-space token is an open parenthesis
511-
$openParenIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true);
524+
$openParenIndex = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true);
512525
if (! is_int($openParenIndex) || $tokens[$openParenIndex]['code'] !== T_OPEN_PARENTHESIS) {
513526
return false;
514527
}
515528
// Find the associated close parenthesis
516529
$closeParenIndex = $tokens[$openParenIndex]['parenthesis_closer'];
517530
// Make sure the next token is a fat arrow
518-
$fatArrowIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $closeParenIndex + 1, null, true);
531+
$fatArrowIndex = $phpcsFile->findNext(self::getEmptyTokens(), $closeParenIndex + 1, null, true);
519532
if (! is_int($fatArrowIndex)) {
520533
return false;
521534
}
@@ -543,14 +556,14 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) {
543556
return null;
544557
}
545558
// Make sure next non-space token is an open parenthesis
546-
$openParenIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true);
559+
$openParenIndex = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true);
547560
if (! is_int($openParenIndex) || $tokens[$openParenIndex]['code'] !== T_OPEN_PARENTHESIS) {
548561
return null;
549562
}
550563
// Find the associated close parenthesis
551564
$closeParenIndex = $tokens[$openParenIndex]['parenthesis_closer'];
552565
// Make sure the next token is a fat arrow
553-
$fatArrowIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $closeParenIndex + 1, null, true);
566+
$fatArrowIndex = $phpcsFile->findNext(self::getEmptyTokens(), $closeParenIndex + 1, null, true);
554567
if (! is_int($fatArrowIndex)) {
555568
return null;
556569
}
@@ -600,7 +613,7 @@ public static function getListAssignments(File $phpcsFile, $listOpenerIndex) {
600613
}
601614

602615
// Find the assignment (equals sign) which, if this is a list assignment, should be the next non-space token
603-
$assignPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $closePtr + 1, null, true);
616+
$assignPtr = $phpcsFile->findNext(self::getEmptyTokens(), $closePtr + 1, null, true);
604617

605618
// If the next token isn't an assignment, check for nested brackets because we might be a nested assignment
606619
if (! is_int($assignPtr) || $tokens[$assignPtr]['code'] !== T_EQUAL) {
@@ -715,7 +728,7 @@ public static function isVariableANumericVariable($varName) {
715728
*/
716729
public static function isVariableInsideElseCondition(File $phpcsFile, $stackPtr) {
717730
$tokens = $phpcsFile->getTokens();
718-
$nonFunctionTokenTypes = array_values(Tokens::$emptyTokens);
731+
$nonFunctionTokenTypes = self::getEmptyTokens();
719732
$nonFunctionTokenTypes[] = T_OPEN_PARENTHESIS;
720733
$nonFunctionTokenTypes[] = T_VARIABLE;
721734
$nonFunctionTokenTypes[] = T_ELLIPSIS;
@@ -837,7 +850,7 @@ public static function getScopeCloseForScopeOpen(File $phpcsFile, $scopeStartInd
837850
public static function getLastNonEmptyTokenIndexInFile(File $phpcsFile) {
838851
$tokens = $phpcsFile->getTokens();
839852
foreach (array_reverse($tokens, true) as $index => $token) {
840-
if (! in_array($token['code'], Tokens::$emptyTokens, true)) {
853+
if (! in_array($token['code'], self::getEmptyTokens(), true)) {
841854
return $index;
842855
}
843856
}
@@ -921,7 +934,7 @@ public static function getFunctionIndexForFunctionCallArgument(File $phpcsFile,
921934
return null;
922935
}
923936

924-
$nonFunctionTokenTypes = array_values(Tokens::$emptyTokens);
937+
$nonFunctionTokenTypes = self::getEmptyTokens();
925938
$functionPtr = self::getIntOrNull($phpcsFile->findPrevious($nonFunctionTokenTypes, $startOfArguments - 1, null, true, null, true));
926939
if (! is_int($functionPtr) || ! isset($tokens[$functionPtr]['code'])) {
927940
return null;
@@ -965,7 +978,7 @@ public static function isVariableInsideIssetOrEmpty(File $phpcsFile, $stackPtr)
965978
*/
966979
public static function isVariableArrayPushShortcut(File $phpcsFile, $stackPtr) {
967980
$tokens = $phpcsFile->getTokens();
968-
$nonFunctionTokenTypes = array_values(Tokens::$emptyTokens);
981+
$nonFunctionTokenTypes = self::getEmptyTokens();
969982

970983
$arrayPushOperatorIndex1 = self::getIntOrNull($phpcsFile->findNext($nonFunctionTokenTypes, $stackPtr + 1, null, true, null, true));
971984
if (! is_int($arrayPushOperatorIndex1)) {
@@ -1063,7 +1076,7 @@ public static function isTokenInsideAssignmentLHS(File $phpcsFile, $stackPtr) {
10631076
public static function isTokenVariableVariable(File $phpcsFile, $stackPtr) {
10641077
$tokens = $phpcsFile->getTokens();
10651078

1066-
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
1079+
$prev = $phpcsFile->findPrevious(self::getEmptyTokens(), ($stackPtr - 1), null, true);
10671080
if ($prev === false) {
10681081
return false;
10691082
}
@@ -1074,7 +1087,7 @@ public static function isTokenVariableVariable(File $phpcsFile, $stackPtr) {
10741087
return false;
10751088
}
10761089

1077-
$prevPrev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), null, true);
1090+
$prevPrev = $phpcsFile->findPrevious(self::getEmptyTokens(), ($prev - 1), null, true);
10781091
if ($prevPrev !== false && $tokens[$prevPrev]['code'] === T_DOLLAR) {
10791092
return true;
10801093
}

0 commit comments

Comments
 (0)