Skip to content

Commit fc60b19

Browse files
committed
Extract MethodPrototypeFinder
1 parent 1f60505 commit fc60b19

File tree

6 files changed

+108
-85
lines changed

6 files changed

+108
-85
lines changed

src/PhpDoc/StubValidator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
use PHPStan\Rules\Generics\VarianceCheck;
6969
use PHPStan\Rules\Methods\ExistingClassesInTypehintsRule;
7070
use PHPStan\Rules\Methods\MethodParameterComparisonHelper;
71+
use PHPStan\Rules\Methods\MethodPrototypeFinder;
7172
use PHPStan\Rules\Methods\MethodSignatureRule;
7273
use PHPStan\Rules\Methods\MethodVisibilityComparisonHelper;
7374
use PHPStan\Rules\Methods\MissingMethodParameterTypehintRule;
@@ -219,7 +220,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
219220
true,
220221
new MethodParameterComparisonHelper($phpVersion),
221222
new MethodVisibilityComparisonHelper(),
222-
$phpClassReflectionExtension,
223+
new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension),
223224
$container->getParameter('checkMissingOverrideMethodAttribute'),
224225
),
225226
new DuplicateDeclarationRule(),
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Methods;
4+
5+
use PHPStan\DependencyInjection\AutowiredService;
6+
use PHPStan\Php\PhpVersion;
7+
use PHPStan\Reflection\ClassReflection;
8+
use PHPStan\Reflection\ExtendedMethodReflection;
9+
use PHPStan\Reflection\MethodPrototypeReflection;
10+
use PHPStan\Reflection\Native\NativeMethodReflection;
11+
use PHPStan\Reflection\Php\PhpClassReflectionExtension;
12+
use PHPStan\Reflection\Php\PhpMethodReflection;
13+
use function is_bool;
14+
use function strtolower;
15+
16+
#[AutowiredService]
17+
final class MethodPrototypeFinder
18+
{
19+
20+
public function __construct(
21+
private PhpVersion $phpVersion,
22+
private PhpClassReflectionExtension $phpClassReflectionExtension,
23+
)
24+
{
25+
}
26+
27+
/**
28+
* @return array{ExtendedMethodReflection, ClassReflection, bool}|null
29+
*/
30+
public function findPrototype(ClassReflection $classReflection, string $methodName): ?array
31+
{
32+
foreach ($classReflection->getImmediateInterfaces() as $immediateInterface) {
33+
if ($immediateInterface->hasNativeMethod($methodName)) {
34+
$method = $immediateInterface->getNativeMethod($methodName);
35+
return [$method, $method->getDeclaringClass(), true];
36+
}
37+
}
38+
39+
if ($this->phpVersion->supportsAbstractTraitMethods()) {
40+
foreach ($classReflection->getTraits(true) as $trait) {
41+
$nativeTraitReflection = $trait->getNativeReflection();
42+
if (!$nativeTraitReflection->hasMethod($methodName)) {
43+
continue;
44+
}
45+
46+
$methodReflection = $nativeTraitReflection->getMethod($methodName);
47+
$isAbstract = $methodReflection->isAbstract();
48+
if ($isAbstract) {
49+
$declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass();
50+
return [
51+
$this->phpClassReflectionExtension->createUserlandMethodReflection(
52+
$trait,
53+
$classReflection,
54+
$methodReflection,
55+
$declaringTrait->getName(),
56+
),
57+
$declaringTrait,
58+
false,
59+
];
60+
}
61+
}
62+
}
63+
64+
$parentClass = $classReflection->getParentClass();
65+
if ($parentClass === null) {
66+
return null;
67+
}
68+
69+
if (!$parentClass->hasNativeMethod($methodName)) {
70+
return null;
71+
}
72+
73+
$method = $parentClass->getNativeMethod($methodName);
74+
if ($method->isPrivate()) {
75+
return null;
76+
}
77+
78+
$declaringClass = $method->getDeclaringClass();
79+
if ($declaringClass->hasConstructor()) {
80+
if ($method->getName() === $declaringClass->getConstructor()->getName()) {
81+
$prototype = $method->getPrototype();
82+
if ($prototype instanceof PhpMethodReflection || $prototype instanceof MethodPrototypeReflection || $prototype instanceof NativeMethodReflection) {
83+
$abstract = $prototype->isAbstract();
84+
if (is_bool($abstract)) {
85+
if (!$abstract) {
86+
return null;
87+
}
88+
} elseif (!$abstract->yes()) {
89+
return null;
90+
}
91+
}
92+
} elseif (strtolower($methodName) === '__construct') {
93+
return null;
94+
}
95+
}
96+
97+
return [$method, $method->getDeclaringClass(), true];
98+
}
99+
100+
}

