Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sniff for 'void' in @return tags #1240

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions WordPress-Docs/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,7 @@
<!-- WP allows @todo's in comments -->
<exclude name="Generic.Commenting.Todo.TaskFound"/>
</rule>

<!-- WP disallows `@return void` outside of the default bundled themes -->
<rule ref="WordPress.Commenting.FunctionComment.NoReturnVoid"/>
</ruleset>
110 changes: 110 additions & 0 deletions WordPress/Sniffs/Commenting/FunctionCommentSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php
/**
* WordPress Coding Standard.
*
* @package WPCS\WordPressCodingStandards
* @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
* @license https://opensource.org/licenses/MIT MIT
*/

namespace WordPress\Sniffs\Commenting;

use WordPress\Sniff;
use PHP_CodeSniffer_Tokens as Tokens;

/**
* Validates function documentation.
*
* @package WPCS\WordPressCodingStandards
*
* @since 0.16.0
*/
class FunctionCommentSniff extends Sniff {

/**
* Registers the tokens that this sniff wants to listen for.
*
* @return array
*/
public function register() {
return array( T_FUNCTION );
}

/**
* Processes this test when one of its tokens is encountered.
*
* @param int $stackPtr The position of the current token in the stack.
* @return int|void Integer stack pointer to skip forward or void to continue
* normal file processing.
*/
public function process_token( $stackPtr ) {
$commentEnd = $this->phpcsFile->findPrevious(
array_merge( Tokens::$methodPrefixes, array( T_WHITESPACE ) ),
( $stackPtr - 1 ),
null,
true
);

if ( T_DOC_COMMENT_CLOSE_TAG !== $this->tokens[ $commentEnd ]['code'] ) {
// Invalid function comment. Handled elsewhere.
return;
}

$commentStart = $this->tokens[ $commentEnd ]['comment_opener'];

$this->process_return( $stackPtr, $commentStart );
}

/**
* Process this function's return comment.
*
* @param int $stackPtr The position of the current token in the stack.
* @param int $commentStart The position in the stack where the comment started.
* @return void
*/
protected function process_return( $stackPtr, $commentStart ) {
$returnTag = null;

foreach ( $this->tokens[ $commentStart ]['comment_tags'] as $tag ) {
if ( '@return' === $this->tokens[ $tag ]['content'] ) {
$returnTag = $tag;
// Multiple return tags are invalid, but flagged elsewhere.
break;
}
}

if ( ! $returnTag ) {
return;
}

$returnCommentPtr = ( $returnTag + 2 );
$returnComment = $this->tokens[ $returnCommentPtr ];

if ( empty( $returnComment['content'] ) || T_DOC_COMMENT_STRING !== $returnComment['code'] ) {
// Invalid return comment. Handled elsewhere.
return;
}

// Extracted from PHP_CodeSniffer\Standards\Squiz\Sniffs\Commenting\FunctionCommentSniff::processReturn().
preg_match( '`^((?:\|?(?:array\([^\)]*\)|[\\\\a-z0-9\[\]]+))*)( .*)?`i', $returnComment['content'], $commentParts );

if ( empty( $commentParts[1] ) ) {
return;
}

$returnTypes = array_unique( explode( '|', $commentParts[1] ) );

/*
* Disallow `@return void`.
* See https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/php/#phpdoc-tags.
*/
if ( array( 'void' ) === $returnTypes ) {
$this->phpcsFile->addError(
'`@return void` should not be used. Omit the `@return` tag instead',
$returnTag,
'NoReturnVoid'
);
}
}

}
51 changes: 51 additions & 0 deletions WordPress/Tests/Commenting/FunctionCommentUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* Function description.
*
* @return void
*/
function with_incorrect_return_void() {
echo 'string';
}

/**
* Function description.
*
* @return void With a comment.
*/
function with_incorrect_return_void_with_comment() {
echo 'string';
}

/**
* Function description.
*/
function with_correct_omitted_return() {
echo 'string';
}

/**
* Function description.
*
* @return string|void
*/
function with_correct_return_void() {
if ( foo() ) {
return 'bar';
}

echo 'baz';
}

/**
* Function description.
*
* @return string|void With a comment.
*/
function with_correct_return_void_with_comment() {
if ( foo() ) {
return 'bar';
}

echo 'baz';
}
44 changes: 44 additions & 0 deletions WordPress/Tests/Commenting/FunctionCommentUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Unit test class for WordPress Coding Standard.
*
* @package WPCS\WordPressCodingStandards
* @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
* @license https://opensource.org/licenses/MIT MIT
*/

namespace WordPress\Tests\Commenting;

use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;

/**
* Unit test class for the NoReturnVoid sniff.
*
* @package WPCS\WordPressCodingStandards
*
* @since 0.16.0
*/
class FunctionCommentUnitTest extends AbstractSniffUnitTest {

/**
* Returns the lines where errors should occur.
*
* @return array <int line number> => <int number of errors>
*/
public function getErrorList() {
return array(
5 => 1,
14 => 1,
);
}

/**
* Returns the lines where warnings should occur.
*
* @return array <int line number> => <int number of warnings>
*/
public function getWarningList() {
return array();
}

} // End class.
5 changes: 4 additions & 1 deletion bin/phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
<exclude name="WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition"/>
</rule>

<rule ref="WordPress-Docs"/>
<rule ref="WordPress-Docs">
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/pull/1240#issuecomment-348019118 -->
<exclude name="WordPress.Commenting.FunctionComment.NoReturnVoid"/>
</rule>

<!-- Enforce PSR1 compatible namespaces. -->
<rule ref="PSR1.Classes.ClassDeclaration"/>
Expand Down