Skip to content

Commit 8733317

Browse files
authored
Add failing test case for Attribute Closure crash (#8802)
* Add failing test case for Attribute Closure * fix with set closure/arrowfunction attribute scope
1 parent 50e653e commit 8733317

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Fixture;
4+
5+
final class AttributeOnClosureAndArrowFunction
6+
{
7+
public function run()
8+
{
9+
$closure = #[\Closure(class: 'Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Source\AnotherClass')] function () {
10+
};
11+
12+
return new \stdClass(#[\Closure(class: 'Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Source\AnotherClass')] fn () => 1);
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Fixture;
21+
22+
final class AttributeOnClosureAndArrowFunction
23+
{
24+
public function run()
25+
{
26+
$closure = #[\Closure(class: \Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Source\AnotherClass::class)] function () {
27+
};
28+
29+
return new \stdClass(#[\Closure(class: \Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\Source\AnotherClass::class)] fn () => 1);
30+
}
31+
}
32+
33+
?>

‎src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpParser\Node\Expr;
1111
use PhpParser\Node\Expr\Array_;
1212
use PhpParser\Node\Expr\ArrayDimFetch;
13+
use PhpParser\Node\Expr\ArrowFunction;
1314
use PhpParser\Node\Expr\Assign;
1415
use PhpParser\Node\Expr\AssignOp;
1516
use PhpParser\Node\Expr\AssignRef;
@@ -20,6 +21,7 @@
2021
use PhpParser\Node\Expr\Cast;
2122
use PhpParser\Node\Expr\ClassConstFetch;
2223
use PhpParser\Node\Expr\Clone_;
24+
use PhpParser\Node\Expr\Closure;
2325
use PhpParser\Node\Expr\ConstFetch;
2426
use PhpParser\Node\Expr\Empty_;
2527
use PhpParser\Node\Expr\ErrorSuppress;
@@ -378,6 +380,11 @@ private function fillScope(array $stmts, string $filePath, MutatingScope $scope)
378380

379381
return;
380382
}
383+
384+
// PHPStan does not process attributes of closures and arrow functions
385+
if (($node instanceof Closure || $node instanceof ArrowFunction) && $node->attrGroups !== []) {
386+
$this->processClosureAttributeGroups($node, $mutatingScope, $nodeCallback);
387+
}
381388
};
382389

383390
try {
@@ -416,6 +423,32 @@ private function processIssetOrUnset(Isset_|Unset_ $node, MutatingScope $mutatin
416423
}
417424
}
418425

426+
/**
427+
* @param callable(Node $node, MutatingScope $scope): void $nodeCallback
428+
*/
429+
private function processClosureAttributeGroups(
430+
Closure|ArrowFunction $node,
431+
MutatingScope $mutatingScope,
432+
callable $nodeCallback
433+
): void {
434+
$argExpressions = [];
435+
foreach ($node->attrGroups as $attrGroup) {
436+
$attrGroup->setAttribute(AttributeKey::SCOPE, $mutatingScope);
437+
438+
foreach ($attrGroup->attrs as $attr) {
439+
$attr->setAttribute(AttributeKey::SCOPE, $mutatingScope);
440+
$attr->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
441+
442+
foreach ($attr->args as $arg) {
443+
$arg->setAttribute(AttributeKey::SCOPE, $mutatingScope);
444+
$argExpressions[] = new Expression($arg->value);
445+
}
446+
}
447+
}
448+
449+
$this->nodeScopeResolverProcessNodes($argExpressions, $mutatingScope, $nodeCallback);
450+
}
451+
419452
private function processEcho(Echo_ $echo, MutatingScope $mutatingScope): void
420453
{
421454
foreach ($echo->exprs as $expr) {

0 commit comments

Comments
 (0)