diff --git a/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php index adb1d6ba77..48e7659e3c 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php @@ -15,6 +15,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractScopeSniff; +use PHP_CodeSniffer\Util\Tokens; class ConstructorNameSniff extends AbstractScopeSniff { @@ -90,7 +91,7 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop } // Stop if the constructor doesn't have a body, like when it is abstract. - if (isset($tokens[$stackPtr]['scope_closer']) === false) { + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } @@ -102,17 +103,29 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop $parentClassNameLc = strtolower($parentClassName); $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; - $startIndex = $stackPtr; - while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, $startIndex, $endFunctionIndex)) !== false) { - if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING - && strtolower($tokens[($doubleColonIndex + 1)]['content']) === $parentClassNameLc + $startIndex = $tokens[$stackPtr]['scope_opener']; + while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, ($startIndex + 1), $endFunctionIndex)) !== false) { + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($doubleColonIndex + 1), null, true); + if ($tokens[$nextNonEmpty]['code'] !== T_STRING + || strtolower($tokens[$nextNonEmpty]['content']) !== $parentClassNameLc + ) { + $startIndex = $nextNonEmpty; + continue; + } + + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($doubleColonIndex - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] === T_PARENT + || $tokens[$prevNonEmpty]['code'] === T_SELF + || $tokens[$prevNonEmpty]['code'] === T_STATIC + || ($tokens[$prevNonEmpty]['code'] === T_STRING + && strtolower($tokens[$prevNonEmpty]['content']) === $parentClassNameLc) ) { $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; - $phpcsFile->addError($error, ($doubleColonIndex + 1), 'OldStyleCall'); + $phpcsFile->addError($error, $nextNonEmpty, 'OldStyleCall'); } - $startIndex = ($doubleColonIndex + 1); - } + $startIndex = $nextNonEmpty; + }//end while }//end processTokenWithinScope() diff --git a/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc index c680591982..2fb02d6aa1 100644 --- a/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc +++ b/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc @@ -95,3 +95,36 @@ interface CustomChildCreator { public function customChildCreator($elementName, Project $project); } + +// Bug: unconventional spacing and unexpected comments were not handled correctly. +class UnconventionalSpacing extends MyParent +{ + public function UnconventionalSpacing() { + self :: MyParent(); + MyParent/*comment*/::/*comment*/MyParent(); + } + + public function __construct() { + parent + //comment + :: + // phpcs:ignore Stnd.Cat.SniffName -- for reasons. + MyParent(); + } +} + +// Bug: calling a method with the same name as the class being extended on another class, should not be flagged. +class HierarchyKeywordBeforeColon extends MyParent +{ + public function HierarchyKeywordBeforeColon() { + parent::MyParent(); + MyParent::MyParent(); + SomeOtherClass::MyParent(); + } + + public function __construct() { + self::MyParent(); + static::MyParent(); + SomeOtherClass::MyParent(); + } +} diff --git a/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.php b/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.php index 616f651347..9df7f37930 100644 --- a/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.php +++ b/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.php @@ -31,11 +31,18 @@ final class ConstructorNameUnitTest extends AbstractSniffUnitTest public function getErrorList() { return [ - 6 => 1, - 11 => 1, - 47 => 1, - 62 => 1, - 91 => 1, + 6 => 1, + 11 => 1, + 47 => 1, + 62 => 1, + 91 => 1, + 103 => 1, + 104 => 1, + 112 => 1, + 120 => 1, + 121 => 1, + 126 => 1, + 127 => 1, ]; }//end getErrorList()