Skip to content

Commit 9c0e0dc

Browse files
ondrejmirtesclaude
andcommitted
Share one NamespaceUses between the exported PHPDocs of a file
ExportedPhpDocNode held its own copy of the namespace, the uses and the constUses of the file, so the exportedNodes in the result cache grew with the number of imports times the number of documented members. It now refers to the NamespaceUses that NamespaceUsesTracker hands out, which is one instance until the next namespace or use statement, and serialize() writes it once per result cache frame. A parallel worker sends the exported nodes as JSON, which repeats the uses for every PHPDoc. ParallelAnalyser decodes the nodes of each file with an ExportedNodeDecoder, passed through every decode() method, that hands out one NamespaceUses for equal values - so the main process holds the imports of a file once as well, and the result cache stays shared. Full self-analysis (parallel, result cache cleared), identical in two repeats: resultCache.php 54.9 MB -> 51.8 MB, peak RSS of the main process 461 MB -> 453 MB. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182BrC263VCQTibEPTJX2UY
1 parent 7fc4197 commit 9c0e0dc

25 files changed

Lines changed: 230 additions & 86 deletions

‎src/Analyser/NamespaceUses.php‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,14 @@ public function getConstUses(): array
5656
return $this->constUses;
5757
}
5858

59+
public function equals(self $other): bool
60+
{
61+
return $this === $other
62+
|| (
63+
$this->namespace === $other->namespace
64+
&& $this->uses === $other->uses
65+
&& $this->constUses === $other->constUses
66+
);
67+
}
68+
5969
}

‎src/Analyser/ResultCache/ResultCacheManager.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ final class ResultCacheManager
9898
*/
9999
private const EXTENSIONS_NOT_INVALIDATING_CACHE = ['xdebug', 'blackfire', 'phpstan_turbo'];
100100

101-
private const CACHE_VERSION = 'v18-missingFileDependencies';
101+
private const CACHE_VERSION = 'v19-sharedNamespaceUses';
102102

103103
/**
104104
* The recorded hash of a dependency that does not exist. A rule can depend on a path rather than on

‎src/Dependency/ExportedNode.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ public static function __set_state(array $properties): self;
1515
/**
1616
* @param mixed[] $data
1717
*/
18-
public static function decode(array $data): self;
18+
public static function decode(array $data, ExportedNodeDecoder $decoder): self;
1919

2020
}

‎src/Dependency/ExportedNode/ExportedAttributeNode.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use ReturnTypeWillChange;
910
use function count;
1011

