@@ -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 )) {
@@ -457,6 +425,36 @@ protected function addProperty(PropertyNode $node)
457425 }
458426 }
459427
428+ /**
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
431+ */
432+ protected function manageHint ($ type , Reflection $ object ): void
433+ {
434+ if ($ type instanceof IntersectionType) {
435+ $ object ->setIntersectionType (true );
436+
437+ $ typeArr = [];
438+ foreach ($ type ->types as $ type ) {
439+ $ typeStr = $ this ->typeToString ($ type );
440+ $ typeArr [] = [$ typeStr , false ];
441+ }
442+
443+ $ object ->setHint ($ this ->resolveHint ($ typeArr ));
444+ } else {
445+ $ typeStr = $ this ->typeToString ($ type );
446+
447+ if (null !== $ typeStr ) {
448+ $ typeArr = [[$ typeStr , false ]];
449+
450+ if ($ type instanceof NullableType) {
451+ $ typeArr [] = ['null ' , false ];
452+ }
453+ $ object ->setHint ($ this ->resolveHint ($ typeArr ));
454+ }
455+ }
456+ }
457+
460458 /**
461459 * @return array<int,PropertyReflection|string[]>
462460 * @phpstan-return array{PropertyReflection,string[]}
@@ -475,6 +473,9 @@ protected function getPropertyReflectionFromParserProperty(PropertyNode $node, P
475473 $ property ->setShortDesc ($ comment ->getShortDesc ());
476474 $ property ->setLongDesc ($ comment ->getLongDesc ());
477475 $ property ->setSee ($ this ->resolveSee ($ comment ->getTag ('see ' )));
476+
477+ $ this ->manageHint ($ node ->type , $ property );
478+
478479 if ($ errors = $ comment ->getErrors ()) {
479480 $ property ->setErrors ($ errors );
480481 } else {
@@ -617,6 +618,9 @@ protected function updateMethodParametersFromTags(Reflection $method, array $tag
617618 return $ errors ;
618619 }
619620
621+ /**
622+ * @phpstan-param $hints array{0: string, 1: bool}
623+ */
620624 protected function resolveHint (array $ hints ): array
621625 {
622626 foreach ($ hints as $ i => $ hint ) {
@@ -626,6 +630,9 @@ protected function resolveHint(array $hints): array
626630 return $ hints ;
627631 }
628632
633+ /**
634+ * @phpstan-param $alias array{0: string, 1: bool}
635+ */
629636 protected function resolveAlias ($ alias )
630637 {
631638 // not a class
0 commit comments