From d6a6cc9e54389897c749a7fa143632c3975f6c76 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 5 Aug 2024 03:13:40 +0200 Subject: [PATCH] Squiz/SelfMemberReference: bug fix - false negative with namespace keyword as operator > The `namespace` keyword can both be used for namespace declarations as well as as an operator - "magic keyword" - to resolve to the current namespace. > See: https://www.php.net/manual/en/language.namespaces.nsconstants.php#example-298 > This last case is not correctly taken into account when determining the current namespace, which leads to false negatives. Fixed now. Includes test. Fixes 553 --- .../Sniffs/Classes/SelfMemberReferenceSniff.php | 14 +++++++++++--- .../Tests/Classes/SelfMemberReferenceUnitTest.inc | 14 ++++++++++++++ .../Classes/SelfMemberReferenceUnitTest.inc.fixed | 14 ++++++++++++++ .../Tests/Classes/SelfMemberReferenceUnitTest.php | 1 + 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php b/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php index 4c54aa4618..8ee4de45a8 100644 --- a/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php +++ b/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php @@ -221,15 +221,23 @@ protected function getDeclarationNameWithNamespace(array $tokens, $stackPtr) */ protected function getNamespaceOfScope(File $phpcsFile, $stackPtr) { - $namespace = '\\'; - $namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr); + $namespace = '\\'; + $tokens = $phpcsFile->getTokens(); + + while (($namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr)) !== false) { + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($namespaceDeclaration + 1), null, true); + if ($tokens[$nextNonEmpty]['code'] === T_NS_SEPARATOR) { + // Namespace operator. Ignore. + $stackPtr = ($namespaceDeclaration - 1); + continue; + } - if ($namespaceDeclaration !== false) { $endOfNamespaceDeclaration = $phpcsFile->findNext([T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_CLOSE_TAG], $namespaceDeclaration); $namespace = $this->getDeclarationNameWithNamespace( $phpcsFile->getTokens(), ($endOfNamespaceDeclaration - 1) ); + break; } return $namespace; diff --git a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc index f2c4713a66..4f17813866 100644 --- a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc +++ b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc @@ -183,3 +183,17 @@ class Baz { \EndsIn\CloseTag\Baz::something(); } } + +// Issue PHPCSStandards/PHP_CodeSniffer#553. +namespace TestMe; + +namespace\functionCall(); +namespace\anotherFunctionCall(); + +class SelfMemberReference +{ + public function falseNegative() + { + $testResults[] = \TestMe\SelfMemberReference::test(); + } +} diff --git a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc.fixed b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc.fixed index 95689d4a9f..770429dc82 100644 --- a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc.fixed +++ b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc.fixed @@ -171,3 +171,17 @@ class Baz { self::something(); } } + +// Issue PHPCSStandards/PHP_CodeSniffer#553. +namespace TestMe; + +namespace\functionCall(); +namespace\anotherFunctionCall(); + +class SelfMemberReference +{ + public function falseNegative() + { + $testResults[] = self::test(); + } +} diff --git a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.php b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.php index 180a010631..84b9c15e55 100644 --- a/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.php +++ b/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.php @@ -47,6 +47,7 @@ public function getErrorList() 162 => 1, 171 => 1, 183 => 1, + 197 => 1, ]; }//end getErrorList()