Skip to content

Commit 53a61dc

Browse files
staabmondrejmirtes
authored andcommitted
Plumbing for @phpstan-require-extends and @phpstan-require-implements
1 parent 9d3eba2 commit 53a61dc

5 files changed

Lines changed: 136 additions & 0 deletions

File tree

src/PhpDoc/PhpDocNodeResolver.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use PHPStan\PhpDoc\Tag\ParamOutTag;
1515
use PHPStan\PhpDoc\Tag\ParamTag;
1616
use PHPStan\PhpDoc\Tag\PropertyTag;
17+
use PHPStan\PhpDoc\Tag\RequireExtendsTag;
18+
use PHPStan\PhpDoc\Tag\RequireImplementsTag;
1719
use PHPStan\PhpDoc\Tag\ReturnTag;
1820
use PHPStan\PhpDoc\Tag\SelfOutTypeTag;
1921
use PHPStan\PhpDoc\Tag\TemplateTag;
@@ -25,6 +27,8 @@
2527
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode;
2628
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
2729
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
30+
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
31+
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
2832
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
2933
use PHPStan\Reflection\PassedByReference;
3034
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
@@ -409,6 +413,26 @@ public function resolveMixinTags(PhpDocNode $phpDocNode, NameScope $nameScope):
409413
), $phpDocNode->getMixinTagValues());
410414
}
411415

416+
/**
417+
* @return array<RequireExtendsTag>
418+
*/
419+
public function resolveRequireExtendsTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
420+
{
421+
return array_map(fn (RequireExtendsTagValueNode $requireExtendsTagValueNode): RequireExtendsTag => new RequireExtendsTag(
422+
$this->typeNodeResolver->resolve($requireExtendsTagValueNode->type, $nameScope),
423+
), $phpDocNode->getRequireExtendsTagValues());
424+
}
425+
426+
/**
427+
* @return array<RequireImplementsTag>
428+
*/
429+
public function resolveRequireImplementsTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
430+
{
431+
return array_map(fn (RequireImplementsTagValueNode $requireImplementsTagValueNode): RequireImplementsTag => new RequireImplementsTag(
432+
$this->typeNodeResolver->resolve($requireImplementsTagValueNode->type, $nameScope),
433+
), $phpDocNode->getRequireImplementsTagValues());
434+
}
435+
412436
/**
413437
* @return array<string, TypeAliasTag>
414438
*/

src/PhpDoc/ResolvedPhpDocBlock.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use PHPStan\PhpDoc\Tag\ParamOutTag;
1313
use PHPStan\PhpDoc\Tag\ParamTag;
1414
use PHPStan\PhpDoc\Tag\PropertyTag;
15+
use PHPStan\PhpDoc\Tag\RequireExtendsTag;
16+
use PHPStan\PhpDoc\Tag\RequireImplementsTag;
1517
use PHPStan\PhpDoc\Tag\ReturnTag;
1618
use PHPStan\PhpDoc\Tag\SelfOutTypeTag;
1719
use PHPStan\PhpDoc\Tag\TemplateTag;
@@ -94,6 +96,12 @@ class ResolvedPhpDocBlock
9496
/** @var array<MixinTag>|false */
9597
private array|false $mixinTags = false;
9698

99+
/** @var array<RequireExtendsTag>|false */
100+
private array|false $requireExtendsTags = false;
101+
102+
/** @var array<RequireImplementsTag>|false */
103+
private array|false $requireImplementsTags = false;
104+
97105
/** @var array<TypeAliasTag>|false */
98106
private array|false $typeAliasTags = false;
99107

