You are here

OperatorSpacingSniff.php in Coder 8.2

Same filename and directory in other branches
  1. 7.2 coder_sniffer/Drupal/Sniffs/WhiteSpace/OperatorSpacingSniff.php

File

coder_sniffer/Drupal/Sniffs/WhiteSpace/OperatorSpacingSniff.php
View source
<?php

/**
 * \Drupal\Sniffs\WhiteSpace\OperatorSpacingSniff.
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @link     http://pear.php.net/package/PHP_CodeSniffer
 */
namespace Drupal\Sniffs\WhiteSpace;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Overrides Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff to allow the plus operator
 * on numbers like "$i = +1;".
 *
 * @category PHP
 * @package  PHP_CodeSniffer
 * @link     http://pear.php.net/package/PHP_CodeSniffer
 */
class OperatorSpacingSniff implements Sniff {

  /**
   * A list of tokenizers this sniff supports.
   *
   * @var array
   */
  public $supportedTokenizers = array(
    'PHP',
    'JS',
  );

  /**
   * Allow newlines instead of spaces.
   *
   * @var boolean
   */
  public $ignoreNewlines = true;

  /**
   * Returns an array of tokens this test wants to listen for.
   *
   * @return array
   */
  public function register() {
    $comparison = Tokens::$comparisonTokens;
    $operators = Tokens::$operators;
    $assignment = Tokens::$assignmentTokens;
    $inlineIf = array(
      T_INLINE_THEN,
      T_INLINE_ELSE,
    );
    return array_unique(array_merge($comparison, $operators, $assignment, $inlineIf));
  }

  //end register()

  /**
   * Processes this sniff, when one of its tokens is encountered.
   *
   * @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
   * @param int                         $stackPtr  The position of the current token in
   *                                               the stack passed in $tokens.
   *
   * @return void
   */
  public function process(File $phpcsFile, $stackPtr) {
    $tokens = $phpcsFile
      ->getTokens();

    // Skip default values in function declarations.
    if ($tokens[$stackPtr]['code'] === T_EQUAL || $tokens[$stackPtr]['code'] === T_MINUS) {
      if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) {
        $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']);
        $bracket = array_pop($parenthesis);
        if (isset($tokens[$bracket]['parenthesis_owner']) === true) {
          $function = $tokens[$bracket]['parenthesis_owner'];
          if ($tokens[$function]['code'] === T_FUNCTION || $tokens[$function]['code'] === T_CLOSURE) {
            return;
          }
        }
      }
    }
    if ($tokens[$stackPtr]['code'] === T_EQUAL) {

      // Skip for '=&' case.
      if (isset($tokens[$stackPtr + 1]) === true && $tokens[$stackPtr + 1]['code'] === T_BITWISE_AND) {
        return;
      }
    }

    // Skip short ternary such as: "$foo = $bar ?: true;".
    if ($tokens[$stackPtr]['code'] === T_INLINE_THEN && $tokens[$stackPtr + 1]['code'] === T_INLINE_ELSE || $tokens[$stackPtr - 1]['code'] === T_INLINE_THEN && $tokens[$stackPtr]['code'] === T_INLINE_ELSE) {
      return;
    }
    if ($tokens[$stackPtr]['code'] === T_BITWISE_AND) {

      // If it's not a reference, then we expect one space either side of the
      // bitwise operator.
      if ($phpcsFile
        ->isReference($stackPtr) === true) {
        return;
      }

      // Check there is one space before the & operator.
      if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) {
        $error = 'Expected 1 space before "&" operator; 0 found';
        $fix = $phpcsFile
          ->addFixableError($error, $stackPtr, 'NoSpaceBeforeAmp');
        if ($fix === true) {
          $phpcsFile->fixer
            ->addContentBefore($stackPtr, ' ');
        }
        $phpcsFile
          ->recordMetric($stackPtr, 'Space before operator', 0);
      }
      else {
        if ($tokens[$stackPtr - 2]['line'] !== $tokens[$stackPtr]['line']) {
          $found = 'newline';
        }
        else {
          $found = $tokens[$stackPtr - 1]['length'];
        }
        $phpcsFile
          ->recordMetric($stackPtr, 'Space before operator', $found);
        if ($found !== 1 && ($found !== 'newline' || $this->ignoreNewlines === false)) {
          $error = 'Expected 1 space before "&" operator; %s found';
          $data = array(
            $found,
          );
          $fix = $phpcsFile
            ->addFixableError($error, $stackPtr, 'SpacingBeforeAmp', $data);
          if ($fix === true) {
            $phpcsFile->fixer
              ->replaceToken($stackPtr - 1, ' ');
          }
        }
      }

      //end if

