@@ -131,18 +131,7 @@ protected function addFunction(FunctionNode $node, ?string $namespace = null)
131131
132132 $ parameter ->setVariadic ($ param ->variadic );
133133
134- $ type = $ param ->type ;
135- $ typeStr = $ this ->typeToString ($ type );
136-
137- if (null !== $ typeStr ) {
138- $ typeArr = [[$ typeStr , false ]];
139-
140- if ($ param ->type instanceof NullableType) {
141- $ typeArr [] = ['null ' , false ];
142- }
143-
144- $ parameter ->setHint ($ this ->resolveHint ($ typeArr ));
145- }
134+ $ this ->manageHint ($ param ->type , $ parameter );
146135
147136 $ function ->addParameter ($ parameter );
148137 }
@@ -167,18 +156,7 @@ protected function addFunction(FunctionNode $node, ?string $namespace = null)
167156 $ function ->setModifiersFromTags ();
168157 $ function ->setErrors ($ errors );
169158
170- $ returnType = $ node ->getReturnType ();
171- $ returnTypeStr = $ this ->typeToString ($ returnType );
172-
173- if (null !== $ returnTypeStr ) {
174- $ returnTypeArr = [[$ returnTypeStr , false ]];
175-
176- if ($ returnType instanceof NullableType) {
177- $ returnTypeArr [] = ['null ' , false ];
178- }
179-
180- $ function ->setHint ($ this ->resolveHint ($ returnTypeArr ));
181- }
159+ $ this ->manageHint ($ node ->getReturnType (), $ function );
182160
183161 $ this ->context ->addFunction ($ function );
184162
@@ -188,7 +166,7 @@ protected function addFunction(FunctionNode $node, ?string $namespace = null)
188166 }
189167
190168 /**
191- * @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|NullableType|UnionType|IntersectionType|null $type Type declaration
169+ * @param \PhpParser\Node\ComplexType|\PhpParser\Node\ Identifier|\PhpParser\Node\Name|NullableType|UnionType|IntersectionType|null $type Type declaration
192170 */
193171 protected function typeToString ($ type ): ?string
194172 {
@@ -206,9 +184,13 @@ protected function typeToString($type): ?string
206184 } elseif ($ type instanceof IntersectionType) {
207185 $ typeString = [];
208186 foreach ($ type ->types as $ type ) {
209- $ typeString [] = $ type ->__toString ();
187+ $ typeAsStr = $ type ->__toString ();
188+ if ($ type instanceof FullyQualified && 0 !== strpos ($ typeAsStr , '\\' )) {
189+ $ typeAsStr = '\\' . $ typeAsStr ;
190+ }
191+ $ typeString [] = $ typeAsStr ;
210192 }
211- $ typeString = implode ('& ' , $ typeString );
193+ return implode ('& ' , $ typeString );
212194 }
213195
214196 if ($ typeString === null ) {
@@ -332,18 +314,7 @@ protected function addMethod(ClassMethodNode $node)
332314
333315 $ parameter ->setVariadic ($ param ->variadic );
334316
335- $ type = $ param ->type ;
336- $ typeStr = $ this ->typeToString ($ type );
337-
338- if (null !== $ typeStr ) {
339- $ typeArr = [[$ typeStr , false ]];
340-
341- if ($ param ->type instanceof NullableType) {
342- $ typeArr [] = ['null ' , false ];
343- }
344-
345- $ parameter ->setHint ($ this ->resolveHint ($ typeArr ));
346- }
317+ $ this ->manageHint ($ param ->type , $ parameter );
347318
348319 $ method ->addParameter ($ parameter );
349320 }
@@ -371,18 +342,7 @@ protected function addMethod(ClassMethodNode $node)
371342 $ method ->setModifiersFromTags ();
372343 $ method ->setErrors ($ errors );
373344
374- $ returnType = $ node ->getReturnType ();
375- $ returnTypeStr = $ this ->typeToString ($ returnType );
376-
377- if (null !== $ returnTypeStr ) {
378- $ returnTypeArr = [[$ returnTypeStr , false ]];
379-
380- if ($ returnType instanceof NullableType) {
381- $ returnTypeArr [] = ['null ' , false ];
382- }
383-
384- $ method ->setHint ($ this ->resolveHint ($ returnTypeArr ));
385- }
345+ $ this ->manageHint ($ node ->getReturnType (), $ method );
386346
387347 if ($ this ->context ->getFilter ()->acceptMethod ($ method )) {
388348 $ this ->context ->getClass ()->addMethod ($ method );
@@ -417,6 +377,14 @@ protected function addTagFromCommentToMethod(
417377 if (is_array ($ firstTagFound )) {
418378 $ hint = $ firstTagFound [0 ];
419379 $ hintDescription = $ firstTagFound [1 ] ?? null ;
380+ if (is_array ($ hint ) && isset ($ hint [0 ]) && stripos ($ hint [0 ][0 ] ?? '' , '& ' ) !== false ) {// Detect intersection type
381+ $ methodOrFunctionOrProperty ->setIntersectionType (true );
382+ $ intersectionParts = explode ('& ' , $ hint [0 ][0 ]);
383+ $ hint = [];
384+ foreach ($ intersectionParts as $ part ) {
385+ $ hint [] = [$ part , false ];
386+ }
387+ }
420388 $ methodOrFunctionOrProperty ->setHint (is_array ($ hint ) ? $ this ->resolveHint ($ hint ) : $ hint );
421389 if ($ hintDescription !== null ) {
422390 if (is_string ($ hintDescription )) {
@@ -458,36 +426,21 @@ protected function addProperty(PropertyNode $node)
458426 }
459427
460428 /**
461- * @return array<int,PropertyReflection|string[]>
462- * @phpstan-return array{ PropertyReflection,string[]}
429+ * @param \PhpParser\Node\ComplexType|\PhpParser\Node\Identifier|\PhpParser\Node\Name|NullableType|UnionType|IntersectionType|null $type Type declaration
430+ * @param MethodReflection|FunctionReflection|ParameterReflection| PropertyReflection $object
463431 */
464- protected function getPropertyReflectionFromParserProperty ( PropertyNode $ node , PropertyProperty $ prop ): array
432+ protected function manageHint ( $ type , Reflection $ object ): void
465433 {
466- $ property = new PropertyReflection ($ prop ->name ->toString (), $ prop ->getLine ());
467- $ property ->setModifiers ($ node ->flags );
468-
469- $ property ->setDefault ($ prop ->default );
470-
471- $ docComment = $ node ->getDocComment ();
472- $ docComment = $ docComment === null ? null : $ docComment ->__toString ();
473- $ comment = $ this ->context ->getDocBlockParser ()->parse ($ docComment , $ this ->context , $ property );
474- $ property ->setDocComment ($ docComment );
475- $ property ->setShortDesc ($ comment ->getShortDesc ());
476- $ property ->setLongDesc ($ comment ->getLongDesc ());
477- $ property ->setSee ($ this ->resolveSee ($ comment ->getTag ('see ' )));
478-
479- $ type = $ node ->type ;
480-
481434 if ($ type instanceof IntersectionType) {
482- $ property ->setIntersectionType (true );
435+ $ object ->setIntersectionType (true );
483436
484437 $ typeArr = [];
485438 foreach ($ type ->types as $ type ) {
486439 $ typeStr = $ this ->typeToString ($ type );
487440 $ typeArr [] = [$ typeStr , false ];
488441 }
489442
490- $ property ->setHint ($ this ->resolveHint ($ typeArr ));
443+ $ object ->setHint ($ this ->resolveHint ($ typeArr ));
491444 } else {
492445 $ typeStr = $ this ->typeToString ($ type );
493446
@@ -497,9 +450,31 @@ protected function getPropertyReflectionFromParserProperty(PropertyNode $node, P
497450 if ($ type instanceof NullableType) {
498451 $ typeArr [] = ['null ' , false ];
499452 }
500- $ property ->setHint ($ this ->resolveHint ($ typeArr ));
453+ $ object ->setHint ($ this ->resolveHint ($ typeArr ));
501454 }
502455 }
456+ }
457+
458+ /**
459+ * @return array<int,PropertyReflection|string[]>
460+ * @phpstan-return array{PropertyReflection,string[]}
461+ */
462+ protected function getPropertyReflectionFromParserProperty (PropertyNode $ node , PropertyProperty $ prop ): array
463+ {
464+ $ property = new PropertyReflection ($ prop ->name ->toString (), $ prop ->getLine ());
465+ $ property ->setModifiers ($ node ->flags );
466+
467+ $ property ->setDefault ($ prop ->default );
468+
469+ $ docComment = $ node ->getDocComment ();
470+ $ docComment = $ docComment === null ? null : $ docComment ->__toString ();
471+ $ comment = $ this ->context ->getDocBlockParser ()->parse ($ docComment , $ this ->context , $ property );
472+ $ property ->setDocComment ($ docComment );
473+ $ property ->setShortDesc ($ comment ->getShortDesc ());
474+ $ property ->setLongDesc ($ comment ->getLongDesc ());
475+ $ property ->setSee ($ this ->resolveSee ($ comment ->getTag ('see ' )));
476+
477+ $ this ->manageHint ($ node ->type , $ property );
503478
504479 if ($ errors = $ comment ->getErrors ()) {
505480 $ property ->setErrors ($ errors );
@@ -643,6 +618,9 @@ protected function updateMethodParametersFromTags(Reflection $method, array $tag
643618 return $ errors ;
644619 }
645620
621+ /**
622+ * @phpstan-param $hints array{0: string, 1: bool}
623+ */
646624 protected function resolveHint (array $ hints ): array
647625 {
648626 foreach ($ hints as $ i => $ hint ) {
@@ -652,6 +630,9 @@ protected function resolveHint(array $hints): array
652630 return $ hints ;
653631 }
654632
633+ /**
634+ * @phpstan-param $alias array{0: string, 1: bool}
635+ */
655636 protected function resolveAlias ($ alias )
656637 {
657638 // not a class
0 commit comments