diff --git a/README.md b/README.md index 85b9a5ab..e56aa34d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ |:---------------------------------------|:--------------------------------------------------------------------------------------------------------| | `booleansInConditions` | Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `\|\|`. | | `booleansInLoopConditions` | Require booleans in `while` and `do while` loop conditions. | -| `numericOperandsInArithmeticOperators` | Require numeric operands or arrays in `+` and numeric operands in `-`/`*`/`/`/`**`/`%`. | +| `numericOperandsInArithmeticOperators` | Require numeric operand in `+$var`, `-$var`, `$var++`, `$var--`, `++$var` and `--$var`. | | `numericOperandsInArithmeticOperators` | Require numeric operand in `$var++`, `$var--`, `++$var`and `--$var`. | | `strictFunctionCalls` | These functions contain a `$strict` parameter for better type safety, it must be set to `true`:
* `in_array` (3rd parameter)
* `array_search` (3rd parameter)
* `array_keys` (3rd parameter; only if the 2nd parameter `$search_value` is provided)
* `base64_decode` (2nd parameter). | | `overwriteVariablesWithLoop` | Variables assigned in `while` loop condition and `for` loop initial assignment cannot be used after the loop. | diff --git a/rules.neon b/rules.neon index dd20b8d1..7a63c4ec 100644 --- a/rules.neon +++ b/rules.neon @@ -106,6 +106,10 @@ conditionalTags: phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule: phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule: + phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%] + PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule: + phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%] PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule: phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% PHPStan\Rules\Operators\OperandsInArithmeticDivisionRule: @@ -242,6 +246,12 @@ services: - class: PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule + - + class: PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule + - class: PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule diff --git a/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php b/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php new file mode 100644 index 00000000..d3db7df5 --- /dev/null +++ b/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php @@ -0,0 +1,47 @@ + + */ +class OperandInArithmeticUnaryMinusRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return UnaryMinus::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + + if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) { + $varType = $scope->getType($node->expr); + + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in unary -, %s given.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('unaryMinus.nonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php b/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php new file mode 100644 index 00000000..78313d8c --- /dev/null +++ b/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php @@ -0,0 +1,47 @@ + + */ +class OperandInArithmeticUnaryPlusRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return UnaryPlus::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + + if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) { + $varType = $scope->getType($node->expr); + + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in unary +, %s given.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('unaryPlus.nonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tests/Rules/Operators/OperandInArithmeticUnaryMinusRuleTest.php b/tests/Rules/Operators/OperandInArithmeticUnaryMinusRuleTest.php new file mode 100644 index 00000000..d202bdbc --- /dev/null +++ b/tests/Rules/Operators/OperandInArithmeticUnaryMinusRuleTest.php @@ -0,0 +1,34 @@ + + */ +class OperandInArithmeticUnaryMinusRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new OperandInArithmeticUnaryMinusRule( + new OperatorRuleHelper( + self::getContainer()->getByType(RuleLevelHelper::class), + ), + ); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in unary -, null given.', + 233, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandInArithmeticUnaryPlusRuleTest.php b/tests/Rules/Operators/OperandInArithmeticUnaryPlusRuleTest.php new file mode 100644 index 00000000..6cc253a3 --- /dev/null +++ b/tests/Rules/Operators/OperandInArithmeticUnaryPlusRuleTest.php @@ -0,0 +1,34 @@ + + */ +class OperandInArithmeticUnaryPlusRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new OperandInArithmeticUnaryPlusRule( + new OperatorRuleHelper( + self::getContainer()->getByType(RuleLevelHelper::class), + ), + ); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in unary +, null given.', + 225, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/data/operators.php b/tests/Rules/Operators/data/operators.php index f3e75598..0c230064 100644 --- a/tests/Rules/Operators/data/operators.php +++ b/tests/Rules/Operators/data/operators.php @@ -215,3 +215,19 @@ function (array $array, int $int, $mixed) { /** @var numeric-string $numericString */ $numericString = doFoo(); $numericString += 1; + ++$int; ++$float; ++$intOrFloat; ++$string; ++$array; ++$object; ++$null; + +-$int; +-$float; +-$intOrFloat; +-$string; +-$array; +-$object; +-$null;