Skip to content

Commit

Permalink
Merge b4c03ab into c4bf9ca
Browse files Browse the repository at this point in the history
  • Loading branch information
nightlinus committed Mar 31, 2020
2 parents c4bf9ca + b4c03ab commit 071083f
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 3 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ Assignment in `while` loop condition is specifically allowed because it's common

This is a great addition to already existing `SlevomatCodingStandard.ControlStructures.DisallowYodaComparison` because it prevents the danger of assigning something by mistake instead of using comparison operator like `===`.

Sniff provides the following settings:
* `ignoreAssignmentsInsideFunctionCalls`: ignores assignment inside function calls, like this:

```php
if (in_array(1, $haystack, $strict = true) {

}
```

#### SlevomatCodingStandard.ControlStructures.DisallowContinueWithoutIntegerOperandInSwitch 🔧

Disallows use of `continue` without integer operand in `switch` because it emits a warning in PHP 7.3 and higher.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function array_keys;
use function max;
use function sprintf;
use const T_DO;
use const T_ELSEIF;
use const T_EQUAL;
use const T_IF;
use const T_STRING;
use const T_WHILE;

class AssignmentInConditionSniff implements Sniff
{

public const CODE_ASSIGNMENT_IN_CONDITION = 'AssignmentInCondition';

/** @var bool */
public $ignoreAssignmentsInsideFunctionCalls = false;

/**
* @return array<int, (int|string)>
*/
Expand Down Expand Up @@ -54,11 +60,37 @@ public function process(File $phpcsFile, $conditionStartPointer): void

private function processCondition(File $phpcsFile, int $parenthesisOpener, int $parenthesisCloser, string $conditionType): void
{
$equalsTokenPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $parenthesisOpener + 1, $parenthesisCloser);
if ($equalsTokenPointer === null) {
$equalsTokenPointers = TokenHelper::findNextAll($phpcsFile, T_EQUAL, $parenthesisOpener + 1, $parenthesisCloser);
$tokens = $phpcsFile->getTokens();
if ($equalsTokenPointers === []) {
return;
}

if (!$this->ignoreAssignmentsInsideFunctionCalls) {
$this->error($phpcsFile, $conditionType, $equalsTokenPointers[0]);
return;
}

foreach ($equalsTokenPointers as $equalsTokenPointer) {
$parenthesisStarts = array_keys($tokens[$equalsTokenPointer]['nested_parenthesis']);

$insideParenthesis = max($parenthesisStarts);
if ($insideParenthesis === $parenthesisOpener) {
$this->error($phpcsFile, $conditionType, $equalsTokenPointer);
continue;
}

$functionCall = TokenHelper::findPrevious($phpcsFile, T_STRING, $insideParenthesis, $parenthesisOpener);
if ($functionCall !== null) {
continue;
}

$this->error($phpcsFile, $conditionType, $equalsTokenPointer);
}
}

private function error(File $phpcsFile, string $conditionType, int $equalsTokenPointer): void
{
$phpcsFile->addError(
sprintf('Assignment in %s condition is not allowed.', $conditionType),
$equalsTokenPointer,
Expand Down
4 changes: 4 additions & 0 deletions build/PHPStan/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ parameters:
message: '#Access to an undefined property PHP_CodeSniffer\\Config::\$tabWidth#'
count: 1
path: %currentWorkingDirectory%/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.php
-
message: '#Offset ''nested_parenthesis'' does not exist on array#'
count: 1
path: %currentWorkingDirectory%/SlevomatCodingStandard/Sniffs/ControlStructures/AssignmentInConditionSniff.php

services:
-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,34 @@ public function testCorrectFile(): void
public function testIncorrectFile(): void
{
$resultFile = self::checkFile(__DIR__ . '/data/allAssignmentsInConditions.php');
foreach (range(3, 6) as $lineNumber) {
self::assertEquals(6, $resultFile->getErrorCount());
foreach (range(3, 8) as $lineNumber) {
self::assertSniffError($resultFile, $lineNumber, AssignmentInConditionSniff::CODE_ASSIGNMENT_IN_CONDITION);
}
}

public function testNoErrorsWithIgnoreAssignmentsInsideFunctionCalls(): void
{
$report = self::checkFile(
__DIR__ . '/data/noAssignmentsInConditionsIgnoreAssignmentsInsideFunctionCalls.php',
[
'ignoreAssignmentsInsideFunctionCalls' => true,
]
);
self::assertNoSniffErrorInFile($report);
}

public function testErrorsWithIgnoreAssignmentsInsideFunctionCalls(): void
{
$resultFile = self::checkFile(
__DIR__ . '/data/allAssignmentsInConditions.php',
[
'ignoreAssignmentsInsideFunctionCalls' => true,
]
);

self::assertEquals(7, $resultFile->getErrorCount());
foreach (range(3, 8) as $lineNumber) {
self::assertSniffError($resultFile, $lineNumber, AssignmentInConditionSniff::CODE_ASSIGNMENT_IN_CONDITION);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
if ($foo) {} elseif ($foo = 5) {}
do { } while ($foo = 5);
if (($line = fgets($fp)) !== null) { }
if (($a = readfile($file = 'test'))) { }
if ($a = 1 && $b = 2) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

if ($foo == 5) {

} elseif ($foo == 10) {

}

if ($foo === 5) {

} elseif ($foo === 10) {

}

if ($foo != 5) {

} elseif ($foo != 10) {

}

if ($foo !== 5) {

} elseif ($foo !== 10) {

}

while ($foo == 5) {

}

while ($foo === 5) {

}

while ($foo = 5) {

}

while (($row = $db->fetch()) !== null) {

}

do {

} while ($foo === 5);

if (in_array($a = 1, [], $strict = true)) {

}

if ($this->call($a = 1)) {

}

0 comments on commit 071083f

Please sign in to comment.