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

Source for file UseDeclarationSniff.php

Documentation is available at UseDeclarationSniff.php

  1. <?php
  2. /**
  3.  * Ensures USE blocks are declared correctly.
  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\PSR2\Sniffs\Namespaces;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class UseDeclarationSniff implements Sniff
  17. {
  18.  
  19.  
  20.     /**
  21.      * Returns an array of tokens this test wants to listen for.
  22.      *
  23.      * @return array 
  24.      */
  25.     public function register()
  26.     {
  27.         return array(T_USE);
  28.  
  29.     }//end register()
  30.  
  31.  
  32.     /**
  33.      * Processes this test, when one of its tokens is encountered.
  34.      *
  35.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  36.      * @param int                         $stackPtr  The position of the current token in
  37.      *                                                the stack passed in $tokens.
  38.      *
  39.      * @return void 
  40.      */
  41.     public function process(File $phpcsFile$stackPtr)
  42.     {
  43.         if ($this->shouldIgnoreUse($phpcsFile$stackPtr=== true{
  44.             return;
  45.         }
  46.  
  47.         $tokens $phpcsFile->getTokens();
  48.  
  49.         // One space after the use keyword.
  50.         if ($tokens[($stackPtr + 1)]['content'!== ' '{
  51.             $error 'There must be a single space after the USE keyword';
  52.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceAfterUse');
  53.             if ($fix === true{
  54.                 $phpcsFile->fixer->replaceToken(($stackPtr + 1)' ');
  55.             }
  56.         }
  57.  
  58.         // Only one USE declaration allowed per statement.
  59.         $next $phpcsFile->findNext(array(T_COMMAT_SEMICOLONT_OPEN_USE_GROUPT_CLOSE_TAG)($stackPtr + 1));
  60.         if ($next !== false
  61.             && $tokens[$next]['code'!== T_SEMICOLON
  62.             && $tokens[$next]['code'!== T_CLOSE_TAG
  63.         {
  64.             $error 'There must be one USE keyword per declaration';
  65.             $fix   $phpcsFile->addFixableError($error$stackPtr'MultipleDeclarations');
  66.             if ($fix === true{
  67.                 if ($tokens[$next]['code'=== T_COMMA{
  68.                     $phpcsFile->fixer->replaceToken($next';'.$phpcsFile->eolChar.'use ');
  69.                 else {
  70.                     $baseUse      rtrim($phpcsFile->getTokensAsString($stackPtr($next $stackPtr)));
  71.                     $closingCurly $phpcsFile->findNext(T_CLOSE_USE_GROUP($next + 1));
  72.  
  73.                     $phpcsFile->fixer->beginChangeset();
  74.  
  75.                     // Remove base use statement.
  76.                     for ($i $stackPtr$i <= $next$i++{
  77.                         $phpcsFile->fixer->replaceToken($i'');
  78.                     }
  79.  
  80.                     // Convert grouped use statements into full use statements.
  81.                     do {
  82.                         $next $phpcsFile->findNext(Tokens::$emptyTokens($next + 1)$closingCurlytrue);
  83.  
  84.                         $whitespace $phpcsFile->findPrevious(T_WHITESPACE($next - 1)nulltrue);
  85.                         for ($i ($whitespace + 1)$i $next$i++{
  86.                             $phpcsFile->fixer->replaceToken($i'');
  87.                         }
  88.  
  89.                         if ($tokens[$next]['code'=== T_CONST || $tokens[$next]['code'=== T_FUNCTION{
  90.                             $phpcsFile->fixer->addContentBefore($next'use ');
  91.                             $next $phpcsFile->findNext(Tokens::$emptyTokens($next + 1)$closingCurlytrue);
  92.                             $phpcsFile->fixer->addContentBefore($nextstr_replace('use '''$baseUse));
  93.                         else {
  94.                             $phpcsFile->fixer->addContentBefore($next$baseUse);
  95.                         }
  96.  
  97.                         $next $phpcsFile->findNext(T_COMMA($next + 1)$closingCurly);
  98.                         if ($next !== false{
  99.                             $phpcsFile->fixer->replaceToken($next';'.$phpcsFile->eolChar);
  100.                         }
  101.                     while ($next !== false);
  102.  
  103.                     $phpcsFile->fixer->replaceToken($closingCurly'');
  104.  
  105.                     // Remove any trailing whitespace.
  106.                     $next       $phpcsFile->findNext(T_SEMICOLON$closingCurly);
  107.                     $whitespace $phpcsFile->findPrevious(T_WHITESPACE($closingCurly - 1)nulltrue);
  108.                     for ($i ($whitespace + 1)$i $next$i++{
  109.                         $phpcsFile->fixer->replaceToken($i'');
  110.                     }
  111.  
  112.                     $phpcsFile->fixer->endChangeset();
  113.                 }//end if
  114.             }//end if
  115.         }//end if
  116.  
  117.         // Make sure this USE comes after the first namespace declaration.
  118.         $prev $phpcsFile->findPrevious(T_NAMESPACE($stackPtr - 1));
  119.         if ($prev !== false{
  120.             $first $phpcsFile->findNext(T_NAMESPACE1);
  121.             if ($prev !== $first{
  122.                 $error 'USE declarations must go after the first namespace declaration';
  123.                 $phpcsFile->addError($error$stackPtr'UseAfterNamespace');
  124.             }
  125.         }
  126.  
  127.         // Only interested in the last USE statement from here onwards.
  128.         $nextUse $phpcsFile->findNext(T_USE($stackPtr + 1));
  129.         while ($this->shouldIgnoreUse($phpcsFile$nextUse=== true{
  130.             $nextUse $phpcsFile->findNext(T_USE($nextUse + 1));
  131.             if ($nextUse === false{
  132.                 break;
  133.             }
  134.         }
  135.  
  136.         if ($nextUse !== false{
  137.             return;
  138.         }
  139.  
  140.         $end $phpcsFile->findNext(T_SEMICOLON($stackPtr + 1));
  141.         if ($end === false{
  142.             return;
  143.         }
  144.  
  145.         $next $phpcsFile->findNext(T_WHITESPACE($end + 1)nulltrue);
  146.  
  147.         if ($next === false || $tokens[$next]['code'=== T_CLOSE_TAG{
  148.             return;
  149.         }
  150.  
  151.         $diff ($tokens[$next]['line'$tokens[$end]['line'- 1);
  152.         if ($diff !== 1{
  153.             if ($diff < 0{
  154.                 $diff = 0;
  155.             }
  156.  
  157.             $error 'There must be one blank line after the last USE statement; %s found;';
  158.             $data  = array($diff);
  159.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceAfterLastUse'$data);
  160.             if ($fix === true{
  161.                 if ($diff === 0{
  162.                     $phpcsFile->fixer->addNewline($end);
  163.                 else {
  164.                     $phpcsFile->fixer->beginChangeset();
  165.                     for ($i ($end + 1)$i $next$i++{
  166.                         if ($tokens[$i]['line'=== $tokens[$next]['line']{
  167.                             break;
  168.                         }
  169.  
  170.                         $phpcsFile->fixer->replaceToken($i'');
  171.                     }
  172.  
  173.                     $phpcsFile->fixer->addNewline($end);
  174.                     $phpcsFile->fixer->endChangeset();
  175.                 }
  176.             }
  177.         }//end if
  178.  
  179.     }//end process()
  180.  
  181.  
  182.     /**
  183.      * Check if this use statement is part of the namespace block.
  184.      *
  185.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  186.      * @param int                         $stackPtr  The position of the current token in
  187.      *                                                the stack passed in $tokens.
  188.      *
  189.      * @return void 
  190.      */
  191.     private function shouldIgnoreUse($phpcsFile$stackPtr)
  192.     {
  193.         $tokens $phpcsFile->getTokens();
  194.  
  195.         // Ignore USE keywords inside closures.
  196.         $next $phpcsFile->findNext(T_WHITESPACE($stackPtr + 1)nulltrue);
  197.         if ($tokens[$next]['code'=== T_OPEN_PARENTHESIS{
  198.             return true;
  199.         }
  200.  
  201.         // Ignore USE keywords for traits.
  202.         if ($phpcsFile->hasCondition($stackPtrarray(T_CLASST_TRAIT)) === true{
  203.             return true;
  204.         }
  205.  
  206.         return false;
  207.  
  208.     }//end shouldIgnoreUse()
  209.  
  210.  
  211. }//end class

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