<?php

PHP_CodeSniffer::$allowedTypes = array_merge(PHP_CodeSniffer::$allowedTypes, array('bool', 'int'));
/**
 * Parses and verifies the doc comments for functions.
 *
 * Verifies that :
 * <ul>
 *  <li>A comment exists</li>
 *  <li>There is a blank newline after the short description.</li>
 *  <li>Parameter names represent those in the method.</li>
 *  <li>Parameter comments are in the correct order</li>
 *  <li>A type hint is provided for array and custom class</li>
 *  <li>Type hint matches the actual variable/class type</li>
 *  <li>A return type exists</li>
 *  <li>There must be one blank line between body and headline comments.</li>
 *  <li>Any throw tag must have an exception class.</li>
 * </ul>
 *
 * @author Jan Prachař <*****@*****.**>
 */
class wikidi_sniffs_commenting_FunctionCommentSniff extends PEAR_Sniffs_Commenting_FunctionCommentSniff
{
    /**
     * The name of the method that we are currently processing.
     *
     * @var string
     */
    private $_methodName = '';
    /**
     * The position in the stack where the function token was found.
 public function __construct()
 {
     PHP_CodeSniffer::$allowedTypes = array_merge(PHP_CodeSniffer::$allowedTypes, $this->allowedTypes);
 }
 /**
  * Process the function parameter comments.
  *
  * @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
  */
 protected function processParams(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
 {
     // Accept inheriting of comments to be sufficient.
     if ($this->isInherited($phpcsFile, $commentStart)) {
         return;
     }
     $previous = PHP_CodeSniffer::$allowedTypes;
     PHP_CodeSniffer::$allowedTypes[] = 'int';
     PHP_CodeSniffer::$allowedTypes[] = 'bool';
     parent::processParams($phpcsFile, $stackPtr, $commentStart);
     PHP_CodeSniffer::$allowedTypes = $previous;
 }
 /**
  * Called to process class member vars.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  *
  * @param int                  $stackPtr  The position of the current token in the stack passed in $tokens.
  *
  * @return void
  *
  * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  */
 public function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $commentToken = array(T_COMMENT, T_DOC_COMMENT_CLOSE_TAG);
     $commentEnd = $phpcsFile->findPrevious($commentToken, $stackPtr);
     if ($commentEnd === false) {
         $phpcsFile->addError('Missing member variable doc comment', $stackPtr, 'Missing');
         return;
     }
     // Make sure the comment we have found belongs to us.
     $commentFor = $phpcsFile->findNext(array(T_VARIABLE, T_CLASS, T_INTERFACE, T_FUNCTION), $commentEnd + 1);
     if ($commentFor !== $stackPtr) {
         $phpcsFile->addError('Missing member variable doc comment', $stackPtr, 'Missing');
         return;
     }
     if ($tokens[$commentEnd]['code'] === T_COMMENT) {
         $phpcsFile->addError('Member variable doc comment must be doc block', $commentEnd, 'NotDocBlock');
         return;
     } elseif ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG) {
         return;
     }
     $commentStart = $tokens[$commentEnd]['comment_opener'];
     $comment = strtolower($phpcsFile->getTokensAsString($commentStart, $commentEnd - $commentStart));
     // Accept inheriting of comments to be sufficient.
     if (strpos($comment, '@inheritdoc') !== false) {
         return;
     }
     // Add well known types phpcs does not know about.
     $previous = PHP_CodeSniffer::$allowedTypes;
     PHP_CodeSniffer::$allowedTypes[] = 'int';
     PHP_CodeSniffer::$allowedTypes[] = 'bool';
     $foundVar = null;
     foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
         if ($tokens[$tag]['content'] === '@var') {
             if ($foundVar !== null) {
                 $phpcsFile->addError('Only one @var tag is allowed in a member variable comment', $tag, 'DuplicateVar');
             } else {
                 $foundVar = $tag;
             }
         } elseif ($tokens[$tag]['content'] === '@see') {
             // Make sure the tag isn't empty.
             $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
             if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
                 $error = 'Content missing for @see tag in member variable comment';
                 $phpcsFile->addError($error, $tag, 'EmptySees');
             }
         } elseif ($tokens[$tag]['content'] === '@deprecated') {
             $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
             if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
                 $error = 'Content missing for @deprecated tag in member variable comment';
                 $phpcsFile->addError($error, $tag, 'EmptyDeprecated');
             }
         }
     }
     // The @var tag is the only one we require.
     if ($foundVar === null) {
         $error = 'Missing @var tag in member variable comment';
         $phpcsFile->addError($error, $commentEnd, 'MissingVar');
         return;
     }
     $firstTag = $tokens[$commentStart]['comment_tags'][0];
     if ($foundVar !== null && $tokens[$firstTag]['content'] !== '@var') {
         $error = 'The @var tag must be the first tag in a member variable comment';
         $phpcsFile->addError($error, $foundVar, 'VarOrder');
     }
     // Make sure the tag isn't empty and has the correct padding.
     $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $foundVar, $commentEnd);
     if ($string === false || $tokens[$string]['line'] !== $tokens[$foundVar]['line']) {
         $error = 'Content missing for @var tag in member variable comment';
         $phpcsFile->addError($error, $foundVar, 'EmptyVar');
         return;
     }
     $varType = $tokens[$foundVar + 2]['content'];
     $suggestedType = PHP_CodeSniffer::suggestType($varType);
     if ($varType !== $suggestedType) {
         $error = 'Expected "%s" but found "%s" for @var tag in member variable comment';
         $data = array($suggestedType, $varType);
         $phpcsFile->addError($error, $foundVar + 2, 'IncorrectVarType', $data);
     }
     PHP_CodeSniffer::$allowedTypes = $previous;
     $this->checkShortComment($phpcsFile, $commentStart, $commentEnd);
 }