From 3a8db71ceb617b168e431029032beecefda73405 Mon Sep 17 00:00:00 2001 From: lacatoire Date: Wed, 15 Apr 2026 22:29:00 +0200 Subject: [PATCH] Strip leading @ from InvalidTag name Tag names are normally exposed without their leading "@", but when an InvalidTag is built from the name PHPStan's phpdoc-parser advertises (e.g. for a malformed `@var $self SomeClass`), the name is passed through as-is and `getName()` ends up returning "@var" instead of "var". Normalizing the name at the single entry point (`InvalidTag::create`) keeps the behaviour consistent with every other tag in the library regardless of the upstream parser's convention. Fixes #449 --- src/DocBlock/Tags/InvalidTag.php | 5 ++++- .../DocBlock/Tags/Factory/AbstractPHPStanFactoryTest.php | 2 +- tests/unit/DocBlock/Tags/InvalidTagTest.php | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/DocBlock/Tags/InvalidTag.php b/src/DocBlock/Tags/InvalidTag.php index 848f34d7..58e9d97e 100644 --- a/src/DocBlock/Tags/InvalidTag.php +++ b/src/DocBlock/Tags/InvalidTag.php @@ -18,6 +18,7 @@ use function is_array; use function is_object; use function is_resource; +use function ltrim; use function sprintf; use const PHP_VERSION_ID; @@ -58,7 +59,9 @@ public function getName(): string public static function create(string $body, string $name = ''): self { - return new self($name, $body); + // Some upstream parsers (e.g. phpstan/phpdoc-parser) keep the leading "@" in the tag name they expose. + // All other tags strip it before reaching the Tag layer, so normalize here to keep getName() consistent. + return new self(ltrim($name, '@'), $body); } public function withError(Throwable $exception): self diff --git a/tests/unit/DocBlock/Tags/Factory/AbstractPHPStanFactoryTest.php b/tests/unit/DocBlock/Tags/Factory/AbstractPHPStanFactoryTest.php index 27eb7e9f..56fb2869 100644 --- a/tests/unit/DocBlock/Tags/Factory/AbstractPHPStanFactoryTest.php +++ b/tests/unit/DocBlock/Tags/Factory/AbstractPHPStanFactoryTest.php @@ -68,7 +68,7 @@ public function testCreateReturnsInvalidTagWhenNoFactorySupports(): void $result = $sut->create('@unknown string $param'); self::assertInstanceOf(InvalidTag::class, $result); - self::assertEquals('@unknown', $result->getName()); + self::assertEquals('unknown', $result->getName()); } /** diff --git a/tests/unit/DocBlock/Tags/InvalidTagTest.php b/tests/unit/DocBlock/Tags/InvalidTagTest.php index dc252cda..e42ee4d2 100644 --- a/tests/unit/DocBlock/Tags/InvalidTagTest.php +++ b/tests/unit/DocBlock/Tags/InvalidTagTest.php @@ -33,6 +33,14 @@ public function testCreationWithoutError(): void self::assertNull($tag->getException()); } + public function testCreationStripsLeadingAtFromName(): void + { + $tag = InvalidTag::create('Body', '@var'); + + self::assertSame('var', $tag->getName()); + self::assertSame('@var Body', $tag->render()); + } + /** * @covers ::withError * @covers ::__toString