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

Source for file MultipleStatementAlignmentSniff.php

Documentation is available at MultipleStatementAlignmentSniff.php

  1. <?php
  2. /**
  3.  * Checks alignment of assignments.
  4.  *
  5.  * If there are multiple adjacent assignments, it will check that the equals signs of
  6.  * each assignment are aligned. It will display a warning to advise that the signs should be aligned.
  7.  *
  8.  * @author    Greg Sherwood <gsherwood@squiz.net>
  9.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  10.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  11.  */
  12.  
  13. namespace PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting;
  14.  
  15. use PHP_CodeSniffer\Sniffs\Sniff;
  16. use PHP_CodeSniffer\Files\File;
  17. use PHP_CodeSniffer\Util\Tokens;
  18.  
  19. class MultipleStatementAlignmentSniff implements Sniff
  20. {
  21.  
  22.     /**
  23.      * A list of tokenizers this sniff supports.
  24.      *
  25.      * @var array 
  26.      */
  27.     public $supportedTokenizers = array(
  28.                                    'PHP',
  29.                                    'JS',
  30.                                   );
  31.  
  32.     /**
  33.      * If true, an error will be thrown; otherwise a warning.
  34.      *
  35.      * @var boolean 
  36.      */
  37.     public $error = false;
  38.  
  39.     /**
  40.      * The maximum amount of padding before the alignment is ignored.
  41.      *
  42.      * If the amount of padding required to align this assignment with the
  43.      * surrounding assignments exceeds this number, the assignment will be
  44.      * ignored and no errors or warnings will be thrown.
  45.      *
  46.      * @var integer 
  47.      */
  48.     public $maxPadding = 1000;
  49.  
  50.  
  51.     /**
  52.      * Returns an array of tokens this test wants to listen for.
  53.      *
  54.      * @return array 
  55.      */
  56.     public function register()
  57.     {
  58.         $tokens = Tokens::$assignmentTokens;
  59.         unset($tokens[T_DOUBLE_ARROW]);
  60.         return $tokens;
  61.  
  62.     }//end register()
  63.  
  64.  
  65.     /**
  66.      * Processes this test, when one of its tokens is encountered.
  67.      *
  68.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  69.      * @param int                         $stackPtr  The position of the current token
  70.      *                                                in the stack passed in $tokens.
  71.      *
  72.      * @return int 
  73.      */
  74.     public function process(File $phpcsFile$stackPtr)
  75.     {
  76.         $tokens $phpcsFile->getTokens();
  77.  
  78.         // Ignore assignments used in a condition, like an IF or FOR.
  79.         if (isset($tokens[$stackPtr]['nested_parenthesis']=== true{
  80.             foreach ($tokens[$stackPtr]['nested_parenthesis'as $start => $end{
  81.                 if (isset($tokens[$start]['parenthesis_owner']=== true{
  82.                     return;
  83.                 }
  84.             }
  85.         }
  86.  
  87.         $lastAssign $this->checkAlignment($phpcsFile$stackPtr);
  88.         return ($lastAssign + 1);
  89.  
  90.     }//end process()
  91.  
  92.  
  93.     /**
  94.      * Processes this test, when one of its tokens is encountered.
  95.      *
  96.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  97.      * @param int                         $stackPtr  The position of the current token
  98.      *                                                in the stack passed in $tokens.
  99.      *
  100.      * @return int 
  101.      */
  102.     public function checkAlignment($phpcsFile$stackPtr)
  103.     {
  104.         $tokens $phpcsFile->getTokens();
  105.  
  106.         $assignments = array();
  107.         $prevAssign  = null;
  108.         $lastLine    $tokens[$stackPtr]['line'];
  109.         $maxPadding  = null;
  110.         $stopped     = null;
  111.         $lastCode    $stackPtr;
  112.         $lastSemi    = null;
  113.  
  114.         $find = Tokens::$assignmentTokens;
  115.         unset($find[T_DOUBLE_ARROW]);
  116.  
  117.         for ($assign $stackPtr$assign $phpcsFile->numTokens; $assign++{
  118.             if (isset($find[$tokens[$assign]['code']]=== false{
  119.                 // A blank line indicates that the assignment block has ended.
  120.                 if (isset(Tokens::$emptyTokens[$tokens[$assign]['code']]=== false{
  121.                     if (($tokens[$assign]['line'$tokens[$lastCode]['line']> 1{
  122.                         break;
  123.                     }
  124.  
  125.                     $lastCode $assign;
  126.  
  127.                     if ($tokens[$assign]['code'=== T_SEMICOLON{
  128.                         if ($tokens[$assign]['conditions'=== $tokens[$stackPtr]['conditions']{
  129.                             if ($lastSemi !== null && $prevAssign !== null && $lastSemi $prevAssign{
  130.                                 // This statement did not have an assignment operator in it.
  131.                                 break;
  132.                             else {
  133.                                 $lastSemi $assign;
  134.                             }
  135.                         else {
  136.                             // Statement is in a different context, so the block is over.
  137.                             break;
  138.                         }
  139.                     }
  140.                 }//end if
  141.  
  142.                 continue;
  143.             else if ($assign !== $stackPtr && $tokens[$assign]['line'=== $lastLine{
  144.                 // Skip multiple assignments on the same line. We only need to
  145.                 // try and align the first assignment.
  146.                 continue;
  147.             }//end if
  148.  
  149.             if ($assign !== $stackPtr{
  150.                 // Has to be nested inside the same conditions as the first assignment.
  151.                 if ($tokens[$assign]['conditions'!== $tokens[$stackPtr]['conditions']{
  152.                     break;
  153.                 }
  154.  
  155.                 // Make sure it is not assigned inside a condition (eg. IF, FOR).
  156.                 if (isset($tokens[$assign]['nested_parenthesis']=== true{
  157.                     foreach ($tokens[$assign]['nested_parenthesis'as $start => $end{
  158.                         if (isset($tokens[$start]['parenthesis_owner']=== true{
  159.                             break(2);
  160.                         }
  161.                     }
  162.                 }
  163.             }//end if
  164.  
  165.             $var $phpcsFile->findPrevious(
  166.                 Tokens::$emptyTokens,
  167.                 ($assign - 1),
  168.                 null,
  169.                 true
  170.             );
  171.  
  172.             // Make sure we wouldn't break our max padding length if we
  173.             // aligned with this statement, or they wouldn't break the max
  174.             // padding length if they aligned with us.
  175.             $varEnd    $tokens[($var + 1)]['column'];
  176.             $assignLen $tokens[$assign]['length'];
  177.             if ($assign !== $stackPtr{
  178.                 if (($varEnd + 1$assignments[$prevAssign]['assign_col']{
  179.                     $padding      = 1;
  180.                     $assignColumn ($varEnd + 1);
  181.                 else {
  182.                     $padding ($assignments[$prevAssign]['assign_col'$varEnd $assignments[$prevAssign]['assign_len'$assignLen);
  183.                     if ($padding === 0{
  184.                         $padding = 1;
  185.                     }
  186.  
  187.                     if ($padding $this->maxPadding{
  188.                         $stopped $assign;
  189.                         break;
  190.                     }
  191.  
  192.                     $assignColumn ($varEnd $padding);
  193.                 }//end if
  194.  
  195.                 if (($assignColumn $assignLen($assignments[$maxPadding]['assign_col'$assignments[$maxPadding]['assign_len'])) {
  196.                     $newPadding ($varEnd $assignments[$maxPadding]['var_end'$assignLen $assignments[$maxPadding]['assign_len'+ 1);
  197.                     if ($newPadding $this->maxPadding{
  198.                         $stopped $assign;
  199.                         break;
  200.                     else {
  201.                         // New alignment settings for previous assignments.
  202.                         foreach ($assignments as $i => $data{
  203.                             if ($i === $assign{
  204.                                 break;
  205.                             }
  206.  
  207.                             $newPadding ($varEnd $data['var_end'$assignLen $data['assign_len'+ 1);
  208.                             $assignments[$i]['expected']   $newPadding;
  209.                             $assignments[$i]['assign_col'($data['var_end'$newPadding);
  210.                         }
  211.  
  212.                         $padding      = 1;
  213.                         $assignColumn ($varEnd + 1);
  214.                     }
  215.                 else if ($padding $assignments[$maxPadding]['expected']{
  216.                     $maxPadding $assign;
  217.                 }//end if
  218.             else {
  219.                 $padding      = 1;
  220.                 $assignColumn ($varEnd + 1);
  221.                 $maxPadding   $assign;
  222.             }//end if
  223.  
  224.             $found = 0;
  225.             if ($tokens[($var + 1)]['code'=== T_WHITESPACE{
  226.                 $found $tokens[($var + 1)]['length'];
  227.                 if ($found === 0{
  228.                     // This means a newline was found.
  229.                     $found = 1;
  230.                 }
  231.             }
  232.  
  233.             $assignments[$assign= array(
  234.                                      'var_end'    => $varEnd,
  235.                                      'assign_len' => $assignLen,
  236.                                      'assign_col' => $assignColumn,
  237.                                      'expected'   => $padding,
  238.                                      'found'      => $found,
  239.                                     );
  240.  
  241.             $lastLine   $tokens[$assign]['line'];
  242.             $prevAssign $assign;
  243.         }//end for
  244.  
  245.         if (empty($assignments=== true{
  246.             return $stackPtr;
  247.         }
  248.  
  249.         $numAssignments count($assignments);
  250.  
  251.         $errorGenerated = false;
  252.         foreach ($assignments as $assignment => $data{
  253.             if ($data['found'=== $data['expected']{
  254.                 continue;
  255.             }
  256.  
  257.             $expectedText $data['expected'].' space';
  258.             if ($data['expected'!== 1{
  259.                 $expectedText .= 's';
  260.             }
  261.  
  262.             if ($data['found'=== null{
  263.                 $foundText 'a new line';
  264.             else {
  265.                 $foundText $data['found'].' space';
  266.                 if ($data['found'!== 1{
  267.                     $foundText .= 's';
  268.                 }
  269.             }
  270.  
  271.             if ($numAssignments === 1{
  272.                 $type  'Incorrect';
  273.                 $error 'Equals sign not aligned correctly; expected %s but found %s';
  274.             else {
  275.                 $type  'NotSame';
  276.                 $error 'Equals sign not aligned with surrounding assignments; expected %s but found %s';
  277.             }
  278.  
  279.             $errorData = array(
  280.                           $expectedText,
  281.                           $foundText,
  282.                          );
  283.  
  284.             if ($this->error === true{
  285.                 $fix $phpcsFile->addFixableError($error$assignment$type$errorData);
  286.             else {
  287.                 $fix $phpcsFile->addFixableWarning($error$assignment$type.'Warning'$errorData);
  288.             }
  289.  
  290.             $errorGenerated = true;
  291.  
  292.             if ($fix === true && $data['found'!== null{
  293.                 $newContent str_repeat(' '$data['expected']);
  294.                 if ($data['found'=== 0{
  295.                     $phpcsFile->fixer->addContentBefore($assignment$newContent);
  296.                 else {
  297.                     $phpcsFile->fixer->replaceToken(($assignment - 1)$newContent);
  298.                 }
  299.             }
  300.         }//end foreach
  301.  
  302.         if ($numAssignments > 1{
  303.             if ($errorGenerated === true{
  304.                 $phpcsFile->recordMetric($stackPtr'Adjacent assignments aligned''no');
  305.             else {
  306.                 $phpcsFile->recordMetric($stackPtr'Adjacent assignments aligned''yes');
  307.             }
  308.         }
  309.  
  310.         if ($stopped !== null{
  311.             return $this->checkAlignment($phpcsFile$stopped);
  312.         else {
  313.             return $assignment;
  314.         }
  315.  
  316.     }//end checkAlignment()
  317.  
  318.  
  319. }//end class

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