diff --git a/conf/config.neon b/conf/config.neon index e0c7bdf0bd..fa026b65a1 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -394,6 +394,8 @@ services: - class: PHPStan\PhpDoc\PhpDocNodeResolver + arguments: + deepInspectTypes: %featureToggles.deepInspectTypes% - class: PHPStan\PhpDoc\PhpDocStringResolver diff --git a/src/PhpDoc/PhpDocNodeResolver.php b/src/PhpDoc/PhpDocNodeResolver.php index aa188fe918..007f03ea3e 100644 --- a/src/PhpDoc/PhpDocNodeResolver.php +++ b/src/PhpDoc/PhpDocNodeResolver.php @@ -29,6 +29,7 @@ use PHPStan\Type\NeverType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; +use PHPStan\Type\TypeTraverser; class PhpDocNodeResolver { @@ -37,10 +38,17 @@ class PhpDocNodeResolver private ConstExprNodeResolver $constExprNodeResolver; - public function __construct(TypeNodeResolver $typeNodeResolver, ConstExprNodeResolver $constExprNodeResolver) + private bool $deepInspectTypes; + + public function __construct( + TypeNodeResolver $typeNodeResolver, + ConstExprNodeResolver $constExprNodeResolver, + bool $deepInspectTypes = false + ) { $this->typeNodeResolver = $typeNodeResolver; $this->constExprNodeResolver = $constExprNodeResolver; + $this->deepInspectTypes = $deepInspectTypes; } /** @@ -463,6 +471,24 @@ private function shouldSkipType(string $tagName, Type $type): bool return false; } + if ($this->deepInspectTypes) { + $shouldSkip = false; + TypeTraverser::map($type, static function (Type $type, callable $traverse) use (&$shouldSkip): Type { + if ($type instanceof ErrorType) { + $shouldSkip = true; + return $type; + } + if ($type instanceof NeverType && !$type->isExplicit()) { + $shouldSkip = true; + return $type; + } + + return $traverse($type); + }); + + return $shouldSkip; + } + if ($type instanceof ErrorType) { return true; } diff --git a/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php index 98f36e78c1..b400fc75b0 100644 --- a/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php @@ -123,4 +123,10 @@ public function testDeepInspectTypes(): void ]); } + public function testBug3723(): void + { + $this->deepInspectTypes = false; + $this->analyse([__DIR__ . '/data/bug-3723.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-3723.php b/tests/PHPStan/Rules/Methods/data/bug-3723.php new file mode 100644 index 0000000000..c333cc1524 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-3723.php @@ -0,0 +1,18 @@ + $bar The raw frame + * + * @psalm-param array{ + * foo?: Foo::TEST, + * bar: string + * } $bar + */ + public function foo(array $bar): void + { + } +}