Ongr/Sniffs/Commenting/FunctionCommentSniff.php
protected function processReturn(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
    {
        $tokens = $phpcsFile->getTokens();

        // Skip constructor and destructor.
        $methodName      = $phpcsFile->getDeclarationName($stackPtr);
        $isSpecialMethod = ($methodName === '__construct' || $methodName === '__destruct');

        $return = null;
        foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
            if ($tokens[$tag]['content'] === '@return') {
                if ($return !== null) {
                    $error = 'Only 1 @return tag is allowed in a function comment';
                    $phpcsFile->addError($error, $tag, 'DuplicateReturn');
                    return;
                }

                $return = $tag;
            }
        }

        if ($isSpecialMethod === true) {
            return;
        }


        if ($return !== null) {
            $content = $tokens[($return + 2)]['content'];
            if (empty($content) === true || $tokens[($return + 2)]['code'] !== T_DOC_COMMENT_STRING) {
                $error = 'Return type missing for @return tag in function comment';
                $phpcsFile->addError($error, $return, 'MissingReturnType');
            } else {
                // Check return type (can be multiple, separated by '|').
                $typeNames      = explode('|', $content);
                $suggestedNames = array();
                foreach ($typeNames as $i => $typeName) {
                    $suggestedName = PHP_CodeSniffer::suggestType($typeName);
                    if ($suggestedName === 'boolean') {
                        $suggestedName = 'bool';
                    } elseif ($suggestedName === 'integer') {
                        $suggestedName = 'int';
                    }
                    if (in_array($suggestedName, $suggestedNames) === false) {
                        $suggestedNames[] = $suggestedName;
                    }
                }
                $suggestedType = implode('|', $suggestedNames);
                if ($content !== $suggestedType) {
                    $error = 'Function return type "%s" is invalid';
                    $data = [$content];
                    $phpcsFile->addError($error, $return, 'InvalidReturn', $data);
                }

                // If the return type is void, make sure there is
                // no return statement in the function.
                if ($content === 'void') {
                    if (isset($tokens[$stackPtr]['scope_closer']) === true) {
                        $endToken = $tokens[$stackPtr]['scope_closer'];
                        for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) {
                            if ($tokens[$returnToken]['code'] === T_CLOSURE) {
                                $returnToken = $tokens[$returnToken]['scope_closer'];
                                continue;
                            }

                            if ($tokens[$returnToken]['code'] === T_RETURN) {
                                break;
                            }
                        }

                        if ($returnToken !== $endToken) {
                            // If the function is not returning anything, just
                            // exiting, then there is no problem.
                            $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
                            if ($tokens[$semicolon]['code'] !== T_SEMICOLON) {
                                $error = 'Function return type is void, but function contains return statement';
                                $phpcsFile->addError($error, $return, 'InvalidReturnVoid');
                            }
                        }
                    }//end if
                } else if ($content !== 'mixed') {
                    // If return type is not void, there needs to be a return statement
                    // somewhere in the function that returns something.
                    if (isset($tokens[$stackPtr]['scope_closer']) === true) {
                        $endToken    = $tokens[$stackPtr]['scope_closer'];
                        $returnToken = $phpcsFile->findNext(T_RETURN, $stackPtr, $endToken);
                        if ($returnToken === false) {
                            $error = 'Function return type is not void, but function has no return statement';
                            $phpcsFile->addError($error, $return, 'InvalidNoReturn');
                        } else {
                            $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
                            if ($tokens[$semicolon]['code'] === T_SEMICOLON) {
                                $error = 'Function return type is not void, but function is returning void here';
                                $phpcsFile->addError($error, $returnToken, 'InvalidReturnNotVoid');
                            }
                        }
                    }
                }//end if

                $comment = null;
                if ($tokens[($return + 2)]['code'] === T_DOC_COMMENT_STRING) {
                    $matches = array();
                    preg_match('/([^\s]+)(?:\s+(.+))?/', $tokens[($return + 2)]['content'], $matches);
                    if (isset($matches[2]) === true) {
                        $comment = $matches[2];
                    }
                }

                //ONGR Validate that return comment begins with capital letter and ends with full stop.
                if ($comment !== null) {
                    if (!preg_match('/^\\p{Lu}/u', $comment)) {
                        $error = 'Return comment must start with a capital letter';
                        $fix = $phpcsFile->addFixableError($error, ($return + 2), 'ReturnCommentNotCapital');

                        if ($fix === true) {
                            $newComment = ucfirst($comment);
                            $tokenLength = strlen($tokens[($return + 2)]['content']);
                            $commentLength = strlen($comment);
                            $tokenWithoutComment
                                = substr($tokens[($return + 2)]['content'], 0, $tokenLength - $commentLength);

                            $phpcsFile->fixer->replaceToken(($return + 2), $tokenWithoutComment . $newComment);
                        }
                    }

                    if (!preg_match('/\\.$/u', $comment)) {
                        $error = 'Return comment must end with a full stop';
                        $fix = $phpcsFile->addFixableError($error, ($return + 2), 'ReturnCommentFullStop');

                        if ($fix === true) {
                            $phpcsFile->fixer->addContent(($return + 2), '.');
                        }
                    }
                }
            }//end if
        } else {
            //ONGR Return is not necessary.
//            $error = 'Missing @return tag in function comment';
//            $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
        }//end if

    }
