-
-
Notifications
You must be signed in to change notification settings - Fork 8
Add Universal.CodeAnalysis.MixedBooleanOperator #271
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
Changes from 19 commits
6b72184
9414411
cca88c1
b4a8ed0
0cc2f34
a051300
b8c6d30
ce00faf
4a34225
1e87cae
8f83191
b713551
54fa62c
5c82b55
06b47f1
ba07bcf
13e9660
7a71b8a
6f8e5ba
2985f82
20541c0
9df7cd2
855e932
9df244b
27f6552
c07507c
ecc5bd4
7b38efb
6d84a98
14f2d22
9f78b15
12ce668
312beb6
d152ea7
3126cd6
100115b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <?xml version="1.0"?> | ||
| <documentation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:noNamespaceSchemaLocation="https://phpcsstandards.github.io/PHPCSDevTools/phpcsdocs.xsd" | ||
| title="Mixed Boolean Operator" | ||
| > | ||
| <standard> | ||
| <![CDATA[ | ||
| Forbids mixing different binary boolean operators within a single expression without making precedence clear using parentheses. | ||
| ]]> | ||
| </standard> | ||
| <code_comparison> | ||
| <code title="Valid: Making precedence clear with parentheses."> | ||
| <![CDATA[ | ||
| $one = false; | ||
| $two = false; | ||
| $three = true; | ||
|
|
||
| $result = <em>($one && $two) || $three</em>; | ||
| $result2 = <em>$one && ($two || $three)</em>; | ||
| $result3 = <em>($one && !$two) xor $three;</em>; | ||
| $result4 = <em>$one && (!$two xor $three);</em>; | ||
| ]]> | ||
| </code> | ||
| <code title="Invalid: Not using parentheses."> | ||
| <![CDATA[ | ||
| $one = false; | ||
| $two = false; | ||
| $three = true; | ||
|
|
||
| $result = <em>$one && $two || $three</em>; | ||
| $result3 = <em>$one && !$two xor $three;</em>; | ||
| ]]> | ||
| </code> | ||
| </code_comparison> | ||
| </documentation> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| <?php | ||
| /** | ||
| * PHPCSExtra, a collection of sniffs and standards for use with PHP_CodeSniffer. | ||
| * | ||
| * @package PHPCSExtra | ||
| * @copyright 2021 WoltLab GmbH, 2023 PHPCSExtra Contributors | ||
TimWolla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 | ||
| * @link https://github.com/PHPCSStandards/PHPCSExtra | ||
| */ | ||
|
|
||
| namespace PHPCSExtra\Universal\Sniffs\CodeAnalysis; | ||
|
|
||
| use PHP_CodeSniffer\Files\File; | ||
| use PHP_CodeSniffer\Sniffs\Sniff; | ||
| use PHP_CodeSniffer\Util\Tokens; | ||
| use PHPCSUtils\BackCompat\BCFile; | ||
|
|
||
| /** | ||
| * Forbid mixing different binary boolean operators within a single expression without making precedence | ||
| * clear using parentheses. | ||
| * | ||
TimWolla marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3205 | ||
| * @link https://github.com/php-fig/per-coding-style/issues/22 | ||
| * | ||
| * @since 1.2.0 | ||
| */ | ||
| final class MixedBooleanOperatorSniff implements Sniff | ||
| { | ||
| private $previousTokens = []; | ||
TimWolla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Returns an array of tokens this test wants to listen for. | ||
| * | ||
| * @since 1.2.0 | ||
| * | ||
| * @return array<int|string> | ||
| */ | ||
| public function register() | ||
| { | ||
| $this->previousTokens = \array_merge( | ||
| Tokens::$booleanOperators, | ||
| [\T_INLINE_THEN, \T_INLINE_ELSE] | ||
| ); | ||
TimWolla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| return Tokens::$booleanOperators; | ||
| } | ||
|
|
||
| /** | ||
| * Processes this test, when one of its tokens is encountered. | ||
| * | ||
| * @since 1.2.0 | ||
| * | ||
| * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. | ||
| * @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(); | ||
|
|
||
| $start = BCFile::findStartOfStatement($phpcsFile, $stackPtr); | ||
|
|
||
| $previous = $phpcsFile->findPrevious( | ||
| $this->previousTokens, | ||
| $stackPtr - 1, | ||
| $start, | ||
| false, | ||
| null, | ||
| true | ||
| ); | ||
|
|
||
| if ( | ||
| // No token found. | ||
| $previous === false | ||
| // Identical operator found. | ||
| || $tokens[$previous]['code'] === $tokens[$stackPtr]['code'] | ||
| // Beginning of the expression found for the ternary conditional operator. | ||
| || \in_array($tokens[$previous]['code'], [\T_INLINE_THEN, \T_INLINE_ELSE], true) | ||
|
||
| ) { | ||
| return; | ||
| } | ||
|
|
||
| // We found a mismatching operator, thus we must report the error. | ||
| $error = "Mixing different binary boolean operators within an expression without using parentheses to clarify precedence."; | ||
| $phpcsFile->addError($error, $stackPtr, 'MissingParentheses', []); | ||
TimWolla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| <?php | ||
TimWolla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (true && true || true); // Not OK. | ||
| if ((true && true) || true); | ||
| if (true && (true || true)); | ||
|
|
||
| $var = true && true || true; // Not OK. | ||
| $var = (true && true) || true; | ||
| $var = true && (true || true); | ||
|
|
||
| $complex = true && (true || true) && true; | ||
| $complex = true && (true || true) || true; // Not OK. | ||
|
|
||
| if ( | ||
| true | ||
| && true | ||
| || true // Not OK. | ||
| ); | ||
|
|
||
| if ( | ||
| true | ||
| && ( | ||
| true | ||
| || true | ||
| ) | ||
| ); | ||
|
|
||
| if (true && foo(true || true)); | ||
| if (true && foo(true && true || true)); // Not OK. | ||
| if (true && $foo[true || true]); | ||
| if (true && $foo[true && true || true]); // Not OK. | ||
|
|
||
| if (true && foo(true) || true); // Not OK. | ||
| if (true && $foo[true] || true); // Not OK. | ||
| if (true && foo($foo[true]) || true); // Not OK. | ||
|
|
||
| $foo[] = true && true || false; // Not OK. | ||
|
|
||
| foo([true && true || false]); // Not OK. | ||
|
|
||
| if (true && true || true && true); // Not OK. | ||
|
|
||
| $foo = false || true && (#[\Attr(true && true || true)] function (#[\SensitiveParameter] $p) { // Not OK. | ||
| echo true || true && true; // Not OK. | ||
|
|
||
| return true; | ||
| })('dummy') || false; // Not OK. | ||
|
|
||
| $foo = false || (true && (#[\Attr((true && true) || true)] function (#[\SensitiveParameter] $p) { | ||
| echo (true || true) && true; | ||
|
|
||
| return true; | ||
| })('dummy')) || false; | ||
|
|
||
| $foo = true || true || (#[\Attr(true && true && true)] function (#[\SensitiveParameter] $p) { | ||
| echo true && true && true; | ||
|
|
||
| return true; | ||
| })('dummy') || false; | ||
|
|
||
| if (true && [true, callMe(), ${true || true}] || true); // Not OK. | ||
| if (true && [true, callMe(), ${true || true}] && true); | ||
|
|
||
| for (true || true || true; true && true && true; true || true || true); | ||
| for (true || true && true; true && true || true; true || true && true); // Not OK. | ||
|
|
||
| for ($a = true || true || true, $b = true && true && true; $a; $b); | ||
| for ($a = true || true && true, $b = true || true && true; $a; $b); // Not OK. | ||
|
|
||
| $foo = true || true || true ? true && true && true : true || true || true; | ||
| $foo = true && true || true // Not OK. | ||
| ? true || true && true // Not OK. | ||
| : true || true && true; // Not OK. | ||
|
|
||
| for(true || true || true, true && true && true); | ||
| for(true && true || true, true && true || true); // Not OK. | ||
|
|
||
| (true && true and true); // Not OK. | ||
| (true && true or true); // Not OK. | ||
| (true and true or true); // Not OK. | ||
| (true and true xor true and true); // Not OK. | ||
|
|
||
| if (true || true && true && true && true); // Not OK. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| <?php | ||
| /** | ||
| * PHPCSExtra, a collection of sniffs and standards for use with PHP_CodeSniffer. | ||
| * | ||
| * @package PHPCSExtra | ||
| * @copyright 2021 WoltLab GmbH, 2023 PHPCSExtra Contributors | ||
| * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 | ||
| * @link https://github.com/PHPCSStandards/PHPCSExtra | ||
| */ | ||
|
|
||
| namespace PHPCSExtra\Universal\Tests\CodeAnalysis; | ||
|
|
||
| use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; | ||
|
|
||
| /** | ||
| * Unit test class for the MixedBooleanOperator sniff. | ||
| * | ||
| * @covers PHPCSExtra\Universal\Sniffs\CodeAnalysis\MixedBooleanOperatorSniff | ||
| * | ||
| * @since 1.2.0 | ||
| */ | ||
| final class MixedBooleanOperatorUnitTest extends AbstractSniffUnitTest | ||
| { | ||
|
|
||
| /** | ||
| * Returns the lines where errors should occur. | ||
| * | ||
| * @return array<int, int> Key is the line number, value is the number of expected errors. | ||
| */ | ||
| public function getErrorList() | ||
| { | ||
| return [ | ||
| 3 => 1, | ||
| 7 => 1, | ||
| 12 => 1, | ||
| 17 => 1, | ||
| 29 => 1, | ||
| 31 => 1, | ||
| 33 => 1, | ||
| 34 => 1, | ||
| 35 => 1, | ||
| 37 => 1, | ||
| 39 => 1, | ||
| 41 => 2, | ||
| 43 => 2, | ||
| 44 => 1, | ||
| 47 => 1, | ||
| 61 => 1, | ||
| 65 => 3, | ||
| 68 => 2, | ||
| 71 => 1, | ||
| 72 => 1, | ||
| 73 => 1, | ||
| 76 => 2, | ||
| 78 => 1, | ||
| 79 => 1, | ||
| 80 => 1, | ||
| 81 => 2, | ||
| 83 => 1, | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the lines where warnings should occur. | ||
| * | ||
| * @return array<int, int> Key is the line number, value is the number of expected warnings. | ||
| */ | ||
| public function getWarningList() | ||
| { | ||
| return []; | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.