33
33
use PHPStan \Type \ArrayType ;
34
34
use PHPStan \Type \Constant \ConstantArrayType ;
35
35
use PHPStan \Type \ErrorType ;
36
+ use PHPStan \Type \FileTypeMapper ;
36
37
use PHPStan \Type \Generic \TemplateTypeHelper ;
37
38
use PHPStan \Type \Generic \TemplateTypeMap ;
38
39
use PHPStan \Type \MixedType ;
@@ -69,6 +70,8 @@ class PhpClassReflectionExtension
69
70
70
71
private \PHPStan \Reflection \ReflectionProvider $ reflectionProvider ;
71
72
73
+ private FileTypeMapper $ fileTypeMapper ;
74
+
72
75
/** @var string[] */
73
76
private array $ universalObjectCratesClasses ;
74
77
@@ -101,6 +104,7 @@ class PhpClassReflectionExtension
101
104
* @param \PHPStan\Parser\Parser $parser
102
105
* @param \PHPStan\PhpDoc\StubPhpDocProvider $stubPhpDocProvider
103
106
* @param \PHPStan\Reflection\ReflectionProvider $reflectionProvider
107
+ * @param FileTypeMapper $fileTypeMapper
104
108
* @param bool $inferPrivatePropertyTypeFromConstructor
105
109
* @param string[] $universalObjectCratesClasses
106
110
*/
@@ -115,6 +119,7 @@ public function __construct(
115
119
Parser $ parser ,
116
120
StubPhpDocProvider $ stubPhpDocProvider ,
117
121
ReflectionProvider $ reflectionProvider ,
122
+ FileTypeMapper $ fileTypeMapper ,
118
123
bool $ inferPrivatePropertyTypeFromConstructor ,
119
124
array $ universalObjectCratesClasses
120
125
)
@@ -129,6 +134,7 @@ public function __construct(
129
134
$ this ->parser = $ parser ;
130
135
$ this ->stubPhpDocProvider = $ stubPhpDocProvider ;
131
136
$ this ->reflectionProvider = $ reflectionProvider ;
137
+ $ this ->fileTypeMapper = $ fileTypeMapper ;
132
138
$ this ->inferPrivatePropertyTypeFromConstructor = $ inferPrivatePropertyTypeFromConstructor ;
133
139
$ this ->universalObjectCratesClasses = $ universalObjectCratesClasses ;
134
140
}
@@ -422,9 +428,11 @@ private function createMethod(
422
428
}
423
429
foreach ($ variantNumbers as $ variantNumber ) {
424
430
$ methodSignature = $ this ->signatureMapProvider ->getMethodSignature ($ declaringClassName , $ methodReflection ->getName (), $ reflectionMethod , $ variantNumber );
425
- $ phpDocReturnType = null ;
431
+ $ stubPhpDocReturnType = null ;
426
432
$ stubPhpDocParameterTypes = [];
427
433
$ stubPhpDocParameterVariadicity = [];
434
+ $ phpDocParameterTypes = [];
435
+ $ phpDocReturnType = null ;
428
436
if (count ($ variantNumbers ) === 1 ) {
429
437
$ stubPhpDocPair = $ this ->findMethodPhpDocIncludingAncestors ($ declaringClass , $ methodReflection ->getName (), array_map (static function (ParameterSignature $ parameterSignature ): string {
430
438
return $ parameterSignature ->getName ();
@@ -435,9 +443,8 @@ private function createMethod(
435
443
$ templateTypeMap = $ stubDeclaringClass ->getActiveTemplateTypeMap ();
436
444
$ returnTag = $ stubPhpDoc ->getReturnTag ();
437
445
if ($ returnTag !== null ) {
438
- $ stubPhpDocReturnType = $ returnTag ->getType ();
439
- $ phpDocReturnType = TemplateTypeHelper::resolveTemplateTypes (
440
- $ stubPhpDocReturnType ,
446
+ $ stubPhpDocReturnType = TemplateTypeHelper::resolveTemplateTypes (
447
+ $ returnTag ->getType (),
441
448
$ templateTypeMap
442
449
);
443
450
}
@@ -449,9 +456,27 @@ private function createMethod(
449
456
);
450
457
$ stubPhpDocParameterVariadicity [$ name ] = $ paramTag ->isVariadic ();
451
458
}
459
+ } elseif ($ reflectionMethod !== null && $ reflectionMethod ->getDocComment () !== false ) {
460
+ $ filename = $ reflectionMethod ->getFileName ();
461
+ if ($ filename !== false ) {
462
+ $ phpDocBlock = $ this ->fileTypeMapper ->getResolvedPhpDoc (
463
+ $ filename ,
464
+ $ declaringClassName ,
465
+ null ,
466
+ $ reflectionMethod ->getName (),
467
+ $ reflectionMethod ->getDocComment ()
468
+ );
469
+ $ returnTag = $ phpDocBlock ->getReturnTag ();
470
+ if ($ returnTag !== null ) {
471
+ $ phpDocReturnType = $ returnTag ->getType ();
472
+ }
473
+ foreach ($ phpDocBlock ->getParamTags () as $ name => $ paramTag ) {
474
+ $ phpDocParameterTypes [$ name ] = $ paramTag ->getType ();
475
+ }
476
+ }
452
477
}
453
478
}
454
- $ variants [] = $ this ->createNativeMethodVariant ($ methodSignature , $ stubPhpDocParameterTypes , $ stubPhpDocParameterVariadicity , $ phpDocReturnType );
479
+ $ variants [] = $ this ->createNativeMethodVariant ($ methodSignature , $ stubPhpDocParameterTypes , $ stubPhpDocParameterVariadicity , $ stubPhpDocReturnType , $ phpDocParameterTypes , $ phpDocReturnType );
455
480
}
456
481
457
482
if ($ this ->signatureMapProvider ->hasMethodMetadata ($ declaringClassName , $ methodReflection ->getName ())) {
@@ -557,36 +582,65 @@ private function createMethod(
557
582
* @param FunctionSignature $methodSignature
558
583
* @param array<string, Type> $stubPhpDocParameterTypes
559
584
* @param array<string, bool> $stubPhpDocParameterVariadicity
585
+ * @param Type|null $stubPhpDocReturnType
586
+ * @param array<string, Type> $phpDocParameterTypes
560
587
* @param Type|null $phpDocReturnType
561
588
* @return FunctionVariantWithPhpDocs
562
589
*/
563
590
private function createNativeMethodVariant (
564
591
FunctionSignature $ methodSignature ,
565
592
array $ stubPhpDocParameterTypes ,
566
593
array $ stubPhpDocParameterVariadicity ,
594
+ ?Type $ stubPhpDocReturnType ,
595
+ array $ phpDocParameterTypes ,
567
596
?Type $ phpDocReturnType
568
597
): FunctionVariantWithPhpDocs
569
598
{
570
599
$ parameters = [];
571
600
foreach ($ methodSignature ->getParameters () as $ parameterSignature ) {
601
+ $ type = null ;
602
+ $ phpDocType = null ;
603
+
604
+ if (isset ($ stubPhpDocParameterTypes [$ parameterSignature ->getName ()])) {
605
+ $ type = $ stubPhpDocParameterTypes [$ parameterSignature ->getName ()];
606
+ $ phpDocType = $ stubPhpDocParameterTypes [$ parameterSignature ->getName ()];
607
+ } elseif (isset ($ phpDocParameterTypes [$ parameterSignature ->getName ()])) {
608
+ $ type = TypehintHelper::decideType (
609
+ $ parameterSignature ->getNativeType (),
610
+ $ phpDocParameterTypes [$ parameterSignature ->getName ()]
611
+ );
612
+ $ phpDocType = $ phpDocParameterTypes [$ parameterSignature ->getName ()];
613
+ }
614
+
572
615
$ parameters [] = new NativeParameterWithPhpDocsReflection (
573
616
$ parameterSignature ->getName (),
574
617
$ parameterSignature ->isOptional (),
575
- $ stubPhpDocParameterTypes [ $ parameterSignature -> getName ()] ?? $ parameterSignature ->getType (),
576
- $ stubPhpDocParameterTypes [ $ parameterSignature -> getName ()] ?? new MixedType (),
618
+ $ type ?? $ parameterSignature ->getType (),
619
+ $ phpDocType ?? new MixedType (),
577
620
$ parameterSignature ->getNativeType (),
578
621
$ parameterSignature ->passedByReference (),
579
622
$ stubPhpDocParameterVariadicity [$ parameterSignature ->getName ()] ?? $ parameterSignature ->isVariadic (),
580
623
null
581
624
);
582
625
}
583
626
627
+ $ returnType = null ;
628
+ if ($ stubPhpDocReturnType !== null ) {
629
+ $ returnType = $ stubPhpDocReturnType ;
630
+ $ phpDocReturnType = $ stubPhpDocReturnType ;
631
+ } elseif ($ phpDocReturnType !== null ) {
632
+ $ returnType = TypehintHelper::decideType (
633
+ $ methodSignature ->getReturnType (),
634
+ $ phpDocReturnType
635
+ );
636
+ }
637
+
584
638
return new FunctionVariantWithPhpDocs (
585
639
TemplateTypeMap::createEmpty (),
586
640
null ,
587
641
$ parameters ,
588
642
$ methodSignature ->isVariadic (),
589
- $ phpDocReturnType ?? $ methodSignature ->getReturnType (),
643
+ $ returnType ?? $ methodSignature ->getReturnType (),
590
644
$ phpDocReturnType ?? new MixedType (),
591
645
$ methodSignature ->getNativeReturnType ()
592
646
);
0 commit comments