From 24a02ee24bbb85e916c9ff8ca0dd3be31887fdc8 Mon Sep 17 00:00:00 2001 From: Tristan Pouliquen Date: Thu, 9 Oct 2025 14:19:58 +0200 Subject: [PATCH] Update packages to use PHPStan v2 --- composer.json | 19 +++++++++--------- phpstan.extension.neon | 4 +++- src/Rector/rules.php | 3 --- src/Rules/DateTimeMustNotBeUsedRule.php | 12 +++++++++-- src/Rules/EnforceHttpsLinksRule.php | 10 +++++++--- .../ForbidIdenticalClassComparisonRule.php | 20 ++++++++++--------- .../EnforceHttpsLinksInPhpDocRuleTest.php | 2 +- tests/Rules/FooBar.php | 20 +++++++++++++++++++ ...orbidIdenticalClassComparisonRule.file.php | 18 ++++------------- ...ForbidIdenticalClassComparisonRuleTest.php | 10 +++++----- 10 files changed, 70 insertions(+), 48 deletions(-) create mode 100644 tests/Rules/FooBar.php diff --git a/composer.json b/composer.json index 6a0d740..295e53f 100644 --- a/composer.json +++ b/composer.json @@ -23,21 +23,20 @@ }, "require": { "php": "^8.2", - "ekino/phpstan-banned-code": "^1.0", + "ekino/phpstan-banned-code": "^3.0", "ergebnis/phpstan-rules": "^2.5", "moxio/php-codesniffer-sniffs": "^2.6", "phpcsstandards/phpcsextra": "^1.0", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", "phpunit/phpunit": "^9.6.16", - "rector/rector": "^1.2", - "roave/no-floaters": "^1.5", - "shipmonk/phpstan-rules": "^3.2", + "rector/rector": "^2.2", + "roave/no-floaters": "^1.13", + "shipmonk/phpstan-rules": "^4.2", "slevomat/coding-standard": "^8.6", - "squizlabs/php_codesniffer": "^3", - "thecodingmachine/phpstan-strict-rules": "^1.0" + "squizlabs/php_codesniffer": "^3" }, "config": { "allow-plugins": { diff --git a/phpstan.extension.neon b/phpstan.extension.neon index 42c4bb8..37a9705 100644 --- a/phpstan.extension.neon +++ b/phpstan.extension.neon @@ -7,7 +7,7 @@ includes: - %currentWorkingDirectory%/vendor/phpstan/phpstan-phpunit/rules.neon - %currentWorkingDirectory%/vendor/phpstan/phpstan-strict-rules/rules.neon - %currentWorkingDirectory%/vendor/roave/no-floaters/rules.neon - - %currentWorkingDirectory%/vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon + #- %currentWorkingDirectory%/vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon rules: - AssoConnect\PHPStanRules\Rules\DateTimeMustNotBeUsedRule @@ -51,6 +51,8 @@ parameters: '>', '>=', '<', '<=', '<=>', # checked by AllowComparingOnlyComparableTypesRule '===', '!==', '??' # valid with null involved ] + banned_code: + non_ignorable: false ignoreErrors: - # Prevents using @return mixed[] for all test providers diff --git a/src/Rector/rules.php b/src/Rector/rules.php index 8a21789..ef799d1 100644 --- a/src/Rector/rules.php +++ b/src/Rector/rules.php @@ -6,7 +6,6 @@ use Rector\CodingStyle\Rector\ArrowFunction\StaticArrowFunctionRector; use Rector\CodingStyle\Rector\Closure\StaticClosureRector; use Rector\Config\RectorConfig; -use Rector\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector; return static function (RectorConfig $rectorConfig): void { @@ -16,8 +15,6 @@ StaticClosureRector::class, // Code Quality LogicalToBooleanRector::class, - // Strict - BooleanInBooleanNotRuleFixerRector::class, // Type Declaration ReturnTypeFromStrictTypedCallRector::class, ]); diff --git a/src/Rules/DateTimeMustNotBeUsedRule.php b/src/Rules/DateTimeMustNotBeUsedRule.php index e7b8b74..4b48ebf 100644 --- a/src/Rules/DateTimeMustNotBeUsedRule.php +++ b/src/Rules/DateTimeMustNotBeUsedRule.php @@ -8,6 +8,7 @@ use PhpParser\Node\Expr\New_; use PhpParser\Node\Name\FullyQualified; use PHPStan\Analyser\Scope; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -24,7 +25,10 @@ public function getNodeType(): string return New_::class; } - /** @param New_ $node */ + /** + * @param New_ $node + * @return list + */ public function processNode(Node $node, Scope $scope): array { if (!$node->class instanceof FullyQualified) { @@ -34,7 +38,11 @@ public function processNode(Node $node, Scope $scope): array $classString = $node->class->toCodeString(); if ('\DateTime' === $classString) { - return [RuleErrorBuilder::message(self::MESSAGE)->tip(self::TIP)->build()]; + return [ + RuleErrorBuilder::message(self::MESSAGE)->tip(self::TIP) + ->identifier('assoconnect.dateTimeMustNotBeUsed') + ->build(), + ]; } return []; } diff --git a/src/Rules/EnforceHttpsLinksRule.php b/src/Rules/EnforceHttpsLinksRule.php index dc9ef0b..3e2aa04 100644 --- a/src/Rules/EnforceHttpsLinksRule.php +++ b/src/Rules/EnforceHttpsLinksRule.php @@ -5,8 +5,8 @@ namespace AssoConnect\PHPStanRules\Rules; use PhpParser\Node; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; /** @@ -17,11 +17,15 @@ abstract class EnforceHttpsLinksRule implements Rule { public const MESSAGE = 'The string contains an insecure link'; - /** @return RuleError[] errors */ + /** @return list errors */ protected function checkStringValue(string $value): array { if (false !== strpos($value, 'http' . ':')) { - return [RuleErrorBuilder::message(self::MESSAGE)->build()]; + return [ + RuleErrorBuilder::message(self::MESSAGE) + ->identifier('assoconnect.insecureLink') + ->build(), + ]; } return[]; diff --git a/src/Rules/ForbidIdenticalClassComparisonRule.php b/src/Rules/ForbidIdenticalClassComparisonRule.php index 11ed051..ac62938 100644 --- a/src/Rules/ForbidIdenticalClassComparisonRule.php +++ b/src/Rules/ForbidIdenticalClassComparisonRule.php @@ -11,13 +11,11 @@ use PhpParser\Node\Expr\BinaryOp\NotIdentical; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\CallableType; -use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; @@ -83,7 +81,7 @@ public function getNodeType(): string /** * @param BinaryOp $node - * @return list + * @return list */ public function processNode(Node $node, Scope $scope): array { @@ -92,7 +90,7 @@ public function processNode(Node $node, Scope $scope): array } $nodeType = $scope->getType($node); - if ($nodeType instanceof ConstantBooleanType) { + if ($nodeType->isTrue()->yes() || $nodeType->isFalse()->yes()) { return []; // always-true or always-false, already reported by native PHPStan (like $a === $a) } @@ -109,7 +107,9 @@ public function processNode(Node $node, Scope $scope): array $node->getOperatorSigil(), $leftType->describe(VerbosityLevel::typeOnly()), $rightType->describe(VerbosityLevel::typeOnly()), - ))->build(), + )) + ->identifier('assoconnect.identicalClassComparison') + ->build(), ]; } @@ -130,12 +130,14 @@ private function isAccepted(Type $firstArm, Type $otherArm): bool } - if ($firstArm instanceof ArrayType) { + $arrays = $firstArm->getArrays(); + if ([] !== $arrays) { + $firstArray = $arrays[0]; // Empty array - if ($firstArm->isIterableAtLeastOnce()->no()) { + if ($firstArray->isIterableAtLeastOnce()->no()) { return true; } - return $this->isAccepted($firstArm->getIterableValueType(), $otherArm); + return $this->isAccepted($firstArray->getIterableValueType(), $otherArm); } if ($this->typeIsEnumOrNull($firstArm) && $this->typeIsEnumOrNull($otherArm)) { diff --git a/tests/Rules/EnforceHttpsLinksInPhpDocRuleTest.php b/tests/Rules/EnforceHttpsLinksInPhpDocRuleTest.php index 64d84dd..cdbfc0d 100644 --- a/tests/Rules/EnforceHttpsLinksInPhpDocRuleTest.php +++ b/tests/Rules/EnforceHttpsLinksInPhpDocRuleTest.php @@ -21,7 +21,7 @@ public function testTruePositivesAreDetected(): void { $this->analyse([__DIR__ . '/EnforceHttpsLinksRule.file.php'], array_fill( 0, - 5, + 1, [ EnforceHttpsLinksRule::MESSAGE, 16, diff --git a/tests/Rules/FooBar.php b/tests/Rules/FooBar.php new file mode 100644 index 0000000..916d52a --- /dev/null +++ b/tests/Rules/FooBar.php @@ -0,0 +1,20 @@ +analyse([__DIR__ . '/ForbidIdenticalClassComparisonRule.file.php'], [ [ 'Using === with DateTime and DateTime is denied', - 5, + 9, ], [ 'Using === with array and array is denied', - 6, + 10, ], [ 'Using === with string|false and string|false is denied', - 12, + 16, ], [ 'Using === with DateTime|string and DateTime|string is denied', - 18, + 22, ], [ 'Using === with int|string and int|string is denied', - 24, + 28, ], ]); }