Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f9f77ef

Browse files
VincentLangletondrejmirtes
authored andcommitted
Add numeric check on unary plus and unary minus
1 parent 1f1358d commit f9f77ef

File tree

7 files changed

+189
-1
lines changed

7 files changed

+189
-1
lines changed

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
|:---------------------------------------|:--------------------------------------------------------------------------------------------------------|
1111
| `booleansInConditions` | Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `\|\|`. |
1212
| `booleansInLoopConditions` | Require booleans in `while` and `do while` loop conditions. |
13-
| `numericOperandsInArithmeticOperators` | Require numeric operands or arrays in `+` and numeric operands in `-`/`*`/`/`/`**`/`%`. |
13+
| `numericOperandsInArithmeticOperators` | Require numeric operand in `+$var`, `-$var`, `$var++`, `$var--`, `++$var` and `--$var`. |
1414
| `numericOperandsInArithmeticOperators` | Require numeric operand in `$var++`, `$var--`, `++$var`and `--$var`. |
1515
| `strictFunctionCalls` | These functions contain a `$strict` parameter for better type safety, it must be set to `true`:<br>* `in_array` (3rd parameter)<br>* `array_search` (3rd parameter)<br>* `array_keys` (3rd parameter; only if the 2nd parameter `$search_value` is provided)<br>* `base64_decode` (2nd parameter). |
1616
| `overwriteVariablesWithLoop` | Variables assigned in `while` loop condition and `for` loop initial assignment cannot be used after the loop. |

‎rules.neon‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ conditionalTags:
106106
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
107107
PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule:
108108
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
109+
PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule:
110+
phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%]
111+
PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule:
112+
phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%]
109113
PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule:
110114
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
111115
PHPStan\Rules\Operators\OperandsInArithmeticDivisionRule:
@@ -242,6 +246,12 @@ services:
242246
-
243247
class: PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule
244248

249+
-
250+
class: PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule
251+
252+
-
253+
class: PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule
254+
245255
-
246256
class: PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule
247257

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Operators;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\UnaryMinus;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use PHPStan\Type\VerbosityLevel;
11+
use function sprintf;
12+
13+
/**
14+
* @phpstan-implements Rule<UnaryMinus>
15+
*/
16+
class OperandInArithmeticUnaryMinusRule implements Rule
17+
{
18+
19+
private OperatorRuleHelper $helper;
20+
21+
public function __construct(OperatorRuleHelper $helper)
22+
{
23+
$this->helper = $helper;
24+
}
25+
26+
public function getNodeType(): string
27+
{
28+
return UnaryMinus::class;
29+
}
30+
31+
public function processNode(Node $node, Scope $scope): array
32+
{
33+
$messages = [];
34+
35+
if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) {
36+
$varType = $scope->getType($node->expr);
37+
38+
$messages[] = RuleErrorBuilder::message(sprintf(
39+
'Only numeric types are allowed in unary -, %s given.',
40+
$varType->describe(VerbosityLevel::typeOnly()),
41+
))->identifier('unaryMinus.nonNumeric')->build();
42+
}
43+
44+
return $messages;
45+
}
46+
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Operators;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\UnaryPlus;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use PHPStan\Type\VerbosityLevel;
11+
use function sprintf;
12+
13+
/**
14+
* @phpstan-implements Rule<UnaryPlus>
15+
*/
16+
class OperandInArithmeticUnaryPlusRule implements Rule
17+
{
18+
19+
private OperatorRuleHelper $helper;
20+
21+
public function __construct(OperatorRuleHelper $helper)
22+
{
23+
$this->helper = $helper;
24+
}
25+
26+
public function getNodeType(): string
27+
{
28+
return UnaryPlus::class;
29+
}
30+
31+
public function processNode(Node $node, Scope $scope): array
32+
{
33+
$messages = [];
34+
35+
if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) {
36+
$varType = $scope->getType($node->expr);
37+
38+
$messages[] = RuleErrorBuilder::message(sprintf(
39+
'Only numeric types are allowed in unary +, %s given.',
40+
$varType->describe(VerbosityLevel::typeOnly()),
41+
))->identifier('unaryPlus.nonNumeric')->build();
42+
}
43+
44+
return $messages;
45+
}
46+
47+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Operators;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Rules\RuleLevelHelper;
7+
use PHPStan\Testing\RuleTestCase;
8+
9+
/**
10+
* @extends RuleTestCase<OperandInArithmeticUnaryMinusRule>
11+
*/
12+
class OperandInArithmeticUnaryMinusRuleTest extends RuleTestCase
13+
{
14+
15+
protected function getRule(): Rule
16+
{
17+
return new OperandInArithmeticUnaryMinusRule(
18+
new OperatorRuleHelper(
19+
self::getContainer()->getByType(RuleLevelHelper::class),
20+
),
21+
);
22+
}
23+
24+
public function testRule(): void
25+
{
26+
$this->analyse([__DIR__ . '/data/operators.php'], [
27+
[
28+
'Only numeric types are allowed in unary -, null given.',
29+
233,
30+
],
31+
]);
32+
}
33+
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Operators;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Rules\RuleLevelHelper;
7+
use PHPStan\Testing\RuleTestCase;
8+
9+
/**
10+
* @extends RuleTestCase<OperandInArithmeticUnaryPlusRule>
11+
*/
12+
class OperandInArithmeticUnaryPlusRuleTest extends RuleTestCase
13+
{
14+
15+
protected function getRule(): Rule
16+
{
17+
return new OperandInArithmeticUnaryPlusRule(
18+
new OperatorRuleHelper(
19+
self::getContainer()->getByType(RuleLevelHelper::class),
20+
),
21+
);
22+
}
23+
24+
public function testRule(): void
25+
{
26+
$this->analyse([__DIR__ . '/data/operators.php'], [
27+
[
28+
'Only numeric types are allowed in unary +, null given.',
29+
225,
30+
],
31+
]);
32+
}
33+
34+
}

‎tests/Rules/Operators/data/operators.php‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,19 @@ function (array $array, int $int, $mixed) {
215215
/** @var numeric-string $numericString */
216216
$numericString = doFoo();
217217
$numericString += 1;
218+
219+
+$int;
220+
+$float;
221+
+$intOrFloat;
222+
+$string;
223+
+$array;
224+
+$object;
225+
+$null;
226+
227+
-$int;
228+
-$float;
229+
-$intOrFloat;
230+
-$string;
231+
-$array;
232+
-$object;
233+
-$null;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /