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

Source for file ControlStructureSpacingSniff.php

Documentation is available at ControlStructureSpacingSniff.php

  1. <?php
  2. /**
  3.  * Checks that control structures have the correct spacing around brackets.
  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\WhiteSpace;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class ControlStructureSpacingSniff implements Sniff
  17. {
  18.  
  19.     /**
  20.      * A list of tokenizers this sniff supports.
  21.      *
  22.      * @var array 
  23.      */
  24.     public $supportedTokenizers = array(
  25.                                    'PHP',
  26.                                    'JS',
  27.                                   );
  28.  
  29.  
  30.     /**
  31.      * Returns an array of tokens this test wants to listen for.
  32.      *
  33.      * @return array 
  34.      */
  35.     public function register()
  36.     {
  37.         return array(
  38.                 T_IF,
  39.                 T_WHILE,
  40.                 T_FOREACH,
  41.                 T_FOR,
  42.                 T_SWITCH,
  43.                 T_DO,
  44.                 T_ELSE,
  45.                 T_ELSEIF,
  46.                 T_TRY,
  47.                 T_CATCH,
  48.                );
  49.  
  50.     }//end register()
  51.  
  52.  
  53.     /**
  54.      * Processes this test, when one of its tokens is encountered.
  55.      *
  56.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  57.      * @param int                         $stackPtr  The position of the current token
  58.      *                                                in the stack passed in $tokens.
  59.      *
  60.      * @return void 
  61.      */
  62.     public function process(File $phpcsFile$stackPtr)
  63.     {
  64.         $tokens $phpcsFile->getTokens();
  65.  
  66.         if (isset($tokens[$stackPtr]['parenthesis_opener']=== true
  67.             && isset($tokens[$stackPtr]['parenthesis_closer']=== true
  68.         {
  69.             $parenOpener $tokens[$stackPtr]['parenthesis_opener'];
  70.             $parenCloser $tokens[$stackPtr]['parenthesis_closer'];
  71.             if ($tokens[($parenOpener + 1)]['code'=== T_WHITESPACE{
  72.                 $gap $tokens[($parenOpener + 1)]['length'];
  73.  
  74.                 if ($gap === 0{
  75.                     $phpcsFile->recordMetric($stackPtr'Spaces after control structure open parenthesis''newline');
  76.                     $gap 'newline';
  77.                 else {
  78.                     $phpcsFile->recordMetric($stackPtr'Spaces after control structure open parenthesis'$gap);
  79.                 }
  80.  
  81.                 $error 'Expected 0 spaces after opening bracket; %s found';
  82.                 $data  = array($gap);
  83.                 $fix   $phpcsFile->addFixableError($error($parenOpener + 1)'SpacingAfterOpenBrace'$data);
  84.                 if ($fix === true{
  85.                     $phpcsFile->fixer->replaceToken(($parenOpener + 1)'');
  86.                 }
  87.             else {
  88.                 $phpcsFile->recordMetric($stackPtr'Spaces after control structure open parenthesis'0);
  89.             }
  90.  
  91.             if ($tokens[$parenOpener]['line'=== $tokens[$parenCloser]['line']
  92.                 && $tokens[($parenCloser - 1)]['code'=== T_WHITESPACE
  93.             {
  94.                 $gap   $tokens[($parenCloser - 1)]['length'];
  95.                 $error 'Expected 0 spaces before closing bracket; %s found';
  96.                 $data  = array($gap);
  97.                 $fix   $phpcsFile->addFixableError($error($parenCloser - 1)'SpaceBeforeCloseBrace'$data);
  98.                 if ($fix === true{
  99.                     $phpcsFile->fixer->replaceToken(($parenCloser - 1)'');
  100.                 }
  101.  
  102.                 if ($gap === 0{
  103.                     $phpcsFile->recordMetric($stackPtr'Spaces before control structure close parenthesis''newline');
  104.                 else {
  105.                     $phpcsFile->recordMetric($stackPtr'Spaces before control structure close parenthesis'$gap);
  106.                 }
  107.             else {
  108.                 $phpcsFile->recordMetric($stackPtr'Spaces before control structure close parenthesis'0);
  109.             }
  110.         }//end if
  111.  
  112.         if (isset($tokens[$stackPtr]['scope_closer']=== false{
  113.             return;
  114.         }
  115.  
  116.         $scopeOpener $tokens[$stackPtr]['scope_opener'];
  117.         $scopeCloser $tokens[$stackPtr]['scope_closer'];
  118.  
  119.         for ($firstContent ($scopeOpener + 1)$firstContent $phpcsFile->numTokens; $firstContent++{
  120.             if ($tokens[$firstContent]['code'!== T_WHITESPACE{
  121.                 break;
  122.             }
  123.         }
  124.  
  125.         // We ignore spacing for some structures that tend to have their own rules.
  126.         $ignore = array(
  127.                    T_FUNCTION             => true,
  128.                    T_CLASS                => true,
  129.                    T_INTERFACE            => true,
  130.                    T_TRAIT                => true,
  131.                    T_DOC_COMMENT_OPEN_TAG => true,
  132.                   );
  133.  
  134.         if (isset($ignore[$tokens[$firstContent]['code']]=== false
  135.             && $tokens[$firstContent]['line'>= ($tokens[$scopeOpener]['line'+ 2)
  136.         {
  137.             $gap ($tokens[$firstContent]['line'$tokens[$scopeOpener]['line'- 1);
  138.             $phpcsFile->recordMetric($stackPtr'Blank lines at start of control structure'$gap);
  139.  
  140.             $error 'Blank line found at start of control structure';
  141.             $fix   $phpcsFile->addFixableError($error$scopeOpener'SpacingAfterOpen');
  142.  
  143.             if ($fix === true{
  144.                 $phpcsFile->fixer->beginChangeset();
  145.                 $i ($scopeOpener + 1);
  146.                 while ($tokens[$i]['line'!== $tokens[$firstContent]['line']{
  147.                     $phpcsFile->fixer->replaceToken($i'');
  148.                     $i++;
  149.                 }
  150.  
  151.                 $phpcsFile->fixer->addNewline($scopeOpener);
  152.                 $phpcsFile->fixer->endChangeset();
  153.             }
  154.         else {
  155.             $phpcsFile->recordMetric($stackPtr'Blank lines at start of control structure'0);
  156.         }//end if
  157.  
  158.         if ($firstContent !== $scopeCloser{
  159.             $lastContent $phpcsFile->findPrevious(
  160.                 T_WHITESPACE,
  161.                 ($scopeCloser - 1),
  162.                 null,
  163.                 true
  164.             );
  165.  
  166.             $lastNonEmptyContent $phpcsFile->findPrevious(
  167.                 Tokens::$emptyTokens,
  168.                 ($scopeCloser - 1),
  169.                 null,
  170.                 true
  171.             );
  172.  
  173.             $checkToken $lastContent;
  174.             if (isset($tokens[$lastNonEmptyContent]['scope_condition']=== true{
  175.                 $checkToken $tokens[$lastNonEmptyContent]['scope_condition'];
  176.             }
  177.  
  178.             if (isset($ignore[$tokens[$checkToken]['code']]=== false
  179.                 && $tokens[$lastContent]['line'<= ($tokens[$scopeCloser]['line'- 2)
  180.             {
  181.                 $errorToken $scopeCloser;
  182.                 for ($i ($scopeCloser - 1)$i $lastContent$i--{
  183.                     if ($tokens[$i]['line'$tokens[$scopeCloser]['line']{
  184.                         $errorToken $i;
  185.                         break;
  186.                     }
  187.                 }
  188.  
  189.                 $gap ($tokens[$scopeCloser]['line'$tokens[$lastContent]['line'- 1);
  190.                 $phpcsFile->recordMetric($stackPtr'Blank lines at end of control structure'$gap);
  191.  
  192.                 $error 'Blank line found at end of control structure';
  193.                 $fix   $phpcsFile->addFixableError($error$errorToken'SpacingBeforeClose');
  194.  
  195.                 if ($fix === true{
  196.                     $phpcsFile->fixer->beginChangeset();
  197.                     $i ($scopeCloser - 1);
  198.                     for ($i ($scopeCloser - 1)$i $lastContent$i--{
  199.                         if ($tokens[$i]['line'=== $tokens[$scopeCloser]['line']{
  200.                             continue;
  201.                         }
  202.  
  203.                         if ($tokens[$i]['line'=== $tokens[$lastContent]['line']{
  204.                             break;
  205.                         }
  206.  
  207.                         $phpcsFile->fixer->replaceToken($i'');
  208.                     }
  209.  
  210.                     $phpcsFile->fixer->endChangeset();
  211.                 }
  212.             else {
  213.                 $phpcsFile->recordMetric($stackPtr'Blank lines at end of control structure'0);
  214.             }//end if
  215.         }//end if
  216.  
  217.         $trailingContent $phpcsFile->findNext(
  218.             T_WHITESPACE,
  219.             ($scopeCloser + 1),
  220.             null,
  221.             true
  222.         );
  223.  
  224.         if ($tokens[$trailingContent]['code'=== T_COMMENT{
  225.             // Special exception for code where the comment about
  226.             // an ELSE or ELSEIF is written between the control structures.
  227.             $nextCode $phpcsFile->findNext(
  228.                 Tokens::$emptyTokens,
  229.                 ($scopeCloser + 1),
  230.                 null,
  231.                 true
  232.             );
  233.  
  234.             if ($tokens[$nextCode]['code'=== T_ELSE
  235.                 || $tokens[$nextCode]['code'=== T_ELSEIF
  236.             {
  237.                 $trailingContent $nextCode;
  238.             }
  239.         }//end if
  240.  
  241.         if ($tokens[$trailingContent]['code'=== T_ELSE{
  242.             if ($tokens[$stackPtr]['code'=== T_IF{
  243.                 // IF with ELSE.
  244.                 return;
  245.             }
  246.         }
  247.  
  248.         if ($tokens[$trailingContent]['code'=== T_WHILE
  249.             && $tokens[$stackPtr]['code'=== T_DO
  250.         {
  251.             // DO with WHILE.
  252.             return;
  253.         }
  254.  
  255.         if ($tokens[$trailingContent]['code'=== T_CLOSE_TAG{
  256.             // At the end of the script or embedded code.
  257.             return;
  258.         }
  259.  
  260.         if (isset($tokens[$trailingContent]['scope_condition']=== true
  261.             && $tokens[$trailingContent]['scope_condition'!== $trailingContent
  262.             && isset($tokens[$trailingContent]['scope_opener']=== true
  263.             && $tokens[$trailingContent]['scope_opener'!== $trailingContent
  264.         {
  265.             // Another control structure's closing brace.
  266.             $owner $tokens[$trailingContent]['scope_condition'];
  267.             if ($tokens[$owner]['code'=== T_FUNCTION{
  268.                 // The next content is the closing brace of a function
  269.                 // so normal function rules apply and we can ignore it.
  270.                 return;
  271.             }
  272.  
  273.             if ($tokens[$owner]['code'=== T_CLOSURE
  274.                 && ($phpcsFile->hasCondition($stackPtrT_FUNCTION=== true
  275.                 || $phpcsFile->hasCondition($stackPtrT_CLOSURE=== true
  276.                 || isset($tokens[$stackPtr]['nested_parenthesis']=== true)
  277.             {
  278.                 return;
  279.             }
  280.  
  281.             if ($tokens[$trailingContent]['line'!== ($tokens[$scopeCloser]['line'+ 1)) {
  282.                 $error 'Blank line found after control structure';
  283.                 $fix   $phpcsFile->addFixableError($error$scopeCloser'LineAfterClose');
  284.  
  285.                 if ($fix === true{
  286.                     $phpcsFile->fixer->beginChangeset();
  287.                     $i ($scopeCloser + 1);
  288.                     while ($tokens[$i]['line'!== $tokens[$trailingContent]['line']{
  289.                         $phpcsFile->fixer->replaceToken($i'');
  290.                         $i++;
  291.                     }
  292.  
  293.                     $phpcsFile->fixer->addNewline($scopeCloser);
  294.                     $phpcsFile->fixer->endChangeset();
  295.                 }
  296.             }
  297.         else if ($tokens[$trailingContent]['code'!== T_ELSE
  298.             && $tokens[$trailingContent]['code'!== T_ELSEIF
  299.             && $tokens[$trailingContent]['code'!== T_CATCH
  300.             && $tokens[$trailingContent]['line'=== ($tokens[$scopeCloser]['line'+ 1)
  301.         {
  302.             $error 'No blank line found after control structure';
  303.             $fix   $phpcsFile->addFixableError($error$scopeCloser'NoLineAfterClose');
  304.             if ($fix === true{
  305.                 $phpcsFile->fixer->addNewline($scopeCloser);
  306.             }
  307.         }//end if
  308.  
  309.     }//end process()
  310.  
  311.  
  312. }//end class

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