99use PhpParser \Node \Stmt \ClassMethod ;
1010use PHPStan \PhpDocParser \Ast \PhpDoc \ReturnTagValueNode ;
1111use PHPStan \PhpDocParser \Ast \Type \GenericTypeNode ;
12+ use PHPStan \PhpDocParser \Ast \Type \IdentifierTypeNode ;
1213use PHPStan \Reflection \ClassReflection ;
1314use PHPStan \Type \ObjectType ;
1415use Rector \BetterPhpDocParser \PhpDocInfo \PhpDocInfo ;
1516use Rector \BetterPhpDocParser \PhpDocInfo \PhpDocInfoFactory ;
1617use Rector \BetterPhpDocParser \ValueObject \Type \FullyQualifiedIdentifierTypeNode ;
1718use Rector \Comments \NodeDocBlock \DocBlockUpdater ;
19+ use Rector \NodeTypeResolver \TypeComparator \TypeComparator ;
1820use Rector \PhpParser \AstResolver ;
1921use Rector \PhpParser \Node \BetterNodeFinder ;
2022use Rector \Rector \AbstractRector ;
2123use Rector \Reflection \ReflectionResolver ;
24+ use Rector \StaticTypeMapper \StaticTypeMapper ;
2225use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2326use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
2427/**
@@ -40,6 +43,14 @@ final class NarrowObjectReturnTypeRector extends AbstractRector
4043 * @readonly
4144 */
4245 private AstResolver $ astResolver ;
46+ /**
47+ * @readonly
48+ */
49+ private StaticTypeMapper $ staticTypeMapper ;
50+ /**
51+ * @readonly
52+ */
53+ private TypeComparator $ typeComparator ;
4354 /**
4455 * @readonly
4556 */
@@ -48,11 +59,13 @@ final class NarrowObjectReturnTypeRector extends AbstractRector
4859 * @readonly
4960 */
5061 private DocBlockUpdater $ docBlockUpdater ;
51- public function __construct (BetterNodeFinder $ betterNodeFinder , ReflectionResolver $ reflectionResolver , AstResolver $ astResolver , PhpDocInfoFactory $ phpDocInfoFactory , DocBlockUpdater $ docBlockUpdater )
62+ public function __construct (BetterNodeFinder $ betterNodeFinder , ReflectionResolver $ reflectionResolver , AstResolver $ astResolver , StaticTypeMapper $ staticTypeMapper , TypeComparator $ typeComparator , PhpDocInfoFactory $ phpDocInfoFactory , DocBlockUpdater $ docBlockUpdater )
5263 {
5364 $ this ->betterNodeFinder = $ betterNodeFinder ;
5465 $ this ->reflectionResolver = $ reflectionResolver ;
5566 $ this ->astResolver = $ astResolver ;
67+ $ this ->staticTypeMapper = $ staticTypeMapper ;
68+ $ this ->typeComparator = $ typeComparator ;
5669 $ this ->phpDocInfoFactory = $ phpDocInfoFactory ;
5770 $ this ->docBlockUpdater = $ docBlockUpdater ;
5871 }
@@ -153,10 +166,24 @@ private function updateDocblock(ClassMethod $classMethod, string $actualReturnCl
153166 if (!$ returnTagValueNode instanceof ReturnTagValueNode) {
154167 return ;
155168 }
156- if (!$ returnTagValueNode ->type instanceof GenericTypeNode) {
169+ if ($ returnTagValueNode ->type instanceof IdentifierTypeNode) {
170+ $ oldType = $ this ->staticTypeMapper ->mapPHPStanPhpDocTypeNodeToPHPStanType ($ returnTagValueNode ->type , $ classMethod );
171+ } elseif ($ returnTagValueNode ->type instanceof GenericTypeNode) {
172+ $ oldType = $ this ->staticTypeMapper ->mapPHPStanPhpDocTypeNodeToPHPStanType ($ returnTagValueNode ->type ->type , $ classMethod );
173+ } else {
157174 return ;
158175 }
159- $ returnTagValueNode ->type ->type = new FullyQualifiedIdentifierTypeNode ($ actualReturnClass );
176+ if ($ oldType instanceof ObjectType) {
177+ $ objectType = new ObjectType ($ actualReturnClass );
178+ if ($ this ->typeComparator ->areTypesEqual ($ oldType , $ objectType )) {
179+ return ;
180+ }
181+ }
182+ if ($ returnTagValueNode ->type instanceof IdentifierTypeNode) {
183+ $ returnTagValueNode ->type = new FullyQualifiedIdentifierTypeNode ($ actualReturnClass );
184+ } else {
185+ $ returnTagValueNode ->type ->type = new FullyQualifiedIdentifierTypeNode ($ actualReturnClass );
186+ }
160187 $ this ->docBlockUpdater ->updateRefactoredNodeWithPhpDocInfo ($ classMethod );
161188 }
162189 private function isDeclaredTypeFinal (string $ declaredType ): bool
0 commit comments