diff --git a/composer.json b/composer.json index 27b4b41835..53d589917a 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "ondram/ci-detector": "^3.4.0", "ondrejmirtes/better-reflection": "4.3.22", "phpdocumentor/reflection-docblock": "4.3.4", - "phpstan/phpdoc-parser": "^0.4.8", + "phpstan/phpdoc-parser": "^0.4.9", "react/child-process": "^0.6.1", "react/event-loop": "^1.1", "react/socket": "^1.3", diff --git a/src/PhpDoc/PhpDocNodeResolver.php b/src/PhpDoc/PhpDocNodeResolver.php index 31a8e79639..7579954241 100644 --- a/src/PhpDoc/PhpDocNodeResolver.php +++ b/src/PhpDoc/PhpDocNodeResolver.php @@ -20,7 +20,6 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode; use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode; -use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode; use PHPStan\Reflection\PassedByReference; use PHPStan\Type\ErrorType; use PHPStan\Type\Generic\TemplateTypeVariance; @@ -317,15 +316,28 @@ public function resolveReturnTag(PhpDocNode $phpDocNode, NameScope $nameScope): public function resolveThrowsTags(PhpDocNode $phpDocNode, NameScope $nameScope): ?\PHPStan\PhpDoc\Tag\ThrowsTag { - $types = array_map(function (ThrowsTagValueNode $throwsTagValue) use ($nameScope): Type { - return $this->typeNodeResolver->resolve($throwsTagValue->type, $nameScope); - }, $phpDocNode->getThrowsTagValues()); + $resolved = null; + + foreach (['@phpstan-throws', '@throws'] as $tagName) { + $types = []; + + foreach ($phpDocNode->getThrowsTagValues($tagName) as $tagValue) { + $type = $this->typeNodeResolver->resolve($tagValue->type, $nameScope); + if ($this->shouldSkipType($tagName, $type)) { + continue; + } - if (count($types) === 0) { - return null; + $types[] = $type; + } + + if (count($types) === 0) { + continue; + } + + $resolved = new ThrowsTag(TypeCombinator::union(...$types)); } - return new ThrowsTag(TypeCombinator::union(...$types)); + return $resolved; } /** diff --git a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php index 830496aee5..d1d3d7a2b5 100644 --- a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php +++ b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php @@ -25,6 +25,7 @@ class InvalidPHPStanDocTagRule implements \PHPStan\Rules\Rule '@phpstan-template', '@phpstan-template-covariant', '@phpstan-return', + '@phpstan-throws', '@phpstan-ignore-next-line', '@phpstan-ignore-line', ]; diff --git a/tests/PHPStan/Reflection/Annotations/ThrowsAnnotationsTest.php b/tests/PHPStan/Reflection/Annotations/ThrowsAnnotationsTest.php index 437fcbe368..d802c56360 100644 --- a/tests/PHPStan/Reflection/Annotations/ThrowsAnnotationsTest.php +++ b/tests/PHPStan/Reflection/Annotations/ThrowsAnnotationsTest.php @@ -22,6 +22,15 @@ public function dataThrowsAnnotations(): array ], ], + [ + \ThrowsAnnotations\PhpstanFoo::class, + [ + 'withoutThrows' => 'void', + 'throwsRuntime' => \RuntimeException::class, + 'staticThrowsRuntime' => \RuntimeException::class, + + ], + ], [ \ThrowsAnnotations\FooInterface::class, [ diff --git a/tests/PHPStan/Reflection/Annotations/data/annotations-throws.php b/tests/PHPStan/Reflection/Annotations/data/annotations-throws.php index 554c2c2f4a..779e27840c 100644 --- a/tests/PHPStan/Reflection/Annotations/data/annotations-throws.php +++ b/tests/PHPStan/Reflection/Annotations/data/annotations-throws.php @@ -41,6 +41,40 @@ public static function staticThrowsRuntime() } +class PhpstanFoo +{ + /** + * @throws \RuntimeException + * + * @phpstan-throws void + */ + public function withoutThrows() + { + + } + + /** + * @throws \Exception + * + * @phpstan-throws \RuntimeException + */ + public function throwsRuntime() + { + + } + + /** + * @throws \Exception + * + * @phpstan-throws \RuntimeException + */ + public static function staticThrowsRuntime() + { + + } + +} + interface FooInterface { diff --git a/tests/PHPStan/Rules/PhpDoc/data/invalid-phpstan-doc.php b/tests/PHPStan/Rules/PhpDoc/data/invalid-phpstan-doc.php index bede104fa6..fa2e510986 100644 --- a/tests/PHPStan/Rules/PhpDoc/data/invalid-phpstan-doc.php +++ b/tests/PHPStan/Rules/PhpDoc/data/invalid-phpstan-doc.php @@ -27,4 +27,12 @@ function baz() /** @phpstan-va */$a = $b; /** @phpstan-ignore-line */ $c = 'foo'; } + + /** + * @phpstan-throws void + */ + function any() + { + + } }