diff --git a/src/Cdn77/Sniffs/NamingConventions/ValidConstantNameSniff.php b/src/Cdn77/Sniffs/NamingConventions/ValidConstantNameSniff.php index caeb424..d13a809 100644 --- a/src/Cdn77/Sniffs/NamingConventions/ValidConstantNameSniff.php +++ b/src/Cdn77/Sniffs/NamingConventions/ValidConstantNameSniff.php @@ -17,8 +17,10 @@ use const T_CONST; use const T_CONSTANT_ENCAPSED_STRING; use const T_DOUBLE_COLON; +use const T_EQUAL; use const T_NULLSAFE_OBJECT_OPERATOR; use const T_OBJECT_OPERATOR; +use const T_SEMICOLON; use const T_STRING; use const T_WHITESPACE; @@ -56,8 +58,16 @@ public function process(File $phpcsFile, $stackPtr): void $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['code'] === T_CONST) { - // This is a class constant. - $constant = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true); + // This is a constant declared with the "const" keyword. + // This may be an OO constant, in which case it could be typed, so we need to + // jump over a potential type to get to the name. + $assignmentOperator = $phpcsFile->findNext([T_EQUAL, T_SEMICOLON], $stackPtr + 1); + if ($assignmentOperator === false || $tokens[$assignmentOperator]['code'] !== T_EQUAL) { + // Parse error/live coding. Nothing to do. Rest of loop is moot. + return; + } + + $constant = $phpcsFile->findPrevious(Tokens::$emptyTokens, $assignmentOperator - 1, $stackPtr + 1, true); if ($constant === false) { return; } diff --git a/tests/Sniffs/NamingConventions/ValidConstantNameSniffTest.php b/tests/Sniffs/NamingConventions/ValidConstantNameSniffTest.php index f624476..f819f8e 100644 --- a/tests/Sniffs/NamingConventions/ValidConstantNameSniffTest.php +++ b/tests/Sniffs/NamingConventions/ValidConstantNameSniffTest.php @@ -12,6 +12,7 @@ use function json_encode; use const JSON_THROW_ON_ERROR; +use const PHP_VERSION_ID; #[CoversClass(ValidConstantNameSniff::class)] class ValidConstantNameSniffTest extends TestCase @@ -41,4 +42,29 @@ public function testErrors(): void self::assertSame(count($errorTypesPerLine), $file->getErrorCount()); } + + public function testErrorsConstantType(): void + { + if (PHP_VERSION_ID < 80300) { + self::markTestSkipped('Test requires PHP 8.3'); + } + + $file = self::checkFile(__DIR__ . '/data/ValidConstantNameWithTypeTest.inc'); + + $errorTypesPerLine = [ + 6 => ValidConstantNameSniff::CodeClassConstantNotMatchPattern, + ]; + $possibleLines = array_keys($errorTypesPerLine); + + $errors = $file->getErrors(); + foreach ($errors as $line => $error) { + self::assertContains($line, $possibleLines, json_encode($error, JSON_THROW_ON_ERROR)); + + $errorType = $errorTypesPerLine[$line]; + + self::assertSniffError($file, $line, $errorType); + } + + self::assertSame(count($errorTypesPerLine), $file->getErrorCount()); + } } diff --git a/tests/Sniffs/NamingConventions/data/ValidConstantNameWithTypeTest.inc b/tests/Sniffs/NamingConventions/data/ValidConstantNameWithTypeTest.inc new file mode 100644 index 0000000..e3f638e --- /dev/null +++ b/tests/Sniffs/NamingConventions/data/ValidConstantNameWithTypeTest.inc @@ -0,0 +1,7 @@ +