From 3f6d648d7da9b42e993bf889e5800545edc41a7b Mon Sep 17 00:00:00 2001 From: Jaapio Date: Thu, 1 Jan 2026 22:36:45 +0100 Subject: [PATCH] More phpstan checks for better code --- composer.json | 3 +- composer.lock | 71 ++++++++++++++++++- phpstan.neon | 7 ++ src/DocBlock/StandardTagFactory.php | 2 + .../Tags/Factory/MethodParameterFactory.php | 2 +- src/DocBlock/Tags/MethodParameter.php | 2 +- src/DocBlock/Tags/TagWithType.php | 44 ------------ src/DocBlock/Tags/Template.php | 11 +-- tests/unit/Assets/CustomParam.php | 5 +- tests/unit/Assets/CustomServiceClass.php | 5 +- tests/unit/Assets/CustomServiceInterface.php | 3 +- tests/unit/Assets/CustomTagFactory.php | 1 + .../unit/DocBlock/DescriptionFactoryTest.php | 3 +- .../unit/DocBlock/StandardTagFactoryTest.php | 26 ++++--- tests/unit/DocBlock/Tags/AuthorTest.php | 3 + tests/unit/DocBlock/Tags/ExampleTest.php | 6 ++ .../Tags/Factory/ParamFactoryTest.php | 2 +- .../Tags/Factory/TagFactoryTestCase.php | 15 ++-- tests/unit/DocBlock/Tags/InvalidTagTest.php | 10 ++- .../DocBlock/Tags/MethodParameterTest.php | 4 ++ tests/unit/DocBlock/Tags/SinceTest.php | 2 + tests/unit/DocBlock/Tags/SourceTest.php | 2 + tests/unit/DocBlock/Tags/VersionTest.php | 2 + tests/unit/DocBlockFactoryTest.php | 2 +- tests/unit/DocBlockTest.php | 5 +- tests/unit/PregSplitTest.php | 8 ++- 26 files changed, 154 insertions(+), 92 deletions(-) diff --git a/composer.json b/composer.json index a0ae92f0..d8d96754 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "phpstan/phpstan-mockery": "^1.1", "phpstan/extension-installer": "^1.1", "phpstan/phpstan-webmozart-assert": "^1.2", - "psalm/phar": "^5.26" + "psalm/phar": "^5.26", + "shipmonk/dead-code-detector": "^0.5.1" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 8ee5b3e7..d70bafc4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69aa0af5bad8d21df103f96a6e42e6dc", + "content-hash": "2af32665428eb750a10f182d03577049", "packages": [ { "name": "doctrine/deprecations", @@ -2391,6 +2391,75 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "shipmonk/dead-code-detector", + "version": "0.5.1", + "source": { + "type": "git", + "url": "https://github.com/shipmonk-rnd/dead-code-detector.git", + "reference": "bcfa0a0ca5c2610422a141d6430727738dbcda36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shipmonk-rnd/dead-code-detector/zipball/bcfa0a0ca5c2610422a141d6430727738dbcda36", + "reference": "bcfa0a0ca5c2610422a141d6430727738dbcda36", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^1.11.7" + }, + "require-dev": { + "doctrine/orm": "^2.19 || ^3.0", + "editorconfig-checker/editorconfig-checker": "^10.3.0", + "ergebnis/composer-normalize": "^2.28", + "nette/application": "^3.1", + "nette/component-model": "^3.0", + "nette/utils": "^3.0 || ^4.0", + "nikic/php-parser": "^4.19", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.2.3", + "phpstan/phpstan-symfony": "^1.4", + "phpunit/phpunit": "^9.5.20", + "shipmonk/composer-dependency-analyser": "^1.6", + "shipmonk/name-collision-detector": "^2.0.0", + "shipmonk/phpstan-rules": "^3.1", + "slevomat/coding-standard": "^8.15.0", + "symfony/contracts": "^2.5 || ^3.0", + "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/routing": "^5.4 || ^6.0 || ^7.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "ShipMonk\\PHPStan\\DeadCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Dead code detector to find unused PHP code via PHPStan extension.", + "keywords": [ + "PHPStan", + "dead code", + "static analysis", + "unused code" + ], + "support": { + "issues": "https://github.com/shipmonk-rnd/dead-code-detector/issues", + "source": "https://github.com/shipmonk-rnd/dead-code-detector/tree/0.5.1" + }, + "time": "2024-11-05T09:28:57+00:00" + }, { "name": "theseer/tokenizer", "version": "1.3.1", diff --git a/phpstan.neon b/phpstan.neon index c2365775..2214f8a7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,5 +3,12 @@ parameters: ignoreErrors: - '#Method phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory::createTag\(\) should return phpDocumentor\\Reflection\\DocBlock\\Tag but returns mixed#' - '#Offset 2 on array\{string, 28, int\} on left side of \?\? always exists and is not nullable\.#' + - + path: src/DocBlockFactoryInterface.php + identifier: shipmonk.deadMethod + - + path: src/DocBlock/TagFactory.php + identifier: shipmonk.deadMethod paths: - src + - tests/unit diff --git a/src/DocBlock/StandardTagFactory.php b/src/DocBlock/StandardTagFactory.php index 75caea28..d282b441 100644 --- a/src/DocBlock/StandardTagFactory.php +++ b/src/DocBlock/StandardTagFactory.php @@ -22,6 +22,7 @@ use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\ImplementsFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\MixinFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory; use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory; @@ -151,6 +152,7 @@ public static function createInstance(FqsenResolver $fqsenResolver): self new PropertyReadFactory($typeResolver, $descriptionFactory), new PropertyWriteFactory($typeResolver, $descriptionFactory), new MethodFactory($typeResolver, $descriptionFactory), + new MixinFactory($typeResolver, $descriptionFactory), new ImplementsFactory($typeResolver, $descriptionFactory), new ExtendsFactory($typeResolver, $descriptionFactory), new TemplateFactory($typeResolver, $descriptionFactory), diff --git a/src/DocBlock/Tags/Factory/MethodParameterFactory.php b/src/DocBlock/Tags/Factory/MethodParameterFactory.php index da968967..d98237cb 100644 --- a/src/DocBlock/Tags/Factory/MethodParameterFactory.php +++ b/src/DocBlock/Tags/Factory/MethodParameterFactory.php @@ -34,7 +34,7 @@ public function format($defaultValue): string { $method = 'format' . ucfirst(gettype($defaultValue)); if (method_exists($this, $method)) { - return ' = ' . $this->{$method}($defaultValue); + return $this->{$method}($defaultValue); } return ''; diff --git a/src/DocBlock/Tags/MethodParameter.php b/src/DocBlock/Tags/MethodParameter.php index ceb87024..68c7ca98 100644 --- a/src/DocBlock/Tags/MethodParameter.php +++ b/src/DocBlock/Tags/MethodParameter.php @@ -84,7 +84,7 @@ public function __toString(): string '$' . $this->getName() . ( $this->defaultValue !== self::NO_DEFAULT_VALUE ? - (new MethodParameterFactory())->format($this->defaultValue) : + ' = ' . (new MethodParameterFactory())->format($this->defaultValue) : '' ); } diff --git a/src/DocBlock/Tags/TagWithType.php b/src/DocBlock/Tags/TagWithType.php index 3611436a..36f43be9 100644 --- a/src/DocBlock/Tags/TagWithType.php +++ b/src/DocBlock/Tags/TagWithType.php @@ -13,17 +13,10 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; -use InvalidArgumentException; use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\Exception\CannotCreateTag; use phpDocumentor\Reflection\Type; -use function in_array; -use function sprintf; -use function strlen; -use function substr; -use function trim; - abstract class TagWithType extends BaseTag { /** @var ?Type */ @@ -42,43 +35,6 @@ final public static function create(string $body): Tag throw new CannotCreateTag('Typed tag cannot be created'); } - /** - * @return string[] - */ - protected static function extractTypeFromBody(string $body): array - { - $type = ''; - $nestingLevel = 0; - for ($i = 0, $iMax = strlen($body); $i < $iMax; $i++) { - $character = $body[$i]; - - if ($nestingLevel === 0 && trim($character) === '') { - break; - } - - $type .= $character; - if (in_array($character, ['<', '(', '[', '{'])) { - $nestingLevel++; - continue; - } - - if (in_array($character, ['>', ')', ']', '}'])) { - $nestingLevel--; - continue; - } - } - - if ($nestingLevel < 0 || $nestingLevel > 0) { - throw new InvalidArgumentException( - sprintf('Could not find type in %s, please check for malformed notations', $body) - ); - } - - $description = trim(substr($body, strlen($type))); - - return [$type, $description]; - } - public function __toString(): string { if ($this->description) { diff --git a/src/DocBlock/Tags/Template.php b/src/DocBlock/Tags/Template.php index cfd6b699..5009879d 100644 --- a/src/DocBlock/Tags/Template.php +++ b/src/DocBlock/Tags/Template.php @@ -13,9 +13,9 @@ namespace phpDocumentor\Reflection\DocBlock\Tags; -use Doctrine\Deprecations\Deprecation; use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\Tag; +use phpDocumentor\Reflection\Exception\CannotCreateTag; use phpDocumentor\Reflection\Type; /** @@ -51,14 +51,7 @@ public function __construct( */ public static function create(string $body): ?Tag { - Deprecation::trigger( - 'phpdocumentor/reflection-docblock', - 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', - 'Create using static factory is deprecated, this method should not be called directly - by library consumers', - ); - - return null; + throw new CannotCreateTag('Template tag cannot be created'); } public function getTemplateName(): string diff --git a/tests/unit/Assets/CustomParam.php b/tests/unit/Assets/CustomParam.php index 57f6f7f7..80b3955a 100644 --- a/tests/unit/Assets/CustomParam.php +++ b/tests/unit/Assets/CustomParam.php @@ -10,7 +10,10 @@ final class CustomParam implements Tag { + /** @var string|null */ public $myParam; + + /** @var FqsenResolver|null */ public $fqsenResolver; public function getName() : string @@ -18,7 +21,7 @@ public function getName() : string return 'spy'; } - public static function create($body, FqsenResolver $fqsenResolver = null, ?string $myParam = null) + public static function create(string $body, FqsenResolver $fqsenResolver = null, ?string $myParam = null) { $tag = new self(); $tag->fqsenResolver = $fqsenResolver; diff --git a/tests/unit/Assets/CustomServiceClass.php b/tests/unit/Assets/CustomServiceClass.php index a5d0e785..c5542602 100644 --- a/tests/unit/Assets/CustomServiceClass.php +++ b/tests/unit/Assets/CustomServiceClass.php @@ -7,11 +7,10 @@ use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tags\Formatter; use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter; -use phpDocumentor\Reflection\FqsenResolver; -use phpDocumentor\Reflection\DocBlock\Tags\Factory\StaticMethod; final class CustomServiceClass implements Tag { + /** @var Formatter|null */ public $formatter; public function getName() : string @@ -19,7 +18,7 @@ public function getName() : string return 'spy'; } - public static function create($body, PassthroughFormatter $formatter = null) + public static function create(string $body, PassthroughFormatter $formatter = null) { $tag = new self(); $tag->formatter = $formatter; diff --git a/tests/unit/Assets/CustomServiceInterface.php b/tests/unit/Assets/CustomServiceInterface.php index ac8f612c..36bd753c 100644 --- a/tests/unit/Assets/CustomServiceInterface.php +++ b/tests/unit/Assets/CustomServiceInterface.php @@ -11,6 +11,7 @@ final class CustomServiceInterface implements Tag { + /** @var Formatter|null */ public $formatter; public function getName() : string @@ -18,7 +19,7 @@ public function getName() : string return 'spy'; } - public static function create($body, Formatter $formatter = null) + public static function create(string $body, Formatter $formatter = null) { $tag = new self(); $tag->formatter = $formatter; diff --git a/tests/unit/Assets/CustomTagFactory.php b/tests/unit/Assets/CustomTagFactory.php index df4a3f69..7a3b3a9e 100644 --- a/tests/unit/Assets/CustomTagFactory.php +++ b/tests/unit/Assets/CustomTagFactory.php @@ -20,6 +20,7 @@ class CustomTagFactory implements Factory { + /** @var CustomServiceClass|null */ public $class; public function create(string $tagLine, ?Context $context = null, CustomServiceClass $class = null): Tag diff --git a/tests/unit/DocBlock/DescriptionFactoryTest.php b/tests/unit/DocBlock/DescriptionFactoryTest.php index 7fc90eff..00304cad 100644 --- a/tests/unit/DocBlock/DescriptionFactoryTest.php +++ b/tests/unit/DocBlock/DescriptionFactoryTest.php @@ -13,7 +13,6 @@ namespace phpDocumentor\Reflection\DocBlock; -use Exception; use Mockery as m; use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag; @@ -216,7 +215,7 @@ public function testDescriptionWithBrokenInlineTags(): void $tagFactory->shouldReceive('create') ->once() ->with('@see $name', $context) - ->andReturn(InvalidTag::create('$name', 'see', new Exception())); + ->andReturn(InvalidTag::create('$name', 'see')); $factory = new DescriptionFactory($tagFactory); $description = $factory->create($contents, $context); diff --git a/tests/unit/DocBlock/StandardTagFactoryTest.php b/tests/unit/DocBlock/StandardTagFactoryTest.php index 0b3aa466..3f8311f5 100644 --- a/tests/unit/DocBlock/StandardTagFactoryTest.php +++ b/tests/unit/DocBlock/StandardTagFactoryTest.php @@ -15,6 +15,7 @@ use InvalidArgumentException; use Mockery as m; +use Name\Spaced\Tag; use phpDocumentor\Reflection\Assets\CustomParam; use phpDocumentor\Reflection\Assets\CustomServiceClass; use phpDocumentor\Reflection\Assets\CustomServiceInterface; @@ -134,10 +135,10 @@ public function testCreatingASpecificTag(): void public function testAnEmptyContextIsCreatedIfNoneIsProvided(): void { $fqsen = '\Tag'; - $resolver = m::mock(FqsenResolver::class) - ->shouldReceive('resolve') + $resolver = m::mock(FqsenResolver::class); + $resolver->allows('resolve') ->with('Tag', m::type(Context::class)) - ->andReturn(new Fqsen($fqsen)) + ->andReturns(new Fqsen($fqsen)) ->getMock(); $descriptionFactory = m::mock(DescriptionFactory::class); $descriptionFactory->shouldIgnoreMissing(); @@ -246,18 +247,14 @@ public function testPassingYourOwnSetOfTagHandlersWithEmptyComment(): void 'The tag "@my-täg " does not seem to be wellformed, please check it for errors' ); - $typeResolver = new TypeResolver(); $fqsenResolver = new FqsenResolver(); - $tagFactory = StandardTagFactory::createInstance($fqsenResolver); - $descriptionFactory = new DescriptionFactory($tagFactory); $context = new Context(''); $tagFactory = StandardTagFactory::createInstance( $fqsenResolver, - ['my-täg' => Author::class] ); - $tag = $tagFactory->create('@my-täg ', $context); + $tagFactory->create('@my-täg ', $context); } /** @@ -291,6 +288,7 @@ public function testAddParameterToServiceLocator(): void $tagFactory->addParameter('myParam', 'myValue'); $spy = $tagFactory->create('@spy'); + self::assertInstanceOf(CustomParam::class, $spy); $this->assertSame($resolver, $spy->fqsenResolver); $this->assertSame('myValue', $spy->myParam); } @@ -311,6 +309,7 @@ public function testAddServiceToServiceLocator(): void $spy = $tagFactory->create('@spy'); + self::assertInstanceOf(CustomServiceClass::class, $spy); $this->assertSame($service, $spy->formatter); } @@ -331,6 +330,7 @@ public function testInjectConcreteServiceForInterfaceToServiceLocator(): void $spy = $tagFactory->create('@spy'); + self::assertInstanceOf(CustomServiceInterface::class, $spy); $this->assertSame($service, $spy->formatter); } @@ -366,7 +366,10 @@ public function testHandlerRegistrationFailsIfProvidedTagNameIsNamespaceButNotFu $resolver = m::mock(FqsenResolver::class); $tagFactory = StandardTagFactory::createInstance($resolver); // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName - $tagFactory->registerTagHandler(\Name\Spaced\Tag::class, Author::class); + $tagFactory->registerTagHandler( + Tag::class, // @phpstan-ignore class.notFound + Author::class + ); } /** @@ -380,6 +383,7 @@ public function testHandlerRegistrationFailsIfProvidedHandlerIsEmpty(): void $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); $tagFactory = StandardTagFactory::createInstance($resolver); + //@phpstan-ignore argument.type $tagFactory->registerTagHandler('my-tag', ''); } @@ -394,6 +398,8 @@ public function testHandlerRegistrationFailsIfProvidedHandlerIsNotAnExistingClas $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); $tagFactory = StandardTagFactory::createInstance($resolver); + + //@phpstan-ignore argument.type $tagFactory->registerTagHandler('my-tag', 'IDoNotExist'); } @@ -408,6 +414,8 @@ public function testHandlerRegistrationFailsIfProvidedHandlerDoesNotImplementThe $this->expectException('InvalidArgumentException'); $resolver = m::mock(FqsenResolver::class); $tagFactory = StandardTagFactory::createInstance($resolver); + + //@phpstan-ignore argument.type $tagFactory->registerTagHandler('my-tag', 'stdClass'); } diff --git a/tests/unit/DocBlock/Tags/AuthorTest.php b/tests/unit/DocBlock/Tags/AuthorTest.php index a1ce4321..5525fdd6 100644 --- a/tests/unit/DocBlock/Tags/AuthorTest.php +++ b/tests/unit/DocBlock/Tags/AuthorTest.php @@ -82,6 +82,7 @@ public function testHasTheAuthorName(): void $fixture = new Author($expected, 'mike@phpdoc.org'); + self::assertInstanceOf(Author::class, $fixture); $this->assertSame($expected, $fixture->getAuthorName()); } @@ -95,6 +96,7 @@ public function testHasTheAuthorMailAddress(): void $fixture = new Author('Mike van Riel', $expected); + self::assertInstanceOf(Author::class, $fixture); $this->assertSame($expected, $fixture->getEmail()); } @@ -156,6 +158,7 @@ public function testFactoryMethod(string $input, string $output, string $name, s { $fixture = Author::create($input); + self::assertInstanceOf(Author::class, $fixture); $this->assertSame($output, (string) $fixture); $this->assertSame($name, $fixture->getAuthorName()); $this->assertSame($email, $fixture->getEmail()); diff --git a/tests/unit/DocBlock/Tags/ExampleTest.php b/tests/unit/DocBlock/Tags/ExampleTest.php index 77bf5a34..6fe97d1b 100644 --- a/tests/unit/DocBlock/Tags/ExampleTest.php +++ b/tests/unit/DocBlock/Tags/ExampleTest.php @@ -23,6 +23,7 @@ class ExampleTest extends TestCase public function testExampleWithoutContent(): void { $tag = Example::create('"example1.php"'); + self::assertInstanceOf(Example::class, $tag); $this->assertEquals('"example1.php"', $tag->getContent()); $this->assertEquals('', $tag->getDescription()); $this->assertEquals('example', $tag->getName()); @@ -39,6 +40,7 @@ public function testExampleWithoutContent(): void public function testWithDescription(): void { $tag = Example::create('"example1.php" some text'); + self::assertInstanceOf(Example::class, $tag); $this->assertEquals('example1.php', $tag->getFilePath()); $this->assertEquals('some text', $tag->getDescription()); } @@ -54,6 +56,7 @@ public function testWithDescription(): void public function testStartlineIsParsed(): void { $tag = Example::create('"example1.php" 10'); + self::assertInstanceOf(Example::class, $tag); $this->assertEquals('example1.php', $tag->getFilePath()); $this->assertEquals(10, $tag->getStartingLine()); } @@ -70,6 +73,7 @@ public function testStartlineIsParsed(): void public function testAllowOmittingLineCount(): void { $tag = Example::create('"example1.php" 10 some text'); + self::assertInstanceOf(Example::class, $tag); $this->assertEquals('example1.php', $tag->getFilePath()); $this->assertEquals(10, $tag->getStartingLine()); $this->assertEquals('some text', $tag->getDescription()); @@ -87,6 +91,7 @@ public function testAllowOmittingLineCount(): void public function testLengthIsParsed(): void { $tag = Example::create('"example1.php" 10 5'); + self::assertInstanceOf(Example::class, $tag); $this->assertEquals('example1.php', $tag->getFilePath()); $this->assertEquals(10, $tag->getStartingLine()); $this->assertEquals(5, $tag->getLineCount()); @@ -159,6 +164,7 @@ public function testFactoryMethod( string $content ): void { $tag = Example::create($input); + self::assertInstanceOf(Example::class, $tag); $this->assertSame($filePath, $tag->getFilePath()); $this->assertSame($startLine, $tag->getStartingLine()); $this->assertSame($lineCount, $tag->getLineCount()); diff --git a/tests/unit/DocBlock/Tags/Factory/ParamFactoryTest.php b/tests/unit/DocBlock/Tags/Factory/ParamFactoryTest.php index aa8c14e1..d5687769 100644 --- a/tests/unit/DocBlock/Tags/Factory/ParamFactoryTest.php +++ b/tests/unit/DocBlock/Tags/Factory/ParamFactoryTest.php @@ -48,7 +48,7 @@ public function testParamIsCreated(string $input, Tag $expected): void } /** - * @return array + * @return array> */ public function paramInputProvider(): array { diff --git a/tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php b/tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php index f7876b2b..721a4847 100644 --- a/tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php +++ b/tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php @@ -27,23 +27,16 @@ use PHPStan\PhpDocParser\ParserConfig; use PHPUnit\Framework\TestCase; -use function class_exists; use function property_exists; abstract class TagFactoryTestCase extends TestCase { public function parseTag(string $tag): PhpDocTagNode { - if (class_exists(ParserConfig::class)) { - $config = new ParserConfig([]); - $lexer = new Lexer($config); - $constParser = new ConstExprParser($config); - $phpDocParser = new PhpDocParser($config, new TypeParser($config, $constParser), $constParser); - } else { - $lexer = new Lexer(); - $constParser = new ConstExprParser(); - $phpDocParser = new PhpDocParser(new TypeParser($constParser), $constParser); - } + $config = new ParserConfig([]); + $lexer = new Lexer($config); + $constParser = new ConstExprParser($config); + $phpDocParser = new PhpDocParser($config, new TypeParser($config, $constParser), $constParser); $tagNode = $phpDocParser->parseTag(new TokenIterator($lexer->tokenize($tag))); if (property_exists($tagNode->value, 'description') === true) { diff --git a/tests/unit/DocBlock/Tags/InvalidTagTest.php b/tests/unit/DocBlock/Tags/InvalidTagTest.php index cb25754c..dc252cda 100644 --- a/tests/unit/DocBlock/Tags/InvalidTagTest.php +++ b/tests/unit/DocBlock/Tags/InvalidTagTest.php @@ -10,6 +10,7 @@ use Throwable; use function fopen; +use function is_string; use function serialize; use function unserialize; @@ -57,9 +58,12 @@ public function testCreationWithErrorContainingClosure(): void self::assertSame('name', $tag->getName()); self::assertSame('@name Body', $tag->render()); self::assertSame($parentException, $tag->getException()); + + self::assertSame($e, $tag->getException()->getPrevious()); $trace = $tag->getException()->getPrevious()->getTrace(); if (isset($trace[0]['args'])) { // Not set by default on 7.4 + self::assertTrue(is_string($trace[0]['args'][0])); self::assertStringStartsWith('(Closure at', $trace[0]['args'][0]); self::assertStringContainsString(__FILE__, $trace[0]['args'][0]); } @@ -70,7 +74,7 @@ public function testCreationWithErrorContainingClosure(): void private function throwExceptionFromClosureWithClosureArgument(): void { - $function = static function (): void { + $function = static function (?callable $foo = null): void { throw new InvalidArgumentException(); }; @@ -87,9 +91,11 @@ public function testCreationWithErrorContainingResource(): void self::assertSame('name', $tag->getName()); self::assertSame('@name Body', $tag->render()); self::assertSame($parentException, $tag->getException()); + self::assertSame($e, $tag->getException()->getPrevious()); $trace = $tag->getException()->getPrevious()->getTrace(); if (isset($trace[0]['args'])) { // Not set by default on 7.4 + self::assertTrue(is_string($trace[0]['args'][0])); self::assertStringStartsWith( 'resource(stream)', $trace[0]['args'][0] @@ -102,7 +108,7 @@ public function testCreationWithErrorContainingResource(): void private function throwExceptionWithResourceArgument(): void { - $function = static function (): void { + $function = static function ($file): void { throw new InvalidArgumentException(); }; diff --git a/tests/unit/DocBlock/Tags/MethodParameterTest.php b/tests/unit/DocBlock/Tags/MethodParameterTest.php index a5fb2f06..89e0bdc2 100644 --- a/tests/unit/DocBlock/Tags/MethodParameterTest.php +++ b/tests/unit/DocBlock/Tags/MethodParameterTest.php @@ -81,6 +81,10 @@ public function testIfTagCanBeRenderedUsingMethodParameterWithDefaultValue( sprintf('%s $argument = %s', $type, $defaultValueStr), (string) $fixture ); + $this->assertSame( + $defaultValueStr, + $fixture->getDefaultValue() + ); } /** diff --git a/tests/unit/DocBlock/Tags/SinceTest.php b/tests/unit/DocBlock/Tags/SinceTest.php index cd221474..1db40bc7 100644 --- a/tests/unit/DocBlock/Tags/SinceTest.php +++ b/tests/unit/DocBlock/Tags/SinceTest.php @@ -158,6 +158,7 @@ public function testFactoryMethod(): void $fixture = Since::create('1.0 My Description', $descriptionFactory, $context); + self::assertInstanceOf(Since::class, $fixture); $this->assertSame('1.0 My Description', (string) $fixture); $this->assertSame($version, $fixture->getVersion()); $this->assertSame($description, $fixture->getDescription()); @@ -178,6 +179,7 @@ public function testFactoryMethodCreatesEmptySinceTag(): void $fixture = Since::create('', $descriptionFactory, new Context('')); + self::assertInstanceOf(Since::class, $fixture); $this->assertSame('', (string) $fixture); $this->assertSame(null, $fixture->getVersion()); $this->assertSame(null, $fixture->getDescription()); diff --git a/tests/unit/DocBlock/Tags/SourceTest.php b/tests/unit/DocBlock/Tags/SourceTest.php index 52defd1a..d45924e3 100644 --- a/tests/unit/DocBlock/Tags/SourceTest.php +++ b/tests/unit/DocBlock/Tags/SourceTest.php @@ -227,6 +227,8 @@ public function testExceptionIsThrownIfStartingLineIsNotInteger(): void public function testExceptionIsThrownIfLineCountIsNotIntegerOrNull(): void { $this->expectException('InvalidArgumentException'); + + //@phpstan-ignore argument.type new Source('1', []); } } diff --git a/tests/unit/DocBlock/Tags/VersionTest.php b/tests/unit/DocBlock/Tags/VersionTest.php index 9a156f9d..03def31d 100644 --- a/tests/unit/DocBlock/Tags/VersionTest.php +++ b/tests/unit/DocBlock/Tags/VersionTest.php @@ -158,6 +158,7 @@ public function testFactoryMethod(): void $fixture = Version::create('1.0 My Description', $descriptionFactory, $context); + self::assertInstanceOf(Version::class, $fixture); $this->assertSame('1.0 My Description', (string) $fixture); $this->assertSame($version, $fixture->getVersion()); $this->assertSame($description, $fixture->getDescription()); @@ -178,6 +179,7 @@ public function testFactoryMethodCreatesEmptyVersionTag(): void $fixture = Version::create('', $descriptionFactory, new Context('')); + self::assertInstanceOf(Version::class, $fixture); $this->assertSame('', (string) $fixture); $this->assertSame(null, $fixture->getVersion()); $this->assertSame(null, $fixture->getDescription()); diff --git a/tests/unit/DocBlockFactoryTest.php b/tests/unit/DocBlockFactoryTest.php index 762a7acc..6f6ee89c 100644 --- a/tests/unit/DocBlockFactoryTest.php +++ b/tests/unit/DocBlockFactoryTest.php @@ -200,7 +200,7 @@ public function testTagsAreInterpretedUsingFactory(): void } /** - * @return string[] + * @return array> */ public function provideSummaryAndDescriptions(): array { diff --git a/tests/unit/DocBlockTest.php b/tests/unit/DocBlockTest.php index f58f7461..29b46d83 100644 --- a/tests/unit/DocBlockTest.php +++ b/tests/unit/DocBlockTest.php @@ -108,8 +108,9 @@ public function testDocBlockCanHaveTags(): void public function testDocBlockAllowsOnlyTags(): void { $this->expectException('InvalidArgumentException'); - $tags = [null]; - $fixture = new DocBlock('', null, $tags); + $tags = [null]; + // @phpstan-ignore argument.type + new DocBlock('', null, $tags); } /** diff --git a/tests/unit/PregSplitTest.php b/tests/unit/PregSplitTest.php index 15ca30d5..96b3d5f8 100644 --- a/tests/unit/PregSplitTest.php +++ b/tests/unit/PregSplitTest.php @@ -41,8 +41,12 @@ public function testSimplePregSplit(): void public function testPregSplitThrowsOnError(): void { //We need to disable the error handler for phpunit... because we expect some errors here - $this->errorHandler = set_error_handler(static function (): void { - }, E_WARNING); + $this->errorHandler = set_error_handler( + static function (int $i, string $s, string $s2, int $x, ?array $trace = null): bool { + return true; + }, + E_WARNING + ); $this->expectException(PcreException::class); Utils::pregSplit('~InvalidRegular)Expression~', 'some word');