diff --git a/src/Reflection/Annotations/AnnotationMethodReflection.php b/src/Reflection/Annotations/AnnotationMethodReflection.php index d33665d4b8a..3c315113896 100644 --- a/src/Reflection/Annotations/AnnotationMethodReflection.php +++ b/src/Reflection/Annotations/AnnotationMethodReflection.php @@ -4,14 +4,14 @@ use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\FunctionVariant; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; -class AnnotationMethodReflection implements MethodReflection +class AnnotationMethodReflection implements ExtendedMethodReflection { /** @var FunctionVariant[]|null */ diff --git a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php index a51ab77b65c..6b3edc1c524 100644 --- a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php +++ b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php @@ -3,6 +3,7 @@ namespace PHPStan\Reflection\Annotations; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; use PHPStan\Type\Generic\TemplateTypeHelper; @@ -11,7 +12,7 @@ class AnnotationsMethodsClassReflectionExtension implements MethodsClassReflectionExtension { - /** @var MethodReflection[][] */ + /** @var ExtendedMethodReflection[][] */ private array $methods = []; public function hasMethod(ClassReflection $classReflection, string $methodName): bool @@ -27,6 +28,9 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): return isset($this->methods[$classReflection->getCacheKey()][$methodName]); } + /** + * @return ExtendedMethodReflection + */ public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection { return $this->methods[$classReflection->getCacheKey()][$methodName]; diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index 59c9512022e..3c91999c58b 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -63,7 +63,7 @@ class ClassReflection { - /** @var MethodReflection[] */ + /** @var ExtendedMethodReflection[] */ private array $methods = []; /** @var PropertyReflection[] */ @@ -365,7 +365,7 @@ public function hasMethod(string $methodName): bool return false; } - public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): MethodReflection + public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection { $key = $methodName; if ($scope->isInClass()) { @@ -377,7 +377,7 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): continue; } - $method = $extension->getMethod($this, $methodName); + $method = $this->wrapExtendedMethod($extension->getMethod($this, $methodName)); if ($scope->canCallMethod($method)) { return $this->methods[$key] = $method; } @@ -392,12 +392,21 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): return $this->methods[$key]; } + private function wrapExtendedMethod(MethodReflection $method): ExtendedMethodReflection + { + if ($method instanceof ExtendedMethodReflection) { + return $method; + } + + return new WrappedExtendedMethodReflection($method); + } + public function hasNativeMethod(string $methodName): bool { return $this->getPhpExtension()->hasNativeMethod($this, $methodName); } - public function getNativeMethod(string $methodName): MethodReflection + public function getNativeMethod(string $methodName): ExtendedMethodReflection { if (!$this->hasNativeMethod($methodName)) { throw new MissingMethodFromReflectionException($this->getName(), $methodName); @@ -410,7 +419,7 @@ public function hasConstructor(): bool return $this->findConstructor() !== null; } - public function getConstructor(): MethodReflection + public function getConstructor(): ExtendedMethodReflection { $constructor = $this->findConstructor(); if ($constructor === null) { diff --git a/src/Reflection/ExtendedMethodReflection.php b/src/Reflection/ExtendedMethodReflection.php new file mode 100644 index 00000000000..a3c2667f20c --- /dev/null +++ b/src/Reflection/ExtendedMethodReflection.php @@ -0,0 +1,19 @@ +> */ @@ -375,7 +376,7 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): return $classReflection->getNativeReflection()->hasMethod($methodName); } - public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection + public function getMethod(ClassReflection $classReflection, string $methodName): ExtendedMethodReflection { if (isset($this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$methodName])) { return $this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$methodName]; @@ -411,7 +412,7 @@ public function hasNativeMethod(ClassReflection $classReflection, string $method return false; } - public function getNativeMethod(ClassReflection $classReflection, string $methodName): MethodReflection + public function getNativeMethod(ClassReflection $classReflection, string $methodName): ExtendedMethodReflection { if (isset($this->nativeMethods[$classReflection->getCacheKey()][$methodName])) { return $this->nativeMethods[$classReflection->getCacheKey()][$methodName]; @@ -450,7 +451,7 @@ private function createMethod( ClassReflection $classReflection, BuiltinMethodReflection $methodReflection, bool $includingAnnotations, - ): MethodReflection + ): ExtendedMethodReflection { if ($includingAnnotations && $this->annotationsMethodsClassReflectionExtension->hasMethod($classReflection, $methodReflection->getName())) { $hierarchyDistances = $classReflection->getClassHierarchyDistances(); diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index 711051fdb3e..715d71ff93c 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -13,10 +13,10 @@ use PHPStan\Parser\Parser; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Reflection\MethodPrototypeReflection; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; @@ -44,7 +44,7 @@ use const PHP_VERSION_ID; /** @api */ -class PhpMethodReflection implements MethodReflection +class PhpMethodReflection implements ExtendedMethodReflection { /** @var PhpParameterReflection[]|null */ diff --git a/src/Reflection/WrappedExtendedMethodReflection.php b/src/Reflection/WrappedExtendedMethodReflection.php new file mode 100644 index 00000000000..dd8b93347fa --- /dev/null +++ b/src/Reflection/WrappedExtendedMethodReflection.php @@ -0,0 +1,85 @@ +method->getDeclaringClass(); + } + + public function isStatic(): bool + { + return $this->method->isStatic(); + } + + public function isPrivate(): bool + { + return $this->method->isPrivate(); + } + + public function isPublic(): bool + { + return $this->method->isPublic(); + } + + public function getDocComment(): ?string + { + return $this->method->getDocComment(); + } + + public function getName(): string + { + return $this->method->getName(); + } + + public function getPrototype(): ClassMemberReflection + { + return $this->method->getPrototype(); + } + + public function getVariants(): array + { + return $this->method->getVariants(); + } + + public function isDeprecated(): TrinaryLogic + { + return $this->method->isDeprecated(); + } + + public function getDeprecatedDescription(): ?string + { + return $this->method->getDeprecatedDescription(); + } + + public function isFinal(): TrinaryLogic + { + return $this->method->isFinal(); + } + + public function isInternal(): TrinaryLogic + { + return $this->method->isInternal(); + } + + public function getThrowType(): ?Type + { + return $this->method->getThrowType(); + } + + public function hasSideEffects(): TrinaryLogic + { + return $this->method->hasSideEffects(); + } + +} diff --git a/src/Rules/Methods/MethodSignatureRule.php b/src/Rules/Methods/MethodSignatureRule.php index 66644363dc4..3065030aba8 100644 --- a/src/Rules/Methods/MethodSignatureRule.php +++ b/src/Rules/Methods/MethodSignatureRule.php @@ -6,7 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\InClassMethodNode; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; @@ -120,7 +120,7 @@ public function processNode(Node $node, Scope $scope): array } /** - * @return MethodReflection[] + * @return ExtendedMethodReflection[] */ private function collectParentMethods(string $methodName, ClassReflection $class): array {