protected function processReturn(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
    {
        $tokens = $phpcsFile->getTokens();

        // Skip constructor and destructor.
        $methodName      = $phpcsFile->getDeclarationName($stackPtr);
        $isSpecialMethod = ($methodName === '__construct' || $methodName === '__destruct');

        $return = null;
        foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
            if ($tokens[$tag]['content'] === '@return') {
                if ($return !== null) {
                    $error = 'Only 1 @return tag is allowed in a function comment';
                    $phpcsFile->addError($error, $tag, 'DuplicateReturn');
                    return;
                }

                $return = $tag;
            }
        }

        if ($isSpecialMethod === true) {
            return;
        }


        if ($return !== null) {
            $content = $tokens[($return + 2)]['content'];
            if (empty($content) === true || $tokens[($return + 2)]['code'] !== T_DOC_COMMENT_STRING) {
                $error = 'Return type missing for @return tag in function comment';
                $phpcsFile->addError($error, $return, 'MissingReturnType');
            } else {
                // Check return type (can be multiple, separated by '|').
                $typeNames      = explode('|', $content);
                $suggestedNames = array();
                foreach ($typeNames as $i => $typeName) {
                    $suggestedName = PHP_CodeSniffer::suggestType($typeName);
                    if ($suggestedName === 'boolean') {
                        $suggestedName = 'bool';
                    } elseif ($suggestedName === 'integer') {
                        $suggestedName = 'int';
                    }
                    if (in_array($suggestedName, $suggestedNames) === false) {
                        $suggestedNames[] = $suggestedName;
                    }
                }
                $suggestedType = implode('|', $suggestedNames);
                if ($content !== $suggestedType) {
                    $error = 'Function return type "%s" is invalid';
                    $data = [$content];
                    $phpcsFile->addError($error, $return, 'InvalidReturn', $data);
                }

                // If the return type is void, make sure there is
                // no return statement in the function.
                if ($content === 'void') {
                    if (isset($tokens[$stackPtr]['scope_closer']) === true) {
                        $endToken = $tokens[$stackPtr]['scope_closer'];
                        for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) {
                            if ($tokens[$returnToken]['code'] === T_CLOSURE) {
                                $returnToken = $tokens[$returnToken]['scope_closer'];
                                continue;
                            }

                            if ($tokens[$returnToken]['code'] === T_RETURN) {
                                break;
                            }
                        }

                        if ($returnToken !== $endToken) {
                            // If the function is not returning anything, just
                            // exiting, then there is no problem.
                            $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
                            if ($tokens[$semicolon]['code'] !== T_SEMICOLON) {
                                $error = 'Function return type is void, but function contains return statement';
                                $phpcsFile->addError($error, $return, 'InvalidReturnVoid');
                            }
                        }
                    }//end if
                } else if ($content !== 'mixed') {
                    // If return type is not void, there needs to be a return statement
                    // somewhere in the function that returns something.
                    if (isset($tokens[$stackPtr]['scope_closer']) === true) {
                        $endToken    = $tokens[$stackPtr]['scope_closer'];
                        $returnToken = $phpcsFile->findNext(T_RETURN, $stackPtr, $endToken);
                        if ($returnToken === false) {
                            $error = 'Function return type is not void, but function has no return statement';
                            $phpcsFile->addError($error, $return, 'InvalidNoReturn');
                        } else {
                            $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
                            if ($tokens[$semicolon]['code'] === T_SEMICOLON) {
                                $error = 'Function return type is not void, but function is returning void here';
                                $phpcsFile->addError($error, $returnToken, 'InvalidReturnNotVoid');
                            }
                        }
                    }
                }//end if

                $comment = null;
                if ($tokens[($return + 2)]['code'] === T_DOC_COMMENT_STRING) {
                    $matches = array();
                    preg_match('/([^\s]+)(?:\s+(.+))?/', $tokens[($return + 2)]['content'], $matches);
                    if (isset($matches[2]) === true) {
                        $comment = $matches[2];
                    }
                }

                //ONGR Validate that return comment begins with capital letter and ends with full stop.
                if ($comment !== null) {
                    if (!preg_match('/^\\p{Lu}/u', $comment)) {
                        $error = 'Return comment must start with a capital letter';
                        $fix = $phpcsFile->addFixableError($error, ($return + 2), 'ReturnCommentNotCapital');

                        if ($fix === true) {
                            $newComment = ucfirst($comment);
                            $tokenLength = strlen($tokens[($return + 2)]['content']);
                            $commentLength = strlen($comment);
                            $tokenWithoutComment
                                = substr($tokens[($return + 2)]['content'], 0, $tokenLength - $commentLength);

                            $phpcsFile->fixer->replaceToken(($return + 2), $tokenWithoutComment . $newComment);
                        }
                    }

                    if (!preg_match('/\\.$/u', $comment)) {
                        $error = 'Return comment must end with a full stop';
                        $fix = $phpcsFile->addFixableError($error, ($return + 2), 'ReturnCommentFullStop');

                        if ($fix === true) {
                            $phpcsFile->fixer->addContent(($return + 2), '.');
                        }
                    }
                }
            }//end if
        } else {
            //ONGR Return is not necessary.
//            $error = 'Missing @return tag in function comment';
//            $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
        }//end if

    }
Process the return comment of this function comment.

@param PHP_CodeSniffer_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.

@return void