From 879faa0cb54c73a6abc700ec94a335ad396e82c0 Mon Sep 17 00:00:00 2001 From: janmohr <259855742+janwaleed09@users.noreply.github.com> Date: Thu, 1 Oct 2026 07:10:48 +0200 Subject: [PATCH] [Performance] Resolve class-like names once per file version in ShortNameResolver --- .../ShortNameResolverTest.php | 28 +++++++++++++++++++ .../ClassNameImport/ShortNameResolver.php | 26 +++++++++++++++++ src/ValueObject/Application/File.php | 11 ++++++++ 3 files changed, 65 insertions(+) diff --git a/rules-tests/CodingStyle/ClassNameImport/ShortNameResolver/ShortNameResolverTest.php b/rules-tests/CodingStyle/ClassNameImport/ShortNameResolver/ShortNameResolverTest.php index 1931d75e3ff..504f5b6679a 100644 --- a/rules-tests/CodingStyle/ClassNameImport/ShortNameResolver/ShortNameResolverTest.php +++ b/rules-tests/CodingStyle/ClassNameImport/ShortNameResolver/ShortNameResolverTest.php @@ -5,6 +5,9 @@ namespace Rector\Tests\CodingStyle\ClassNameImport\ShortNameResolver; use Iterator; +use PhpParser\Node\Identifier; +use PhpParser\Node\Stmt\Class_; +use PhpParser\NodeFinder; use PHPUnit\Framework\Attributes\DataProvider; use Rector\CodingStyle\ClassNameImport\ShortNameResolver; use Rector\Testing\PHPUnit\AbstractLazyTestCase; @@ -36,6 +39,31 @@ public function test(string $filePath, array $expectedShortNames): void $this->assertSame($expectedShortNames, $shortNames); } + public function testResolveShortClassLikeNamesAgainAfterStmtsChange(): void + { + $file = $this->testingParser->parseFilePathToFile(__DIR__ . '/Fixture/various_imports.php.inc'); + $this->assertSame(['VariousImports'], $this->shortNameResolver->resolveShortClassLikeNames($file)); + + $class = new NodeFinder() + ->findFirstInstanceOf($file->getNewStmts(), Class_::class); + $this->assertInstanceOf(Class_::class, $class); + + $class->name = new Identifier('RenamedClass'); + $file->changeNewStmts($file->getNewStmts()); + + $this->assertSame(['RenamedClass'], $this->shortNameResolver->resolveShortClassLikeNames($file)); + } + + public function testResolveShortClassLikeNamesPerFile(): void + { + $firstFile = $this->testingParser->parseFilePathToFile(__DIR__ . '/Fixture/various_imports.php.inc'); + $secondFile = $this->testingParser->parseFilePathToFile(__DIR__ . '/Fixture/partial_names.php.inc'); + + $this->assertSame(['VariousImports'], $this->shortNameResolver->resolveShortClassLikeNames($firstFile)); + $this->assertSame(['PartialNames'], $this->shortNameResolver->resolveShortClassLikeNames($secondFile)); + $this->assertSame(['VariousImports'], $this->shortNameResolver->resolveShortClassLikeNames($firstFile)); + } + /** * @return Iterator, mixed>> */ diff --git a/rules/CodingStyle/ClassNameImport/ShortNameResolver.php b/rules/CodingStyle/ClassNameImport/ShortNameResolver.php index 7b53fab2602..871833c6aff 100644 --- a/rules/CodingStyle/ClassNameImport/ShortNameResolver.php +++ b/rules/CodingStyle/ClassNameImport/ShortNameResolver.php @@ -31,6 +31,15 @@ final class ShortNameResolver */ private array $shortNamesByFilePath = []; + private ?File $shortClassLikeNamesFile = null; + + private int $shortClassLikeNamesVersion = 0; + + /** + * @var string[] + */ + private array $shortClassLikeNames = []; + public function __construct( private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser, private readonly NodeNameResolver $nodeNameResolver, @@ -62,6 +71,23 @@ public function resolveFromFile(File $file): array * @return string[] */ public function resolveShortClassLikeNames(File $file): array + { + // asked for every imported name, while the class-likes only change with a new version of the file stmts + if ($file === $this->shortClassLikeNamesFile && $file->getNewStmtsVersion() === $this->shortClassLikeNamesVersion) { + return $this->shortClassLikeNames; + } + + $this->shortClassLikeNamesFile = $file; + $this->shortClassLikeNamesVersion = $file->getNewStmtsVersion(); + $this->shortClassLikeNames = $this->findShortClassLikeNames($file); + + return $this->shortClassLikeNames; + } + + /** + * @return string[] + */ + private function findShortClassLikeNames(File $file): array { $rootNode = $file->getUseImportsRootNode(); diff --git a/src/ValueObject/Application/File.php b/src/ValueObject/Application/File.php index 33c354d4a05..ca87c687614 100644 --- a/src/ValueObject/Application/File.php +++ b/src/ValueObject/Application/File.php @@ -33,6 +33,8 @@ final class File */ private array $newStmts = []; + private int $newStmtsVersion = 0; + /** * @var array */ @@ -146,6 +148,15 @@ public function getOldTokens(): array public function changeNewStmts(array $newStmts): void { $this->newStmts = $newStmts; + ++$this->newStmtsVersion; + } + + /** + * Increases with every change of the new stmts, so data derived from them can be cached per version + */ + public function getNewStmtsVersion(): int + { + return $this->newStmtsVersion; } public function addRectorClassWithLine(RectorWithLineChange $rectorWithLineChange): void