Skip to content

Commit fb19eed

Browse files
staabmondrejmirtes
authored andcommitted
Support for @pure-unless-parameter-passed
1 parent 4ad7ea9 commit fb19eed

6 files changed

Lines changed: 108 additions & 0 deletions

File tree

src/Ast/PhpDoc/PhpDocNode.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,17 @@ public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-
118118
);
119119
}
120120

121+
/**
122+
* @return PureUnlessParameterIsPassedTagValueNode[]
123+
*/
124+
public function getPureUnlessParameterIsPassedTagValues(string $tagName = '@pure-unless-parameter-passed'): array
125+
{
126+
return array_filter(
127+
array_column($this->getTagsByName($tagName), 'value'),
128+
static fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessParameterIsPassedTagValueNode,
129+
);
130+
}
131+
121132
/**
122133
* @return TemplateTagValueNode[]
123134
*/
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 PureUnlessParameterIsPassedTagValueNode implements PhpDocTagValueNode
9+
{
10+
11+
use NodeAttributes;
12+
13+
public string $parameterName;
14+
15+
/** @var string (may be empty) */
16+
public string $description;
17+
18+
public function __construct(string $parameterName, string $description)
19+
{
20+
$this->parameterName = $parameterName;
21+
$this->description = $description;
22+
}
23+
24+
public function __toString(): string
25+
{
26+
return trim("{$this->parameterName} {$this->description}");
27+
}
28+
29+
}

src/Parser/PhpDocParser.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
362362
$tagValue = $this->parsePureUnlessCallableIsImpureTagValue($tokens);
363363
break;
364364

365+
case '@pure-unless-parameter-passed':
366+
case '@phpstan-pure-unless-parameter-passed':
367+
$tagValue = $this->parsePureUnlessParameterIsPassed($tokens);
368+
break;
369+
365370
case '@var':
366371
case '@phpstan-var':
367372
case '@psalm-var':
@@ -877,6 +882,14 @@ private function parsePureUnlessCallableIsImpureTagValue(TokenIterator $tokens):
877882
return new Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode($parameterName, $description);
878883
}
879884

885+
private function parsePureUnlessParameterIsPassed(TokenIterator $tokens): Ast\PhpDoc\PureUnlessParameterIsPassedTagValueNode
886+
{
887+
$parameterName = $this->parseRequiredVariableName($tokens);
888+
$description = $this->parseOptionalDescription($tokens, false);
889+
890+
return new Ast\PhpDoc\PureUnlessParameterIsPassedTagValueNode($parameterName, $description);
891+
}
892+
880893
private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode
881894
{
882895
$type = $this->typeParser->parse($tokens);

src/Printer/Printer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
3434
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
3535
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
36+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessParameterIsPassedTagValueNode;
3637
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
3738
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
3839
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -354,6 +355,9 @@ private function printTagValue(PhpDocTagValueNode $node): string
354355
if ($node instanceof PureUnlessCallableIsImpureTagValueNode) {
355356
return trim("{$node->parameterName} {$node->description}");
356357
}
358+
if ($node instanceof PureUnlessParameterIsPassedTagValueNode) {
359+
return trim("{$node->parameterName} {$node->description}");
360+
}
357361
if ($node instanceof PropertyTagValueNode) {
358362
$type = $this->printType($node->type);
359363
return trim("{$type} {$node->propertyName} {$node->description}");

tests/PHPStan/Parser/PhpDocParserTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
4040
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
4141
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
42+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessParameterIsPassedTagValueNode;
4243
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
4344
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
4445
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -762,6 +763,37 @@ public function providePureUnlessCallableIsImpureTagsData(): Iterator
762763
];
763764
}
764765

766+
public function providePureUnlessParameterIsPassedTagsData(): Iterator
767+
{
768+
yield [
769+
'OK',
770+
'/** @pure-unless-parameter-passed $foo */',
771+
new PhpDocNode([
772+
new PhpDocTagNode(
773+
'@pure-unless-parameter-passed',
774+
new PureUnlessParameterIsPassedTagValueNode(
775+
'$foo',
776+
'',
777+
),
778+
),
779+
]),
780+
];
781+
782+
yield [
783+
'OK with description',
784+
'/** @pure-unless-parameter-passed $foo test two three */',
785+
new PhpDocNode([
786+
new PhpDocTagNode(
787+
'@pure-unless-parameter-passed',
788+
new PureUnlessParameterIsPassedTagValueNode(
789+
'$foo',
790+
'test two three',
791+
),
792+
),
793+
]),
794+
];
795+
}
796+
765797
public function provideVarTagsData(): Iterator
766798
{
767799
yield [

tests/PHPStan/Printer/PrinterTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
2626
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
2727
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
28+
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessParameterIsPassedTagValueNode;
2829
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
2930
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
3031
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
@@ -2115,6 +2116,24 @@ public function enterNode(Node $node)
21152116
},
21162117
];
21172118

2119+
yield [
2120+
'/** @pure-unless-parameter-passed $foo test */',
2121+
'/** @pure-unless-parameter-passed $bar foo */',
2122+
new class extends AbstractNodeVisitor {
2123+
2124+
public function enterNode(Node $node)
2125+
{
2126+
if ($node instanceof PureUnlessParameterIsPassedTagValueNode) {
2127+
$node->parameterName = '$bar';
2128+
$node->description = 'foo';
2129+
}
2130+
2131+
return $node;
2132+
}
2133+
2134+
},
2135+
];
2136+
21182137
yield [
21192138
'/** @return Foo[abc] */',
21202139
'/** @return self::FOO[abc] */',

0 commit comments

Comments
 (0)