src/Rules/Methods/OverridingMethodRule.php

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,8 @@
99
use PHPStan\DependencyInjection\RegisteredRule;
1010
use PHPStan\Node\InClassMethodNode;
1111
use PHPStan\Php\PhpVersion;
12-
use PHPStan\Reflection\ClassReflection;
1312
use PHPStan\Reflection\ExtendedFunctionVariant;
14-
use PHPStan\Reflection\ExtendedMethodReflection;
1513
use PHPStan\Reflection\MethodPrototypeReflection;
16-
use PHPStan\Reflection\Native\NativeMethodReflection;
17-
use PHPStan\Reflection\Php\PhpClassReflectionExtension;
18-
use PHPStan\Reflection\Php\PhpMethodReflection;
1914
use PHPStan\Rules\IdentifierRuleError;
2015
use PHPStan\Rules\Rule;
2116
use PHPStan\Rules\RuleErrorBuilder;
@@ -41,7 +36,7 @@ public function __construct(
4136
private bool $checkPhpDocMethodSignatures,
4237
private MethodParameterComparisonHelper $methodParameterComparisonHelper,
4338
private MethodVisibilityComparisonHelper $methodVisibilityComparisonHelper,
44-
private PhpClassReflectionExtension $phpClassReflectionExtension,
39+
private MethodPrototypeFinder $methodPrototypeFinder,
4540
#[AutowiredParameter]
4641
private bool $checkMissingOverrideMethodAttribute,
4742
)
@@ -56,7 +51,7 @@ public function getNodeType(): string
5651
public function processNode(Node $node, Scope $scope): array
5752
{
5853
$method = $node->getMethodReflection();
59-
$prototypeData = $this->findPrototype($node->getClassReflection(), $method->getName());
54+
$prototypeData = $this->methodPrototypeFinder->findPrototype($node->getClassReflection(), $method->getName());
6055
if ($prototypeData === null) {
6156
if (strtolower($method->getName()) === '__construct') {
6257
$parent = $method->getDeclaringClass()->getParentClass();
@@ -368,77 +363,4 @@ private function hasOverrideAttribute(Node\Stmt\ClassMethod $method): bool
368363
return false;
369364
}
370365

371-
/**
372-
* @return array{ExtendedMethodReflection, ClassReflection, bool}|null
373-
*/
374-
private function findPrototype(ClassReflection $classReflection, string $methodName): ?array
375-
{
376-
foreach ($classReflection->getImmediateInterfaces() as $immediateInterface) {
377-
if ($immediateInterface->hasNativeMethod($methodName)) {
378-
$method = $immediateInterface->getNativeMethod($methodName);
379-
return [$method, $method->getDeclaringClass(), true];
380-
}
381-
}
382-
383-
if ($this->phpVersion->supportsAbstractTraitMethods()) {
384-
foreach ($classReflection->getTraits(true) as $trait) {
385-
$nativeTraitReflection = $trait->getNativeReflection();
386-
if (!$nativeTraitReflection->hasMethod($methodName)) {
387-
continue;
388-
}
389-
390-
$methodReflection = $nativeTraitReflection->getMethod($methodName);
391-
$isAbstract = $methodReflection->isAbstract();
392-
if ($isAbstract) {
393-
$declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass();
394-
return [
395-
$this->phpClassReflectionExtension->createUserlandMethodReflection(
396-
$trait,
397-
$classReflection,
398-
$methodReflection,
399-
$declaringTrait->getName(),
400-
),
401-
$declaringTrait,
402-
false,
403-
];
404-
}
405-
}
406-
}
407-
408-
$parentClass = $classReflection->getParentClass();
409-
if ($parentClass === null) {
410-
return null;
411-
}
412-
413-
if (!$parentClass->hasNativeMethod($methodName)) {
414-
return null;
415-
}
416-
417-
$method = $parentClass->getNativeMethod($methodName);
418-
if ($method->isPrivate()) {
419-
return null;
420-
}
421-
422-
$declaringClass = $method->getDeclaringClass();
423-
if ($declaringClass->hasConstructor()) {
424-
if ($method->getName() === $declaringClass->getConstructor()->getName()) {
425-
$prototype = $method->getPrototype();
426-
if ($prototype instanceof PhpMethodReflection || $prototype instanceof MethodPrototypeReflection || $prototype instanceof NativeMethodReflection) {
427-
$abstract = $prototype->isAbstract();
428-
if (is_bool($abstract)) {
429-
if (!$abstract) {
430-
return null;
431-
}
432-
} elseif (!$abstract->yes()) {
433-
return null;
434-
}
435-
}
436-
} elseif (strtolower($methodName) === '__construct') {
437-
return null;
438-
}
439-
}
440-
441-
return [$method, $method->getDeclaringClass(), true];
442-
}
443-
444366
}

tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected function getRule(): Rule
3030
true,
3131
new MethodParameterComparisonHelper($phpVersion),
3232
new MethodVisibilityComparisonHelper(),
33-
$phpClassReflectionExtension,
33+
new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension),
3434
false,
3535
);
3636
}

tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ protected function getRule(): Rule
3232
false,
3333
new MethodParameterComparisonHelper($phpVersion),
3434
new MethodVisibilityComparisonHelper(),
35-
$phpClassReflectionExtension,
35+
new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension),
3636
$this->checkMissingOverrideMethodAttribute,
3737
);
3838
}

tests/PHPStan/Rules/Playground/PromoteParameterRuleWithOriginalRuleTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use PHPStan\Node\InClassMethodNode;
66
use PHPStan\Php\PhpVersion;
7-
use PHPStan\Reflection\Php\PhpClassReflectionExtension;
87
use PHPStan\Rules\Methods\MethodParameterComparisonHelper;
8+
use PHPStan\Rules\Methods\MethodPrototypeFinder;
99
use PHPStan\Rules\Methods\MethodSignatureRule;
1010
use PHPStan\Rules\Methods\MethodVisibilityComparisonHelper;
1111
use PHPStan\Rules\Methods\OverridingMethodRule;
@@ -28,7 +28,7 @@ protected function getRule(): Rule
2828
true,
2929
self::getContainer()->getByType(MethodParameterComparisonHelper::class),
3030
self::getContainer()->getByType(MethodVisibilityComparisonHelper::class),
31-
self::getContainer()->getByType(PhpClassReflectionExtension::class),
31+
self::getContainer()->getByType(MethodPrototypeFinder::class),
3232
true,
3333
),
3434
self::getContainer(),

0 commit comments

Comments
 (0)