Skip to content

Commit 1eedc10

Browse files
committed
Get native type from reflection
1 parent c11ab15 commit 1eedc10

3 files changed

Lines changed: 72 additions & 5 deletions

File tree

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,15 @@ private function createMethod(
414414

415415
$stubPhpDocString = null;
416416
$variants = [];
417+
$reflectionMethod = null;
418+
if (class_exists($classReflection->getName(), false)) {
419+
$reflectionClass = new \ReflectionClass($classReflection->getName());
420+
if ($reflectionClass->hasMethod($methodReflection->getName())) {
421+
$reflectionMethod = $reflectionClass->getMethod($methodReflection->getName());
422+
}
423+
} else {
424+
$reflectionMethod = $classReflection->getNativeReflection()->getMethod($methodReflection->getName());
425+
}
417426
foreach ($variantNames as $innerVariantName) {
418427
$methodSignature = $this->signatureMapProvider->getFunctionSignature($innerVariantName, $declaringClassName);
419428
$phpDocReturnType = null;
@@ -445,7 +454,7 @@ private function createMethod(
445454
}
446455
}
447456
}
448-
$variants[] = $this->createNativeMethodVariant($methodSignature, $stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity, $phpDocReturnType);
457+
$variants[] = $this->createNativeMethodVariant($methodSignature, $stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity, $phpDocReturnType, $reflectionMethod);
449458
}
450459

451460
if ($this->signatureMapProvider->hasFunctionMetadata($signatureMapMethodName)) {
@@ -552,23 +561,49 @@ private function createMethod(
552561
* @param array<string, Type> $stubPhpDocParameterTypes
553562
* @param array<string, bool> $stubPhpDocParameterVariadicity
554563
* @param Type|null $phpDocReturnType
564+
* @param \ReflectionMethod|null $reflectionMethod
555565
* @return FunctionVariantWithPhpDocs
556566
*/
557567
private function createNativeMethodVariant(
558568
FunctionSignature $methodSignature,
559569
array $stubPhpDocParameterTypes,
560570
array $stubPhpDocParameterVariadicity,
561-
?Type $phpDocReturnType
571+
?Type $phpDocReturnType,
572+
?\ReflectionMethod $reflectionMethod
562573
): FunctionVariantWithPhpDocs
563574
{
564575
$parameters = [];
565-
foreach ($methodSignature->getParameters() as $parameterSignature) {
576+
$nativeParameters = null;
577+
$nativeReturnType = null;
578+
if ($reflectionMethod !== null) {
579+
$nativeParameters = $reflectionMethod->getParameters();
580+
$nativeReturnType = TypehintHelper::decideTypeFromReflection(
581+
$reflectionMethod->getReturnType(),
582+
null,
583+
null,
584+
false
585+
);
586+
}
587+
foreach ($methodSignature->getParameters() as $i => $parameterSignature) {
588+
if (
589+
$nativeParameters !== null
590+
&& array_key_exists($i, $nativeParameters)
591+
) {
592+
$nativeParameterType = TypehintHelper::decideTypeFromReflection(
593+
$nativeParameters[$i]->getType(),
594+
null,
595+
null,
596+
$nativeParameters[$i]->isVariadic()
597+
);
598+
} else {
599+
$nativeParameterType = new MixedType();
600+
}
566601
$parameters[] = new NativeParameterWithPhpDocsReflection(
567602
$parameterSignature->getName(),
568603
$parameterSignature->isOptional(),
569604
$stubPhpDocParameterTypes[$parameterSignature->getName()] ?? $parameterSignature->getType(),
570605
$stubPhpDocParameterTypes[$parameterSignature->getName()] ?? new MixedType(),
571-
new MixedType(true), // todo
606+
$nativeParameterType,
572607
$parameterSignature->passedByReference(),
573608
$stubPhpDocParameterVariadicity[$parameterSignature->getName()] ?? $parameterSignature->isVariadic(),
574609
null,
@@ -583,7 +618,7 @@ private function createNativeMethodVariant(
583618
$methodSignature->isVariadic(),
584619
$phpDocReturnType ?? $methodSignature->getReturnType(),
585620
$phpDocReturnType ?? new MixedType(),
586-
new MixedType(true) // todo $methodSignature->getNativeReturnType()
621+
$nativeReturnType ?? new MixedType()
587622
);
588623
}
589624

tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,23 @@ public function testReturnTypeCovariance(
278278
$this->analyse([__DIR__ . '/data/return-type-covariance.php'], $expectedErrors);
279279
}
280280

281+
public function testParle(): void
282+
{
283+
if (!self::$useStaticReflectionProvider) {
284+
$this->markTestSkipped('Test requires static reflection.');
285+
}
286+
287+
$this->phpVersionId = PHP_VERSION_ID;
288+
$this->analyse([__DIR__ . '/data/parle.php'], [
289+
[
290+
'Parameter #1 $state (int) of method OverridingParle\Foo::pushState() is not contravariant with parameter #1 $state (string) of method Parle\RLexer::pushState().',
291+
8,
292+
],
293+
[
294+
'Return type string of method OverridingParle\Foo::pushState() is not covariant with return type int of method Parle\RLexer::pushState().',
295+
8,
296+
],
297+
]);
298+
}
299+
281300
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace OverridingParle;
4+
5+
class Foo extends \Parle\RLexer
6+
{
7+
8+
public function pushState(int $state): string
9+
{
10+
11+
}
12+
13+
}

0 commit comments

Comments
 (0)