From 4df6e0bdc97d82a39ded39fada78f32ab2428d62 Mon Sep 17 00:00:00 2001 From: Carlos Granados Date: Fri, 15 Nov 2024 13:04:39 +0100 Subject: [PATCH] Updates for PHPStan 2.0 --- composer.json | 4 ++-- phpstan.neon | 1 - .../ClassMethodCallReferenceResolver.php | 4 ++-- src/Printer/CollectorMetadataPrinter.php | 23 +++++++++---------- src/Printer/NodeComparator.php | 6 ++--- src/Reflection/ReflectionParser.php | 3 ++- .../NarrowPrivateClassMethodParamTypeRule.php | 5 +--- src/Rules/NarrowReturnObjectTypeRule.php | 14 ++++++----- src/Rules/NoArrayAccessOnObjectRule.php | 1 + src/Rules/NoMixedMethodCallerRule.php | 6 ++--- src/Rules/NoMixedPropertyFetcherRule.php | 6 ++--- src/Rules/NoParamTypeRemovalRule.php | 1 + src/Rules/ReturnNullOverFalseRule.php | 3 ++- ...rowPrivateClassMethodParamTypeRuleTest.php | 2 +- ...rrowPublicClassMethodParamTypeRuleTest.php | 2 +- .../NarrowReturnObjectTypeRuleTest.php | 2 +- .../NoArrayAccessOnObjectRuleTest.php | 2 +- .../NoEmptyOnObjectRuleTest.php | 2 +- .../NoIssetOnObjectRuleTest.php | 2 +- .../NoMixedMethodCallerRuleTest.php | 3 +++ .../NoMixedPropertyFetcherRuleTest.php | 3 +++ .../NoParamTypeRemovalRuleTest.php | 2 +- .../ReturnNullOverFalseRuleTest.php | 2 +- 23 files changed, 53 insertions(+), 46 deletions(-) diff --git a/composer.json b/composer.json index 1c2c2f8b..8893230e 100644 --- a/composer.json +++ b/composer.json @@ -5,11 +5,11 @@ "license": "MIT", "require": { "php": "^8.2", - "phpstan/phpstan": "^1.11", + "phpstan/phpstan": "^2.0", "webmozart/assert": "^1.11" }, "require-dev": { - "nikic/php-parser": "^4.19", + "nikic/php-parser": "^5.0", "symplify/phpstan-extensions": "^11.4", "symplify/rule-doc-generator": "^12.1", "phpunit/phpunit": "^10.5", diff --git a/phpstan.neon b/phpstan.neon index 8d75e428..47de06c2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -19,4 +19,3 @@ parameters: # overly detailed generics - '#Rector\\TypePerfect\\Tests\\Rules\\(.*?) generic (class|interface)#' - - '#Method Rector\\TypePerfect\\Tests\\Rules\\(.*?)testRule\(\) has parameter \$expectedErrorsWithLines with no value type specified in iterable type array#' diff --git a/src/Matcher/ClassMethodCallReferenceResolver.php b/src/Matcher/ClassMethodCallReferenceResolver.php index 747be901..714333e8 100644 --- a/src/Matcher/ClassMethodCallReferenceResolver.php +++ b/src/Matcher/ClassMethodCallReferenceResolver.php @@ -40,12 +40,12 @@ public function resolve(MethodCall|MethodCallableNode $methodCallOrMethodCallabl return null; } - if (! $callerType instanceof TypeWithClassName) { + if (count($callerType->getObjectClassNames()) !== 1) { return null; } // move to the class where method is defined, e.g. parent class defines the method, so it should be checked there - $className = $callerType->getClassName(); + $className = $callerType->getObjectClassNames()[0]; $methodNameString = $methodName->toString(); return new MethodCallReference($className, $methodNameString); diff --git a/src/Printer/CollectorMetadataPrinter.php b/src/Printer/CollectorMetadataPrinter.php index a92b5bec..b8c9f86d 100644 --- a/src/Printer/CollectorMetadataPrinter.php +++ b/src/Printer/CollectorMetadataPrinter.php @@ -13,7 +13,7 @@ use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\UnionType; -use PhpParser\PrettyPrinter\Standard; +use PHPStan\Node\Printer\Printer; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; @@ -35,11 +35,9 @@ final readonly class CollectorMetadataPrinter { - private Standard $printerStandard; - - public function __construct() - { - $this->printerStandard = new Standard(); + public function __construct( + private Printer $printer + ) { } public function printArgTypesAsString(MethodCall $methodCall, ExtendedMethodReflection $extendedMethodReflection, Scope $scope): string @@ -56,6 +54,7 @@ public function printArgTypesAsString(MethodCall $methodCall, ExtendedMethodRefl return ResolvedTypes::UNKNOWN_TYPES; } + // @phpstan-ignore phpstanApi.instanceofType if ($argType instanceof IntersectionType) { return ResolvedTypes::UNKNOWN_TYPES; } @@ -100,7 +99,7 @@ public function printParamTypesToString(ClassMethod $classMethod, ?string $class $paramType = $this->resolveSortedTypes($paramType, $className); } - $printedParamType = $this->printerStandard->prettyPrint([$paramType]); + $printedParamType = $this->printer->prettyPrint([$paramType]); $printedParamType = str_replace('\Closure', 'callable', $printedParamType); $printedParamType = ltrim($printedParamType, '\\'); $printedParamType = str_replace('|\\', '|', $printedParamType); @@ -160,15 +159,15 @@ private function resolveSortedTypes(UnionType|NodeIntersectionType $paramType, ? private function printTypeToString(Type $type): string { - if ($type instanceof ClassStringType) { + if ($type->isClassString()->yes()) { return 'string'; } - if ($type instanceof ArrayType) { + if ($type->isArray()->yes()) { return 'array'; } - if ($type instanceof BooleanType) { + if ($type->isBoolean()->yes()) { return 'bool'; } @@ -180,8 +179,8 @@ private function printTypeToString(Type $type): string return 'callable'; } - if ($type instanceof EnumCaseObjectType) { - return $type->getClassName(); + if (count($type->getEnumCases()) === 1) { + return $type->getEnumCases()[0]->getClassName(); } return $type->describe(VerbosityLevel::typeOnly()); diff --git a/src/Printer/NodeComparator.php b/src/Printer/NodeComparator.php index c8cbc7fe..1d1efaef 100644 --- a/src/Printer/NodeComparator.php +++ b/src/Printer/NodeComparator.php @@ -5,12 +5,12 @@ namespace Rector\TypePerfect\Printer; use PhpParser\Node; -use PhpParser\PrettyPrinter\Standard; +use PHPStan\Node\Printer\Printer; final readonly class NodeComparator { public function __construct( - private Standard $standard + private Printer $printer ) { } @@ -20,6 +20,6 @@ public function areNodesEqual(Node $firstNode, Node $secondNode): bool $firstNode->setAttribute('comments', null); $secondNode->setAttribute('comments', null); - return $this->standard->prettyPrint([$firstNode]) === $this->standard->prettyPrint([$secondNode]); + return $this->printer->prettyPrint([$firstNode]) === $this->printer->prettyPrint([$secondNode]); } } diff --git a/src/Reflection/ReflectionParser.php b/src/Reflection/ReflectionParser.php index 2419be1e..df982ab6 100644 --- a/src/Reflection/ReflectionParser.php +++ b/src/Reflection/ReflectionParser.php @@ -11,6 +11,7 @@ use PhpParser\NodeVisitor\NameResolver; use PhpParser\Parser; use PhpParser\ParserFactory; +use PhpParser\PhpVersion; use PHPStan\Reflection\ClassReflection; use Throwable; @@ -26,7 +27,7 @@ final class ReflectionParser public function __construct() { $parserFactory = new ParserFactory(); - $this->parser = $parserFactory->create(ParserFactory::PREFER_PHP7); + $this->parser = $parserFactory->createForVersion(PhpVersion::fromString('7.4')); } public function parseClassReflection(ClassReflection $classReflection): ?ClassLike diff --git a/src/Rules/NarrowPrivateClassMethodParamTypeRule.php b/src/Rules/NarrowPrivateClassMethodParamTypeRule.php index a2a8bd03..3d45e0c6 100644 --- a/src/Rules/NarrowPrivateClassMethodParamTypeRule.php +++ b/src/Rules/NarrowPrivateClassMethodParamTypeRule.php @@ -110,10 +110,6 @@ private function validateArgVsParamTypes(array $args, MethodCall $methodCall, Sc continue; } - if (! $arg instanceof Arg) { - continue; - } - $paramRuleError = $this->validateParam($param, $position, $arg->value, $scope); if (! $paramRuleError instanceof RuleError) { continue; @@ -149,6 +145,7 @@ private function validateParam(Param $param, int $position, Expr $expr, Scope $s return null; } + // @phpstan-ignore phpstanApi.instanceofType if ($argType instanceof IntersectionType) { return null; } diff --git a/src/Rules/NarrowReturnObjectTypeRule.php b/src/Rules/NarrowReturnObjectTypeRule.php index 5d7655e5..ad63368e 100644 --- a/src/Rules/NarrowReturnObjectTypeRule.php +++ b/src/Rules/NarrowReturnObjectTypeRule.php @@ -94,8 +94,11 @@ public function processNode(Node $node, Scope $scope): array return []; } - /** @var TypeWithClassName $returnExprType */ - $errorMessage = sprintf(self::ERROR_MESSAGE, $returnExprType->getClassName()); + if (count($returnExprType->getObjectClassNames()) !== 1) { + return []; + } + + $errorMessage = sprintf(self::ERROR_MESSAGE, $returnExprType->getObjectClassNames()[0]); return [ RuleErrorBuilder::message($errorMessage) @@ -127,15 +130,14 @@ private function shouldSkipScope(Scope $scope): bool private function shouldSkipReturnExprType(Type $type): bool { - if (! $type instanceof TypeWithClassName) { + if (count($type->getObjectClassNames()) !== 1) { return true; } - $classReflection = $type->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { + if (count($type->getObjectClassReflections()) !== 1) { return true; } - return $classReflection->isAnonymous(); + return $type->getObjectClassReflections()[0]->isAnonymous(); } } diff --git a/src/Rules/NoArrayAccessOnObjectRule.php b/src/Rules/NoArrayAccessOnObjectRule.php index 577cac7d..45f5c633 100644 --- a/src/Rules/NoArrayAccessOnObjectRule.php +++ b/src/Rules/NoArrayAccessOnObjectRule.php @@ -43,6 +43,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $varType = $scope->getType($node->var); + // @phpstan-ignore phpstanApi.instanceofType if (! $varType instanceof ObjectType) { return []; } diff --git a/src/Rules/NoMixedMethodCallerRule.php b/src/Rules/NoMixedMethodCallerRule.php index 5f667f4f..44b7b2df 100644 --- a/src/Rules/NoMixedMethodCallerRule.php +++ b/src/Rules/NoMixedMethodCallerRule.php @@ -6,7 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; -use PhpParser\PrettyPrinter\Standard; +use PHPStan\Node\Printer\Printer; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleError; @@ -27,7 +27,7 @@ public const ERROR_MESSAGE = 'Mixed variable in a `%s->...()` can skip important errors. Make sure the type is known'; public function __construct( - private Standard $printerStandard, + private Printer $printer, private Configuration $configuration, ) { } @@ -65,7 +65,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $printedMethodCall = $this->printerStandard->prettyPrintExpr($node->var); + $printedMethodCall = $this->printer->prettyPrintExpr($node->var); return [ RuleErrorBuilder::message(sprintf(self::ERROR_MESSAGE, $printedMethodCall)) diff --git a/src/Rules/NoMixedPropertyFetcherRule.php b/src/Rules/NoMixedPropertyFetcherRule.php index 66e2af2b..5f49047b 100644 --- a/src/Rules/NoMixedPropertyFetcherRule.php +++ b/src/Rules/NoMixedPropertyFetcherRule.php @@ -6,7 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\PrettyPrinter\Standard; +use PHPStan\Node\Printer\Printer; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleError; @@ -26,7 +26,7 @@ public const ERROR_MESSAGE = 'Mixed property fetch in a "%s->..." can skip important errors. Make sure the type is known'; public function __construct( - private Standard $standard, + private Printer $printer, private Configuration $configuration, ) { } @@ -54,7 +54,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $printedVar = $this->standard->prettyPrintExpr($node->var); + $printedVar = $this->printer->prettyPrintExpr($node->var); return [ RuleErrorBuilder::message(sprintf(self::ERROR_MESSAGE, $printedVar)) diff --git a/src/Rules/NoParamTypeRemovalRule.php b/src/Rules/NoParamTypeRemovalRule.php index a6046036..9f1e195d 100644 --- a/src/Rules/NoParamTypeRemovalRule.php +++ b/src/Rules/NoParamTypeRemovalRule.php @@ -55,6 +55,7 @@ public function processNode(Node $node, Scope $scope): array } $parentClassMethodReflection = $this->methodNodeAnalyser->matchFirstParentClassMethod($scope, $classMethodName); + // @phpstan-ignore phpstanApi.instanceofAssumption if (! $parentClassMethodReflection instanceof PhpMethodReflection) { return []; } diff --git a/src/Rules/ReturnNullOverFalseRule.php b/src/Rules/ReturnNullOverFalseRule.php index 81fc8dd0..659c4a1d 100644 --- a/src/Rules/ReturnNullOverFalseRule.php +++ b/src/Rules/ReturnNullOverFalseRule.php @@ -74,8 +74,9 @@ public function processNode(Node $node, Scope $scope): array } $exprType = $scope->getType($return->expr); + // @phpstan-ignore phpstanApi.instanceofType if (! $exprType instanceof ConstantBooleanType) { - if ($exprType instanceof BooleanType) { + if ($exprType->isBoolean()->yes()) { return []; } diff --git a/tests/Rules/NarrowPrivateClassMethodParamTypeRule/NarrowPrivateClassMethodParamTypeRuleTest.php b/tests/Rules/NarrowPrivateClassMethodParamTypeRule/NarrowPrivateClassMethodParamTypeRuleTest.php index d8a0a3f1..1005cc1d 100644 --- a/tests/Rules/NarrowPrivateClassMethodParamTypeRule/NarrowPrivateClassMethodParamTypeRuleTest.php +++ b/tests/Rules/NarrowPrivateClassMethodParamTypeRule/NarrowPrivateClassMethodParamTypeRuleTest.php @@ -16,7 +16,7 @@ final class NarrowPrivateClassMethodParamTypeRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorsWithLines + * @param list $expectedErrorsWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorsWithLines): void diff --git a/tests/Rules/NarrowPublicClassMethodParamTypeRule/NarrowPublicClassMethodParamTypeRuleTest.php b/tests/Rules/NarrowPublicClassMethodParamTypeRule/NarrowPublicClassMethodParamTypeRuleTest.php index 42046f45..88578e0c 100644 --- a/tests/Rules/NarrowPublicClassMethodParamTypeRule/NarrowPublicClassMethodParamTypeRuleTest.php +++ b/tests/Rules/NarrowPublicClassMethodParamTypeRule/NarrowPublicClassMethodParamTypeRuleTest.php @@ -16,7 +16,7 @@ final class NarrowPublicClassMethodParamTypeRuleTest extends RuleTestCase { /** * @param string[] $filePaths - * @param mixed[] $expectedErrorsWithLines + * @param list $expectedErrorsWithLines */ #[DataProvider('provideData')] public function testRule(array $filePaths, array $expectedErrorsWithLines): void diff --git a/tests/Rules/NarrowReturnObjectTypeRule/NarrowReturnObjectTypeRuleTest.php b/tests/Rules/NarrowReturnObjectTypeRule/NarrowReturnObjectTypeRuleTest.php index e5ae2264..ad525cac 100644 --- a/tests/Rules/NarrowReturnObjectTypeRule/NarrowReturnObjectTypeRuleTest.php +++ b/tests/Rules/NarrowReturnObjectTypeRule/NarrowReturnObjectTypeRuleTest.php @@ -14,7 +14,7 @@ final class NarrowReturnObjectTypeRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void diff --git a/tests/Rules/NoArrayAccessOnObjectRule/NoArrayAccessOnObjectRuleTest.php b/tests/Rules/NoArrayAccessOnObjectRule/NoArrayAccessOnObjectRuleTest.php index 8977e63c..7b5030f0 100644 --- a/tests/Rules/NoArrayAccessOnObjectRule/NoArrayAccessOnObjectRuleTest.php +++ b/tests/Rules/NoArrayAccessOnObjectRule/NoArrayAccessOnObjectRuleTest.php @@ -13,7 +13,7 @@ final class NoArrayAccessOnObjectRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void diff --git a/tests/Rules/NoEmptyOnObjectRule/NoEmptyOnObjectRuleTest.php b/tests/Rules/NoEmptyOnObjectRule/NoEmptyOnObjectRuleTest.php index 1509b964..59ce9fd4 100644 --- a/tests/Rules/NoEmptyOnObjectRule/NoEmptyOnObjectRuleTest.php +++ b/tests/Rules/NoEmptyOnObjectRule/NoEmptyOnObjectRuleTest.php @@ -13,7 +13,7 @@ final class NoEmptyOnObjectRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void diff --git a/tests/Rules/NoIssetOnObjectRule/NoIssetOnObjectRuleTest.php b/tests/Rules/NoIssetOnObjectRule/NoIssetOnObjectRuleTest.php index aafa1472..a9f915b4 100644 --- a/tests/Rules/NoIssetOnObjectRule/NoIssetOnObjectRuleTest.php +++ b/tests/Rules/NoIssetOnObjectRule/NoIssetOnObjectRuleTest.php @@ -13,7 +13,7 @@ final class NoIssetOnObjectRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void diff --git a/tests/Rules/NoMixedMethodCallerRule/NoMixedMethodCallerRuleTest.php b/tests/Rules/NoMixedMethodCallerRule/NoMixedMethodCallerRuleTest.php index 1e8d2749..ffc37211 100644 --- a/tests/Rules/NoMixedMethodCallerRule/NoMixedMethodCallerRuleTest.php +++ b/tests/Rules/NoMixedMethodCallerRule/NoMixedMethodCallerRuleTest.php @@ -12,6 +12,9 @@ final class NoMixedMethodCallerRuleTest extends RuleTestCase { + /** + * @param list $expectedErrorsWithLines + */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorsWithLines): void { diff --git a/tests/Rules/NoMixedPropertyFetcherRule/NoMixedPropertyFetcherRuleTest.php b/tests/Rules/NoMixedPropertyFetcherRule/NoMixedPropertyFetcherRuleTest.php index 215f5028..6d84b500 100644 --- a/tests/Rules/NoMixedPropertyFetcherRule/NoMixedPropertyFetcherRuleTest.php +++ b/tests/Rules/NoMixedPropertyFetcherRule/NoMixedPropertyFetcherRuleTest.php @@ -12,6 +12,9 @@ final class NoMixedPropertyFetcherRuleTest extends RuleTestCase { + /** + * @param list $expectedErrorsWithLines + */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorsWithLines): void { diff --git a/tests/Rules/NoParamTypeRemovalRule/NoParamTypeRemovalRuleTest.php b/tests/Rules/NoParamTypeRemovalRule/NoParamTypeRemovalRuleTest.php index 0e2fbfc9..d79d8ef2 100644 --- a/tests/Rules/NoParamTypeRemovalRule/NoParamTypeRemovalRuleTest.php +++ b/tests/Rules/NoParamTypeRemovalRule/NoParamTypeRemovalRuleTest.php @@ -13,7 +13,7 @@ final class NoParamTypeRemovalRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void diff --git a/tests/Rules/ReturnNullOverFalseRule/ReturnNullOverFalseRuleTest.php b/tests/Rules/ReturnNullOverFalseRule/ReturnNullOverFalseRuleTest.php index 7c53c9cb..677156db 100644 --- a/tests/Rules/ReturnNullOverFalseRule/ReturnNullOverFalseRuleTest.php +++ b/tests/Rules/ReturnNullOverFalseRule/ReturnNullOverFalseRuleTest.php @@ -13,7 +13,7 @@ final class ReturnNullOverFalseRuleTest extends RuleTestCase { /** - * @param mixed[] $expectedErrorMessagesWithLines + * @param list $expectedErrorMessagesWithLines */ #[DataProvider('provideData')] public function testRule(string $filePath, array $expectedErrorMessagesWithLines): void