diff --git a/Universal/Sniffs/Classes/RequireFinalClassSniff.php b/Universal/Sniffs/Classes/RequireFinalClassSniff.php index 5477a6b5..ed3b3ab9 100644 --- a/Universal/Sniffs/Classes/RequireFinalClassSniff.php +++ b/Universal/Sniffs/Classes/RequireFinalClassSniff.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\GetTokensAsString; use PHPCSUtils\Utils\ObjectDeclarations; @@ -73,18 +74,27 @@ public function process(File $phpcsFile, $stackPtr) $phpcsFile->recordMetric($stackPtr, self::METRIC_NAME, 'not abstract, not final'); - $tokens = $phpcsFile->getTokens(); - if (isset($tokens[$stackPtr]['scope_opener']) === false) { + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($nextNonEmpty === false) { // Live coding or parse error. return; } - $snippet = GetTokensAsString::compact($phpcsFile, $stackPtr, $tokens[$stackPtr]['scope_opener'], true); + $snippetEnd = $nextNonEmpty; + $classCloser = ''; + + $tokens = $phpcsFile->getTokens(); + if (isset($tokens[$stackPtr]['scope_opener']) === true) { + $snippetEnd = $tokens[$stackPtr]['scope_opener']; + $classCloser = '}'; + } + + $snippet = GetTokensAsString::compact($phpcsFile, $stackPtr, $snippetEnd, true); $fix = $phpcsFile->addFixableError( - 'A non-abstract class should be declared as final. Found: %s}', + 'A non-abstract class should be declared as final. Found: %s%s', $stackPtr, 'NonFinalClassFound', - [$snippet] + [$snippet, $classCloser] ); if ($fix === true) { diff --git a/Universal/Tests/Classes/RequireFinalClassUnitTest.inc b/Universal/Tests/Classes/RequireFinalClassUnitTest.inc index fea17339..1a8d3be7 100644 --- a/Universal/Tests/Classes/RequireFinalClassUnitTest.inc +++ b/Universal/Tests/Classes/RequireFinalClassUnitTest.inc @@ -29,5 +29,8 @@ class ClassImplementing implements MyInterface {} readonly class ReadonlyClass {} -// Live coding. Ignore. This must be the last test in the file. +// Live coding/parse error, but not one which concerns us. Add the final keyword. class LiveCoding + +// Live coding. Ignore. This must be the last test in the file. +class diff --git a/Universal/Tests/Classes/RequireFinalClassUnitTest.inc.fixed b/Universal/Tests/Classes/RequireFinalClassUnitTest.inc.fixed index c489d9d9..8878d41d 100644 --- a/Universal/Tests/Classes/RequireFinalClassUnitTest.inc.fixed +++ b/Universal/Tests/Classes/RequireFinalClassUnitTest.inc.fixed @@ -29,5 +29,8 @@ final class ClassImplementing implements MyInterface {} readonly final class ReadonlyClass {} +// Live coding/parse error, but not one which concerns us. Add the final keyword. +final class LiveCoding + // Live coding. Ignore. This must be the last test in the file. -class LiveCoding +class diff --git a/Universal/Tests/Classes/RequireFinalClassUnitTest.php b/Universal/Tests/Classes/RequireFinalClassUnitTest.php index 007b9e10..386e0786 100644 --- a/Universal/Tests/Classes/RequireFinalClassUnitTest.php +++ b/Universal/Tests/Classes/RequireFinalClassUnitTest.php @@ -34,6 +34,7 @@ public function getErrorList() 26 => 1, 28 => 1, 30 => 1, + 33 => 1, ]; }