@@ -181,6 +189,8 @@ public static function createEmpty(): self
181189
$self->returnTag = null;
182190
$self->throwsTag = null;
183191
$self->mixinTags = [];
192+
$self->requireExtendsTags = [];
193+
$self->requireImplementsTags = [];
184194
$self->typeAliasTags = [];
185195
$self->typeAliasImportTags = [];
186196
$self->assertTags = [];
@@ -241,6 +251,8 @@ public function merge(array $parents, array $parentPhpDocBlocks): self
241251
$result->returnTag = self::mergeReturnTags($this->getReturnTag(), $classReflection, $parents, $parentPhpDocBlocks);
242252
$result->throwsTag = self::mergeThrowsTags($this->getThrowsTag(), $parents);
243253
$result->mixinTags = $this->getMixinTags();
254+
$result->requireExtendsTags = $this->getRequireExtendsTags();
255+
$result->requireImplementsTags = $this->getRequireImplementsTags();
244256
$result->typeAliasTags = $this->getTypeAliasTags();
245257
$result->typeAliasImportTags = $this->getTypeAliasImportTags();
246258
$result->assertTags = self::mergeAssertTags($this->getAssertTags(), $parents, $parentPhpDocBlocks);
@@ -336,6 +348,8 @@ public function changeParameterNamesByMapping(array $parameterNameMapping): self
336348
$self->returnTag = $returnTag;
337349
$self->throwsTag = $this->throwsTag;
338350
$self->mixinTags = $this->mixinTags;
351+
$self->requireImplementsTags = $this->requireImplementsTags;
352+
$self->requireExtendsTags = $this->requireExtendsTags;
339353
$self->typeAliasTags = $this->typeAliasTags;
340354
$self->typeAliasImportTags = $this->typeAliasImportTags;
341355
$self->assertTags = $assertTags;
@@ -540,6 +554,36 @@ public function getMixinTags(): array
540554
return $this->mixinTags;
541555
}
542556

557+
/**
558+
* @return array<RequireExtendsTag>
559+
*/
560+
public function getRequireExtendsTags(): array
561+
{
562+
if ($this->requireExtendsTags === false) {
563+
$this->requireExtendsTags = $this->phpDocNodeResolver->resolveRequireExtendsTags(
564+
$this->phpDocNode,
565+
$this->getNameScope(),
566+
);
567+
}
568+
569+
return $this->requireExtendsTags;
570+
}
571+
572+
/**
573+
* @return array<RequireImplementsTag>
574+
*/
575+
public function getRequireImplementsTags(): array
576+
{
577+
if ($this->requireImplementsTags === false) {
578+
$this->requireImplementsTags = $this->phpDocNodeResolver->resolveRequireImplementsTags(
579+
$this->phpDocNode,
580+
$this->getNameScope(),
581+
);
582+
}
583+
584+
return $this->requireImplementsTags;
585+
}
586+
543587
/**
544588
* @return array<TypeAliasTag>
545589
*/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDoc\Tag;
4+
5+
use PHPStan\Type\Type;
6+
7+
/** @api */
8+
class RequireExtendsTag
9+
{
10+
11+
public function __construct(private Type $type)
12+
{
13+
}
14+
15+
public function getType(): Type
16+
{
17+
return $this->type;
18+
}
19+
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDoc\Tag;
4+
5+
use PHPStan\Type\Type;
6+
7+
/** @api */
8+
class RequireImplementsTag
9+
{
10+
11+
public function __construct(private Type $type)
12+
{
13+
}
14+
15+
public function getType(): Type
16+
{
17+
return $this->type;
18+
}
19+
20+
}

src/Reflection/ClassReflection.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
use PHPStan\PhpDoc\Tag\MethodTag;
2222
use PHPStan\PhpDoc\Tag\MixinTag;
2323
use PHPStan\PhpDoc\Tag\PropertyTag;
24+
use PHPStan\PhpDoc\Tag\RequireExtendsTag;
25+
use PHPStan\PhpDoc\Tag\RequireImplementsTag;
2426
use PHPStan\PhpDoc\Tag\TemplateTag;
2527
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
2628
use PHPStan\PhpDoc\Tag\TypeAliasTag;
@@ -1594,6 +1596,32 @@ public function getMixinTags(): array
15941596
return $resolvedPhpDoc->getMixinTags();
15951597
}
15961598

1599+
/**
1600+
* @return array<RequireExtendsTag>
1601+
*/
1602+
public function getRequireExtendsTags(): array
1603+
{
1604+
$resolvedPhpDoc = $this->getResolvedPhpDoc();
1605+
if ($resolvedPhpDoc === null) {
1606+
return [];
1607+
}
1608+
1609+
return $resolvedPhpDoc->getRequireExtendsTags();
1610+
}
1611+
1612+
/**
1613+
* @return array<RequireImplementsTag>
1614+
*/
1615+
public function getRequireImplementsTags(): array
1616+
{
1617+
$resolvedPhpDoc = $this->getResolvedPhpDoc();
1618+
if ($resolvedPhpDoc === null) {
1619+
return [];
1620+
}
1621+
1622+
return $resolvedPhpDoc->getRequireImplementsTags();
1623+
}
1624+
15971625
/**
15981626
* @return array<PropertyTag>
15991627
*/

0 commit comments

Comments
 (0)