From d6c6539746b1c0e10260b1d40e625697ac2d20aa Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Fri, 18 Jun 2021 15:26:37 -0400 Subject: [PATCH 1/4] Add test for mixed html and php --- .../ClosingPhpTagsTest.php | 24 +++++++++++++++++++ .../fixtures/ClosingPhpTagsFixture.php | 18 ++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php create mode 100644 Tests/VariableAnalysisSniff/fixtures/ClosingPhpTagsFixture.php diff --git a/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php b/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php new file mode 100644 index 0000000..cbbcc08 --- /dev/null +++ b/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php @@ -0,0 +1,24 @@ +getFixture('ClosingPhpTagsFixture.php'); + $phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile); + $phpcsFile->process(); + $lines = $this->getWarningLineNumbersFromFile($phpcsFile); + $expectedWarnings = [ + 6, + 8, + 13, + 16, + ]; + $this->assertEquals($expectedWarnings, $lines); + + // $warnings = $phpcsFile->getWarnings(); + // $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[2][49][0]['source']); + // $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[2][49][0]['source']); + } +} diff --git a/Tests/VariableAnalysisSniff/fixtures/ClosingPhpTagsFixture.php b/Tests/VariableAnalysisSniff/fixtures/ClosingPhpTagsFixture.php new file mode 100644 index 0000000..487964b --- /dev/null +++ b/Tests/VariableAnalysisSniff/fixtures/ClosingPhpTagsFixture.php @@ -0,0 +1,18 @@ + +

Page Title

+ +

More stuff

