Skip to content

Commit

Permalink
Added support for @require-extends phpdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Jan 4, 2024
1 parent 77db537 commit a3b4058
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/Ast/PhpDoc/PhpDocNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ static function (PhpDocTagValueNode $value): bool {
);
}

/**
* @return RequireExtendsTagValueNode[]
*/
public function getRequireExtendsTagValues(string $tagName = '@require-extends'): array
{
return array_filter(
array_column($this->getTagsByName($tagName), 'value'),
static function (PhpDocTagValueNode $value): bool {
return $value instanceof RequireExtendsTagValueNode;
}
);
}


/**
* @return DeprecatedTagValueNode[]
Expand Down
32 changes: 32 additions & 0 deletions src/Ast/PhpDoc/RequireExtendsTagValueNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class RequireExtendsTagValueNode implements PhpDocTagValueNode
{

use NodeAttributes;

/** @var TypeNode */
public $type;

/** @var string (may be empty) */
public $description;

public function __construct(TypeNode $type, string $description)
{
$this->type = $type;
$this->description = $description;
}


public function __toString(): string
{
return trim("{$this->type} {$this->description}");
}

}
13 changes: 13 additions & 0 deletions src/Parser/PhpDocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
$tagValue = $this->parseMixinTagValue($tokens);
break;

case '@require-extends':
case '@psalm-require-extends':
case '@phpstan-require-extends':
$tagValue = $this->parseRequireExtendsTagValue($tokens);
break;

case '@deprecated':
$tagValue = $this->parseDeprecatedTagValue($tokens);
break;
Expand Down Expand Up @@ -877,6 +883,13 @@ private function parseMixinTagValue(TokenIterator $tokens): Ast\PhpDoc\MixinTagV
return new Ast\PhpDoc\MixinTagValueNode($type, $description);
}

private function parseRequireExtendsTagValue(TokenIterator $tokens): Ast\PhpDoc\RequireExtendsTagValueNode
{
$type = $this->typeParser->parse($tokens);
$description = $this->parseOptionalDescription($tokens, true);
return new Ast\PhpDoc\RequireExtendsTagValueNode($type, $description);
}

private function parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode
{
$description = $this->parseOptionalDescription($tokens);
Expand Down
82 changes: 82 additions & 0 deletions tests/PHPStan/Parser/PhpDocParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
Expand Down Expand Up @@ -100,6 +101,7 @@ protected function setUp(): void
* @dataProvider provideReturnTagsData
* @dataProvider provideThrowsTagsData
* @dataProvider provideMixinTagsData
* @dataProvider provideRequireExtendsTagsData
* @dataProvider provideDeprecatedTagsData
* @dataProvider providePropertyTagsData
* @dataProvider provideMethodTagsData
Expand Down Expand Up @@ -1908,6 +1910,86 @@ public function provideMixinTagsData(): Iterator
];
}

public function provideRequireExtendsTagsData(): Iterator
{
yield [
'OK without description',
'/** @require-extends Foo */',
new PhpDocNode([
new PhpDocTagNode(
'@require-extends',
new RequireExtendsTagValueNode(
new IdentifierTypeNode('Foo'),
''
)
),
]),
];

yield [
'OK with description',
'/** @require-extends Foo optional description */',
new PhpDocNode([
new PhpDocTagNode(
'@require-extends',
new RequireExtendsTagValueNode(
new IdentifierTypeNode('Foo'),
'optional description'
)
),
]),
];

yield [
'OK with phpstan-prefix description',
'/** @phpstan-require-extends Foo optional description */',
new PhpDocNode([
new PhpDocTagNode(
'@phpstan-require-extends',
new RequireExtendsTagValueNode(
new IdentifierTypeNode('Foo'),
'optional description'
)
),
]),
];

yield [
'OK with psalm-prefix description',
'/** @psalm-require-extends Foo optional description */',
new PhpDocNode([
new PhpDocTagNode(
'@psalm-require-extends',
new RequireExtendsTagValueNode(
new IdentifierTypeNode('Foo'),
'optional description'
)
),
]),
];

yield [
'invalid without type and description',
'/** @require-extends */',
new PhpDocNode([
new PhpDocTagNode(
'@require-extends',
new InvalidTagValueNode(
'',
new ParserException(
'*/',
Lexer::TOKEN_CLOSE_PHPDOC,
21,
Lexer::TOKEN_IDENTIFIER,
null,
1
)
)
),
]),
];
}

public function provideDeprecatedTagsData(): Iterator
{
yield [
Expand Down

0 comments on commit a3b4058

Please sign in to comment.