Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added space after not operator checker #100

Merged
merged 1 commit into from
Apr 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @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 <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @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 <info@nfq.com>
*
* 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 <info@nfq.com>
*
* 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