Skip to content

Commit

Permalink
[TypeDeclaration] Return new static from different object on ReturnTy…
Browse files Browse the repository at this point in the history
…peFromStrictTypedCallRector (#5357)

* [TypeDeclaration] Return new static from different object on ReturnTypeFromStrictTypedCallRector

* Fix
  • Loading branch information
samsonasik committed Dec 13, 2023
1 parent fea5d6c commit 0817980
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
@@ -0,0 +1,31 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeNamedConstructorClass;

final class ReturnStaticDifferentObject
{
public function getData()
{
return SomeNamedConstructorClass::from();
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeNamedConstructorClass;

final class ReturnStaticDifferentObject
{
public function getData(): \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeNamedConstructorClass
{
return SomeNamedConstructorClass::from();
}
}

?>
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source;

class SomeNamedConstructorClass {
public static function from(): static
{
return new static();
}
}
25 changes: 25 additions & 0 deletions rules/TypeDeclaration/TypeAnalyzer/ReturnStrictTypeAnalyzer.php
Expand Up @@ -20,11 +20,16 @@
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Return_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\FunctionVariantWithPhpDocs;
use PHPStan\Type\MixedType;
use PHPStan\Type\StaticType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\TypeDeclaration\NodeAnalyzer\TypeNodeUnwrapper;

final class ReturnStrictTypeAnalyzer
Expand Down Expand Up @@ -105,9 +110,29 @@ public function resolveMethodCallReturnNode(MethodCall | StaticCall | FuncCall $
return null;
}

$returnType = $this->normalizeStaticType($call, $returnType);
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType, TypeKind::RETURN);
}

private function normalizeStaticType(MethodCall | StaticCall | FuncCall $call, Type $type): Type
{
$reflectionClass = $this->reflectionResolver->resolveClassReflection($call);
if (! $reflectionClass instanceof ClassReflection) {
return $type;
}

$currentClassName = $reflectionClass->getName();
return TypeTraverser::map($type, static function (Type $currentType, callable $traverseCallback) use (
$currentClassName
): Type {
if ($currentType instanceof StaticType && $currentClassName !== $currentType->getClassName()) {
return new FullyQualifiedObjectType($currentType->getClassName());
}

return $traverseCallback($currentType);
});
}

private function resolveLiteralReturnNode(Array_|Scalar $returnedExpr, Scope $scope): ?Node
{
$returnType = $scope->getType($returnedExpr);
Expand Down

0 comments on commit 0817980

Please sign in to comment.