Skip to content

Commit b2667d6

Browse files
authored
[Php81] Fix first class callable should not have trailing comma on FunctionLikeToFirstClassCallableRector (#7551)
* [Php81] Fix first class callable should not have trailing comma on FunctionLikeToFirstClassCallableRector * [Php81] Fix first class callable should not have trailing comma on FunctionLikeToFirstClassCallableRector
1 parent d549d62 commit b2667d6

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector\Fixture;
4+
5+
final class WithTrailingComma
6+
{
7+
public function run(): void
8+
{
9+
$array = [1, 2, 3];
10+
11+
$this->map(
12+
$array,
13+
fn($item) => var_dump(
14+
$item,
15+
)
16+
);
17+
}
18+
19+
private function map(array $items, callable $callback): void {
20+
foreach($items as $i) {
21+
$callback($i);
22+
}
23+
}
24+
}
25+
26+
?>
27+
-----
28+
<?php
29+
30+
namespace Rector\Tests\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector\Fixture;
31+
32+
final class WithTrailingComma
33+
{
34+
public function run(): void
35+
{
36+
$array = [1, 2, 3];
37+
38+
$this->map(
39+
$array,
40+
var_dump(
41+
...
42+
)
43+
);
44+
}
45+
46+
private function map(array $items, callable $callback): void {
47+
foreach($items as $i) {
48+
$callback($i);
49+
}
50+
}
51+
}
52+
53+
?>

src/PhpParser/Printer/BetterStandardPrinter.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use PhpParser\Node\Stmt\InlineHTML;
3232
use PhpParser\Node\Stmt\Nop;
3333
use PhpParser\PrettyPrinter\Standard;
34+
use PhpParser\Token;
3435
use PHPStan\Node\AnonymousClassNode;
3536
use PHPStan\Node\Expr\AlwaysRememberedExpr;
3637
use Rector\Configuration\Option;
@@ -39,6 +40,7 @@
3940
use Rector\NodeTypeResolver\Node\AttributeKey;
4041
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
4142
use Rector\Util\NewLineSplitter;
43+
use Rector\Util\Reflection\PrivatesAccessor;
4244
use Rector\Util\StringUtils;
4345

4446
/**
@@ -62,7 +64,8 @@ final class BetterStandardPrinter extends Standard
6264
private const SPACED_NEW_START_REGEX = '#^new\s+#';
6365

6466
public function __construct(
65-
private readonly ExprAnalyzer $exprAnalyzer
67+
private readonly ExprAnalyzer $exprAnalyzer,
68+
private readonly PrivatesAccessor $privatesAccessor,
6669
) {
6770
parent::__construct();
6871
}
@@ -165,6 +168,10 @@ protected function p(
165168
$content = 'new ' . $content;
166169
}
167170

171+
if ($node instanceof CallLike) {
172+
$this->cleanVariadicPlaceHolderTrailingComma($node);
173+
}
174+
168175
return $node->getAttribute(AttributeKey::WRAPPED_IN_PARENTHESES) === true
169176
? ('(' . $content . ')')
170177
: $content;
@@ -453,6 +460,45 @@ protected function pExpr_Instanceof(Instanceof_ $instanceof, int $precedence, in
453460
return parent::pExpr_Instanceof($instanceof, $precedence, $lhsPrecedence);
454461
}
455462

463+
private function cleanVariadicPlaceHolderTrailingComma(CallLike $callLike): void
464+
{
465+
$originalNode = $callLike->getAttribute(AttributeKey::ORIGINAL_NODE);
466+
if (! $originalNode instanceof CallLike) {
467+
return;
468+
}
469+
470+
if ($originalNode->isFirstClassCallable()) {
471+
return;
472+
}
473+
474+
if (! $callLike->isFirstClassCallable()) {
475+
return;
476+
}
477+
478+
if (! $this->origTokens instanceof TokenStream) {
479+
return;
480+
}
481+
482+
/** @var Token[] $tokens */
483+
$tokens = $this->privatesAccessor->getPrivateProperty($this->origTokens, 'tokens');
484+
485+
$iteration = 1;
486+
while (isset($tokens[$callLike->getEndTokenPos() - $iteration])) {
487+
$text = trim((string) $tokens[$callLike->getEndTokenPos() - $iteration]->text);
488+
489+
if (in_array($text, [')', ''], true)) {
490+
++$iteration;
491+
continue;
492+
}
493+
494+
if ($text === ',') {
495+
$tokens[$callLike->getEndTokenPos() - $iteration]->text = '';
496+
}
497+
498+
break;
499+
}
500+
}
501+
456502
private function wrapBinaryOp(Node $node): void
457503
{
458504
if ($this->exprAnalyzer->isExprWithExprPropertyWrappable($node)) {

0 commit comments

Comments
 (0)