Skip to content

Commit 86e4d5a

Browse files
committed
Support for @param-closure-this
1 parent 8ce0d65 commit 86e4d5a

File tree

6 files changed

+139
-0
lines changed

6 files changed

+139
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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 ParamClosureThisTagValueNode implements PhpDocTagValueNode
10+
{
11+
12+
use NodeAttributes;
13+
14+
/** @var TypeNode */
15+
public $type;
16+
17+
/** @var string */
18+
public $parameterName;
19+
20+
/** @var string (may be empty) */
21+
public $description;
22+
23+
public function __construct(TypeNode $type, string $parameterName, string $description)
24+
{
25+
$this->type = $type;
26+
$this->parameterName = $parameterName;
27+
$this->description = $description;
28+
}
29+
30+
public function __toString(): string
31+
{
32+
return trim("{$this->type} {$this->parameterName} {$this->description}");
33+
}
34+
35+
}

src/Ast/PhpDoc/PhpDocNode.php

+14
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ static function (PhpDocTagValueNode $value): bool {
118118
}
119119

120120

121+
/**
122+
* @return ParamClosureThisTagValueNode[]
123+
*/
124+
public function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array
125+
{
126+
return array_filter(
127+
array_column($this->getTagsByName($tagName), 'value'),
128+
static function (PhpDocTagValueNode $value): bool {
129+
return $value instanceof ParamClosureThisTagValueNode;
130+
}
131+
);
132+
}
133+
134+
121135
/**
122136
* @return TemplateTagValueNode[]
123137
*/

src/Parser/PhpDocParser.php

+15
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
397397
$tagValue = $this->parseParamLaterInvokedCallableTagValue($tokens);
398398
break;
399399

400+
case '@param-closure-this':
401+
case '@phpstan-param-closure-this':
402+
$tagValue = $this->parseParamClosureThisTagValue($tokens);
403+
break;
404+
400405
case '@var':
401406
case '@phpstan-var':
402407
case '@psalm-var':
@@ -889,6 +894,16 @@ private function parseParamLaterInvokedCallableTagValue(TokenIterator $tokens):
889894
}
890895

891896

897+
private function parseParamClosureThisTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamClosureThisTagValueNode
898+
{
899+
$type = $this->typeParser->parse($tokens);
900+
$parameterName = $this->parseRequiredVariableName($tokens);
901+
$description = $this->parseOptionalDescription($tokens);
902+
903+
return new Ast\PhpDoc\ParamClosureThisTagValueNode($type, $parameterName, $description);
904+
}
905+
906+
892907
private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode
893908
{
894909
$type = $this->typeParser->parse($tokens);

src/Printer/Printer.php

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
2121
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
2222
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
23+
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamClosureThisTagValueNode;
2324
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode;
2425
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode;
2526
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamOutTagValueNode;
@@ -312,6 +313,9 @@ private function printTagValue(PhpDocTagValueNode $node): string
312313
if ($node instanceof ParamLaterInvokedCallableTagValueNode) {
313314
return trim("{$node->parameterName} {$node->description}");
314315
}
316+
if ($node instanceof ParamClosureThisTagValueNode) {
317+
return trim("{$node->type} {$node->parameterName} {$node->description}");
318+
}
315319
if ($node instanceof PropertyTagValueNode) {
316320
$type = $this->printType($node->type);
317321
return trim("{$type} {$node->propertyName} {$node->description}");

tests/PHPStan/Parser/PhpDocParserTest.php

+51
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
3030
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
3131
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
32+
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamClosureThisTagValueNode;
3233
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode;
3334
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode;
3435
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamOutTagValueNode;
@@ -102,6 +103,7 @@ protected function setUp(): void
102103
* @dataProvider provideParamImmediatelyInvokedCallableTagsData
103104
* @dataProvider provideParamLaterInvokedCallableTagsData
104105
* @dataProvider provideTypelessParamTagsData
106+
* @dataProvider provideParamClosureThisTagsData
105107
* @dataProvider provideVarTagsData
106108
* @dataProvider provideReturnTagsData
107109
* @dataProvider provideThrowsTagsData
@@ -686,6 +688,54 @@ public function provideParamLaterInvokedCallableTagsData(): Iterator
686688
];
687689
}
688690

691+
public function provideParamClosureThisTagsData(): Iterator
692+
{
693+
yield [
694+
'OK',
695+
'/** @param-closure-this Foo $a */',
696+
new PhpDocNode([
697+
new PhpDocTagNode(
698+
'@param-closure-this',
699+
new ParamClosureThisTagValueNode(
700+
new IdentifierTypeNode('Foo'),
701+
'$a',
702+
''
703+
)
704+
),
705+
]),
706+
];
707+
708+
yield [
709+
'OK with prefix',
710+
'/** @phpstan-param-closure-this Foo $a */',
711+
new PhpDocNode([
712+
new PhpDocTagNode(
713+
'@phpstan-param-closure-this',
714+
new ParamClosureThisTagValueNode(
715+
new IdentifierTypeNode('Foo'),
716+
'$a',
717+
''
718+
)
719+
),
720+
]),
721+
];
722+
723+
yield [
724+
'OK with description',
725+
'/** @param-closure-this Foo $a test */',
726+
new PhpDocNode([
727+
new PhpDocTagNode(
728+
'@param-closure-this',
729+
new ParamClosureThisTagValueNode(
730+
new IdentifierTypeNode('Foo'),
731+
'$a',
732+
'test'
733+
)
734+
),
735+
]),
736+
];
737+
}
738+
689739
public function provideVarTagsData(): Iterator
690740
{
691741
yield [
@@ -7185,6 +7235,7 @@ public function testReturnTypeLinesAndIndexes(string $phpDoc, array $lines): voi
71857235
* @dataProvider provideTypelessParamTagsData
71867236
* @dataProvider provideParamImmediatelyInvokedCallableTagsData
71877237
* @dataProvider provideParamLaterInvokedCallableTagsData
7238+
* @dataProvider provideParamClosureThisTagsData
71887239
* @dataProvider provideVarTagsData
71897240
* @dataProvider provideReturnTagsData
71907241
* @dataProvider provideThrowsTagsData

tests/PHPStan/Printer/PrinterTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArray;
1818
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArrayItem;
1919
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
20+
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamClosureThisTagValueNode;
2021
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode;
2122
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode;
2223
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
@@ -1703,6 +1704,25 @@ public function enterNode(Node $node)
17031704

17041705
},
17051706
];
1707+
1708+
yield [
1709+
'/** @param-closure-this Foo $test haha */',
1710+
'/** @param-closure-this Bar $taste hehe */',
1711+
new class extends AbstractNodeVisitor {
1712+
1713+
public function enterNode(Node $node)
1714+
{
1715+
if ($node instanceof ParamClosureThisTagValueNode) {
1716+
$node->type = new IdentifierTypeNode('Bar');
1717+
$node->parameterName = '$taste';
1718+
$node->description = 'hehe';
1719+
}
1720+
1721+
return $node;
1722+
}
1723+
1724+
},
1725+
];
17061726
}
17071727

17081728
/**

0 commit comments

Comments
 (0)