Skip to content

Commit a3b4058

Browse files
committed
Added support for @require-extends phpdoc
1 parent 77db537 commit a3b4058

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

src/Ast/PhpDoc/PhpDocNode.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,19 @@ static function (PhpDocTagValueNode $value): bool {
187187
);
188188
}
189189

190+
/**
191+
* @return RequireExtendsTagValueNode[]
192+
*/
193+
public function getRequireExtendsTagValues(string $tagName = '@require-extends'): array
194+
{
195+
return array_filter(
196+
array_column($this->getTagsByName($tagName), 'value'),
197+
static function (PhpDocTagValueNode $value): bool {
198+
return $value instanceof RequireExtendsTagValueNode;
199+
}
200+
);
201+
}
202+
190203

191204
/**
192205
* @return DeprecatedTagValueNode[]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Ast\PhpDoc;
4+
5+
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7+
use function trim;
8+
9+
class RequireExtendsTagValueNode implements PhpDocTagValueNode
10+
{
11+
12+
use NodeAttributes;
13+
14+
/** @var TypeNode */
15+
public $type;
16+
17+
/** @var string (may be empty) */
18+
public $description;
19+
20+
public function __construct(TypeNode $type, string $description)
21+
{
22+
$this->type = $type;
23+
$this->description = $description;
24+
}
25+
26+
27+
public function __toString(): string
28+
{
29+
return trim("{$this->type} {$this->description}");
30+
}
31+
32+
}

src/Parser/PhpDocParser.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,12 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
408408
$tagValue = $this->parseMixinTagValue($tokens);
409409
break;
410410

411+
case '@require-extends':
412+
case '@psalm-require-extends':
413+
case '@phpstan-require-extends':
414+
$tagValue = $this->parseRequireExtendsTagValue($tokens);
415+
break;
416+
411417
case '@deprecated':
412418
$tagValue = $this->parseDeprecatedTagValue($tokens);
413419
break;
@@ -877,6 +883,13 @@ private function parseMixinTagValue(TokenIterator $tokens): Ast\PhpDoc\MixinTagV
877883
return new Ast\PhpDoc\MixinTagValueNode($type, $description);
878884
}
879885

886+
private function parseRequireExtendsTagValue(TokenIterator $tokens): Ast\PhpDoc\RequireExtendsTagValueNode
887+
{
888+
$type = $this->typeParser->parse($tokens);
889+
$description = $this->parseOptionalDescription($tokens, true);
890+
return new Ast\PhpDoc\RequireExtendsTagValueNode($type, $description);
891+
}
892+
880893
private function parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode
881894
{
882895
$description = $this->parseOptionalDescription($tokens);

tests/PHPStan/Parser/PhpDocParserTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
3636
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
3737
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
38+
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
3839
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
3940
use PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
4041
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
@@ -100,6 +101,7 @@ protected function setUp(): void
100101
* @dataProvider provideReturnTagsData
101102
* @dataProvider provideThrowsTagsData
102103
* @dataProvider provideMixinTagsData
104+
* @dataProvider provideRequireExtendsTagsData
103105
* @dataProvider provideDeprecatedTagsData
104106
* @dataProvider providePropertyTagsData
105107
* @dataProvider provideMethodTagsData
@@ -1908,6 +1910,86 @@ public function provideMixinTagsData(): Iterator
19081910
];
19091911
}
19101912

1913+
public function provideRequireExtendsTagsData(): Iterator
1914+
{
1915+
yield [
1916+
'OK without description',
1917+
'/** @require-extends Foo */',
1918+
new PhpDocNode([
1919+
new PhpDocTagNode(
1920+
'@require-extends',
1921+
new RequireExtendsTagValueNode(
1922+
new IdentifierTypeNode('Foo'),
1923+
''
1924+
)
1925+
),
1926+
]),
1927+
];
1928+
1929+
yield [
1930+
'OK with description',
1931+
'/** @require-extends Foo optional description */',
1932+
new PhpDocNode([
1933+
new PhpDocTagNode(
1934+
'@require-extends',
1935+
new RequireExtendsTagValueNode(
1936+
new IdentifierTypeNode('Foo'),
1937+
'optional description'
1938+
)
1939+
),
1940+
]),
1941+
];
1942+
1943+
yield [
1944+
'OK with phpstan-prefix description',
1945+
'/** @phpstan-require-extends Foo optional description */',
1946+
new PhpDocNode([
1947+
new PhpDocTagNode(
1948+
'@phpstan-require-extends',
1949+
new RequireExtendsTagValueNode(
1950+
new IdentifierTypeNode('Foo'),
1951+
'optional description'
1952+
)
1953+
),
1954+
]),
1955+
];
1956+
1957+
yield [
1958+
'OK with psalm-prefix description',
1959+
'/** @psalm-require-extends Foo optional description */',
1960+
new PhpDocNode([
1961+
new PhpDocTagNode(
1962+
'@psalm-require-extends',
1963+
new RequireExtendsTagValueNode(
1964+
new IdentifierTypeNode('Foo'),
1965+
'optional description'
1966+
)
1967+
),
1968+
]),
1969+
];
1970+
1971+
yield [
1972+
'invalid without type and description',
1973+
'/** @require-extends */',
1974+
new PhpDocNode([
1975+
new PhpDocTagNode(
1976+
'@require-extends',
1977+
new InvalidTagValueNode(
1978+
'',
1979+
new ParserException(
1980+
'*/',
1981+
Lexer::TOKEN_CLOSE_PHPDOC,
1982+
21,
1983+
Lexer::TOKEN_IDENTIFIER,
1984+
null,
1985+
1
1986+
)
1987+
)
1988+
),
1989+
]),
1990+
];
1991+
}
1992+
19111993
public function provideDeprecatedTagsData(): Iterator
19121994
{
19131995
yield [

0 commit comments

Comments
 (0)