From 41ab4a7d1fca60cd5a8152d3156542900bfb17df Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 6 Jun 2020 22:03:39 +0200 Subject: [PATCH] Fix --- .../Native/NativeMethodReflection.php | 6 +- .../NativeParameterWithPhpDocsReflection.php | 118 ++++++++++++++++++ .../Php/PhpClassReflectionExtension.php | 16 ++- src/Rules/Methods/OverridingMethodRule.php | 19 ++- .../Methods/OverridingMethodRuleTest.php | 2 +- .../Rules/Methods/data/overriding-method.php | 17 ++- 6 files changed, 156 insertions(+), 22 deletions(-) create mode 100644 src/Reflection/Native/NativeParameterWithPhpDocsReflection.php diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index c13403122d..faa623ff6c 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -20,7 +20,7 @@ class NativeMethodReflection implements MethodReflection private BuiltinMethodReflection $reflection; - /** @var \PHPStan\Reflection\ParametersAcceptor[] */ + /** @var \PHPStan\Reflection\ParametersAcceptorWithPhpDocs[] */ private array $variants; private TrinaryLogic $hasSideEffects; @@ -31,7 +31,7 @@ class NativeMethodReflection implements MethodReflection * @param \PHPStan\Reflection\ReflectionProvider $reflectionProvider * @param \PHPStan\Reflection\ClassReflection $declaringClass * @param BuiltinMethodReflection $reflection - * @param \PHPStan\Reflection\ParametersAcceptor[] $variants + * @param \PHPStan\Reflection\ParametersAcceptorWithPhpDocs[] $variants * @param TrinaryLogic $hasSideEffects * @param string|null $stubPhpDocString */ @@ -104,7 +104,7 @@ public function getName(): string } /** - * @return \PHPStan\Reflection\ParametersAcceptor[] + * @return \PHPStan\Reflection\ParametersAcceptorWithPhpDocs[] */ public function getVariants(): array { diff --git a/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php b/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php new file mode 100644 index 0000000000..7a2d4ff265 --- /dev/null +++ b/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php @@ -0,0 +1,118 @@ +name = $name; + $this->optional = $optional; + $this->type = $type; + $this->phpDocType = $phpDocType; + $this->nativeType = $nativeType; + $this->passedByReference = $passedByReference; + $this->variadic = $variadic; + $this->defaultValue = $defaultValue; + $this->variadicParameterAlreadyExpanded = $variadicParameterAlreadyExpanded; + } + + public function getName(): string + { + return $this->name; + } + + public function isOptional(): bool + { + return $this->optional; + } + + public function getType(): Type + { + $type = $this->type; + if ($this->variadic && !$this->variadicParameterAlreadyExpanded) { + $type = new ArrayType(new IntegerType(), $type); + } + + return $type; + } + + public function getPhpDocType(): Type + { + return $this->phpDocType; + } + + public function getNativeType(): Type + { + return $this->nativeType; + } + + public function passedByReference(): PassedByReference + { + return $this->passedByReference; + } + + public function isVariadic(): bool + { + return $this->variadic; + } + + public function getDefaultValue(): ?Type + { + return $this->defaultValue; + } + + /** + * @param mixed[] $properties + * @return self + */ + public static function __set_state(array $properties): self + { + return new self( + $properties['name'], + $properties['optional'], + $properties['type'], + $properties['phpDocType'], + $properties['nativeType'], + $properties['passedByReference'], + $properties['variadic'], + $properties['defaultValue'] + ); + } + +} diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index 9bb6bf1ac4..32a6612aed 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -18,11 +18,11 @@ use PHPStan\Reflection\Annotations\AnnotationsMethodsClassReflectionExtension; use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\FunctionVariant; +use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; use PHPStan\Reflection\Native\NativeMethodReflection; -use PHPStan\Reflection\Native\NativeParameterReflection; +use PHPStan\Reflection\Native\NativeParameterWithPhpDocsReflection; use PHPStan\Reflection\PropertiesClassReflectionExtension; use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\ReflectionProvider; @@ -444,14 +444,16 @@ private function createMethod( } } } - $variants[] = new FunctionVariant( + $variants[] = new FunctionVariantWithPhpDocs( TemplateTypeMap::createEmpty(), null, - array_map(static function (ParameterSignature $parameterSignature) use ($stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity): NativeParameterReflection { - return new NativeParameterReflection( + array_map(static function (ParameterSignature $parameterSignature) use ($stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity): NativeParameterWithPhpDocsReflection { + return new NativeParameterWithPhpDocsReflection( $parameterSignature->getName(), $parameterSignature->isOptional(), $stubPhpDocParameterTypes[$parameterSignature->getName()] ?? $parameterSignature->getType(), + $stubPhpDocParameterTypes[$parameterSignature->getName()] ?? new MixedType(), + new MixedType(true), // todo $parameterSignature->passedByReference(), $stubPhpDocParameterVariadicity[$parameterSignature->getName()] ?? $parameterSignature->isVariadic(), null, @@ -459,7 +461,9 @@ private function createMethod( ); }, $methodSignature->getParameters()), $methodSignature->isVariadic(), - $phpDocReturnType ?? $methodSignature->getReturnType() + $phpDocReturnType ?? $methodSignature->getReturnType(), + $phpDocReturnType ?? new MixedType(), + new MixedType(true) // todo $methodSignature->getNativeReturnType() ); } diff --git a/src/Rules/Methods/OverridingMethodRule.php b/src/Rules/Methods/OverridingMethodRule.php index 592944a9df..d9cb8dc5d8 100644 --- a/src/Rules/Methods/OverridingMethodRule.php +++ b/src/Rules/Methods/OverridingMethodRule.php @@ -8,10 +8,9 @@ use PHPStan\Php\PhpVersion; use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\MethodPrototypeReflection; -use PHPStan\Reflection\Native\NativeParameterReflection; +use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection; -use PHPStan\Reflection\Php\PhpParameterReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ArrayType; @@ -212,14 +211,12 @@ public function processNode(Node $node, Scope $scope): array $methodParameterType = $methodParameter->getNativeType(); - if ($prototypeParameter instanceof PhpParameterReflection) { - $prototypeParameterType = $prototypeParameter->getNativeType(); - } elseif ($prototypeParameter instanceof NativeParameterReflection) { - $prototypeParameterType = $prototypeParameter->getType(); - } else { + if (!$prototypeParameter instanceof ParameterReflectionWithPhpDocs) { continue; } + $prototypeParameterType = $prototypeParameter->getNativeType(); + if ($this->isTypeCompatible($methodParameterType, $prototypeParameterType, $this->phpVersion->supportsParameterContravariance())) { continue; } @@ -279,12 +276,12 @@ public function processNode(Node $node, Scope $scope): array $methodReturnType = $methodVariant->getNativeReturnType(); - if ($prototypeVariant instanceof FunctionVariantWithPhpDocs) { - $prototypeReturnType = $prototypeVariant->getNativeReturnType(); - } else { - $prototypeReturnType = $prototypeVariant->getReturnType(); + if (!$prototypeVariant instanceof FunctionVariantWithPhpDocs) { + return $messages; } + $prototypeReturnType = $prototypeVariant->getNativeReturnType(); + if (!$this->isTypeCompatible($prototypeReturnType, $methodReturnType, $this->phpVersion->supportsReturnCovariance())) { if ($this->phpVersion->supportsReturnCovariance()) { $messages[] = RuleErrorBuilder::message(sprintf( diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index ee07583554..06171c4db4 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -80,7 +80,7 @@ public function testOverridingFinalMethod(int $phpVersion, string $message): voi 115, ], [ - 'Parameter #1 $size (string) of method OverridingFinalMethod\FixedArray::setSize() is not ' . $message . ' with parameter #1 $size (int) of method SplFixedArray::setSize().', + 'Parameter #1 $size (int) of method OverridingFinalMethod\FixedArray::setSize() is not ' . $message . ' with parameter #1 $size (mixed) of method SplFixedArray::setSize().', 125, ], [ diff --git a/tests/PHPStan/Rules/Methods/data/overriding-method.php b/tests/PHPStan/Rules/Methods/data/overriding-method.php index 3d83d29afc..295e82a00e 100644 --- a/tests/PHPStan/Rules/Methods/data/overriding-method.php +++ b/tests/PHPStan/Rules/Methods/data/overriding-method.php @@ -122,7 +122,7 @@ public function doFoo() class FixedArray extends \SplFixedArray { - public function setSize(string $size): bool + public function setSize(int $size): bool { } @@ -238,3 +238,18 @@ public function doFoo(int $i, int $j = null) } } + +/** + * @implements \IteratorAggregate + */ +class SomeIterator implements \IteratorAggregate +{ + /** + * @return \Traversable + */ + public function getIterator() + { + yield new Foo; + } + +}