From ad8be34ec1744d64997c6e46cdc82b83ecac1bf6 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Sat, 23 Mar 2024 13:49:57 +0800 Subject: [PATCH] Add sniff to check for first line descriptions (#134) --- .../Commenting/DocblockDescriptionSniff.php | 102 ++++++++++++++++++ .../DocblockDescriptionSniffTest.php | 90 ++++++++++++++++ .../no_description_in_file.php | 12 +++ .../DocblockDescription/no_file_docblock.php | 10 ++ .../fixtures/DocblockDescription/standard.php | 60 +++++++++++ 5 files changed, 274 insertions(+) create mode 100644 moodle/Sniffs/Commenting/DocblockDescriptionSniff.php create mode 100644 moodle/Tests/Sniffs/Commenting/DocblockDescriptionSniffTest.php create mode 100644 moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/no_description_in_file.php create mode 100644 moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/no_file_docblock.php create mode 100644 moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/standard.php diff --git a/moodle/Sniffs/Commenting/DocblockDescriptionSniff.php b/moodle/Sniffs/Commenting/DocblockDescriptionSniff.php new file mode 100644 index 0000000..330a87c --- /dev/null +++ b/moodle/Sniffs/Commenting/DocblockDescriptionSniff.php @@ -0,0 +1,102 @@ +. + +namespace MoodleHQ\MoodleCS\moodle\Sniffs\Commenting; + +use MoodleHQ\MoodleCS\moodle\Util\Docblocks; +use MoodleHQ\MoodleCS\moodle\Util\TokenUtil; +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Checks that all docblocks for a main scope have a simple description. + * + * This is typically a one-line description. + * + * @copyright 2024 Andrew Lyons + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class DocblockDescriptionSniff implements Sniff +{ + /** + * Register for open tag (only process once per file). + */ + public function register() { + return [ + T_OPEN_TAG, + ]; + } + + /** + * Processes php files and perform various checks with file. + * + * @param File $phpcsFile The file being scanned. + * @param int $stackPtr The position in the stack. + */ + public function process(File $phpcsFile, $stackPtr) { + $tokens = $phpcsFile->getTokens(); + $toCheck = []; + + $docblockPtr = Docblocks::getDocBlockPointer($phpcsFile, $stackPtr); + if ($docblockPtr !== null) { + $toCheck[$stackPtr] = $docblockPtr; + } + $find = Tokens::$ooScopeTokens; + $find[T_FUNCTION] = T_FUNCTION; + + $typePtr = $stackPtr + 1; + while ($typePtr = $phpcsFile->findNext($find, $typePtr + 1)) { + $docblockPtr = Docblocks::getDocBlockPointer($phpcsFile, $typePtr); + if ($docblockPtr === null) { + // Other sniffs check for missing blocks. Not my job. + continue; + } + + $toCheck[$typePtr] = $docblockPtr; + } + + foreach ($toCheck as $typePtr => $docblockPtr) { + $docblock = $tokens[$docblockPtr]; + if (count($docblock['comment_tags'])) { + $stopAt = reset($docblock['comment_tags']); + } else { + $stopAt = $docblock['comment_closer']; + } + $faultAtLine = $tokens[$stopAt]['line']; + + // Skip to the next T_DOC_COMMENT_STAR line. We do not accept single line docblocks. + $docblockLinePtr = $docblockPtr; + while ($docblockLinePtr = $phpcsFile->findNext(T_DOC_COMMENT_STAR, $docblockLinePtr + 1, $stopAt)) { + if ($tokens[$docblockLinePtr]['line'] !== $faultAtLine) { + continue 2; + } + break; + } + + $objectName = TokenUtil::getObjectName($phpcsFile, $typePtr); + $objectType = TokenUtil::getObjectType($phpcsFile, $typePtr); + + $phpcsFile->addError( + 'No one-line description found in phpdocs for docblock of %s %s', + $typePtr, + 'Missing', + [$objectType, $objectName] + ); + } + } +} diff --git a/moodle/Tests/Sniffs/Commenting/DocblockDescriptionSniffTest.php b/moodle/Tests/Sniffs/Commenting/DocblockDescriptionSniffTest.php new file mode 100644 index 0000000..b9092f0 --- /dev/null +++ b/moodle/Tests/Sniffs/Commenting/DocblockDescriptionSniffTest.php @@ -0,0 +1,90 @@ +. + +namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Commenting; + +use MoodleHQ\MoodleCS\moodle\Tests\MoodleCSBaseTestCase; +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; + +/** + * Test the MissingDocblockSniff sniff. + * + * @copyright 2024 onwards Andrew Lyons + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + * @covers \MoodleHQ\MoodleCS\moodle\Sniffs\Commenting\DocblockDescriptionSniff + */ +class DocblockDescriptionSniffTest extends MoodleCSBaseTestCase +{ + /** + * @dataProvider fixtureProvider + */ + public function testFixtures( + string $fixture, + ?string $fixtureFilename, + array $errors, + array $warnings + ): void { + $this->setStandard('moodle'); + $this->setSniff('moodle.Commenting.DocblockDescription'); + $this->setFixture(sprintf("%s/fixtures/DocblockDescription/%s.php", __DIR__, $fixture), $fixtureFilename); + $this->setWarnings($warnings); + $this->setErrors($errors); + + $this->verifyCsResults(); + } + + public static function fixtureProvider(): array { + $cases = [ + 'Standard tests' => [ + 'fixture' => 'standard', + 'fixtureFilename' => null, + 'errors' => [ + 22 => 'No one-line description found in phpdocs for docblock of function method_with_param_docblock', + 47 => 'No one-line description found in phpdocs for docblock of class class_with_docblock_but_no_description', + 51 => 'No one-line description found in phpdocs for docblock of interface int_with_docblock_but_no_description', + 55 => 'No one-line description found in phpdocs for docblock of trait trait_with_docblock_but_no_description', + 60 => 'No one-line description found in phpdocs for docblock of ' + . 'function function_with_docblock_but_no_description', + ], + 'warnings' => [ + ], + ], + 'No file docblock' => [ + 'fixture' => 'no_file_docblock', + 'fixtureFilename' => null, + 'errors' => [ + ], + 'warnings' => [ + ], + ], + 'No description for file docblock' => [ + 'fixture' => 'no_description_in_file', + 'fixtureFilename' => null, + 'errors' => [ + 1 => 'No one-line description found in phpdocs for docblock of file no_description_in_file', + ], + 'warnings' => [ + ], + ], + ]; + + return $cases; + } +} diff --git a/moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/no_description_in_file.php b/moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/no_description_in_file.php new file mode 100644 index 0000000..d0f1dee --- /dev/null +++ b/moodle/Tests/Sniffs/Commenting/fixtures/DocblockDescription/no_description_in_file.php @@ -0,0 +1,12 @@ +