+ + From 01463356a98bf8000b389f616154c23552834bdb Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Fri, 18 Jun 2021 15:40:01 -0400 Subject: [PATCH 2/4] Consider html and closing tags to be empty tokens --- VariableAnalysis/Lib/Helpers.php | 45 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index b9ffb1b..dffb4e0 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -9,6 +9,19 @@ use PHP_CodeSniffer\Util\Tokens; class Helpers { + /** + * return int[] + */ + public static function getEmptyTokens(): array { + return array_merge( + array_values(Tokens::$emptyTokens), + [ + T_INLINE_HTML, + T_CLOSE_TAG, + ] + ); + } + /** * @param int|bool $value * @@ -146,7 +159,7 @@ public static function getFunctionIndexForFunctionArgument(File $phpcsFile, $sta return null; } - $nonFunctionTokenTypes = array_values(Tokens::$emptyTokens); + $nonFunctionTokenTypes = self::getEmptyTokens(); $nonFunctionTokenTypes[] = T_STRING; $nonFunctionTokenTypes[] = T_BITWISE_AND; $functionPtr = self::getIntOrNull($phpcsFile->findPrevious($nonFunctionTokenTypes, $startOfArguments - 1, null, true, null, true)); @@ -186,7 +199,7 @@ public static function isTokenInsideFunctionUseImport(File $phpcsFile, $stackPtr public static function getUseIndexForUseImport(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $nonUseTokenTypes = array_values(Tokens::$emptyTokens); + $nonUseTokenTypes = self::getEmptyTokens(); $nonUseTokenTypes[] = T_VARIABLE; $nonUseTokenTypes[] = T_ELLIPSIS; $nonUseTokenTypes[] = T_COMMA; @@ -215,7 +228,7 @@ public static function findFunctionCall(File $phpcsFile, $stackPtr) { $openPtr = Helpers::findContainingOpeningBracket($phpcsFile, $stackPtr); if (is_int($openPtr)) { // First non-whitespace thing and see if it's a T_STRING function name - $functionPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $openPtr - 1, null, true, null, true); + $functionPtr = $phpcsFile->findPrevious(self::getEmptyTokens(), $openPtr - 1, null, true, null, true); if (is_int($functionPtr) && $tokens[$functionPtr]['code'] === T_STRING) { return $functionPtr; } @@ -242,7 +255,7 @@ public static function findFunctionCallArguments(File $phpcsFile, $stackPtr) { } // $stackPtr is the function name, find our brackets after it - $openPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true); + $openPtr = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true, null, true); if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) { return []; } @@ -280,7 +293,7 @@ public static function getNextAssignPointer(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Is the next non-whitespace an assignment? - $nextPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true); + $nextPtr = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true, null, true); if (is_int($nextPtr) && isset(Tokens::$assignmentTokens[$tokens[$nextPtr]['code']]) // Ignore double arrow to prevent triggering on `foreach ( $array as $k => $v )`. @@ -508,14 +521,14 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) { return false; } // Make sure next non-space token is an open parenthesis - $openParenIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true); + $openParenIndex = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true); if (! is_int($openParenIndex) || $tokens[$openParenIndex]['code'] !== T_OPEN_PARENTHESIS) { return false; } // Find the associated close parenthesis $closeParenIndex = $tokens[$openParenIndex]['parenthesis_closer']; // Make sure the next token is a fat arrow - $fatArrowIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $closeParenIndex + 1, null, true); + $fatArrowIndex = $phpcsFile->findNext(self::getEmptyTokens(), $closeParenIndex + 1, null, true); if (! is_int($fatArrowIndex)) { return false; } @@ -543,14 +556,14 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) { return null; } // Make sure next non-space token is an open parenthesis - $openParenIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true); + $openParenIndex = $phpcsFile->findNext(self::getEmptyTokens(), $stackPtr + 1, null, true); if (! is_int($openParenIndex) || $tokens[$openParenIndex]['code'] !== T_OPEN_PARENTHESIS) { return null; } // Find the associated close parenthesis $closeParenIndex = $tokens[$openParenIndex]['parenthesis_closer']; // Make sure the next token is a fat arrow - $fatArrowIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $closeParenIndex + 1, null, true); + $fatArrowIndex = $phpcsFile->findNext(self::getEmptyTokens(), $closeParenIndex + 1, null, true); if (! is_int($fatArrowIndex)) { return null; } @@ -600,7 +613,7 @@ public static function getListAssignments(File $phpcsFile, $listOpenerIndex) { } // Find the assignment (equals sign) which, if this is a list assignment, should be the next non-space token - $assignPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $closePtr + 1, null, true); + $assignPtr = $phpcsFile->findNext(self::getEmptyTokens(), $closePtr + 1, null, true); // If the next token isn't an assignment, check for nested brackets because we might be a nested assignment if (! is_int($assignPtr) || $tokens[$assignPtr]['code'] !== T_EQUAL) { @@ -715,7 +728,7 @@ public static function isVariableANumericVariable($varName) { */ public static function isVariableInsideElseCondition(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $nonFunctionTokenTypes = array_values(Tokens::$emptyTokens); + $nonFunctionTokenTypes = self::getEmptyTokens(); $nonFunctionTokenTypes[] = T_OPEN_PARENTHESIS; $nonFunctionTokenTypes[] = T_VARIABLE; $nonFunctionTokenTypes[] = T_ELLIPSIS; @@ -837,7 +850,7 @@ public static function getScopeCloseForScopeOpen(File $phpcsFile, $scopeStartInd public static function getLastNonEmptyTokenIndexInFile(File $phpcsFile) { $tokens = $phpcsFile->getTokens(); foreach (array_reverse($tokens, true) as $index => $token) { - if (! in_array($token['code'], Tokens::$emptyTokens, true)) { + if (! in_array($token['code'], self::getEmptyTokens(), true)) { return $index; } } @@ -921,7 +934,7 @@ public static function getFunctionIndexForFunctionCallArgument(File $phpcsFile, return null; } - $nonFunctionTokenTypes = array_values(Tokens::$emptyTokens); + $nonFunctionTokenTypes = self::getEmptyTokens(); $functionPtr = self::getIntOrNull($phpcsFile->findPrevious($nonFunctionTokenTypes, $startOfArguments - 1, null, true, null, true)); if (! is_int($functionPtr) || ! isset($tokens[$functionPtr]['code'])) { return null; @@ -965,7 +978,7 @@ public static function isVariableInsideIssetOrEmpty(File $phpcsFile, $stackPtr) */ public static function isVariableArrayPushShortcut(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $nonFunctionTokenTypes = array_values(Tokens::$emptyTokens); + $nonFunctionTokenTypes = self::getEmptyTokens(); $arrayPushOperatorIndex1 = self::getIntOrNull($phpcsFile->findNext($nonFunctionTokenTypes, $stackPtr + 1, null, true, null, true)); if (! is_int($arrayPushOperatorIndex1)) { @@ -1063,7 +1076,7 @@ public static function isTokenInsideAssignmentLHS(File $phpcsFile, $stackPtr) { public static function isTokenVariableVariable(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + $prev = $phpcsFile->findPrevious(self::getEmptyTokens(), ($stackPtr - 1), null, true); if ($prev === false) { return false; } @@ -1074,7 +1087,7 @@ public static function isTokenVariableVariable(File $phpcsFile, $stackPtr) { return false; } - $prevPrev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), null, true); + $prevPrev = $phpcsFile->findPrevious(self::getEmptyTokens(), ($prev - 1), null, true); if ($prevPrev !== false && $tokens[$prevPrev]['code'] === T_DOLLAR) { return true; } From 7191e41ae9fa573443fd085a551ad9acc1adcd73 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Fri, 18 Jun 2021 15:43:27 -0400 Subject: [PATCH 3/4] Remove explicit return type to support PHP 5.6 --- VariableAnalysis/Lib/Helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index dffb4e0..d9dab91 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -12,7 +12,7 @@ class Helpers { /** * return int[] */ - public static function getEmptyTokens(): array { + public static function getEmptyTokens() { return array_merge( array_values(Tokens::$emptyTokens), [ From d3ae74c04cddb115504f396058bd9c745483c2d3 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Fri, 18 Jun 2021 15:48:23 -0400 Subject: [PATCH 4/4] Add additional test for sniff codes for closing tags fixture --- Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php b/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php index cbbcc08..e7856fb 100644 --- a/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php +++ b/Tests/VariableAnalysisSniff/ClosingPhpTagsTest.php @@ -16,9 +16,16 @@ public function testVariableWarningsWhenClosingTagsAreUsed() { 16, ]; $this->assertEquals($expectedWarnings, $lines); + } - // $warnings = $phpcsFile->getWarnings(); - // $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[2][49][0]['source']); - // $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[2][49][0]['source']); + public function testVariableWarningsHaveCorrectSniffCodesWhenClosingTagsAreUsed() { + $fixtureFile = $this->getFixture('ClosingPhpTagsFixture.php'); + $phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile); + $phpcsFile->process(); + $warnings = $phpcsFile->getWarnings(); + $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[6][1][0]['source']); + $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[8][6][0]['source']); + $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable', $warnings[13][1][0]['source']); + $this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable', $warnings[16][6][0]['source']); } }