Skip to content

Commit

Permalink
[DeadCode] Remove useless nullable @return doc on RemoveUselessReturn…
Browse files Browse the repository at this point in the history
…TagRector (#5321)

* [DeadCode] Remove useless nullable return tag on RemoveUselessReturnTagRector

* cs fix

* Fix phpstan
  • Loading branch information
samsonasik committed Dec 4, 2023
1 parent 41729c2 commit 80cf578
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector\Fixture;

use stdClass;

class UselessNullableDoc
{
/**
* @return stdClass|null
*/
function foo(): stdClass
{
return new stdClass();
}
}

?>
-----
<?php

namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector\Fixture;

use stdClass;

class UselessNullableDoc
{
function foo(): stdClass
{
return new stdClass();
}
}

?>
32 changes: 30 additions & 2 deletions rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
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;
use Rector\DeadCode\TypeNodeAnalyzer\GenericTypeNodeAnalyzer;
use Rector\DeadCode\TypeNodeAnalyzer\MixedArrayTypeNodeAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
use Rector\StaticTypeMapper\StaticTypeMapper;

final class DeadReturnTagValueNodeAnalyzer
{
Expand All @@ -26,6 +30,7 @@ public function __construct(
private readonly MixedArrayTypeNodeAnalyzer $mixedArrayTypeNodeAnalyzer,
private readonly StandaloneTypeRemovalGuard $standaloneTypeRemovalGuard,
private readonly PhpDocTypeChanger $phpDocTypeChanger,
private readonly StaticTypeMapper $staticTypeMapper
) {
}

Expand All @@ -46,7 +51,7 @@ public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $clas
}

// 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';
}

Expand All @@ -55,7 +60,7 @@ public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $clas
$returnTagValueNode->type,
$classMethod,
)) {
return $returnTagValueNode->type instanceof IdentifierTypeNode && (string) $returnTagValueNode->type === 'void';
return $this->isDeadNotEqual($returnTagValueNode, $returnType, $classMethod);
}

if ($this->phpDocTypeChanger->isAllowed($returnTagValueNode->type)) {
Expand All @@ -77,6 +82,29 @@ 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;
Expand Down

0 comments on commit 80cf578

Please sign in to comment.