      // Check there is one space after the & operator.
      if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) {
        $error = 'Expected 1 space after "&" operator; 0 found';
        $fix = $phpcsFile
          ->addFixableError($error, $stackPtr, 'NoSpaceAfterAmp');
        if ($fix === true) {
          $phpcsFile->fixer
            ->addContent($stackPtr, ' ');
        }
        $phpcsFile
          ->recordMetric($stackPtr, 'Space after operator', 0);
      }
      else {
        if ($tokens[$stackPtr + 2]['line'] !== $tokens[$stackPtr]['line']) {
          $found = 'newline';
        }
        else {
          $found = $tokens[$stackPtr + 1]['length'];
        }
        $phpcsFile
          ->recordMetric($stackPtr, 'Space after operator', $found);
        if ($found !== 1 && ($found !== 'newline' || $this->ignoreNewlines === false)) {
          $error = 'Expected 1 space after "&" operator; %s found';
          $data = array(
            $found,
          );
          $fix = $phpcsFile
            ->addFixableError($error, $stackPtr, 'SpacingAfterAmp', $data);
          if ($fix === true) {
            $phpcsFile->fixer
              ->replaceToken($stackPtr + 1, ' ');
          }
        }
      }

      //end if
      return;
    }

    //end if
    if ($tokens[$stackPtr]['code'] === T_MINUS || $tokens[$stackPtr]['code'] === T_PLUS) {

      // Check minus spacing, but make sure we aren't just assigning
      // a minus value or returning one.
      $prev = $phpcsFile
        ->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
      if ($tokens[$prev]['code'] === T_RETURN) {

        // Just returning a negative value; eg. (return -1).
        return;
      }
      if (isset(Tokens::$operators[$tokens[$prev]['code']]) === true) {

        // Just trying to operate on a negative value; eg. ($var * -1).
        return;
      }
      if (isset(Tokens::$comparisonTokens[$tokens[$prev]['code']]) === true) {

        // Just trying to compare a negative value; eg. ($var === -1).
        return;
      }
      if (isset(Tokens::$booleanOperators[$tokens[$prev]['code']]) === true) {

        // Just trying to compare a negative value; eg. ($var || -1 === $b).
        return;
      }
      if (isset(Tokens::$assignmentTokens[$tokens[$prev]['code']]) === true) {

        // Just trying to assign a negative value; eg. ($var = -1).
        return;
      }

      // A list of tokens that indicate that the token is not
      // part of an arithmetic operation.
      $invalidTokens = array(
        T_COMMA => true,
        T_OPEN_PARENTHESIS => true,
        T_OPEN_SQUARE_BRACKET => true,
        T_OPEN_SHORT_ARRAY => true,
        T_DOUBLE_ARROW => true,
        T_COLON => true,
        T_INLINE_THEN => true,
        T_INLINE_ELSE => true,
        T_CASE => true,
      );
      if (isset($invalidTokens[$tokens[$prev]['code']]) === true) {

        // Just trying to use a negative value; eg. myFunction($var, -2).
        return;
      }
    }

    //end if
    $operator = $tokens[$stackPtr]['content'];
    if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) {
      $error = "Expected 1 space before \"{$operator}\"; 0 found";
      $fix = $phpcsFile
        ->addFixableError($error, $stackPtr, 'NoSpaceBefore');
      if ($fix === true) {
        $phpcsFile->fixer
          ->addContentBefore($stackPtr, ' ');
      }
      $phpcsFile
        ->recordMetric($stackPtr, 'Space before operator', 0);
    }
    else {
      if (isset(Tokens::$assignmentTokens[$tokens[$stackPtr]['code']]) === false) {

        // Don't throw an error for assignments, because other standards allow
        // multiple spaces there to align multiple assignments.
        if ($tokens[$stackPtr - 2]['line'] !== $tokens[$stackPtr]['line']) {
          $found = 'newline';
        }
        else {
          $found = $tokens[$stackPtr - 1]['length'];
        }
        $phpcsFile
          ->recordMetric($stackPtr, 'Space before operator', $found);
        if ($found !== 1 && ($found !== 'newline' || $this->ignoreNewlines === false)) {
          $error = 'Expected 1 space before "%s"; %s found';
          $data = array(
            $operator,
            $found,
          );
          $fix = $phpcsFile
            ->addFixableError($error, $stackPtr, 'SpacingBefore', $data);
          if ($fix === true) {
            $phpcsFile->fixer
              ->beginChangeset();
            if ($found === 'newline') {
              $i = $stackPtr - 2;
              while ($tokens[$i]['code'] === T_WHITESPACE) {
                $phpcsFile->fixer
                  ->replaceToken($i, '');
                $i--;
              }
            }
            $phpcsFile->fixer
              ->replaceToken($stackPtr - 1, ' ');
            $phpcsFile->fixer
              ->endChangeset();
          }
        }

        //end if
      }
    }

    //end if
    if (isset($tokens[$stackPtr + 1]) === false) {
      return;
    }
    if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) {
      $error = "Expected 1 space after \"{$operator}\"; 0 found";
      $fix = $phpcsFile
        ->addFixableError($error, $stackPtr, 'NoSpaceAfter');
      if ($fix === true) {
        $phpcsFile->fixer
          ->addContent($stackPtr, ' ');
      }
      $phpcsFile
        ->recordMetric($stackPtr, 'Space after operator', 0);
    }
    else {
      if (isset($tokens[$stackPtr + 2]) === true && $tokens[$stackPtr + 2]['line'] !== $tokens[$stackPtr]['line']) {
        $found = 'newline';
      }
      else {
        $found = $tokens[$stackPtr + 1]['length'];
      }
      $phpcsFile
        ->recordMetric($stackPtr, 'Space after operator', $found);
      if ($found !== 1 && ($found !== 'newline' || $this->ignoreNewlines === false)) {
        $error = 'Expected 1 space after "%s"; %s found';
        $data = array(
          $operator,
          $found,
        );
        $fix = $phpcsFile
          ->addFixableError($error, $stackPtr, 'SpacingAfter', $data);
        if ($fix === true) {
          $phpcsFile->fixer
            ->replaceToken($stackPtr + 1, ' ');
        }
      }
    }

    //end if
  }

}

//end class

Classes

Namesort descending Description
OperatorSpacingSniff Overrides Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff to allow the plus operator on numbers like "$i = +1;".