View source  
  <?php
namespace Drupal\Sniffs\Commenting;
use Drupal\Sniffs\Commenting\FunctionCommentSniff;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\AbstractVariableSniff;
use PHP_CodeSniffer\Util\Tokens;
class VariableCommentSniff extends AbstractVariableSniff {
  
  public function processMemberVar(File $phpcsFile, $stackPtr) {
    $tokens = $phpcsFile
      ->getTokens();
    $commentToken = array(
      T_COMMENT,
      T_DOC_COMMENT_CLOSE_TAG,
    );
    $commentEnd = $phpcsFile
      ->findPrevious($commentToken, $stackPtr);
    if ($commentEnd === false) {
      return;
    }
    if ($tokens[$commentEnd]['code'] === T_COMMENT) {
      $fix = $phpcsFile
        ->addFixableError('You must use "/**" style comments for a member variable comment', $stackPtr, 'WrongStyle');
      if ($fix === true) {
        
        $phpcsFile->fixer
          ->beginChangeset();
        $comment = '';
        for ($i = $commentEnd; $tokens[$i]['code'] === T_COMMENT; $i--) {
          $comment = ' *' . ltrim($tokens[$i]['content'], '/* ') . $comment;
          $phpcsFile->fixer
            ->replaceToken($i, '');
        }
        $phpcsFile->fixer
          ->replaceToken($commentEnd, "/**\n" . rtrim($comment, "*/\n") . "\n */\n");
        $phpcsFile->fixer
          ->endChangeset();
      }
      return;
    }
    else {
      if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG) {
        return;
      }
      else {
        
        $commentFor = $phpcsFile
          ->findNext(array(
          T_VARIABLE,
          T_CLASS,
          T_INTERFACE,
        ), $commentEnd + 1);
        if ($commentFor !== $stackPtr) {
          return;
        }
      }
    }
    
    $commentStart = $tokens[$commentEnd]['comment_opener'];
    $commentContent = $phpcsFile
      ->getTokensAsString($commentStart, $commentEnd - $commentStart);
    if (strpos($commentContent, '{@inheritdoc}') !== false) {
      return;
    }
    $foundVar = null;
    foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
      if ($tokens[$tag]['content'] === '@var') {
        if ($foundVar !== null) {
          $error = 'Only one @var tag is allowed in a member variable comment';
          $phpcsFile
            ->addError($error, $tag, 'DuplicateVar');
        }
        else {
          $foundVar = $tag;
        }
      }
      else {
        if ($tokens[$tag]['content'] === '@see') {
          
          $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');
          }
        }
      }
      
    }
    
    
    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');
    }
    
    $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'];
    
    $suggestedTypes = array();
    foreach (explode('|', $varType) as $type) {
      $suggestedTypes[] = FunctionCommentSniff::suggestType($type);
    }
    $suggestedType = implode('|', $suggestedTypes);
    
    $matches = array();
    if (preg_match('/^([^\\s]+)(\\s+\\$.+)$/', $varType, $matches) === 1) {
      $error = 'Do not append variable name "%s" to the type declaration in a member variable comment';
      $data = array(
        trim($matches[2]),
      );
      $fix = $phpcsFile
        ->addFixableError($error, $foundVar + 2, 'InlineVariableName', $data);
      if ($fix === true) {
        $phpcsFile->fixer
          ->replaceToken($foundVar + 2, $matches[1]);
      }
    }
    else {
      if ($varType !== $suggestedType) {
        $error = 'Expected "%s" but found "%s" for @var tag in member variable comment';
        $data = array(
          $suggestedType,
          $varType,
        );
        $fix = $phpcsFile
          ->addFixableError($error, $foundVar + 2, 'IncorrectVarType', $data);
        if ($fix === true) {
          $phpcsFile->fixer
            ->replaceToken($foundVar + 2, $suggestedType);
        }
      }
    }
    
  }
  
  
  protected function processVariable(File $phpcsFile, $stackPtr) {
  }
  
  
  protected function processVariableInString(File $phpcsFile, $stackPtr) {
  }
}