From c074f1dd60d697d203e49d7119962d44ea6ed3fc Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 21 Oct 2025 21:40:23 +0200 Subject: [PATCH 1/4] simplify ClassMethodParamVendorLockResolver check --- .../ClassMethodParamVendorLockResolver.php | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/VendorLocker/NodeVendorLocker/ClassMethodParamVendorLockResolver.php b/src/VendorLocker/NodeVendorLocker/ClassMethodParamVendorLockResolver.php index ba68a2adfb6..10c793967fb 100644 --- a/src/VendorLocker/NodeVendorLocker/ClassMethodParamVendorLockResolver.php +++ b/src/VendorLocker/NodeVendorLocker/ClassMethodParamVendorLockResolver.php @@ -6,7 +6,6 @@ use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Reflection\ClassReflection; -use Rector\FileSystem\FilePathHelper; use Rector\NodeNameResolver\NodeNameResolver; use Rector\Reflection\ReflectionResolver; @@ -15,7 +14,6 @@ public function __construct( private NodeNameResolver $nodeNameResolver, private ReflectionResolver $reflectionResolver, - private FilePathHelper $filePathHelper ) { } @@ -38,11 +36,7 @@ public function isVendorLocked(ClassMethod $classMethod): bool $methodName = $this->nodeNameResolver->getName($classMethod); // has interface vendor lock? → better skip it, as PHPStan has access only to just analyzed classes - if ($this->hasParentInterfaceMethod($classReflection, $methodName)) { - return true; - } - - return $this->hasClassMethodLockMatchingFileName($classReflection, $methodName, '/vendor/'); + return $this->hasParentInterfaceMethod($classReflection, $methodName); } /** @@ -60,37 +54,4 @@ private function hasParentInterfaceMethod(ClassReflection $classReflection, stri return false; } - - private function hasClassMethodLockMatchingFileName( - ClassReflection $classReflection, - string $methodName, - string $filePathPartName - ): bool { - $ancestorClassReflections = [...$classReflection->getParents(), ...$classReflection->getInterfaces()]; - foreach ($ancestorClassReflections as $ancestorClassReflection) { - // parent type - if (! $ancestorClassReflection->hasNativeMethod($methodName)) { - continue; - } - - // is file in vendor? - $fileName = $ancestorClassReflection->getFileName(); - // probably internal class - if ($fileName === null) { - continue; - } - - // not conditions? its a match - if ($filePathPartName === '') { - return true; - } - - $normalizedFileName = $this->filePathHelper->normalizePathAndSchema($fileName); - if (str_contains($normalizedFileName, $filePathPartName)) { - return true; - } - } - - return false; - } } From 6a73bb50c9d310f14601ff3ebd8a1aee9885da50 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 21 Oct 2025 21:42:09 +0200 Subject: [PATCH 2/4] const --- composer.json | 4 + ...emoveUnusedPublicMethodParameterRector.php | 4 +- ...actorDuplicatedNodeInstanceCheckRector.php | 80 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php diff --git a/composer.json b/composer.json index 33e4d87ee0a..1d5eb6bcccb 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,11 @@ "doctrine/inflector": "^2.1", "illuminate/container": "^11.46", "nette/utils": "^4.0", +<<<<<<< HEAD "nikic/php-parser": "^5.6.2", +======= + "nikic/php-parser": "5.6.1", +>>>>>>> 2a1a5105ab (lock php parser to 5.6.1 to avoid breaking space on attributes) "ondram/ci-detector": "^4.2", "phpstan/phpdoc-parser": "^2.3", "phpstan/phpstan": "^2.1.26", diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php index 18e603a8ba1..423b2a91e3e 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php @@ -13,6 +13,8 @@ use Rector\NodeAnalyzer\MagicClassMethodAnalyzer; use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer; use Rector\Rector\AbstractRector; +use Rector\Symfony\Enum\SymfonyClass; +use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -115,7 +117,7 @@ private function shouldSkipClassMethod(ClassMethod $classMethod, Class_ $class): } // parameter is required for contract coupling - if ($this->isName($classMethod->name, '__invoke') && $this->phpAttributeAnalyzer->hasPhpAttribute( + if ($this->isName($classMethod->name, MethodName::INVOKE) && $this->phpAttributeAnalyzer->hasPhpAttribute( $class, 'Symfony\Component\Messenger\Attribute\AsMessageHandler' )) { diff --git a/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php new file mode 100644 index 00000000000..f66fcc605f5 --- /dev/null +++ b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php @@ -0,0 +1,80 @@ +isName($node->name, 'refactor')) { + return null; + } + + if (! $node->isPublic()) { + return null; + } + + $firstStmt = $node->stmts[0] ?? null; + if (! $firstStmt instanceof If_) { + return null; + } + + // remove already added properties + + if ($typesToAdd === []) { + return null; + } + + $hasChanged = false; + + foreach ($typesToAdd as $propertyNameToAdd => $propertyTypeToAdd) { + // skip if property already exists + if ($node->getProperty($propertyNameToAdd) instanceof Property) { + continue; + } + + $this->classDependencyManipulator->addConstructorDependency( + $node, + new PropertyMetadata($propertyNameToAdd, new ObjectType($propertyTypeToAdd)) + ); + + $hasChanged = true; + } + + if (! $hasChanged) { + return null; + } + + return $node; + } +} From 2869153f857ff0ca1819b8e204336a9684d31069 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 21 Oct 2025 22:03:20 +0200 Subject: [PATCH 3/4] [utils] Add RemoveRefactorDuplicatedNodeInstanceCheckRector --- rector.php | 3 +- ...emoveUnusedPublicMethodParameterRector.php | 1 - ...actorDuplicatedNodeInstanceCheckRector.php | 68 ++++++++++++------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/rector.php b/rector.php index b24f7fe82f0..76c431a644c 100644 --- a/rector.php +++ b/rector.php @@ -6,6 +6,7 @@ use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; +use Rector\Utils\Rector\RemoveRefactorDuplicatedNodeInstanceCheckRector; return RectorConfig::configure() ->withPreparedSets( @@ -18,7 +19,6 @@ naming: true, instanceOf: true, earlyReturn: true, - strictBooleans: true, rectorPreset: true, phpunitCodeQuality: true ) @@ -37,6 +37,7 @@ ]) ->withRootFiles() ->withImportNames(removeUnusedImports: true) + ->withRules([RemoveRefactorDuplicatedNodeInstanceCheckRector::class]) ->withSkip([ StringClassNameToClassConstantRector::class, // tests diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php index 423b2a91e3e..842d7ce3581 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPublicMethodParameterRector.php @@ -13,7 +13,6 @@ use Rector\NodeAnalyzer\MagicClassMethodAnalyzer; use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer; use Rector\Rector\AbstractRector; -use Rector\Symfony\Enum\SymfonyClass; use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; diff --git a/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php index f66fcc605f5..bbb79252b3b 100644 --- a/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php +++ b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php @@ -5,34 +5,36 @@ namespace Rector\Utils\Rector; use PhpParser\Node; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\Property; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; -use Rector\NodeManipulator\ClassDependencyManipulator; -use Rector\PhpParser\Node\BetterNodeFinder; -use Rector\PhpParser\Node\Value\ValueResolver; -use Rector\PostRector\ValueObject\PropertyMetadata; use Rector\Rector\AbstractRector; -use Rector\StaticTypeMapper\StaticTypeMapper; +use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; final class RemoveRefactorDuplicatedNodeInstanceCheckRector extends AbstractRector { + public function __construct( + private readonly PhpDocInfoFactory $phpDocInfoFactory + ) { + } + public function getRuleDefinition(): RuleDefinition { - return new RuleDefinition('Remove refactor() method of Rector rule double check of $node instance, if already defined in @param type', []); + return new RuleDefinition( + 'Remove refactor() method of Rector rule double check of $node instance, if already defined in @param type', + [] + ); } public function getNodeTypes(): array { - return [Node\Stmt\ClassMethod::class]; + return [ClassMethod::class]; } /** - * @param Node\Stmt\ClassMethod $node + * @param ClassMethod $node */ public function refactor(Node $node): ?Node { @@ -49,32 +51,48 @@ public function refactor(Node $node): ?Node return null; } - // remove already added properties + if (! $firstStmt->cond instanceof Node\Expr\BooleanNot) { + return null; + } + + $booleanNot = $firstStmt->cond; - if ($typesToAdd === []) { + if (! $booleanNot->expr instanceof Node\Expr\Instanceof_) { return null; } - $hasChanged = false; + $instanceIf = $booleanNot->expr; + $checkedClassType = $this->getType($instanceIf->class); - foreach ($typesToAdd as $propertyNameToAdd => $propertyTypeToAdd) { - // skip if property already exists - if ($node->getProperty($propertyNameToAdd) instanceof Property) { - continue; - } + if (! $checkedClassType instanceof ObjectType) { + return null; + } - $this->classDependencyManipulator->addConstructorDependency( - $node, - new PropertyMetadata($propertyNameToAdd, new ObjectType($propertyTypeToAdd)) - ); + $classReflection = $checkedClassType->getClassReflection(); - $hasChanged = true; + if (! $classReflection->is(Node::class)) { + return null; } - if (! $hasChanged) { + $classMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); + + $paramType = $classMethodPhpDocInfo->getParamType('$node'); + if (! $paramType instanceof ObjectType) { return null; } + if ($paramType instanceof ShortenedObjectType) { + $className = $paramType->getFullyQualifiedName(); + } else { + $className = $paramType->getClassName(); + } + + if ($className !== $checkedClassType->getClassName()) { + return null; + } + + unset($node->stmts[0]); + return $node; } } From 6cb502d38881bff9896b634a7b37c644a0d10804 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 21 Oct 2025 22:33:57 +0200 Subject: [PATCH 4/4] add test --- composer.json | 5 +- phpstan.neon | 2 + phpunit.xml | 1 + .../ReplaceConstantBooleanNotRector.php | 4 - .../FunctionFirstClassCallableRector.php | 7 +- .../Fixture/cover_bare_get_node_types.php.inc | 54 +++++++++ .../Fixture/some_class.php.inc | 60 ++++++++++ ...rDuplicatedNodeInstanceCheckRectorTest.php | 28 +++++ .../config/configured_rule.php | 11 ++ ...actorDuplicatedNodeInstanceCheckRector.php | 113 ++++++++++++++---- 10 files changed, 250 insertions(+), 35 deletions(-) create mode 100644 utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/cover_bare_get_node_types.php.inc create mode 100644 utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/some_class.php.inc create mode 100644 utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/RemoveRefactorDuplicatedNodeInstanceCheckRectorTest.php create mode 100644 utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/config/configured_rule.php diff --git a/composer.json b/composer.json index 1d5eb6bcccb..850a0ece814 100644 --- a/composer.json +++ b/composer.json @@ -20,11 +20,7 @@ "doctrine/inflector": "^2.1", "illuminate/container": "^11.46", "nette/utils": "^4.0", -<<<<<<< HEAD "nikic/php-parser": "^5.6.2", -======= - "nikic/php-parser": "5.6.1", ->>>>>>> 2a1a5105ab (lock php parser to 5.6.1 to avoid breaking space on attributes) "ondram/ci-detector": "^4.2", "phpstan/phpdoc-parser": "^2.3", "phpstan/phpstan": "^2.1.26", @@ -85,6 +81,7 @@ "rules-tests", "tests" ], + "Rector\\Utils\\Tests\\": "utils-tests", "E2e\\Parallel\\Reflection\\Resolver\\": [ "e2e/parallel-reflection-resolver/src/", "e2e/no-parallel-reflection-resolver/src" diff --git a/phpstan.neon b/phpstan.neon index 6091df0d97b..db92a0ee7e1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -352,3 +352,5 @@ parameters: - identifier: offsetAccess.invalidOffset path: src/CustomRules/SimpleNodeDumper.php + + - '#Method Rector\\Utils\\Rector\\RemoveRefactorDuplicatedNodeInstanceCheckRector\:\:getInstanceofNodeClass\(\) should return class\-string\|null but returns class\-string#' diff --git a/phpunit.xml b/phpunit.xml index 8607c5b0eb2..9f15cef2ecf 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -13,6 +13,7 @@ tests rules-tests + utils-tests diff --git a/rules/CodeQuality/Rector/BooleanNot/ReplaceConstantBooleanNotRector.php b/rules/CodeQuality/Rector/BooleanNot/ReplaceConstantBooleanNotRector.php index 9b70b143f1f..0d395974f3a 100644 --- a/rules/CodeQuality/Rector/BooleanNot/ReplaceConstantBooleanNotRector.php +++ b/rules/CodeQuality/Rector/BooleanNot/ReplaceConstantBooleanNotRector.php @@ -69,10 +69,6 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - if (! $node instanceof BooleanNot) { - return null; - } - if ($this->valueResolver->isFalse($node->expr)) { return new ConstFetch(new Name('true')); } diff --git a/rules/CodingStyle/Rector/FuncCall/FunctionFirstClassCallableRector.php b/rules/CodingStyle/Rector/FuncCall/FunctionFirstClassCallableRector.php index 905da135b3a..5a610bc3e15 100644 --- a/rules/CodingStyle/Rector/FuncCall/FunctionFirstClassCallableRector.php +++ b/rules/CodingStyle/Rector/FuncCall/FunctionFirstClassCallableRector.php @@ -61,12 +61,11 @@ public function getNodeTypes(): array return [FuncCall::class]; } + /** + * @param FuncCall $node + */ public function refactor(Node $node): ?FuncCall { - if (! $node instanceof FuncCall) { - return null; - } - if (! $node->name instanceof Name) { return null; } diff --git a/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/cover_bare_get_node_types.php.inc b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/cover_bare_get_node_types.php.inc new file mode 100644 index 00000000000..456c6bd025a --- /dev/null +++ b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/cover_bare_get_node_types.php.inc @@ -0,0 +1,54 @@ + +----- + diff --git a/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/some_class.php.inc b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/some_class.php.inc new file mode 100644 index 00000000000..f4991045b08 --- /dev/null +++ b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/Fixture/some_class.php.inc @@ -0,0 +1,60 @@ + +----- + diff --git a/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/RemoveRefactorDuplicatedNodeInstanceCheckRectorTest.php b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/RemoveRefactorDuplicatedNodeInstanceCheckRectorTest.php new file mode 100644 index 00000000000..1ae75654141 --- /dev/null +++ b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/RemoveRefactorDuplicatedNodeInstanceCheckRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/config/configured_rule.php b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/config/configured_rule.php new file mode 100644 index 00000000000..f4ae1bb7e60 --- /dev/null +++ b/utils-tests/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector/config/configured_rule.php @@ -0,0 +1,11 @@ +withRules([ + RemoveRefactorDuplicatedNodeInstanceCheckRector::class, + ]); diff --git a/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php index bbb79252b3b..35bb54987e5 100644 --- a/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php +++ b/utils/Rector/RemoveRefactorDuplicatedNodeInstanceCheckRector.php @@ -5,76 +5,151 @@ namespace Rector\Utils\Rector; use PhpParser\Node; +use PhpParser\Node\Expr; +use PhpParser\Node\Expr\BooleanNot; +use PhpParser\Node\Expr\Instanceof_; +use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\If_; +use PhpParser\Node\Stmt\Return_; +use PHPStan\Reflection\ClassReflection; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; +use Rector\PhpParser\Node\Value\ValueResolver; +use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; +use Webmozart\Assert\Assert; +/** + * @see \Rector\Utils\Tests\Rector\RemoveRefactorDuplicatedNodeInstanceCheckRector\RemoveRefactorDuplicatedNodeInstanceCheckRectorTest + */ final class RemoveRefactorDuplicatedNodeInstanceCheckRector extends AbstractRector { public function __construct( - private readonly PhpDocInfoFactory $phpDocInfoFactory + private readonly PhpDocInfoFactory $phpDocInfoFactory, + private readonly ValueResolver $valueResolver, ) { } public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( - 'Remove refactor() method of Rector rule double check of $node instance, if already defined in @param type', + 'Remove refactor() method of Rector rule double check of $classMethod instance, if already defined in @param type', [] ); } public function getNodeTypes(): array { - return [ClassMethod::class]; + return [Class_::class]; } /** - * @param ClassMethod $node + * @param Class_ $node */ public function refactor(Node $node): ?Node { - if (! $this->isName($node->name, 'refactor')) { + $scope = ScopeFetcher::fetch($node); + $classReflection = $scope->getClassReflection(); + + if (! $classReflection instanceof ClassReflection) { return null; } - if (! $node->isPublic()) { + if (! $classReflection->is('Rector\Rector\AbstractRector')) { return null; } - $firstStmt = $node->stmts[0] ?? null; + $refactorClassMethod = $node->getMethod('refactor'); + if (! $refactorClassMethod instanceof ClassMethod) { + return null; + } + + $firstStmt = $refactorClassMethod->stmts[0] ?? null; if (! $firstStmt instanceof If_) { return null; } - if (! $firstStmt->cond instanceof Node\Expr\BooleanNot) { + $instanceofNodeClass = $this->matchBooleanNotInstanceOfNodeClass($firstStmt->cond); + if (! is_string($instanceofNodeClass)) { + return null; + } + + $nodeParamTypeClass = $this->matchNodeParamType($refactorClassMethod); + + $getNodeTypesClassMethod = $node->getMethod('getNodeTypes'); + if (! $getNodeTypesClassMethod instanceof ClassMethod) { + return null; + } + + $soleReturn = $getNodeTypesClassMethod->stmts[0] ?? null; + + $nodeTypeClass = null; + if ($soleReturn instanceof Return_) { + Assert::isInstanceOf($soleReturn->expr, Expr::class); + + $nodeTypes = $this->valueResolver->getValue($soleReturn->expr); + if (count($nodeTypes) === 1) { + $nodeTypeClass = $nodeTypes[0]; + } + } + + if ($nodeParamTypeClass !== null) { + if ($nodeParamTypeClass !== $instanceofNodeClass) { + return null; + } + } elseif ($nodeTypeClass !== null) { + if ($nodeTypeClass !== $instanceofNodeClass) { + return null; + } + } else { return null; } - $booleanNot = $firstStmt->cond; + unset($refactorClassMethod->stmts[0]); + + return $node; + } + + private function matchBooleanNotInstanceOfNodeClass(Expr $expr): ?string + { + if (! $expr instanceof BooleanNot) { + return null; + } - if (! $booleanNot->expr instanceof Node\Expr\Instanceof_) { + $booleanNot = $expr; + if (! $booleanNot->expr instanceof Instanceof_) { return null; } - $instanceIf = $booleanNot->expr; - $checkedClassType = $this->getType($instanceIf->class); + return $this->getInstanceofNodeClass($booleanNot->expr); + } + /** + * @return class-string|null + */ + private function getInstanceofNodeClass(Instanceof_ $instanceof): ?string + { + $checkedClassType = $this->getType($instanceof->class); if (! $checkedClassType instanceof ObjectType) { return null; } + /** @var ClassReflection $classReflection */ $classReflection = $checkedClassType->getClassReflection(); if (! $classReflection->is(Node::class)) { return null; } - $classMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); + return $classReflection->getName(); + } + + private function matchNodeParamType(ClassMethod $classMethod): ?string + { + $classMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod); $paramType = $classMethodPhpDocInfo->getParamType('$node'); if (! $paramType instanceof ObjectType) { @@ -82,17 +157,9 @@ public function refactor(Node $node): ?Node } if ($paramType instanceof ShortenedObjectType) { - $className = $paramType->getFullyQualifiedName(); - } else { - $className = $paramType->getClassName(); + return $paramType->getFullyQualifiedName(); } - if ($className !== $checkedClassType->getClassName()) { - return null; - } - - unset($node->stmts[0]); - - return $node; + return $paramType->getClassName(); } }