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

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