Skip to content

Commit

Permalink
Merge pull request #100 from chyzas/patch-operator-spacing
Browse files Browse the repository at this point in the history
Added space after not operator checker
  • Loading branch information
saimaz committed Apr 20, 2015
2 parents bca93ea + 72c3c22 commit c2fd59c
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 0 deletions.
324 changes: 324 additions & 0 deletions Sniffs/WhiteSpace/OperatorSpacingSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
<?php
/**
* Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <[email protected]>
* @author Marc McIntyre <[email protected]>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @link http://pear.php.net/package/PHP_CodeSniffer
*/

/**
* Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff.
*
* Verifies that operators have valid spacing surrounding them.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <[email protected]>
* @author Marc McIntyre <[email protected]>
* @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class Ongr_Sniffs_WhiteSpace_OperatorSpacingSniff implements PHP_CodeSniffer_Sniff
{

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

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


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

return array_unique(
array_merge($comparison, $operators, $assignment, $inlineIf, [T_BOOLEAN_NOT])
);

}//end register()


/**
* Processes this sniff, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_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(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

// Ongr check space after not operator.
if ($tokens[$stackPtr]['code'] === T_BOOLEAN_NOT && $tokens[$stackPtr + 1]['code'] === T_WHITESPACE) {
$error = 'Whitespace found after not operator';
$phpcsFile->addError($error, $stackPtr, 'SpacingAfterNot');
return;
}

// 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) {
// 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(PHP_CodeSniffer_Tokens::$operators[$tokens[$prev]['code']]) === true) {
// Just trying to operate on a negative value; eg. ($var * -1).
return;
}

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

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

if (isset(PHP_CodeSniffer_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_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(PHP_CodeSniffer_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 ($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 ($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 process()


}//end class
35 changes: 35 additions & 0 deletions Tests/Unit/WhiteSpace/OperatorSpacingSniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the ONGR package.
*
* (c) NFQ Technologies UAB <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Ongr\Tests\Unit\WhiteSpace;

use Ongr\Tests\AbstractSniffUnitTest;

class OperatorSpacingSniffTest extends AbstractSniffUnitTest
{
/**
* {@inheritdoc}
*/
protected function getErrorList()
{
return [
12 => 1,
];
}

/**
* {@inheritdoc}
*/
protected function getWarningList()
{
return [];
}
}
14 changes: 14 additions & 0 deletions Tests/Unit/WhiteSpace/OperatorSpacingSniffTest.phptest
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

/*
* This file is part of the ONGR package.
*
* (c) NFQ Technologies UAB <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

if (! $foo) {
true;
}
1 change: 1 addition & 0 deletions ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<exclude name="Squiz.WhiteSpace.FunctionSpacing"/>
<exclude name="Squiz.WhiteSpace.MemberVarSpacing"/>
<exclude name="Squiz.WhiteSpace.ObjectOperatorSpacing"/>
<exclude name="Squiz.WhiteSpace.OperatorSpacing"/>


<!--Experimenting-->
Expand Down

0 comments on commit c2fd59c

Please sign in to comment.