jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/383004 )
Change subject: Validate doc syntax ...................................................................... Validate doc syntax Check for /**, *, */, aligned * and spacing around all of them Added the following checks: - SyntaxOpenTag: Comment open tag must be '/**' - SyntaxDocStar: Comment star must be '*' - SyntaxMultiDocStar: Comment star must be a single '*' - SpacingDocStar: Expected at least %s spaces after doc star; %s found - SpacingDocStarSingleLine: Expected %s spaces after doc star on single line; %s found - SpacingDocTag: Expected %s spaces before %s; %s found - SyntaxAlignedDocStar: Comment star tag not aligned with open tag - SyntaxAlignedDocClose: Comment close tag not aligned with open tag - SyntaxCloseTag: Comment close tag must be '*/' - CloseTagOwnLine: Comment close tag should have own line - SpacingSingleLineCloseTag: Expected %s spaces before close comment tag on single line; %s found Change-Id: I8fe953c1f83b75c9b4f024173c46bc02e6bcc8d4 --- M MediaWiki/Sniffs/Commenting/FunctionCommentSniff.php M MediaWiki/Tests/files/Commenting/commenting_function.php M MediaWiki/Tests/files/Commenting/commenting_function.php.expect M MediaWiki/Tests/files/Commenting/commenting_function.php.fixed 4 files changed, 409 insertions(+), 3 deletions(-) Approvals: Legoktm: Looks good to me, approved jenkins-bot: Verified diff --git a/MediaWiki/Sniffs/Commenting/FunctionCommentSniff.php b/MediaWiki/Sniffs/Commenting/FunctionCommentSniff.php index 8bd2db2..0debd9e 100644 --- a/MediaWiki/Sniffs/Commenting/FunctionCommentSniff.php +++ b/MediaWiki/Sniffs/Commenting/FunctionCommentSniff.php @@ -159,6 +159,9 @@ $skipDoc = true; } } + + $this->validateDocSyntax( $phpcsFile, $stackPtr, $commentStart, $commentEnd ); + if ( $skipDoc ) { // Don't need to validate anything else return; @@ -665,5 +668,251 @@ $content .= $fixParam['comment_first']; $phpcsFile->fixer->replaceToken( ( $fixParam['tag'] + 2 ), $content ); } + + /** + * Check the doc syntax like start or end tags + * + * @param File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the stack passed in $tokens. + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function validateDocSyntax( File $phpcsFile, $stackPtr, $commentStart, $commentEnd ) { + $tokens = $phpcsFile->getTokens(); + $isMultiLineDoc = ( $tokens[$commentStart]['line'] !== $tokens[$commentEnd]['line'] ); + + // Start token should exact /** + if ( $tokens[$commentStart]['code'] === T_DOC_COMMENT_OPEN_TAG && + $tokens[$commentStart]['content'] !== '/**' + ) { + $error = 'Comment open tag must be \'/**\''; + $fix = $phpcsFile->addFixableError( $error, $commentStart, 'SyntaxOpenTag' ); + if ( $fix === true ) { + $phpcsFile->fixer->replaceToken( $commentStart, '/**' ); + } + } + // Calculate the column to align all doc stars. Use column of /**, add 1 to skip char / + $columnDocStar = $tokens[$commentStart]['column'] + 1; + $prevLineDocStar = $tokens[$commentStart]['line']; + + for ( $i = $commentStart; $i <= $commentEnd; $i++ ) { + $initialStarChars = 0; + + // Star token should exact * + if ( $tokens[$i]['code'] === T_DOC_COMMENT_STAR ) { + if ( $tokens[$i]['content'] !== '*' ) { + $error = 'Comment star must be \'*\''; + $fix = $phpcsFile->addFixableError( $error, $i, 'SyntaxDocStar' ); + if ( $fix === true ) { + $phpcsFile->fixer->replaceToken( $i, '*' ); + } + } + // Multi stars in a line are parsed as a new token + $initialStarChars = strspn( $tokens[$i + 1]['content'], '*' ); + if ( $initialStarChars > 0 ) { + $error = 'Comment star must be a single \'*\''; + $fix = $phpcsFile->addFixableError( $error, $i, 'SyntaxMultiDocStar' ); + if ( $fix === true ) { + $phpcsFile->fixer->replaceToken( + $i + 1, + substr( $tokens[$i + 1]['content'], $initialStarChars ) + ); + } + } + } + + // Ensure whitespace after /** or * + if ( ( $tokens[$i]['code'] === T_DOC_COMMENT_OPEN_TAG || + $tokens[$i]['code'] === T_DOC_COMMENT_STAR ) && + $tokens[$i + 1]['length'] > 0 + ) { + $commentStarSpacing = $i + 1; + $expectedSpaces = 1; + $currentSpaces = 0; + // ignore * removed by SyntaxMultiDocStar and count spaces after that + $currentSpaces = strspn( + $tokens[$commentStarSpacing]['content'], ' ', $initialStarChars + ); + $error = null; + $code = null; + if ( $isMultiLineDoc && $currentSpaces < $expectedSpaces ) { + // be relax for multiline docs, because some line breaks in @param can + // have more than one space after a doc star + $error = 'Expected at least %s spaces after doc star; %s found'; + $code = 'SpacingDocStar'; + } elseif ( !$isMultiLineDoc && $currentSpaces !== $expectedSpaces ) { + $error = 'Expected %s spaces after doc star on single line; %s found'; + $code = 'SpacingDocStarSingleLine'; + } + if ( $error !== null && $code !== null ) { + $data = [ + $expectedSpaces, + $currentSpaces, + ]; + $fix = $phpcsFile->addFixableError( + $error, + $commentStarSpacing, + $code, + $data + ); + if ( $fix ) { + if ( $currentSpaces > $expectedSpaces ) { + // Remove whitespace + $content = $tokens[$commentStarSpacing]['content']; + $phpcsFile->fixer->replaceToken( + $commentStarSpacing, + substr( $content, 0, $expectedSpaces - $currentSpaces ) + ); + } else { + // Add whitespace + $phpcsFile->fixer->addContent( + $i, str_repeat( ' ', $expectedSpaces ) + ); + } + } + } + } + + // Ensure one whitespace before @param/@return + if ( $isMultiLineDoc && $tokens[$i]['code'] === T_DOC_COMMENT_TAG && + $tokens[$i]['line'] === $tokens[$i - 1]['line'] + ) { + $commentTagSpacing = $i - 1; + $expectedSpaces = 1; + $currentSpaces = strspn( strrev( $tokens[$commentTagSpacing]['content'] ), ' ' ); + if ( $expectedSpaces !== $currentSpaces ) { + $data = [ + $expectedSpaces, + $tokens[$i]['content'], + $currentSpaces, + ]; + $fix = $phpcsFile->addFixableError( + 'Expected %s spaces before %s; %s found', + $commentTagSpacing, + 'SpacingDocTag', + $data + ); + if ( $fix ) { + if ( $currentSpaces > $expectedSpaces ) { + // Remove whitespace + $content = $tokens[$commentTagSpacing]['content']; + $phpcsFile->fixer->replaceToken( + $commentTagSpacing, + substr( $content, 0, $expectedSpaces - $currentSpaces ) + ); + } else { + // Add whitespace + $phpcsFile->fixer->addContentBefore( + $i, str_repeat( ' ', $expectedSpaces ) + ); + } + } + } + } + + // Ensure aligned * or */ for multiline comments + if ( $isMultiLineDoc && ( $tokens[$i]['code'] === T_DOC_COMMENT_STAR || + $tokens[$i]['code'] === T_DOC_COMMENT_CLOSE_TAG ) && + $tokens[$i]['column'] !== $columnDocStar && + $tokens[$i]['line'] !== $prevLineDocStar + ) { + if ( $tokens[$i]['code'] === T_DOC_COMMENT_STAR ) { + $error = 'Comment star tag not aligned with open tag'; + $code = 'SyntaxAlignedDocStar'; + } else { + $error = 'Comment close tag not aligned with open tag'; + $code = 'SyntaxAlignedDocClose'; + } + $fix = $phpcsFile->addFixableError( $error, $i, $code ); + if ( $fix === true ) { + $columnOff = $columnDocStar - $tokens[$i]['column']; + if ( $columnOff < 0 ) { + $tokenBefore = $i - 1; + // Ensure to remove only whitespaces + if ( $tokens[$tokenBefore]['code'] === T_DOC_COMMENT_WHITESPACE ) { + $columnOff = max( $columnOff, $tokens[$tokenBefore]['length'] * -1 ); + // remove whitespaces + $phpcsFile->fixer->replaceToken( + $tokenBefore, + substr( $tokens[$tokenBefore]['content'], 0, $columnOff ) + ); + } + } else { + // Add whitespaces + $phpcsFile->fixer->addContentBefore( $i, str_repeat( ' ', $columnOff ) ); + } + } + $prevLineDocStar = $tokens[$i]['line']; + } + } + + // End token should exact */ + if ( $tokens[$commentEnd]['code'] === T_DOC_COMMENT_CLOSE_TAG && + $tokens[$commentEnd]['content'] !== '*/' + ) { + $error = 'Comment close tag must be \'*/\''; + $fix = $phpcsFile->addFixableError( $error, $commentEnd, 'SyntaxCloseTag' ); + if ( $fix === true ) { + $phpcsFile->fixer->replaceToken( $commentEnd, '*/' ); + } + } + + // For multi line comments the closing tag must have it own line + if ( $isMultiLineDoc ) { + $prev = $commentEnd - 1; + $prevNonWhitespace = $phpcsFile->findPrevious( + [ T_DOC_COMMENT_WHITESPACE ], $prev, null, true + ); + if ( $tokens[$prevNonWhitespace]['line'] === $tokens[$commentEnd]['line'] ) { + $firstWhitespaceOnLine = $phpcsFile->findFirstOnLine( + [ T_DOC_COMMENT_WHITESPACE ], $prevNonWhitespace + ); + $error = 'Comment close tag should have own line'; + $fix = $phpcsFile->addFixableError( $error, $commentEnd, 'CloseTagOwnLine' ); + if ( $fix === true ) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addNewline( $prev ); + // Copy the indent of the previous line to the new line + $phpcsFile->fixer->addContent( + $prev, $tokens[$firstWhitespaceOnLine]['content'] + ); + $phpcsFile->fixer->endChangeset(); + } + } + } else { + // Ensure a whitespace before the token + $commentCloseSpacing = $commentEnd - 1; + $expectedSpaces = 1; + $currentSpaces = strspn( strrev( $tokens[$commentCloseSpacing]['content'] ), ' ' ); + if ( $currentSpaces !== $expectedSpaces ) { + $data = [ + $expectedSpaces, + $currentSpaces, + ]; + $fix = $phpcsFile->addFixableError( + 'Expected %s spaces before close comment tag on single line; %s found', + $commentCloseSpacing, + 'SpacingSingleLineCloseTag', + $data + ); + if ( $fix ) { + if ( $currentSpaces > $expectedSpaces ) { + // Remove whitespace + $content = $tokens[$commentCloseSpacing]['content']; + $phpcsFile->fixer->replaceToken( + $commentCloseSpacing, substr( $content, 0, $expectedSpaces - $currentSpaces ) + ); + } else { + // Add whitespace + $phpcsFile->fixer->addContentBefore( + $commentEnd, str_repeat( ' ', $expectedSpaces ) + ); + } + } + } + } + } } // end class diff --git a/MediaWiki/Tests/files/Commenting/commenting_function.php b/MediaWiki/Tests/files/Commenting/commenting_function.php index ffa889a..a09fd43 100644 --- a/MediaWiki/Tests/files/Commenting/commenting_function.php +++ b/MediaWiki/Tests/files/Commenting/commenting_function.php @@ -125,6 +125,49 @@ public function testDeprecated( $stuff, $more, $blah ) { $blah = $more . $stuff . $blah; } + + /** + * Some text + * + * And other test + */ + public function testStarAlignedDoc() { + } + + /***SomeTextWithoutSpaces + *** + ***AndNoSpacesHere + ***/ + public function testSyntaxDoc() { + } + + /*** NoSpaceHere + *** + *** AndHere + ***/ + public function testVerySpacyDoc() { + } + + /***SingleLineNoSpaceHere***/ + public function testSpacingDocSingleLine() { + } + + /** SingleLineSpacy */ + public function testSpacingDocSingleLineSpacy() { + } + + /*** + *NewLineNoSpaceHere***/ + public function testCloseTagOwnLine() { + } + + /** Comment + *@param string $a A comment + * @return string A comment + */ + public function testSyntaxDocTag( $a ) { + return $a; + } } class TestPassedExamples { diff --git a/MediaWiki/Tests/files/Commenting/commenting_function.php.expect b/MediaWiki/Tests/files/Commenting/commenting_function.php.expect index a140814..94b65e6 100644 --- a/MediaWiki/Tests/files/Commenting/commenting_function.php.expect +++ b/MediaWiki/Tests/files/Commenting/commenting_function.php.expect @@ -83,8 +83,78 @@ | | (MediaWiki.Commenting.FunctionComment.NotPunctuationReturn) 116 | ERROR | [x] Incorrect capitalization of @inheritDoc | | (MediaWiki.Commenting.FunctionComment.LowercaseInheritDoc) - 130 | ERROR | [ ] Only one class is allowed in a file + 130 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 131 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 132 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 133 | ERROR | [x] Comment close tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocClose) + 137 | ERROR | [x] Comment open tag must be '/**' + | | (MediaWiki.Commenting.FunctionComment.SyntaxOpenTag) + 137 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 138 | ERROR | [x] Comment star must be a single '*' + | | (MediaWiki.Commenting.FunctionComment.SyntaxMultiDocStar) + 138 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 138 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 139 | ERROR | [x] Comment star must be a single '*' + | | (MediaWiki.Commenting.FunctionComment.SyntaxMultiDocStar) + 139 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 139 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 140 | ERROR | [x] Comment close tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocClose) + 140 | ERROR | [x] Comment close tag must be '*/' + | | (MediaWiki.Commenting.FunctionComment.SyntaxCloseTag) + 144 | ERROR | [x] Comment open tag must be '/**' + | | (MediaWiki.Commenting.FunctionComment.SyntaxOpenTag) + 145 | ERROR | [x] Comment star must be a single '*' + | | (MediaWiki.Commenting.FunctionComment.SyntaxMultiDocStar) + 145 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 146 | ERROR | [x] Comment star must be a single '*' + | | (MediaWiki.Commenting.FunctionComment.SyntaxMultiDocStar) + 147 | ERROR | [x] Comment close tag must be '*/' + | | (MediaWiki.Commenting.FunctionComment.SyntaxCloseTag) + 151 | ERROR | [x] Comment open tag must be '/**' + | | (MediaWiki.Commenting.FunctionComment.SyntaxOpenTag) + 151 | ERROR | [x] Expected 1 spaces after doc star on single line; 0 + | | found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStarSingleLine) + 151 | ERROR | [x] Expected 1 spaces before close comment tag on single + | | line; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingSingleLineCloseTag) + 151 | ERROR | [x] Comment close tag must be '*/' + | | (MediaWiki.Commenting.FunctionComment.SyntaxCloseTag) + 155 | ERROR | [x] Expected 1 spaces after doc star on single line; 3 + | | found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStarSingleLine) + 155 | ERROR | [x] Expected 1 spaces before close comment tag on single + | | line; 2 found + | | (MediaWiki.Commenting.FunctionComment.SpacingSingleLineCloseTag) + 159 | ERROR | [x] Comment open tag must be '/**' + | | (MediaWiki.Commenting.FunctionComment.SyntaxOpenTag) + 160 | ERROR | [x] Comment star tag not aligned with open tag + | | (MediaWiki.Commenting.FunctionComment.SyntaxAlignedDocStar) + 160 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 160 | ERROR | [x] Comment close tag must be '*/' + | | (MediaWiki.Commenting.FunctionComment.SyntaxCloseTag) + 160 | ERROR | [x] Comment close tag should have own line + | | (MediaWiki.Commenting.FunctionComment.CloseTagOwnLine) + 165 | ERROR | [x] Expected 1 spaces before @param; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocTag) + 165 | ERROR | [x] Expected at least 1 spaces after doc star; 0 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocStar) + 166 | ERROR | [x] Expected 1 spaces before @return; 2 found + | | (MediaWiki.Commenting.FunctionComment.SpacingDocTag) + 173 | ERROR | [ ] Only one class is allowed in a file | | (MediaWiki.Files.OneClassPerFile.MultipleFound) - 197 | ERROR | [ ] Only one class is allowed in a file + 240 | ERROR | [ ] Only one class is allowed in a file | | (MediaWiki.Files.OneClassPerFile.MultipleFound) -PHPCBF CAN FIX THE 32 MARKED SNIFF VIOLATIONS AUTOMATICALLY +PHPCBF CAN FIX THE 65 MARKED SNIFF VIOLATIONS AUTOMATICALLY diff --git a/MediaWiki/Tests/files/Commenting/commenting_function.php.fixed b/MediaWiki/Tests/files/Commenting/commenting_function.php.fixed index cdd105c..2f4a517 100644 --- a/MediaWiki/Tests/files/Commenting/commenting_function.php.fixed +++ b/MediaWiki/Tests/files/Commenting/commenting_function.php.fixed @@ -125,6 +125,50 @@ public function testDeprecated( $stuff, $more, $blah ) { $blah = $more . $stuff . $blah; } + + /** + * Some text + * + * And other test + */ + public function testStarAlignedDoc() { + } + + /** SomeTextWithoutSpaces + * + * AndNoSpacesHere + */ + public function testSyntaxDoc() { + } + + /** NoSpaceHere + * + * AndHere + */ + public function testVerySpacyDoc() { + } + + /** SingleLineNoSpaceHere */ + public function testSpacingDocSingleLine() { + } + + /** SingleLineSpacy */ + public function testSpacingDocSingleLineSpacy() { + } + + /** + * NewLineNoSpaceHere + */ + public function testCloseTagOwnLine() { + } + + /** Comment + * @param string $a A comment + * @return string A comment + */ + public function testSyntaxDocTag( $a ) { + return $a; + } } class TestPassedExamples { -- To view, visit https://gerrit.wikimedia.org/r/383004 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8fe953c1f83b75c9b4f024173c46bc02e6bcc8d4 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/tools/codesniffer Gerrit-Branch: master Gerrit-Owner: Umherirrender <umherirrender_de...@web.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Legoktm <lego...@member.fsf.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits