From e9dd3a30339de34a3fe11092b3aa245216038953 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 22 Dec 2021 07:52:17 +0100 Subject: [PATCH] Fix normal vs. stub PHPDoc --- src/PhpDoc/PhpDocInheritanceResolver.php | 41 ++++++++++++++++--- .../Native/NativeMethodReflection.php | 8 ---- .../Php/PhpClassReflectionExtension.php | 10 ----- src/Reflection/Php/PhpMethodReflection.php | 8 ---- .../Php/PhpMethodReflectionFactory.php | 1 - src/Reflection/Php/PhpPropertyReflection.php | 8 ---- tests/PHPStan/Analyser/AnalyserTest.php | 2 +- .../PHPStan/Levels/data/stubs-methods-3.json | 5 --- .../PHPStan/Levels/data/stubs-methods-6.json | 27 ------------ 9 files changed, 36 insertions(+), 74 deletions(-) delete mode 100644 tests/PHPStan/Levels/data/stubs-methods-6.json diff --git a/src/PhpDoc/PhpDocInheritanceResolver.php b/src/PhpDoc/PhpDocInheritanceResolver.php index 2e6a438f93..c94c47ec1a 100644 --- a/src/PhpDoc/PhpDocInheritanceResolver.php +++ b/src/PhpDoc/PhpDocInheritanceResolver.php @@ -4,6 +4,8 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Type\FileTypeMapper; +use ReflectionParameter; +use function array_map; use function strtolower; class PhpDocInheritanceResolver @@ -11,11 +13,15 @@ class PhpDocInheritanceResolver private FileTypeMapper $fileTypeMapper; + private StubPhpDocProvider $stubPhpDocProvider; + public function __construct( FileTypeMapper $fileTypeMapper, + StubPhpDocProvider $stubPhpDocProvider, ) { $this->fileTypeMapper = $fileTypeMapper; + $this->stubPhpDocProvider = $stubPhpDocProvider; } public function resolvePhpDocForProperty( @@ -37,7 +43,7 @@ public function resolvePhpDocForProperty( [], ); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $declaringTraitName, null); + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $declaringTraitName, null, $propertyName, null); } public function resolvePhpDocForConstant( @@ -58,7 +64,7 @@ public function resolvePhpDocForConstant( [], ); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, null, null); + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, null, null, null, $constantName); } /** @@ -84,10 +90,10 @@ public function resolvePhpDocForMethod( $positionalParameterNames, ); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $phpDocBlock->getTrait(), $methodName); + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $phpDocBlock->getTrait(), $methodName, null, null); } - private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName): ResolvedPhpDocBlock + private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName, ?string $propertyName, ?string $constantName): ResolvedPhpDocBlock { $parents = []; $parentPhpDocBlocks = []; @@ -104,17 +110,40 @@ private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?strin $parentPhpDocBlock, $parentPhpDocBlock->getTrait(), $functionName, + $propertyName, + $constantName, ); $parentPhpDocBlocks[] = $parentPhpDocBlock; } - $oneResolvedDockBlock = $this->docBlockToResolvedDocBlock($phpDocBlock, $traitName, $functionName); + $oneResolvedDockBlock = $this->docBlockToResolvedDocBlock($phpDocBlock, $traitName, $functionName, $propertyName, $constantName); return $oneResolvedDockBlock->merge($parents, $parentPhpDocBlocks); } - private function docBlockToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName): ResolvedPhpDocBlock + private function docBlockToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName, ?string $propertyName, ?string $constantName): ResolvedPhpDocBlock { $classReflection = $phpDocBlock->getClassReflection(); + if ($functionName !== null && $classReflection->getNativeReflection()->hasMethod($functionName)) { + $methodReflection = $classReflection->getNativeReflection()->getMethod($functionName); + $stub = $this->stubPhpDocProvider->findMethodPhpDoc($classReflection->getName(), $functionName, array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters())); + if ($stub !== null) { + return $stub; + } + } + + if ($propertyName !== null && $classReflection->getNativeReflection()->hasProperty($propertyName)) { + $stub = $this->stubPhpDocProvider->findPropertyPhpDoc($classReflection->getName(), $propertyName); + if ($stub !== null) { + return $stub; + } + } + + if ($constantName !== null && $classReflection->getNativeReflection()->hasConstant($constantName)) { + $stub = $this->stubPhpDocProvider->findClassConstantPhpDoc($classReflection->getName(), $constantName); + if ($stub !== null) { + return $stub; + } + } return $this->fileTypeMapper->getResolvedPhpDoc( $phpDocBlock->getFile(), diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index 4c9ab63256..a46b4d483c 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -30,8 +30,6 @@ class NativeMethodReflection implements MethodReflection private TrinaryLogic $hasSideEffects; - private ?string $stubPhpDocString; - private ?Type $throwType; /** @@ -43,7 +41,6 @@ public function __construct( BuiltinMethodReflection $reflection, array $variants, TrinaryLogic $hasSideEffects, - ?string $stubPhpDocString, ?Type $throwType, ) { @@ -52,7 +49,6 @@ public function __construct( $this->reflection = $reflection; $this->variants = $variants; $this->hasSideEffects = $hasSideEffects; - $this->stubPhpDocString = $stubPhpDocString; $this->throwType = $throwType; } @@ -173,10 +169,6 @@ private function isVoid(): bool public function getDocComment(): ?string { - if ($this->stubPhpDocString !== null) { - return $this->stubPhpDocString; - } - return $this->reflection->getDocComment(); } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index 1911cb1eea..3a5031b671 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -221,7 +221,6 @@ private function createProperty( $declaringClassName, $propertyReflection->getName(), ); - $stubPhpDocString = null; if ($resolvedPhpDoc === null) { if ($declaringClassReflection->getFileName() !== null) { $declaringTraitName = $this->findPropertyTrait($propertyReflection); @@ -253,7 +252,6 @@ private function createProperty( } } else { $phpDocBlockClassReflection = $declaringClassReflection; - $stubPhpDocString = $resolvedPhpDoc->getPhpDocString(); } if ($resolvedPhpDoc !== null) { @@ -338,7 +336,6 @@ private function createProperty( $deprecatedDescription, $isDeprecated, $isInternal, - $stubPhpDocString, ); } @@ -463,7 +460,6 @@ private function createMethod( $i++; } - $stubPhpDocString = null; $variants = []; $reflectionMethod = null; $throwType = null; @@ -491,7 +487,6 @@ private function createMethod( $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($declaringClass, $methodReflection->getName(), array_map(static fn (ParameterSignature $parameterSignature): string => $parameterSignature->getName(), $methodSignature->getParameters())); if ($stubPhpDocPair !== null) { [$stubPhpDoc, $stubDeclaringClass] = $stubPhpDocPair; - $stubPhpDocString = $stubPhpDoc->getPhpDocString(); $templateTypeMap = $stubDeclaringClass->getActiveTemplateTypeMap(); $returnTag = $stubPhpDoc->getReturnTag(); if ($returnTag !== null) { @@ -561,7 +556,6 @@ private function createMethod( $methodReflection, $variants, $hasSideEffects, - $stubPhpDocString, $throwType, ); } @@ -573,7 +567,6 @@ private function createMethod( if ($stubPhpDocPair !== null) { [$resolvedPhpDoc, $phpDocBlockClassReflection] = $stubPhpDocPair; } - $stubPhpDocString = null; if ($resolvedPhpDoc === null) { if ($declaringClass->getFileName() !== null) { @@ -590,8 +583,6 @@ private function createMethod( ); $phpDocBlockClassReflection = $declaringClass; } - } else { - $stubPhpDocString = $resolvedPhpDoc->getPhpDocString(); } $declaringTrait = null; @@ -692,7 +683,6 @@ private function createMethod( $isDeprecated, $isInternal, $isFinal, - $stubPhpDocString, $isPure, ); } diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index cd98446a8d..d9c0d50485 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -86,8 +86,6 @@ class PhpMethodReflection implements MethodReflection private ?bool $isPure; - private ?string $stubPhpDocString; - /** @var FunctionVariantWithPhpDocs[]|null */ private ?array $variants = null; @@ -110,7 +108,6 @@ public function __construct( bool $isDeprecated, bool $isInternal, bool $isFinal, - ?string $stubPhpDocString, ?bool $isPure, ) { @@ -129,7 +126,6 @@ public function __construct( $this->isDeprecated = $isDeprecated; $this->isInternal = $isInternal; $this->isFinal = $isFinal; - $this->stubPhpDocString = $stubPhpDocString; $this->isPure = $isPure; } @@ -145,10 +141,6 @@ public function getDeclaringTrait(): ?ClassReflection public function getDocComment(): ?string { - if ($this->stubPhpDocString !== null) { - return $this->stubPhpDocString; - } - return $this->reflection->getDocComment(); } diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index 3b7019ed73..8b56043ac5 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -25,7 +25,6 @@ public function create( bool $isDeprecated, bool $isInternal, bool $isFinal, - ?string $stubPhpDocString, ?bool $isPure = null, ): PhpMethodReflection; diff --git a/src/Reflection/Php/PhpPropertyReflection.php b/src/Reflection/Php/PhpPropertyReflection.php index f249af123a..878b9caeea 100644 --- a/src/Reflection/Php/PhpPropertyReflection.php +++ b/src/Reflection/Php/PhpPropertyReflection.php @@ -36,8 +36,6 @@ class PhpPropertyReflection implements PropertyReflection private bool $isInternal; - private ?string $stubPhpDocString; - public function __construct( ClassReflection $declaringClass, ?ClassReflection $declaringTrait, @@ -47,7 +45,6 @@ public function __construct( ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, - ?string $stubPhpDocString, ) { $this->declaringClass = $declaringClass; @@ -58,7 +55,6 @@ public function __construct( $this->deprecatedDescription = $deprecatedDescription; $this->isDeprecated = $isDeprecated; $this->isInternal = $isInternal; - $this->stubPhpDocString = $stubPhpDocString; } public function getDeclaringClass(): ClassReflection @@ -73,10 +69,6 @@ public function getDeclaringTrait(): ?ClassReflection public function getDocComment(): ?string { - if ($this->stubPhpDocString !== null) { - return $this->stubPhpDocString; - } - $docComment = $this->reflection->getDocComment(); if ($docComment === false) { return null; diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index dd8fcfe069..d22ced96e3 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -492,7 +492,7 @@ private function createAnalyser(bool $reportUnmatchedIgnoredErrors): Analyser $typeSpecifier = self::getContainer()->getService('typeSpecifier'); $fileTypeMapper = self::getContainer()->getByType(FileTypeMapper::class); - $phpDocInheritanceResolver = new PhpDocInheritanceResolver($fileTypeMapper); + $phpDocInheritanceResolver = new PhpDocInheritanceResolver($fileTypeMapper, self::getContainer()->getByType(StubPhpDocProvider::class)); $nodeScopeResolver = new NodeScopeResolver( $reflectionProvider, diff --git a/tests/PHPStan/Levels/data/stubs-methods-3.json b/tests/PHPStan/Levels/data/stubs-methods-3.json index 1c0402a627..9f8132c6e9 100644 --- a/tests/PHPStan/Levels/data/stubs-methods-3.json +++ b/tests/PHPStan/Levels/data/stubs-methods-3.json @@ -23,10 +23,5 @@ "message": "Anonymous function should return int but returns string.", "line": 128, "ignorable": true - }, - { - "message": "Method StubsIntegrationTest\\YetYetAnotherFoo::doFoo() should return stdClass but returns string.", - "line": 219, - "ignorable": true } ] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/stubs-methods-6.json b/tests/PHPStan/Levels/data/stubs-methods-6.json deleted file mode 100644 index d626c962a0..0000000000 --- a/tests/PHPStan/Levels/data/stubs-methods-6.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "message": "Method StubsIntegrationTest\\Foo::doFoo() has no return type specified.", - "line": 8, - "ignorable": true - }, - { - "message": "Method StubsIntegrationTest\\Foo::doFoo() has parameter $i with no type specified.", - "line": 8, - "ignorable": true - }, - { - "message": "Method StubsIntegrationTest\\InterfaceWithStubPhpDoc2::doFoo() has no return type specified.", - "line": 151, - "ignorable": true - }, - { - "message": "Method StubsIntegrationTest\\YetAnotherFoo::doFoo() has no return type specified.", - "line": 197, - "ignorable": true - }, - { - "message": "Method StubsIntegrationTest\\YetAnotherFoo::doFoo() has parameter $j with no type specified.", - "line": 197, - "ignorable": true - } -] \ No newline at end of file