From 2baaf8e53a70ff6e579c8403f19169d97a29577d Mon Sep 17 00:00:00 2001 From: Michael Moravec Date: Fri, 4 May 2018 20:33:11 +0200 Subject: [PATCH] Add rules for operands in arithmetic operations --- README.md | 1 + rules.neon | 6 ++ .../OperandsInArithmeticAddition.php | 39 ++++++++ .../OperandsInArithmeticDivision.php | 30 ++++++ .../OperandsInArithmeticExponentiation.php | 30 ++++++ .../Operators/OperandsInArithmeticModulo.php | 30 ++++++ .../OperandsInArithmeticMultiplication.php | 30 ++++++ .../OperandsInArithmeticSubtraction.php | 30 ++++++ src/Rules/Operators/OperatorRuleHelper.php | 20 ++++ .../OperandsInArithmeticAdditionTest.php | 57 +++++++++++ .../OperandsInArithmeticDivisionTest.php | 57 +++++++++++ ...OperandsInArithmeticExponentiationTest.php | 53 +++++++++++ .../OperandsInArithmeticModuloTest.php | 53 +++++++++++ ...OperandsInArithmeticMultiplicationTest.php | 57 +++++++++++ .../OperandsInArithmeticSubtractionTest.php | 57 +++++++++++ tests/Rules/Operators/data/operators.php | 95 +++++++++++++++++++ 16 files changed, 645 insertions(+) create mode 100644 src/Rules/Operators/OperandsInArithmeticAddition.php create mode 100644 src/Rules/Operators/OperandsInArithmeticDivision.php create mode 100644 src/Rules/Operators/OperandsInArithmeticExponentiation.php create mode 100644 src/Rules/Operators/OperandsInArithmeticModulo.php create mode 100644 src/Rules/Operators/OperandsInArithmeticMultiplication.php create mode 100644 src/Rules/Operators/OperandsInArithmeticSubtraction.php create mode 100644 src/Rules/Operators/OperatorRuleHelper.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticAdditionTest.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticDivisionTest.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticExponentiationTest.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticModuloTest.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticMultiplicationTest.php create mode 100644 tests/Rules/Operators/OperandsInArithmeticSubtractionTest.php create mode 100644 tests/Rules/Operators/data/operators.php diff --git a/README.md b/README.md index 115745ba..882d6b1b 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [PHPStan](https://github.com/phpstan/phpstan) focuses on finding bugs in your code. But in PHP there's a lot of leeway in how stuff can be written. This repository contains additional rules that revolve around strictly and strongly typed code with no loose casting for those who want additional safety in extremely defensive programming: * Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `||`. +* Require numeric operands or arrays in `+` and numeric operands in `-`/`*`/`/`/`**`/`%`. * These functions contain a `$strict` parameter for better type safety, it must be set to `true`: * `in_array` (3rd parameter) * `array_search` (3rd parameter) diff --git a/rules.neon b/rules.neon index 3e540e67..9236a92e 100644 --- a/rules.neon +++ b/rules.neon @@ -17,6 +17,12 @@ rules: - PHPStan\Rules\Methods\MissingMethodParameterTypehintRule - PHPStan\Rules\Methods\MissingMethodReturnTypehintRule - PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule + - PHPStan\Rules\Operators\OperandsInArithmeticAddition + - PHPStan\Rules\Operators\OperandsInArithmeticDivision + - PHPStan\Rules\Operators\OperandsInArithmeticExponentiation + - PHPStan\Rules\Operators\OperandsInArithmeticModulo + - PHPStan\Rules\Operators\OperandsInArithmeticMultiplication + - PHPStan\Rules\Operators\OperandsInArithmeticSubtraction - PHPStan\Rules\Properties\MissingPropertyTypehintRule - PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule - PHPStan\Rules\StrictCalls\StrictFunctionCallsRule diff --git a/src/Rules/Operators/OperandsInArithmeticAddition.php b/src/Rules/Operators/OperandsInArithmeticAddition.php new file mode 100644 index 00000000..9ad57c47 --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticAddition.php @@ -0,0 +1,39 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + $mixedArrayType = new ArrayType(new MixedType(), new MixedType()); + + if ($mixedArrayType->isSuperTypeOf($leftType)->yes() && $mixedArrayType->isSuperTypeOf($rightType)->yes()) { + return []; + } + + return ['Only numeric types or arrays are allowed in arithmetic addition.']; + } + +} diff --git a/src/Rules/Operators/OperandsInArithmeticDivision.php b/src/Rules/Operators/OperandsInArithmeticDivision.php new file mode 100644 index 00000000..30a118a5 --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticDivision.php @@ -0,0 +1,30 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + return ['Only numeric types are allowed in arithmetic division.']; + } + +} diff --git a/src/Rules/Operators/OperandsInArithmeticExponentiation.php b/src/Rules/Operators/OperandsInArithmeticExponentiation.php new file mode 100644 index 00000000..6a098ae2 --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticExponentiation.php @@ -0,0 +1,30 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + return ['Only numeric types are allowed in arithmetic exponentiation.']; + } + +} diff --git a/src/Rules/Operators/OperandsInArithmeticModulo.php b/src/Rules/Operators/OperandsInArithmeticModulo.php new file mode 100644 index 00000000..89991c4c --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticModulo.php @@ -0,0 +1,30 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + return ['Only numeric types are allowed in arithmetic modulo.']; + } + +} diff --git a/src/Rules/Operators/OperandsInArithmeticMultiplication.php b/src/Rules/Operators/OperandsInArithmeticMultiplication.php new file mode 100644 index 00000000..03547163 --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticMultiplication.php @@ -0,0 +1,30 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + return ['Only numeric types are allowed in arithmetic multiplication.']; + } + +} diff --git a/src/Rules/Operators/OperandsInArithmeticSubtraction.php b/src/Rules/Operators/OperandsInArithmeticSubtraction.php new file mode 100644 index 00000000..7301eb39 --- /dev/null +++ b/src/Rules/Operators/OperandsInArithmeticSubtraction.php @@ -0,0 +1,30 @@ +getType($node->left); + $rightType = $scope->getType($node->right); + + if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) { + return []; + } + + return ['Only numeric types are allowed in arithmetic subtraction.']; + } + +} diff --git a/src/Rules/Operators/OperatorRuleHelper.php b/src/Rules/Operators/OperatorRuleHelper.php new file mode 100644 index 00000000..de7cc950 --- /dev/null +++ b/src/Rules/Operators/OperatorRuleHelper.php @@ -0,0 +1,20 @@ +isSuperTypeOf($leftType)->yes() && $acceptedType->isSuperTypeOf($rightType)->yes(); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticAdditionTest.php b/tests/Rules/Operators/OperandsInArithmeticAdditionTest.php new file mode 100644 index 00000000..ccfa2eec --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticAdditionTest.php @@ -0,0 +1,57 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 25, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 26, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 27, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 28, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 29, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 29, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 30, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 30, + ], + [ + 'Only numeric types or arrays are allowed in arithmetic addition.', + 30, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticDivisionTest.php b/tests/Rules/Operators/OperandsInArithmeticDivisionTest.php new file mode 100644 index 00000000..67520244 --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticDivisionTest.php @@ -0,0 +1,57 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in arithmetic division.', + 64, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 65, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 66, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 67, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 68, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 68, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 69, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 69, + ], + [ + 'Only numeric types are allowed in arithmetic division.', + 69, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticExponentiationTest.php b/tests/Rules/Operators/OperandsInArithmeticExponentiationTest.php new file mode 100644 index 00000000..18a6e98a --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticExponentiationTest.php @@ -0,0 +1,53 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 77, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 78, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 79, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 80, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 81, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 82, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 82, + ], + [ + 'Only numeric types are allowed in arithmetic exponentiation.', + 82, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticModuloTest.php b/tests/Rules/Operators/OperandsInArithmeticModuloTest.php new file mode 100644 index 00000000..39b279b1 --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticModuloTest.php @@ -0,0 +1,53 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in arithmetic modulo.', + 90, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 91, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 92, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 93, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 94, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 94, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 95, + ], + [ + 'Only numeric types are allowed in arithmetic modulo.', + 95, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticMultiplicationTest.php b/tests/Rules/Operators/OperandsInArithmeticMultiplicationTest.php new file mode 100644 index 00000000..562dc640 --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticMultiplicationTest.php @@ -0,0 +1,57 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 51, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 52, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 53, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 54, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 55, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 55, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 56, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 56, + ], + [ + 'Only numeric types are allowed in arithmetic multiplication.', + 56, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/OperandsInArithmeticSubtractionTest.php b/tests/Rules/Operators/OperandsInArithmeticSubtractionTest.php new file mode 100644 index 00000000..a70e743f --- /dev/null +++ b/tests/Rules/Operators/OperandsInArithmeticSubtractionTest.php @@ -0,0 +1,57 @@ +analyse([__DIR__ . '/data/operators.php'], [ + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 38, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 39, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 40, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 41, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 42, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 42, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 43, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 43, + ], + [ + 'Only numeric types are allowed in arithmetic subtraction.', + 43, + ], + ]); + } + +} diff --git a/tests/Rules/Operators/data/operators.php b/tests/Rules/Operators/data/operators.php new file mode 100644 index 00000000..e5da5ff0 --- /dev/null +++ b/tests/Rules/Operators/data/operators.php @@ -0,0 +1,95 @@ +