diff --git a/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php b/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php index 06edecc1d862..f3c17bf2eec4 100644 --- a/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php +++ b/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php @@ -4,11 +4,14 @@ namespace Rector\DeadCode\PhpDoc; use PhpParser\Node\Identifier; +use PhpParser\Node; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Analyser\Scope; use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; +use PHPStan\Type\TypeCombinator; +use PHPStan\Type\UnionType; use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode; use Rector\DeadCode\PhpDoc\Guard\StandaloneTypeRemovalGuard; @@ -16,6 +19,7 @@ use Rector\DeadCode\TypeNodeAnalyzer\MixedArrayTypeNodeAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\TypeComparator\TypeComparator; +use Rector\StaticTypeMapper\StaticTypeMapper; final class DeadReturnTagValueNodeAnalyzer { /** @@ -43,13 +47,19 @@ final class DeadReturnTagValueNodeAnalyzer * @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger */ private $phpDocTypeChanger; - public function __construct(TypeComparator $typeComparator, GenericTypeNodeAnalyzer $genericTypeNodeAnalyzer, MixedArrayTypeNodeAnalyzer $mixedArrayTypeNodeAnalyzer, StandaloneTypeRemovalGuard $standaloneTypeRemovalGuard, PhpDocTypeChanger $phpDocTypeChanger) + /** + * @readonly + * @var \Rector\StaticTypeMapper\StaticTypeMapper + */ + private $staticTypeMapper; + public function __construct(TypeComparator $typeComparator, GenericTypeNodeAnalyzer $genericTypeNodeAnalyzer, MixedArrayTypeNodeAnalyzer $mixedArrayTypeNodeAnalyzer, StandaloneTypeRemovalGuard $standaloneTypeRemovalGuard, PhpDocTypeChanger $phpDocTypeChanger, StaticTypeMapper $staticTypeMapper) { $this->typeComparator = $typeComparator; $this->genericTypeNodeAnalyzer = $genericTypeNodeAnalyzer; $this->mixedArrayTypeNodeAnalyzer = $mixedArrayTypeNodeAnalyzer; $this->standaloneTypeRemovalGuard = $standaloneTypeRemovalGuard; $this->phpDocTypeChanger = $phpDocTypeChanger; + $this->staticTypeMapper = $staticTypeMapper; } public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $classMethod) : bool { @@ -65,11 +75,11 @@ public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $clas return \false; } // in case of void, there is no added value in @return tag - if ($returnType instanceof Identifier && $returnType->toString() === 'void') { + if ($this->isVoidReturnType($returnType)) { return !$returnTagValueNode->type instanceof IdentifierTypeNode || (string) $returnTagValueNode->type !== 'never'; } if (!$this->typeComparator->arePhpParserAndPhpStanPhpDocTypesEqual($returnType, $returnTagValueNode->type, $classMethod)) { - return $returnTagValueNode->type instanceof IdentifierTypeNode && (string) $returnTagValueNode->type === 'void'; + return $this->isDeadNotEqual($returnTagValueNode, $returnType, $classMethod); } if ($this->phpDocTypeChanger->isAllowed($returnTagValueNode->type)) { return \false; @@ -85,6 +95,19 @@ public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $clas } return !$this->hasTrueFalsePseudoType($returnTagValueNode->type); } + private function isVoidReturnType(Node $node) : bool + { + return $node instanceof Identifier && $node->toString() === 'void'; + } + private function isDeadNotEqual(ReturnTagValueNode $returnTagValueNode, Node $node, ClassMethod $classMethod) : bool + { + if ($returnTagValueNode->type instanceof IdentifierTypeNode && (string) $returnTagValueNode->type === 'void') { + return \true; + } + $nodeType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($node); + $docType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($returnTagValueNode->type, $classMethod); + return $docType instanceof UnionType && $this->typeComparator->areTypesEqual(TypeCombinator::removeNull($docType), $nodeType); + } private function hasTrueFalsePseudoType(BracketsAwareUnionTypeNode $bracketsAwareUnionTypeNode) : bool { $unionTypes = $bracketsAwareUnionTypeNode->types; diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 9cb057d631a8..1077b4b22825 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = '41729c25cb33ec5219433d5e101d6d54ed4045a2'; + public const PACKAGE_VERSION = '80cf5781c3bf477076753e2a0c2890ae0ecbb4c1'; /** * @api * @var string */ - public const RELEASE_DATE = '2023-12-04 08:54:10'; + public const RELEASE_DATE = '2023-12-04 12:20:21'; /** * @var int */