Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Collector/BufferedUsageCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private function tryFlushBuffer(
return $data === []
? null
: array_map(
static fn (CollectedUsage $usage): string => $usage->serialize(),
static fn (CollectedUsage $usage): string => $usage->serialize($scope->getFile()),
$data,
);
}
Expand Down
22 changes: 18 additions & 4 deletions src/Graph/CollectedUsage.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@ public function concretizeMixedUsage(string $className): self
);
}

public function serialize(): string
/**
* Scope file is passed to optimize transferred data size (and thus result cache size)
* - PHPStan itself transfers all collector data along with scope file
* - thus if our data match those already-transferred ones, lets omit those
*
* @see https://github.com/phpstan/phpstan-src/blob/2fe4e0f94e75fe8844a21fdb81799f01f0591dfe/src/Analyser/FileAnalyser.php#L198
*/
public function serialize(string $scopeFile): string
{
$origin = $this->usage->getOrigin();
$memberRef = $this->usage->getMemberRef();
Expand All @@ -63,7 +70,7 @@ public function serialize(): string
'o' => [
'c' => $origin->getClassName(),
'm' => $origin->getMethodName(),
'f' => $origin->getFile(),
'f' => $origin->getFile() === $scopeFile ? '_' : $origin->getFile(),
'l' => $origin->getLine(),
'p' => $origin->getProvider(),
'n' => $origin->getNote(),
Expand All @@ -82,7 +89,7 @@ public function serialize(): string
}
}

public static function deserialize(string $data): self
public static function deserialize(string $data, string $scopeFile): self
{
try {
/** @var array{e: string|null, t: MemberType::*, o: array{c: string|null, m: string|null, f: string|null, l: int|null, p: string|null, n: string|null}, m: array{c: string|null, m: string, d: bool}} $result */
Expand All @@ -92,7 +99,14 @@ public static function deserialize(string $data): self
}

$memberType = $result['t'];
$origin = new UsageOrigin($result['o']['c'], $result['o']['m'], $result['o']['f'], $result['o']['l'], $result['o']['p'], $result['o']['n']);
$origin = new UsageOrigin(
$result['o']['c'],
$result['o']['m'],
$result['o']['f'] === '_' ? $scopeFile : $result['o']['f'],
$result['o']['l'],
$result['o']['p'],
$result['o']['n'],
);
$exclusionReason = $result['e'];

$usage = $memberType === MemberType::CONSTANT
Expand Down
4 changes: 2 additions & 2 deletions src/Rule/DeadCodeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ public function processNode(
$memberUseData = array_merge_recursive($methodCallData, $providedUsagesData, $constFetchData);
unset($methodCallData, $providedUsagesData, $constFetchData);

foreach ($memberUseData as $usesPerFile) {
foreach ($memberUseData as $file => $usesPerFile) {
foreach ($usesPerFile as $useStrings) {
foreach ($useStrings as $useString) {
$collectedUsage = CollectedUsage::deserialize($useString);
$collectedUsage = CollectedUsage::deserialize($useString, $file);
$memberUsage = $collectedUsage->getUsage();

if ($memberUsage->getMemberRef()->getClassName() === null) {
Expand Down
23 changes: 18 additions & 5 deletions tests/Graph/SerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,31 @@ class SerializationTest extends TestCase
/**
* @dataProvider provideData
*/
public function testSerialization(CollectedUsage $expected, string $serialized): void
public function testSerialization(string $filePath, CollectedUsage $expected, string $serialized): void
{
self::assertSame($serialized, $expected->serialize());
self::assertEquals($expected, CollectedUsage::deserialize($serialized));
self::assertSame($serialized, $expected->serialize($filePath));
self::assertEquals($expected, CollectedUsage::deserialize($serialized, $filePath));
}

/**
* @return iterable<array{CollectedUsage, string}>
* @return iterable<string, array{string, CollectedUsage, string}>
*/
public static function provideData(): iterable
{
yield [
yield 'path optimized' => [
'/app/index.php',
new CollectedUsage(
new ClassConstantUsage(
new UsageOrigin('Clazz', 'method', '/app/index.php', 7, null, null),
new ClassConstantRef(null, 'CONSTANT', true),
),
'excluder',
),
'{"e":"excluder","t":2,"o":{"c":"Clazz","m":"method","f":"_","l":7,"p":null,"n":null},"m":{"c":null,"m":"CONSTANT","d":true}}',
];

yield 'path differs' => [
'/app/different.php',
new CollectedUsage(
new ClassConstantUsage(
new UsageOrigin('Clazz', 'method', '/app/index.php', 7, null, null),
Expand Down