Skip to content

Commit 070ca62

Browse files
committed
Wire RichParser node visitors via DI factory instead of private property hack
Replace PHPStanContainerMemento reflection with a RichParserFactory service, registered in config/phpstan/parser.neon. The factory builds RichParser with a DirectExtensionsCollection of the two visitors Rector needs, so no private property of PHPStan internals is touched. A plain "nodeVisitors" argument in the config is not enough: PHPStan's AutowiredExtensionsExtension::beforeCompile() overwrites that argument for every service definition that instantiates the class directly. Factory-created definitions are skipped, so the explicit visitor list survives.
1 parent c5b890e commit 070ca62

6 files changed

Lines changed: 63 additions & 49 deletions

File tree

.github/workflows/code_analysis.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
-
5454
name: 'Active Classes'
5555
run: |
56-
vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\Set\\Contract\\SetListInterface"
56+
vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\Set\\Contract\\SetListInterface" --skip-type="Rector\\DependencyInjection\\PHPStan\\RichParserFactory"
5757
5858
-
5959
name: 'Compatible PHPStan versions'

config/phpstan/parser.neon

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ services:
2222

2323
rectorParser:
2424
class: PHPStan\Parser\RichParser
25+
factory: @rectorRichParserFactory::create()
26+
arguments!: []
27+
autowired: no
28+
29+
# RichParser used directly by Rector, see PHPStanServicesFactory::createPHPStanParser()
30+
currentPhpVersionRichParser:
31+
class: PHPStan\Parser\RichParser
32+
factory: @rectorRichParserFactory::create()
33+
arguments!: []
34+
autowired: no
35+
36+
rectorRichParserFactory:
37+
class: Rector\DependencyInjection\PHPStan\RichParserFactory
2538
arguments:
2639
parser: @currentPhpVersionPhpParser
40+
nodeVisitors:
41+
- @PHPStan\Parser\AnonymousClassVisitor
42+
- @PHPStan\Parser\ArrayMapArgVisitor
2743
autowired: no

src/DependencyInjection/PHPStan/PHPStanContainerMemento.php

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\DependencyInjection\PHPStan;
6+
7+
use PhpParser\NodeVisitor;
8+
use PhpParser\NodeVisitor\NameResolver;
9+
use PhpParser\Parser;
10+
use PHPStan\Analyser\Ignore\IgnoreLexer;
11+
use PHPStan\DependencyInjection\DirectExtensionsCollection;
12+
use PHPStan\Parser\RichParser;
13+
14+
/**
15+
* Creates PHPStan RichParser with only the node visitors Rector needs,
16+
* to avoid issues caused by node replacement, like @see https://github.com/rectorphp/rector/issues/9492
17+
*
18+
* The visitors have to be passed here, as PHPStan autowires them into every RichParser
19+
* service definition, see PHPStan\DependencyInjection\AutowiredExtensionsExtension
20+
*/
21+
final readonly class RichParserFactory
22+
{
23+
/**
24+
* @param NodeVisitor[] $nodeVisitors
25+
*/
26+
public function __construct(
27+
private Parser $parser,
28+
private NameResolver $nameResolver,
29+
private IgnoreLexer $ignoreLexer,
30+
private array $nodeVisitors
31+
) {
32+
}
33+
34+
/**
35+
* @api used by config/phpstan/parser.neon
36+
*/
37+
public function create(): RichParser
38+
{
39+
return new RichParser(
40+
$this->parser,
41+
$this->nameResolver,
42+
new DirectExtensionsCollection($this->nodeVisitors),
43+
$this->ignoreLexer
44+
);
45+
}
46+
}

src/PhpParser/Parser/RectorParser.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use PhpParser\PhpVersion;
1010
use PHPStan\Parser\Parser;
1111
use PHPStan\Parser\RichParser;
12-
use Rector\DependencyInjection\PHPStan\PHPStanContainerMemento;
1312
use Rector\PhpParser\ValueObject\StmtsAndTokens;
1413
use Rector\Util\Reflection\PrivatesAccessor;
1514

@@ -22,8 +21,6 @@ public function __construct(
2221
private Parser $parser,
2322
private PrivatesAccessor $privatesAccessor
2423
) {
25-
26-
PHPStanContainerMemento::removeRichVisitors($parser);
2724
}
2825

2926
/**

tests/PhpParser/Printer/PHPStanPrinterTest.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PhpParser\PrettyPrinter\Standard;
88
use PHPStan\Parser\Parser;
99
use PHPStan\Parser\RichParser;
10-
use Rector\DependencyInjection\PHPStan\PHPStanContainerMemento;
1110
use Rector\Testing\PHPUnit\AbstractLazyTestCase;
1211
use ReflectionProperty;
1312

@@ -24,8 +23,6 @@ public function testAddingCommentOnSomeNodesFail(): void
2423
/** @var RichParser $phpstanParser */
2524
$phpstanParser = $this->make(Parser::class);
2625

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

3128
// get private property "parser"

0 commit comments

Comments
 (0)