Skip to content

Commit 539b3fe

Browse files
authored
[fix] Fix named arg broken printer on array_map (#7715)
* [issue 9492] create reproducer for modified array_map args, as creates changed args on print * try to remove breaking service from container * remove docblock based type, as might be invalid
1 parent d29e5aa commit 539b3fe

File tree

7 files changed

+70
-40
lines changed

7 files changed

+70
-40
lines changed

rules-tests/TypeDeclaration/Rector/ArrowFunction/AddArrowFunctionReturnTypeRector/Fixture/return_by_array_shape_type.php.inc

Lines changed: 0 additions & 33 deletions
This file was deleted.

rules/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ private function convertToPascalCase(string $name): string
208208
fn ($part): string =>
209209
// If part is all uppercase, convert to ucfirst(strtolower())
210210
// If part is already mixed or PascalCase, keep as is except ucfirst
211-
ctype_upper($part)
212-
? ucfirst(strtolower($part))
213-
: ucfirst($part),
211+
ctype_upper((string) $part)
212+
? ucfirst(strtolower((string) $part))
213+
: ucfirst((string) $part),
214214
$parts
215215
)
216216
);

rules/TypeDeclaration/Rector/FuncCall/AddArrowFunctionParamArrayWhereDimFetchRector.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PhpParser\Node\Expr\Instanceof_;
1313
use PhpParser\Node\Expr\Variable;
1414
use PhpParser\Node\Identifier;
15+
use PhpParser\Node\Scalar\String_;
1516
use PHPStan\Type\ArrayType;
1617
use Rector\PhpParser\Node\BetterNodeFinder;
1718
use Rector\Rector\AbstractRector;
@@ -148,7 +149,8 @@ private function resolveDimFetchVariableNames(Closure|ArrowFunction $closureExpr
148149
if ($arrayDimFetch->var instanceof Variable) {
149150
$type = $this->nodeTypeResolver->getNativeType($arrayDimFetch->var);
150151

151-
if ($type->isString()->yes()) {
152+
// skip string values
153+
if (! $arrayDimFetch->dim instanceof String_ && ($type->isString()->yes() || $type->isString()->maybe())) {
152154
continue;
153155
}
154156

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\DependencyInjection\PHPStan;
6+
7+
use PHPStan\DependencyInjection\MemoizingContainer;
8+
use PHPStan\DependencyInjection\Nette\NetteContainer;
9+
use PHPStan\Parser\AnonymousClassVisitor;
10+
use PHPStan\Parser\RichParser;
11+
use PHPStan\Parser\VariadicFunctionsVisitor;
12+
use PHPStan\Parser\VariadicMethodsVisitor;
13+
use Rector\Util\Reflection\PrivatesAccessor;
14+
15+
/**
16+
* Helper service to modify PHPStan container
17+
* To avoid issues caused by node replacement, like @see https://github.com/rectorphp/rector/issues/9492
18+
*/
19+
final class PHPStanContainerMemento
20+
{
21+
public static function removeRichVisitors(RichParser $richParser): void
22+
{
23+
// the only way now seems to access container early and remove unwanted services
24+
// here https://github.com/phpstan/phpstan-src/blob/522421b007cbfc674bebb93e823c774167ac78cd/src/Parser/RichParser.php#L90-L92
25+
$privatesAccessor = new PrivatesAccessor();
26+
27+
/** @var MemoizingContainer $container */
28+
$container = $privatesAccessor->getPrivateProperty($richParser, 'container');
29+
30+
/** @var NetteContainer $originalContainer */
31+
$originalContainer = $privatesAccessor->getPrivateProperty($container, 'originalContainer');
32+
33+
/** @var NetteContainer $originalContainer */
34+
$deeperContainer = $privatesAccessor->getPrivateProperty($originalContainer, 'container');
35+
36+
// get tags property
37+
$tags = $privatesAccessor->getPrivateProperty($deeperContainer, 'tags');
38+
39+
// keep visitors that are useful
40+
// remove all the rest, https://github.com/phpstan/phpstan-src/tree/1d86de8bb9371534983a8dbcd879e057d2ff028f/src/Parser
41+
$nodeVisitorsToKeep = [
42+
$container->findServiceNamesByType(AnonymousClassVisitor::class)[0] => true,
43+
$container->findServiceNamesByType(VariadicFunctionsVisitor::class)[0] => true,
44+
$container->findServiceNamesByType(VariadicMethodsVisitor::class)[0] => true,
45+
];
46+
47+
$tags[RichParser::VISITOR_SERVICE_TAG] = $nodeVisitorsToKeep;
48+
49+
$privatesAccessor->setPrivateProperty($deeperContainer, 'tags', $tags);
50+
}
51+
}

src/PhpParser/Parser/RectorParser.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@
88
use PhpParser\ParserFactory;
99
use PhpParser\PhpVersion;
1010
use PHPStan\Parser\Parser;
11+
use PHPStan\Parser\RichParser;
12+
use Rector\DependencyInjection\PHPStan\PHPStanContainerMemento;
1113
use Rector\PhpParser\ValueObject\StmtsAndTokens;
1214
use Rector\Util\Reflection\PrivatesAccessor;
1315

1416
final readonly class RectorParser
1517
{
18+
/**
19+
* @param RichParser $parser
20+
*/
1621
public function __construct(
1722
private Parser $parser,
1823
private PrivatesAccessor $privatesAccessor
1924
) {
25+
26+
PHPStanContainerMemento::removeRichVisitors($parser);
2027
}
2128

2229
/**
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
<?php
22

3-
namespace Rector\Tests\PhpParser\Printer\Fixture;
4-
5-
$result = array_map(array: [1, 2, 3], callback: fn(int $value) => $value);
3+
$result = \array_map(array: [1, 2, 3], callback: fn(int $value) => $value);

tests/PhpParser/Printer/PHPStanPrinterTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
use PhpParser\PrettyPrinter\Standard;
88
use PHPStan\Parser\Parser;
99
use PHPStan\Parser\RichParser;
10+
use Rector\DependencyInjection\PHPStan\PHPStanContainerMemento;
1011
use Rector\Testing\PHPUnit\AbstractLazyTestCase;
1112
use ReflectionProperty;
1213

1314
/**
1415
* Test case for: https://github.com/rectorphp/rector/issues/9492
1516
* Most likely caused by https://github.com/phpstan/phpstan-src/pull/3763
17+
*
18+
* @see https://github.com/phpstan/phpstan-src/blob/2.1.x/src/Parser/ArrayMapArgVisitor.php
1619
*/
1720
final class PHPStanPrinterTest extends AbstractLazyTestCase
1821
{
@@ -21,6 +24,8 @@ public function testAddingCommentOnSomeNodesFail(): void
2124
/** @var RichParser $phpstanParser */
2225
$phpstanParser = $this->make(Parser::class);
2326

27+
PHPStanContainerMemento::removeRichVisitors($phpstanParser);
28+
2429
$stmts = $phpstanParser->parseFile(__DIR__ . '/Fixture/some_array_map.php');
2530

2631
// get private property "parser"

0 commit comments

Comments
 (0)