PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file FileCommentSniff.php

Documentation is available at FileCommentSniff.php

  1. <?php
  2. /**
  3.  * Parses and verifies the file doc comment.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Commenting;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14.  
  15. class FileCommentSniff implements Sniff
  16. {
  17.  
  18.     /**
  19.      * A list of tokenizers this sniff supports.
  20.      *
  21.      * @var array 
  22.      */
  23.     public $supportedTokenizers = array(
  24.                                    'PHP',
  25.                                    'JS',
  26.                                   );
  27.  
  28.  
  29.     /**
  30.      * Returns an array of tokens this test wants to listen for.
  31.      *
  32.      * @return array 
  33.      */
  34.     public function register()
  35.     {
  36.         return array(T_OPEN_TAG);
  37.  
  38.     }//end register()
  39.  
  40.  
  41.     /**
  42.      * Processes this test, when one of its tokens is encountered.
  43.      *
  44.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  45.      * @param int                         $stackPtr  The position of the current token
  46.      *                                                in the stack passed in $tokens.
  47.      *
  48.      * @return int 
  49.      */
  50.     public function process(File $phpcsFile, $stackPtr)
  51.     {
  52.         $this->currentFile = $phpcsFile;
  53.  
  54.         $tokens       = $phpcsFile->getTokens();
  55.         $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
  56.  
  57.         if ($tokens[$commentStart]['code'] === T_COMMENT) {
  58.             $phpcsFile->addError('You must use "/**" style comments for a file comment', $commentStart, 'WrongStyle');
  59.             $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes');
  60.             return ($phpcsFile->numTokens + 1);
  61.         } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT_OPEN_TAG) {
  62.             $phpcsFile->addError('Missing file doc comment', $stackPtr, 'Missing');
  63.             $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no');
  64.             return ($phpcsFile->numTokens + 1);
  65.         }
  66.  
  67.         $commentEnd = $tokens[$commentStart]['comment_closer'];
  68.  
  69.         $nextToken = $phpcsFile->findNext(
  70.             T_WHITESPACE,
  71.             ($commentEnd + 1),
  72.             null,
  73.             true
  74.         );
  75.  
  76.         $ignore = array(
  77.                    T_CLASS,
  78.                    T_INTERFACE,
  79.                    T_TRAIT,
  80.                    T_FUNCTION,
  81.                    T_CLOSURE,
  82.                    T_PUBLIC,
  83.                    T_PRIVATE,
  84.                    T_PROTECTED,
  85.                    T_FINAL,
  86.                    T_STATIC,
  87.                    T_ABSTRACT,
  88.                    T_CONST,
  89.                    T_PROPERTY,
  90.                    T_INCLUDE,
  91.                    T_INCLUDE_ONCE,
  92.                    T_REQUIRE,
  93.                    T_REQUIRE_ONCE,
  94.                   );
  95.  
  96.         if (in_array($tokens[$nextToken]['code'], $ignore) === true) {
  97.             $phpcsFile->addError('Missing file doc comment', $stackPtr, 'Missing');
  98.             $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no');
  99.             return ($phpcsFile->numTokens + 1);
  100.         }
  101.  
  102.         $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes');
  103.  
  104.         // No blank line between the open tag and the file comment.
  105.         if ($tokens[$commentStart]['line'] > ($tokens[$stackPtr]['line'] + 1)) {
  106.             $error = 'There must be no blank lines before the file comment';
  107.             $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen');
  108.         }
  109.  
  110.         // Exactly one blank line after the file comment.
  111.         $next = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), null, true);
  112.         if ($tokens[$next]['line'] !== ($tokens[$commentEnd]['line'] + 2)) {
  113.             $error = 'There must be exactly one blank line after the file comment';
  114.             $phpcsFile->addError($error, $commentEnd, 'SpacingAfterComment');
  115.         }
  116.  
  117.         // Required tags in correct order.
  118.         $required = array(
  119.                      '@package'    => true,
  120.                      '@subpackage' => true,
  121.                      '@author'     => true,
  122.                      '@copyright'  => true,
  123.                     );
  124.  
  125.         $foundTags = array();
  126.         foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
  127.             $name       = $tokens[$tag]['content'];
  128.             $isRequired = isset($required[$name]);
  129.  
  130.             if ($isRequired === true && in_array($name, $foundTags) === true) {
  131.                 $error = 'Only one %s tag is allowed in a file comment';
  132.                 $data  = array($name);
  133.                 $phpcsFile->addError($error, $tag, 'Duplicate'.ucfirst(substr($name, 1)).'Tag', $data);
  134.             }
  135.  
  136.             $foundTags[] = $name;
  137.  
  138.             if ($isRequired === false) {
  139.                 continue;
  140.             }
  141.  
  142.             $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
  143.             if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
  144.                 $error = 'Content missing for %s tag in file comment';
  145.                 $data  = array($name);
  146.                 $phpcsFile->addError($error, $tag, 'Empty'.ucfirst(substr($name, 1)).'Tag', $data);
  147.                 continue;
  148.             }
  149.  
  150.             if ($name === '@author') {
  151.                 if ($tokens[$string]['content'] !== 'Squiz Pty Ltd <products@squiz.net>') {
  152.                     $error = 'Expected "Squiz Pty Ltd <products@squiz.net>" for author tag';
  153.                     $fix   = $phpcsFile->addFixableError($error, $tag, 'IncorrectAuthor');
  154.                     if ($fix === true) {
  155.                         $expected = 'Squiz Pty Ltd <products@squiz.net>';
  156.                         $phpcsFile->fixer->replaceToken($string, $expected);
  157.                     }
  158.                 }
  159.             } else if ($name === '@copyright') {
  160.                 if (preg_match('/^([0-9]{4})(-[0-9]{4})? (Squiz Pty Ltd \(ABN 77 084 670 600\))$/', $tokens[$string]['content']) === 0) {
  161.                     $error = 'Expected "xxxx-xxxx Squiz Pty Ltd (ABN 77 084 670 600)" for copyright declaration';
  162.                     $fix   = $phpcsFile->addFixableError($error, $tag, 'IncorrectCopyright');
  163.                     if ($fix === true) {
  164.                         $matches = array();
  165.                         preg_match('/^(([0-9]{4})(-[0-9]{4})?)?.*$/', $tokens[$string]['content'], $matches);
  166.                         if (isset($matches[1]) === false) {
  167.                             $matches[1] = date('Y');
  168.                         }
  169.  
  170.                         $expected = $matches[1].' Squiz Pty Ltd (ABN 77 084 670 600)';
  171.                         $phpcsFile->fixer->replaceToken($string, $expected);
  172.                     }
  173.                 }
  174.             }//end if
  175.         }//end foreach
  176.  
  177.         // Check if the tags are in the correct position.
  178.         $pos = 0;
  179.         foreach ($required as $tag => $true) {
  180.             if (in_array($tag, $foundTags) === false) {
  181.                 $error = 'Missing %s tag in file comment';
  182.                 $data  = array($tag);
  183.                 $phpcsFile->addError($error, $commentEnd, 'Missing'.ucfirst(substr($tag, 1)).'Tag', $data);
  184.             }
  185.  
  186.             if (isset($foundTags[$pos]) === false) {
  187.                 break;
  188.             }
  189.  
  190.             if ($foundTags[$pos] !== $tag) {
  191.                 $error = 'The tag in position %s should be the %s tag';
  192.                 $data  = array(
  193.                           ($pos + 1),
  194.                           $tag,
  195.                          );
  196.                 $phpcsFile->addError($error, $tokens[$commentStart]['comment_tags'][$pos], ucfirst(substr($tag, 1)).'TagOrder', $data);
  197.             }
  198.  
  199.             $pos++;
  200.         }//end foreach
  201.  
  202.         // Ignore the rest of the file.
  203.         return ($phpcsFile->numTokens + 1);
  204.  
  205.     }//end process()
  206.  
  207.  
  208. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:28 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.