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_GROUP)($stackPtr + 1));
  60.         if ($tokens[$next]['code'!== T_SEMICOLON{
  61.             $error 'There must be one USE keyword per declaration';
  62.             $fix   $phpcsFile->addFixableError($error$stackPtr'MultipleDeclarations');
  63.             if ($fix === true{
  64.                 if ($tokens[$next]['code'=== T_COMMA{
  65.                     $phpcsFile->fixer->replaceToken($next';'.$phpcsFile->eolChar.'use ');
  66.                 else {
  67.                     $baseUse      rtrim($phpcsFile->getTokensAsString($stackPtr($next $stackPtr)));
  68.                     $closingCurly $phpcsFile->findNext(T_CLOSE_USE_GROUP($next + 1));
  69.  
  70.                     $phpcsFile->fixer->beginChangeset();
  71.  
  72.                     // Remove base use statement.
  73.                     for ($i $stackPtr$i <= $next$i++{
  74.                         $phpcsFile->fixer->replaceToken($i'');
  75.                     }
  76.  
  77.                     // Convert grouped use statements into full use statements.
  78.                     do {
  79.                         $next $phpcsFile->findNext(Tokens::$emptyTokens($next + 1)$closingCurlytrue);
  80.  
  81.                         $whitespace $phpcsFile->findPrevious(T_WHITESPACE($next - 1)nulltrue);
  82.                         for ($i ($whitespace + 1)$i $next$i++{
  83.                             $phpcsFile->fixer->replaceToken($i'');
  84.                         }
  85.  
  86.                         if ($tokens[$next]['code'=== T_CONST || $tokens[$next]['code'=== T_FUNCTION{
  87.                             $phpcsFile->fixer->addContentBefore($next'use ');
  88.                             $next $phpcsFile->findNext(Tokens::$emptyTokens($next + 1)$closingCurlytrue);
  89.                             $phpcsFile->fixer->addContentBefore($nextstr_replace('use '''$baseUse));
  90.                         else {
  91.                             $phpcsFile->fixer->addContentBefore($next$baseUse);
  92.                         }
  93.  
  94.                         $next $phpcsFile->findNext(T_COMMA($next + 1)$closingCurly);
  95.                         if ($next !== false{
  96.                             $phpcsFile->fixer->replaceToken($next';'.$phpcsFile->eolChar);
  97.                         }
  98.                     while ($next !== false);
  99.  
  100.                     $phpcsFile->fixer->replaceToken($closingCurly'');
  101.  
  102.                     // Remove any trailing whitespace.
  103.                     $next       $phpcsFile->findNext(T_SEMICOLON$closingCurly);
  104.                     $whitespace $phpcsFile->findPrevious(T_WHITESPACE($closingCurly - 1)nulltrue);
  105.                     for ($i ($whitespace + 1)$i $next$i++{
  106.                         $phpcsFile->fixer->replaceToken($i'');
  107.                     }
  108.  
  109.                     $phpcsFile->fixer->endChangeset();
  110.                 }//end if
  111.             }//end if
  112.         }//end if
  113.  
  114.         // Make sure this USE comes after the first namespace declaration.
  115.         $prev $phpcsFile->findPrevious(T_NAMESPACE($stackPtr - 1));
  116.         if ($prev !== false{
  117.             $first $phpcsFile->findNext(T_NAMESPACE1);
  118.             if ($prev !== $first{
  119.                 $error 'USE declarations must go after the first namespace declaration';
  120.                 $phpcsFile->addError($error$stackPtr'UseAfterNamespace');
  121.             }
  122.         }
  123.  
  124.         // Only interested in the last USE statement from here onwards.
  125.         $nextUse $phpcsFile->findNext(T_USE($stackPtr + 1));
  126.         while ($this->shouldIgnoreUse($phpcsFile$nextUse=== true{
  127.             $nextUse $phpcsFile->findNext(T_USE($nextUse + 1));
  128.             if ($nextUse === false{
  129.                 break;
  130.             }
  131.         }
  132.  
  133.         if ($nextUse !== false{
  134.             return;
  135.         }
  136.  
  137.         $end  $phpcsFile->findNext(T_SEMICOLON($stackPtr + 1));
  138.         $next $phpcsFile->findNext(T_WHITESPACE($end + 1)nulltrue);
  139.  
  140.         if ($tokens[$next]['code'=== T_CLOSE_TAG{
  141.             return;
  142.         }
  143.  
  144.         $diff ($tokens[$next]['line'$tokens[$end]['line'- 1);
  145.         if ($diff !== 1{
  146.             if ($diff < 0{
  147.                 $diff = 0;
  148.             }
  149.  
  150.             $error 'There must be one blank line after the last USE statement; %s found;';
  151.             $data  = array($diff);
  152.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceAfterLastUse'$data);
  153.             if ($fix === true{
  154.                 if ($diff === 0{
  155.                     $phpcsFile->fixer->addNewline($end);
  156.                 else {
  157.                     $phpcsFile->fixer->beginChangeset();
  158.                     for ($i ($end + 1)$i $next$i++{
  159.                         if ($tokens[$i]['line'=== $tokens[$next]['line']{
  160.                             break;
  161.                         }
  162.  
  163.                         $phpcsFile->fixer->replaceToken($i'');
  164.                     }
  165.  
  166.                     $phpcsFile->fixer->addNewline($end);
  167.                     $phpcsFile->fixer->endChangeset();
  168.                 }
  169.             }
  170.         }//end if
  171.  
  172.     }//end process()
  173.  
  174.  
  175.     /**
  176.      * Check if this use statement is part of the namespace block.
  177.      *
  178.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  179.      * @param int                         $stackPtr  The position of the current token in
  180.      *                                                the stack passed in $tokens.
  181.      *
  182.      * @return void 
  183.      */
  184.     private function shouldIgnoreUse($phpcsFile$stackPtr)
  185.     {
  186.         $tokens $phpcsFile->getTokens();
  187.  
  188.         // Ignore USE keywords inside closures.
  189.         $next $phpcsFile->findNext(T_WHITESPACE($stackPtr + 1)nulltrue);
  190.         if ($tokens[$next]['code'=== T_OPEN_PARENTHESIS{
  191.             return true;
  192.         }
  193.  
  194.         // Ignore USE keywords for traits.
  195.         if ($phpcsFile->hasCondition($stackPtrarray(T_CLASST_TRAIT)) === true{
  196.             return true;
  197.         }
  198.  
  199.         return false;
  200.  
  201.     }//end shouldIgnoreUse()
  202.  
  203.  
  204. }//end class

Documentation generated on Mon, 11 Mar 2019 14:23:30 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.