Skip to content

Commit 6ca22b1

Browse files
staabmondrejmirtes
authored andcommittedSep 26, 2024
Support for @pure-unless-callable-is-impure
1 parent 249f15f commit 6ca22b1

File tree

6 files changed

+110
-0
lines changed

6 files changed

+110
-0
lines changed
 

‎src/Ast/PhpDoc/PhpDocNode.php

+12
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ static function (PhpDocTagValueNode $value): bool {
131131
);
132132
}
133133

134+
/**
135+
* @return PureUnlessCallableIsImpureTagValueNode[]
136+
*/
137+
public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array
138+
{
139+
return array_filter(
140+
array_column($this->getTagsByName($tagName), 'value'),
141+
static function (PhpDocTagValueNode $value): bool {
142+
return $value instanceof PureUnlessCallableIsImpureTagValueNode;
143+
}
144+
);
145+
}
134146

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

‎src/Parser/PhpDocParser.php

+12
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
403403
$tagValue = $this->parseParamClosureThisTagValue($tokens);
404404
break;
405405

406+
case '@pure-unless-callable-is-impure':
407+
case '@phpstan-pure-unless-callable-is-impure':
408+
$tagValue = $this->parsePureUnlessCallableIsImpureTagValue($tokens);
409+
break;
410+
406411
case '@var':
407412
case '@phpstan-var':
408413
case '@psalm-var':
@@ -919,6 +924,13 @@ private function parseParamClosureThisTagValue(TokenIterator $tokens): Ast\PhpDo
919924
return new Ast\PhpDoc\ParamClosureThisTagValueNode($type, $parameterName, $description);
920925
}
921926

927+
private function parsePureUnlessCallableIsImpureTagValue(TokenIterator $tokens): Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode
928+
{
929+
$parameterName = $this->parseRequiredVariableName($tokens);
930+
$description = $this->parseOptionalDescription($tokens);
931+
932+
return new Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode($parameterName, $description);
933+
}
922934

923935
private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode
924936
{

‎src/Printer/Printer.php

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
3232
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
3333
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
34+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
3435
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
3536
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
3637
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -322,6 +323,9 @@ private function printTagValue(PhpDocTagValueNode $node): string
322323
if ($node instanceof ParamClosureThisTagValueNode) {
323324
return trim("{$node->type} {$node->parameterName} {$node->description}");
324325
}
326+
if ($node instanceof PureUnlessCallableIsImpureTagValueNode) {
327+
return trim("{$node->parameterName} {$node->description}");
328+
}
325329
if ($node instanceof PropertyTagValueNode) {
326330
$type = $this->printType($node->type);
327331
return trim("{$type} {$node->propertyName} {$node->description}");

‎tests/PHPStan/Parser/PhpDocParserTest.php

+33
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
3939
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
4040
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
41+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
4142
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
4243
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
4344
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -104,6 +105,7 @@ protected function setUp(): void
104105
* @dataProvider provideParamLaterInvokedCallableTagsData
105106
* @dataProvider provideTypelessParamTagsData
106107
* @dataProvider provideParamClosureThisTagsData
108+
* @dataProvider providePureUnlessCallableIsImpureTagsData
107109
* @dataProvider provideVarTagsData
108110
* @dataProvider provideReturnTagsData
109111
* @dataProvider provideThrowsTagsData
@@ -736,6 +738,37 @@ public function provideParamClosureThisTagsData(): Iterator
736738
];
737739
}
738740

741+
public function providePureUnlessCallableIsImpureTagsData(): Iterator
742+
{
743+
yield [
744+
'OK',
745+
'/** @pure-unless-callable-is-impure $foo */',
746+
new PhpDocNode([
747+
new PhpDocTagNode(
748+
'@pure-unless-callable-is-impure',
749+
new PureUnlessCallableIsImpureTagValueNode(
750+
'$foo',
751+
''
752+
)
753+
),
754+
]),
755+
];
756+
757+
yield [
758+
'OK with description',
759+
'/** @pure-unless-callable-is-impure $foo test two three */',
760+
new PhpDocNode([
761+
new PhpDocTagNode(
762+
'@pure-unless-callable-is-impure',
763+
new PureUnlessCallableIsImpureTagValueNode(
764+
'$foo',
765+
'test two three'
766+
)
767+
),
768+
]),
769+
];
770+
}
771+
739772
public function provideVarTagsData(): Iterator
740773
{
741774
yield [

‎tests/PHPStan/Printer/PrinterTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
2424
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
2525
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
26+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
2627
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
2728
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
2829
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
@@ -1782,6 +1783,24 @@ public function enterNode(Node $node)
17821783
},
17831784
];
17841785

1786+
yield [
1787+
'/** @pure-unless-callable-is-impure $foo test */',
1788+
'/** @pure-unless-callable-is-impure $bar foo */',
1789+
new class extends AbstractNodeVisitor {
1790+
1791+
public function enterNode(Node $node)
1792+
{
1793+
if ($node instanceof PureUnlessCallableIsImpureTagValueNode) {
1794+
$node->parameterName = '$bar';
1795+
$node->description = 'foo';
1796+
}
1797+
1798+
return $node;
1799+
}
1800+
1801+
},
1802+
];
1803+
17851804
yield [
17861805
'/** @return Foo[abc] */',
17871806
'/** @return self::FOO[abc] */',

0 commit comments

Comments
 (0)
Failed to load comments.