<commit_before><?php
/**
 * Ensures type comments follow basic formatting.
 *
 * PHP version 5
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @author   <NAME> <<EMAIL>>
 * @license  https://github.com/aik099/CodingStandard/blob/master/LICENSE BSD 3-Clause
 * @link     https://github.com/aik099/CodingStandard
 */

namespace CodingStandard\Sniffs\Commenting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

/**
 * Ensures type comments follow basic formatting.
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @author   <NAME> <<EMAIL>>
 * @license  https://github.com/aik099/CodingStandard/blob/master/LICENSE BSD 3-Clause
 * @link     https://github.com/aik099/CodingStandard
 */

class TypeCommentSniff implements Sniff
{

    const TYPE_TAG = '@var';

    /**
     * A list of tokenizers this sniff supports.
     *
     * @var array
     */
    public $supportedTokenizers = array('PHP');


    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return array(
                T_COMMENT,
                T_DOC_COMMENT_OPEN_TAG,
               );

    }//end register()


    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token in the
     *                        stack passed in $tokens.
     *
     * @return void
     */
    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();

        if ($tokens[$stackPtr]['code'] === T_COMMENT) {
            $this->processComment($phpcsFile, $stackPtr);
        } else if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_OPEN_TAG) {
            $this->processDocBlock($phpcsFile, $stackPtr);
        }

    }//end process()


    /**
     * Processes comment.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token
     *                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function processComment(File $phpcsFile, $stackPtr)
    {
        $tokens      = $phpcsFile->getTokens();
        $commentText = $tokens[$stackPtr]['content'];

        // Multi-line block comment.
        if (substr($commentText, 0, 2) !== '/*' || substr($commentText, -2) !== '*/') {
            return;
        }

        // Not a type comment.
        if ($this->isTypeComment($commentText) === false) {
            return;
        }

        // The "/**@var ...*/" comment isn't parsed as DocBlock and is fixed here.
        $error = 'Type comment must be in "/** %s ClassName $variable_name */" format';
        $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'WrongStyle', array(self::TYPE_TAG));
        if ($fix === true) {
            $phpcsFile->fixer->replaceToken($stackPtr, '/** '.trim($commentText, ' /*').' */');
        }

    }//end processComment()


    /**
     * Processes DocBlock.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token
     *                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function processDocBlock(File $phpcsFile, $stackPtr)
    {
        $tokens       = $phpcsFile->getTokens();
        $commentStart = $stackPtr;
        $commentEnd   = $tokens[$stackPtr]['comment_closer'];

        // Multi-line DocBlock.
        if ($tokens[$commentEnd]['line'] !== $tokens[$commentStart]['line']) {
            return;
        }

        $commentTags = $tokens[$stackPtr]['comment_tags'];

        // Single-line DocBlock without tags inside.
        if (empty($commentTags) === true) {
            return;
        }

        // First tag will always exist.
        $firstTagPtr = $commentTags[0];

        // Not a type comment.
        if ($this->isTypeComment($tokens[$firstTagPtr]['content']) === false) {
            return;
        }

        $structure = new TypeCommentStructure($phpcsFile, $stackPtr);

        if ($structure->className === null) {
            $error = 'Type comment must be in "/** %s ClassName $variable_name */" format';
            $phpcsFile->addError($error, $firstTagPtr, 'WrongStyle', array(self::TYPE_TAG));

            return;
        }

        $this->processDocBlockContent($phpcsFile, $stackPtr, $structure);
        $this->processVariableAssociation($phpcsFile, $stackPtr, $structure);

    }//end processDocBlock()


    /**
     * Processes DocBlock content.
     *
     * @param File                 $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     * @param TypeCommentStructure $structure Type comment structure.
     *
     * @return void
     */
    public function processDocBlockContent(
        File $phpcsFile,
        $stackPtr,
        TypeCommentStructure $structure
    ) {
        $tokens      = $phpcsFile->getTokens();
        $commentTags = $tokens[$stackPtr]['comment_tags'];
        $firstTagPtr = $commentTags[0];
<commit_msg>Update sniff to support correct (as DocBlock) tokenizing of "/**@var ...*/ comments<commit_after><?php
/**
 * Ensures type comments follow basic formatting.
 *
 * PHP version 5
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @author   <NAME> <<EMAIL>>
 * @license  https://github.com/aik099/CodingStandard/blob/master/LICENSE BSD 3-Clause
 * @link     https://github.com/aik099/CodingStandard
 */

namespace CodingStandard\Sniffs\Commenting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

/**
 * Ensures type comments follow basic formatting.
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @author   <NAME> <<EMAIL>>
 * @license  https://github.com/aik099/CodingStandard/blob/master/LICENSE BSD 3-Clause
 * @link     https://github.com/aik099/CodingStandard
 */

class TypeCommentSniff implements Sniff
{

    const TYPE_TAG = '@var';

    /**
     * A list of tokenizers this sniff supports.
     *
     * @var array
     */
    public $supportedTokenizers = array('PHP');


    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return array(
                T_COMMENT,
                T_DOC_COMMENT_OPEN_TAG,
               );

    }//end register()


    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token in the
     *                        stack passed in $tokens.
     *
     * @return void
     */
    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();

        if ($tokens[$stackPtr]['code'] === T_COMMENT) {
            $this->processComment($phpcsFile, $stackPtr);
        } else if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_OPEN_TAG) {
            $this->processDocBlock($phpcsFile, $stackPtr);
        }

    }//end process()


    /**
     * Processes comment.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token
     *                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function processComment(File $phpcsFile, $stackPtr)
    {
        $tokens      = $phpcsFile->getTokens();
        $commentText = $tokens[$stackPtr]['content'];

        // Multi-line block comment.
        if (substr($commentText, 0, 2) !== '/*' || substr($commentText, -2) !== '*/') {
            return;
        }

        // Not a type comment.
        if ($this->isTypeComment($commentText) === false) {
            return;
        }

        // The "/**@var ...*/" comment isn't parsed as DocBlock and is fixed here.
        $error = 'Type comment must be in "/** %s ClassName $variable_name */" format';
        $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'WrongStyle', array(self::TYPE_TAG));
        if ($fix === true) {
            $phpcsFile->fixer->replaceToken($stackPtr, '/** '.trim($commentText, ' /*').' */');
        }

    }//end processComment()


    /**
     * Processes DocBlock.
     *
     * @param File $phpcsFile The file being scanned.
     * @param int  $stackPtr  The position of the current token
     *                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function processDocBlock(File $phpcsFile, $stackPtr)
    {
        $tokens       = $phpcsFile->getTokens();
        $commentStart = $stackPtr;
        $commentEnd   = $tokens[$stackPtr]['comment_closer'];

        // Multi-line DocBlock.
        if ($tokens[$commentEnd]['line'] !== $tokens[$commentStart]['line']) {
            return;
        }

        $commentTags = $tokens[$stackPtr]['comment_tags'];

        // Single-line DocBlock without tags inside.
        if (empty($commentTags) === true) {
            return;
        }

        // First tag will always exist.
        $firstTagPtr = $commentTags[0];

        // Not a type comment.
        if ($this->isTypeComment($tokens[$firstTagPtr]['content']) === false) {
            return;
        }

        $structure = new TypeCommentStructure($phpcsFile, $stackPtr);

        if ($structure->className === null) {
            $error              = 'Type comment must be in "/** %s ClassName $variable_name */" format';
            $leadingWhitespace  = $tokens[$stackPtr + 1]['code'] === T_DOC_COMMENT_WHITESPACE;
            $trailingWhitespace = $tokens[$commentEnd - 1]['code'] === T_DOC_COMMENT_WHITESPACE;

            if ($leadingWhitespace === false || $trailingWhitespace === false) {
                $fix = $phpcsFile->addFixableError($error, $stackPtr, 'WrongStyle', array(self::TYPE_TAG));
                if ($fix === true) {
                    if ($leadingWhitespace === false) {
                        $phpcsFile->fixer->addContentBefore($stackPtr + 1, ' ');
                    }

                    if ($trailingWhitespace === false) {
                        $phpcsFile->fixer->addContent($commentEnd - 1, ' ');
                    }
                }
            } else {
                $phpcsFile->addError($error, $firstTagPtr, 'WrongStyle', array(self::TYPE_TAG));
            }

            return;
        }//end if

        $this->processDocBlockContent($phpcsFile, $stackPtr, $structure);
        $this->processVariableAssociation($phpcsFile, $stackPtr, $structure);

    }//end processDocBlock()


    /**
     * Processes DocBlock content.
     *
     * @param File                 $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     * @param TypeCommentStructure $structure Type comment structure.
     *
     * @return void
     */
    public function processDocBlockContent(
        File $phpcsFile,
        $stackPtr,
        TypeCommentStructure $structure
    ) {
        $tokens      = $phpcsFile->getTokens();
        $commentTags = $tokens[$stackPtr]['comment_tags'];
        $firstTagPtr = $commentTags[0];

{'fraction_non_alphanumeric': 0.13260201842913558, 'fraction_numerical': 0.003861342694164107, 'mean_word_length': 2.037313432835821, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 50, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '931096', 'n_tokens_mistral': 3331, 'n_tokens_neox': 3204, 'n_words': 794}