Skip to content

Commit

Permalink
Merge 8ec9ea4 into c4bf9ca
Browse files Browse the repository at this point in the history
  • Loading branch information
nightlinus committed Mar 31, 2020
2 parents c4bf9ca + 8ec9ea4 commit b4bfffb
Show file tree
Hide file tree
Showing 5 changed files with 123 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,26 @@
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function array_keys;
use function count;
use function max;
use function reset;
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 +62,36 @@ 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 (!$this->ignoreAssignmentsInsideFunctionCalls && count($equalsTokenPointers) !== 0) {
$this->error($phpcsFile, $conditionType, reset($equalsTokenPointers));
return;
}

foreach ($equalsTokenPointers as $equalsTokenPointer) {
$parenthesisStarts = array_keys($tokens[$equalsTokenPointer]['nested_parenthesis'] ?? []);
$insideParenthesis = max($parenthesisStarts);
if ($insideParenthesis === $parenthesisOpener) {
$this->error($phpcsFile, $conditionType, $equalsTokenPointer);
//this is assignment inside if expression
continue;
}

$functionCall = TokenHelper::findPrevious($phpcsFile, T_STRING, $insideParenthesis, $parenthesisOpener);
if ($functionCall !== null) {
//this is assignment inside function call
continue;
}

//this is assignment inside nested parenthesis
$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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,31 @@ public function testCorrectFile(): void
public function testIncorrectFile(): void
{
$resultFile = self::checkFile(__DIR__ . '/data/allAssignmentsInConditions.php');
foreach (range(3, 6) as $lineNumber) {
foreach (range(3, 7) 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,
]
);
foreach (range(3, 7) 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,4 @@
if ($foo) {} elseif ($foo = 5) {}
do { } while ($foo = 5);
if (($line = fgets($fp)) !== null) { }
if (($a = readfile($file = 'test'))) { }
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 b4bfffb

Please sign in to comment.