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

Source for file OperatorSpacingSniff.php

Documentation is available at OperatorSpacingSniff.php

  1. <?php
  2. /**
  3.  * Verifies that operators have valid spacing surrounding them.
  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 OperatorSpacingSniff 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.      * Allow newlines instead of spaces.
  31.      *
  32.      * @var boolean 
  33.      */
  34.     public $ignoreNewlines = false;
  35.  
  36.  
  37.     /**
  38.      * Returns an array of tokens this test wants to listen for.
  39.      *
  40.      * @return array 
  41.      */
  42.     public function register()
  43.     {
  44.         $comparison = Tokens::$comparisonTokens;
  45.         $operators  = Tokens::$operators;
  46.         $assignment = Tokens::$assignmentTokens;
  47.         $inlineIf   = array(
  48.                        T_INLINE_THEN,
  49.                        T_INLINE_ELSE,
  50.                       );
  51.  
  52.         return array_unique(
  53.             array_merge($comparison$operators$assignment$inlineIf)
  54.         );
  55.  
  56.     }//end register()
  57.  
  58.  
  59.     /**
  60.      * Processes this sniff, when one of its tokens is encountered.
  61.      *
  62.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
  63.      * @param int                         $stackPtr  The position of the current token in
  64.      *                                                the stack passed in $tokens.
  65.      *
  66.      * @return void 
  67.      */
  68.     public function process(File $phpcsFile$stackPtr)
  69.     {
  70.         $tokens $phpcsFile->getTokens();
  71.  
  72.         // Skip default values in function declarations.
  73.         // Skip declare statements.
  74.         if ($tokens[$stackPtr]['code'=== T_EQUAL
  75.             || $tokens[$stackPtr]['code'=== T_MINUS
  76.         {
  77.             if (isset($tokens[$stackPtr]['nested_parenthesis']=== true{
  78.                 $parenthesis array_keys($tokens[$stackPtr]['nested_parenthesis']);
  79.                 $bracket     array_pop($parenthesis);
  80.                 if (isset($tokens[$bracket]['parenthesis_owner']=== true{
  81.                     $function $tokens[$bracket]['parenthesis_owner'];
  82.                     if ($tokens[$function]['code'=== T_FUNCTION
  83.                         || $tokens[$function]['code'=== T_CLOSURE
  84.                         || $tokens[$function]['code'=== T_DECLARE
  85.                     {
  86.                         return;
  87.                     }
  88.                 }
  89.             }
  90.         }
  91.  
  92.         if ($tokens[$stackPtr]['code'=== T_EQUAL{
  93.             // Skip for '=&' case.
  94.             if (isset($tokens[($stackPtr + 1)]=== true
  95.                 && $tokens[($stackPtr + 1)]['code'=== T_BITWISE_AND
  96.             {
  97.                 return;
  98.             }
  99.         }
  100.  
  101.         if ($tokens[$stackPtr]['code'=== T_BITWISE_AND{
  102.             // If it's not a reference, then we expect one space either side of the
  103.             // bitwise operator.
  104.             if ($phpcsFile->isReference($stackPtr=== true{
  105.                 return;
  106.             }
  107.  
  108.             // Check there is one space before the & operator.
  109.             if ($tokens[($stackPtr - 1)]['code'!== T_WHITESPACE{
  110.                 $error 'Expected 1 space before "&" operator; 0 found';
  111.                 $fix   $phpcsFile->addFixableError($error$stackPtr'NoSpaceBeforeAmp');
  112.                 if ($fix === true{
  113.                     $phpcsFile->fixer->addContentBefore($stackPtr' ');
  114.                 }
  115.  
  116.                 $phpcsFile->recordMetric($stackPtr'Space before operator'0);
  117.             else {
  118.                 if ($tokens[($stackPtr - 2)]['line'!== $tokens[$stackPtr]['line']{
  119.                     $found 'newline';
  120.                 else {
  121.                     $found $tokens[($stackPtr - 1)]['length'];
  122.                 }
  123.  
  124.                 $phpcsFile->recordMetric($stackPtr'Space before operator'$found);
  125.                 if ($found !== 1
  126.                     && ($found !== 'newline' || $this->ignoreNewlines === false)
  127.                 {
  128.                     $error 'Expected 1 space before "&" operator; %s found';
  129.                     $data  = array($found);
  130.                     $fix   $phpcsFile->addFixableError($error$stackPtr'SpacingBeforeAmp'$data);
  131.                     if ($fix === true{
  132.                         $phpcsFile->fixer->replaceToken(($stackPtr - 1)' ');
  133.                     }
  134.                 }
  135.             }//end if
  136.  
  137.             // Check there is one space after the & operator.
  138.             if ($tokens[($stackPtr + 1)]['code'!== T_WHITESPACE{
  139.                 $error 'Expected 1 space after "&" operator; 0 found';
  140.                 $fix   $phpcsFile->addFixableError($error$stackPtr'NoSpaceAfterAmp');
  141.                 if ($fix === true{
  142.                     $phpcsFile->fixer->addContent($stackPtr' ');
  143.                 }
  144.  
  145.                 $phpcsFile->recordMetric($stackPtr'Space after operator'0);
  146.             else {
  147.                 if ($tokens[($stackPtr + 2)]['line'!== $tokens[$stackPtr]['line']{
  148.                     $found 'newline';
  149.                 else {
  150.                     $found $tokens[($stackPtr + 1)]['length'];
  151.                 }
  152.  
  153.                 $phpcsFile->recordMetric($stackPtr'Space after operator'$found);
  154.                 if ($found !== 1
  155.                     && ($found !== 'newline' || $this->ignoreNewlines === false)
  156.                 {
  157.                     $error 'Expected 1 space after "&" operator; %s found';
  158.                     $data  = array($found);
  159.                     $fix   $phpcsFile->addFixableError($error$stackPtr'SpacingAfterAmp'$data);
  160.                     if ($fix === true{
  161.                         $phpcsFile->fixer->replaceToken(($stackPtr + 1)' ');
  162.                     }
  163.                 }
  164.             }//end if
  165.  
  166.             return;
  167.         }//end if
  168.  
  169.         if ($tokens[$stackPtr]['code'=== T_MINUS || $tokens[$stackPtr]['code'=== T_PLUS{
  170.             // Check minus spacing, but make sure we aren't just assigning
  171.             // a minus value or returning one.
  172.             $prev $phpcsFile->findPrevious(Tokens::$emptyTokens($stackPtr - 1)nulltrue);
  173.             if ($tokens[$prev]['code'=== T_RETURN{
  174.                 // Just returning a negative value; eg. (return -1).
  175.                 return;
  176.             }
  177.  
  178.             if (isset(Tokens::$operators[$tokens[$prev]['code']]=== true{
  179.                 // Just trying to operate on a negative value; eg. ($var * -1).
  180.                 return;
  181.             }
  182.  
  183.             if (isset(Tokens::$comparisonTokens[$tokens[$prev]['code']]=== true{
  184.                 // Just trying to compare a negative value; eg. ($var === -1).
  185.                 return;
  186.             }
  187.  
  188.             if (isset(Tokens::$booleanOperators[$tokens[$prev]['code']]=== true{
  189.                 // Just trying to compare a negative value; eg. ($var || -1 === $b).
  190.                 return;
  191.             }
  192.  
  193.             if (isset(Tokens::$assignmentTokens[$tokens[$prev]['code']]=== true{
  194.                 // Just trying to assign a negative value; eg. ($var = -1).
  195.                 return;
  196.             }
  197.  
  198.             // A list of tokens that indicate that the token is not
  199.             // part of an arithmetic operation.
  200.             $invalidTokens = array(
  201.                               T_COMMA               => true,
  202.                               T_OPEN_PARENTHESIS    => true,
  203.                               T_OPEN_SQUARE_BRACKET => true,
  204.                               T_OPEN_SHORT_ARRAY    => true,
  205.                               T_DOUBLE_ARROW        => true,
  206.                               T_COLON               => true,
  207.                               T_INLINE_THEN         => true,
  208.                               T_INLINE_ELSE         => true,
  209.                               T_CASE                => true,
  210.                              );
  211.  
  212.             if (isset($invalidTokens[$tokens[$prev]['code']]=== true{
  213.                 // Just trying to use a negative value; eg. myFunction($var, -2).
  214.                 return;
  215.             }
  216.         }//end if
  217.  
  218.         $operator $tokens[$stackPtr]['content'];
  219.  
  220.         if ($tokens[($stackPtr - 1)]['code'!== T_WHITESPACE
  221.             && (($tokens[($stackPtr - 1)]['code'=== T_INLINE_THEN
  222.             && $tokens[($stackPtr )]['code'=== T_INLINE_ELSE=== false)
  223.         {
  224.             $error = "Expected 1 space before \"$operator\"; 0 found";
  225.             $fix   $phpcsFile->addFixableError($error$stackPtr'NoSpaceBefore');
  226.             if ($fix === true{
  227.                 $phpcsFile->fixer->addContentBefore($stackPtr' ');
  228.             }
  229.  
  230.             $phpcsFile->recordMetric($stackPtr'Space before operator'0);
  231.         else if (isset(Tokens::$assignmentTokens[$tokens[$stackPtr]['code']]=== false{
  232.             // Don't throw an error for assignments, because other standards allow
  233.             // multiple spaces there to align multiple assignments.
  234.             if ($tokens[($stackPtr - 2)]['line'!== $tokens[$stackPtr]['line']{
  235.                 $found 'newline';
  236.             else {
  237.                 $found $tokens[($stackPtr - 1)]['length'];
  238.             }
  239.  
  240.             $phpcsFile->recordMetric($stackPtr'Space before operator'$found);
  241.             if ($found !== 1
  242.                 && ($found !== 'newline' || $this->ignoreNewlines === false)
  243.             {
  244.                 $error 'Expected 1 space before "%s"; %s found';
  245.                 $data  = array(
  246.                           $operator,
  247.                           $found,
  248.                          );
  249.                 $fix   $phpcsFile->addFixableError($error$stackPtr'SpacingBefore'$data);
  250.                 if ($fix === true{
  251.                     $phpcsFile->fixer->beginChangeset();
  252.                     if ($found === 'newline'{
  253.                         $i ($stackPtr - 2);
  254.                         while ($tokens[$i]['code'=== T_WHITESPACE{
  255.                             $phpcsFile->fixer->replaceToken($i'');
  256.                             $i--;
  257.                         }
  258.                     }
  259.  
  260.                     $phpcsFile->fixer->replaceToken(($stackPtr - 1)' ');
  261.                     $phpcsFile->fixer->endChangeset();
  262.                 }
  263.             }//end if
  264.         }//end if
  265.  
  266.         if (isset($tokens[($stackPtr + 1)]=== false{
  267.             return;
  268.         }
  269.  
  270.         if ($tokens[($stackPtr + 1)]['code'!== T_WHITESPACE{
  271.             // Skip short ternary such as: "$foo = $bar ?: true;".
  272.             if (($tokens[$stackPtr]['code'=== T_INLINE_THEN
  273.                 && $tokens[($stackPtr + 1)]['code'=== T_INLINE_ELSE)
  274.             {
  275.                 return;
  276.             }
  277.  
  278.             $error = "Expected 1 space after \"$operator\"; 0 found";
  279.             $fix   $phpcsFile->addFixableError($error$stackPtr'NoSpaceAfter');
  280.             if ($fix === true{
  281.                 $phpcsFile->fixer->addContent($stackPtr' ');
  282.             }
  283.  
  284.             $phpcsFile->recordMetric($stackPtr'Space after operator'0);
  285.         else {
  286.             if (isset($tokens[($stackPtr + 2)]=== true
  287.                 && $tokens[($stackPtr + 2)]['line'!== $tokens[$stackPtr]['line']
  288.             {
  289.                 $found 'newline';
  290.             else {
  291.                 $found $tokens[($stackPtr + 1)]['length'];
  292.             }
  293.  
  294.             $phpcsFile->recordMetric($stackPtr'Space after operator'$found);
  295.             if ($found !== 1
  296.                 && ($found !== 'newline' || $this->ignoreNewlines === false)
  297.             {
  298.                 $error 'Expected 1 space after "%s"; %s found';
  299.                 $data  = array(
  300.                           $operator,
  301.                           $found,
  302.                          );
  303.                 $fix   $phpcsFile->addFixableError($error$stackPtr'SpacingAfter'$data);
  304.                 if ($fix === true{
  305.                     $phpcsFile->fixer->replaceToken(($stackPtr + 1)' ');
  306.                 }
  307.             }
  308.         }//end if
  309.  
  310.     }//end process()
  311.  
  312.  
  313. }//end class

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