@@ -74,7 +75,7 @@ public function jsonSerialize()
7475
/**
7576
* @param mixed[] $data
7677
*/
77-
public static function decode(array $data): self
78+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
7879
{
7980
return new self(
8081
$data['name'],

‎src/Dependency/ExportedNode/ExportedClassConstantNode.php‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use PHPStan\ShouldNotHappenException;
910
use ReturnTypeWillChange;
1011
use function array_map;
@@ -59,16 +60,16 @@ public static function __set_state(array $properties): self
5960
/**
6061
* @param mixed[] $data
6162
*/
62-
public static function decode(array $data): self
63+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
6364
{
6465
return new self(
6566
$data['name'],
6667
$data['value'],
67-
array_map(static function (array $attributeData): ExportedAttributeNode {
68+
array_map(static function (array $attributeData) use ($decoder): ExportedAttributeNode {
6869
if ($attributeData['type'] !== ExportedAttributeNode::class) {
6970
throw new ShouldNotHappenException();
7071
}
71-
return ExportedAttributeNode::decode($attributeData['data']);
72+
return ExportedAttributeNode::decode($attributeData['data'], $decoder);
7273
}, $data['attributes']),
7374
);
7475
}

‎src/Dependency/ExportedNode/ExportedClassConstantsNode.php‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use PHPStan\ShouldNotHappenException;
910
use ReturnTypeWillChange;
1011
use function array_map;
@@ -70,19 +71,19 @@ public static function __set_state(array $properties): self
7071
/**
7172
* @param mixed[] $data
7273
*/
73-
public static function decode(array $data): self
74+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
7475
{
7576
return new self(
76-
array_map(static function (array $constantData): ExportedClassConstantNode {
77+
array_map(static function (array $constantData) use ($decoder): ExportedClassConstantNode {
7778
if ($constantData['type'] !== ExportedClassConstantNode::class) {
7879
throw new ShouldNotHappenException();
7980
}
80-
return ExportedClassConstantNode::decode($constantData['data']);
81+
return ExportedClassConstantNode::decode($constantData['data'], $decoder);
8182
}, $data['constants']),
8283
$data['public'],
8384
$data['private'],
8485
$data['final'],
85-
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null,
86+
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data'], $decoder) : null,
8687
);
8788
}
8889

‎src/Dependency/ExportedNode/ExportedClassNode.php‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use PHPStan\Dependency\RootExportedNode;
910
use PHPStan\ShouldNotHappenException;
1011
use ReturnTypeWillChange;
@@ -141,32 +142,32 @@ public function jsonSerialize()
141142
/**
142143
* @param mixed[] $data
143144
*/
144-
public static function decode(array $data): self
145+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
145146
{
146147
return new self(
147148
$data['name'],
148-
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null,
149+
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data'], $decoder) : null,
149150
$data['abstract'],
150151
$data['final'],
151152
$data['extends'],
152153
$data['implements'],
153154
$data['usedTraits'],
154-
array_map(static function (array $traitUseAdaptationData): ExportedTraitUseAdaptation {
155+
array_map(static function (array $traitUseAdaptationData) use ($decoder): ExportedTraitUseAdaptation {
155156
if ($traitUseAdaptationData['type'] !== ExportedTraitUseAdaptation::class) {
156157
throw new ShouldNotHappenException();
157158
}
158-
return ExportedTraitUseAdaptation::decode($traitUseAdaptationData['data']);
159+
return ExportedTraitUseAdaptation::decode($traitUseAdaptationData['data'], $decoder);
159160
}, $data['traitUseAdaptations']),
160-
array_map(static function (array $node): ExportedNode {
161+
array_map(static function (array $node) use ($decoder): ExportedNode {
161162
$nodeType = $node['type'];
162163

163-
return $nodeType::decode($node['data']);
164+
return $nodeType::decode($node['data'], $decoder);
164165
}, $data['statements']),
165-
array_map(static function (array $attributeData): ExportedAttributeNode {
166+
array_map(static function (array $attributeData) use ($decoder): ExportedAttributeNode {
166167
if ($attributeData['type'] !== ExportedAttributeNode::class) {
167168
throw new ShouldNotHappenException();
168169
}
169-
return ExportedAttributeNode::decode($attributeData['data']);
170+
return ExportedAttributeNode::decode($attributeData['data'], $decoder);
170171
}, $data['attributes']),
171172
);
172173
}

‎src/Dependency/ExportedNode/ExportedConstantNode.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use ReturnTypeWillChange;
910

1011
final class ExportedConstantNode implements ExportedNode, JsonSerializable
@@ -43,7 +44,7 @@ public static function __set_state(array $properties): self
4344
/**
4445
* @param mixed[] $data
4546
*/
46-
public static function decode(array $data): self
47+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
4748
{
4849
return new self(
4950
$data['name'],

‎src/Dependency/ExportedNode/ExportedConstantsNode.php‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use PHPStan\Dependency\RootExportedNode;
910
use PHPStan\ShouldNotHappenException;
1011
use ReturnTypeWillChange;
@@ -63,15 +64,15 @@ public static function __set_state(array $properties): self
6364
/**
6465
* @param mixed[] $data
6566
*/
66-
public static function decode(array $data): self
67+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
6768
{
6869
return new self(
69-
array_map(static function (array $constantData): ExportedConstantNode {
70+
array_map(static function (array $constantData) use ($decoder): ExportedConstantNode {
7071
if ($constantData['type'] !== ExportedConstantNode::class) {
7172
throw new ShouldNotHappenException();
7273
}
7374

74-
return ExportedConstantNode::decode($constantData['data']);
75+
return ExportedConstantNode::decode($constantData['data'], $decoder);
7576
}, $data['constants']),
7677
);
7778
}

‎src/Dependency/ExportedNode/ExportedEnumCaseNode.php‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use JsonSerializable;
66
use Override;
77
use PHPStan\Dependency\ExportedNode;
8+
use PHPStan\Dependency\ExportedNodeDecoder;
89
use ReturnTypeWillChange;
910

1011
final class ExportedEnumCaseNode implements ExportedNode, JsonSerializable
@@ -51,12 +52,12 @@ public static function __set_state(array $properties): self
5152
/**
5253
* @param mixed[] $data
5354
*/
54-
public static function decode(array $data): self
55+
public static function decode(array $data, ExportedNodeDecoder $decoder): self
5556
{
5657
return new self(
5758
$data['name'],
5859
$data['value'],
59-
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null,
60+
$data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data'], $decoder) : null,
6061
);
6162
}
6263

0 commit comments

Comments
 (0)