diff --git a/WordPress/Sniffs/Functions/ReturnTypeSniff.php b/WordPress/Sniffs/Functions/ReturnTypeSniff.php new file mode 100644 index 0000000000..4f99bbae56 --- /dev/null +++ b/WordPress/Sniffs/Functions/ReturnTypeSniff.php @@ -0,0 +1,140 @@ +phpcsFile->findPrevious( T_COLON, $stackPtr - 1 ); + + // Space before colon disallowed. + if ( T_CLOSE_PARENTHESIS !== $this->tokens[ $colon - 1 ]['code'] ) { + $error = 'There must be no space before colon before a return type.'; + $fix = $this->phpcsFile->addFixableError( $error, $colon - 1, 'SpaceBeforeColon' ); + + if ( true === $fix ) { + $this->phpcsFile->fixer->beginChangeset(); + $token = $colon - 1; + do { + $this->phpcsFile->fixer->replaceToken( $token, '' ); + -- $token; + } while ( T_CLOSE_PARENTHESIS !== $this->tokens[ $token ]['code'] ); + $this->phpcsFile->fixer->endChangeset(); + } + } + + // Only one space after colon. + if ( T_WHITESPACE !== $this->tokens[ $colon + 1 ]['code'] ) { + $error = 'There must be a space after colon and before return type declaration.'; + $fix = $this->phpcsFile->addFixableError( $error, $colon, 'NoSpaceAfterColon' ); + if ( true === $fix ) { + $this->phpcsFile->fixer->addContent( $colon, ' ' ); + } + } elseif ( ' ' !== $this->tokens[ $colon + 1 ]['content'] ) { + $error = 'There must be exactly one space after colon and before return type declaration.'; + $fix = $this->phpcsFile->addFixableError( $error, $colon + 1, 'TooManySpacesAfterColon' ); + if ( true === $fix ) { + $this->phpcsFile->fixer->replaceToken( $colon + 1, ' ' ); + } + } + + $nullable = $this->phpcsFile->findNext( T_NULLABLE, $colon + 1, $stackPtr ); + if ( $nullable ) { + // Check if there is space after nullable operator. + if ( T_WHITESPACE === $this->tokens[ $nullable + 1 ]['code'] ) { + $error = 'Space is not not allowed after nullable operator.'; + $fix = $this->phpcsFile->addFixableError( $error, $nullable + 1, 'SpaceAfterNullable' ); + if ( $fix ) { + $this->phpcsFile->fixer->replaceToken( $nullable + 1, '' ); + } + } + } + + $first = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $nullable ?: $colon ) + 1, null, true ); + $end = $this->phpcsFile->findNext( [ T_SEMICOLON, T_OPEN_CURLY_BRACKET ], $stackPtr + 1 ); + $last = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $end - 1, null, true ); + $invalid = $this->phpcsFile->findNext( [ T_STRING, T_NS_SEPARATOR, T_RETURN_TYPE ], $first, $last + 1, true ); + if ( $invalid ) { + $error = 'Return type declaration contains invalid token %s'; + $data = array( $this->tokens[ $invalid ]['type'] ); + $fix = $this->phpcsFile->addFixableError( $error, $invalid, 'InvalidToken', $data ); + if ( true === $fix ) { + $this->phpcsFile->fixer->replaceToken( $invalid, '' ); + } + + return; + } + + $returnType = trim( $this->phpcsFile->getTokensAsString( $first, $last - $first + 1 ) ); + + if ( $first === $last + && in_array( strtolower( $returnType ), $this->simple_return_types, true ) + && ! in_array( $returnType, $this->simple_return_types, true ) + ) { + $error = 'Simple return type must be lowercase. Found "%s", expected "%s"'; + $data = array( + $returnType, + strtolower( $returnType ), + ); + $fix = $this->phpcsFile->addFixableError( $error, $first, 'LowerCaseSimpleType', $data ); + if ( true === $fix ) { + $this->phpcsFile->fixer->replaceToken( $stackPtr, strtolower( $returnType ) ); + } + } + } +} diff --git a/WordPress/Tests/Functions/ReturnTypeUnitTest.inc b/WordPress/Tests/Functions/ReturnTypeUnitTest.inc new file mode 100644 index 0000000000..7f9867ea18 --- /dev/null +++ b/WordPress/Tests/Functions/ReturnTypeUnitTest.inc @@ -0,0 +1,84 @@ + => + */ + public function getErrorList() { + return array( + 4 => 1, + 5 => 1, + 6 => 1, + 8 => 1, + 9 => 1, + 10 => 1, + 29 => 2, + 38 => 1, + 44 => 2, + 52 => 2, + 57 => 2, + 58 => 2, + 59 => 2, + 60 => 3, + 61 => 3, + 62 => 2, + 63 => 1, + 64 => 2, + 65 => 1, + 66 => 2, + 67 => 1, + 68 => 2, + 69 => 1, + 70 => 2, + 71 => 1, + 72 => 2, + 73 => 1, + 74 => 2, + 75 => 1, + 76 => 2, + 77 => 1, + 79 => 2, + 80 => 1, + 82 => 1, + 83 => 3, + ); + } + + /** + * Returns the lines where warnings should occur. + * + * @return array => + */ + public function getWarningList() { + return array(); + + } + +}