Skip to content

Commit 0536d11

Browse files
committed
Fix result cache getting stale when editing files mid-analysis
1 parent 94a6678 commit 0536d11

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

src/Analyser/ResultCache/ResultCache.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ final class ResultCache
2424
* @param array<string, array<string>> $dependencies
2525
* @param array<string, array<RootExportedNode>> $exportedNodes
2626
* @param array<string, array{string, bool, string}> $projectExtensionFiles
27+
* @param array<string, string> $currentFileHashes
2728
*/
2829
public function __construct(
2930
private array $filesToAnalyse,
@@ -38,6 +39,7 @@ public function __construct(
3839
private array $dependencies,
3940
private array $exportedNodes,
4041
private array $projectExtensionFiles,
42+
private array $currentFileHashes,
4143
)
4244
{
4345
}
@@ -132,4 +134,12 @@ public function getProjectExtensionFiles(): array
132134
return $this->projectExtensionFiles;
133135
}
134136

137+
/**
138+
* @return array<string, string>
139+
*/
140+
public function getCurrentFileHashes(): array
141+
{
142+
return $this->currentFileHashes;
143+
}
144+
135145
}

src/Analyser/ResultCache/ResultCacheManager.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,29 @@ public function __construct(
9191
public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?array $projectConfigArray, Output $output): ResultCache
9292
{
9393
$startTime = microtime(true);
94+
$currentFileHashes = [];
95+
foreach ($allAnalysedFiles as $analysedFile) {
96+
$currentFileHashes[$analysedFile] = $this->getFileHash($analysedFile);
97+
}
9498
if ($debug) {
9599
if ($output->isVeryVerbose()) {
96100
$output->writeLineFormatted('Result cache not used because of debug mode.');
97101
}
98-
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], []);
102+
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], $currentFileHashes);
99103
}
100104
if ($onlyFiles) {
101105
if ($output->isVeryVerbose()) {
102106
$output->writeLineFormatted('Result cache not used because only files were passed as analysed paths.');
103107
}
104-
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], []);
108+
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], $currentFileHashes);
105109
}
106110

107111
$cacheFilePath = $this->cacheFilePath;
108112
if (!is_file($cacheFilePath)) {
109113
if ($output->isVeryVerbose()) {
110114
$output->writeLineFormatted('Result cache not used because the cache file does not exist.');
111115
}
112-
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], []);
116+
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], $currentFileHashes);
113117
}
114118

115119
try {
@@ -121,7 +125,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
121125

122126
@unlink($cacheFilePath);
123127

124-
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], []);
128+
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], $currentFileHashes);
125129
}
126130

127131
if (!is_array($data)) {
@@ -130,7 +134,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
130134
$output->writeLineFormatted('Result cache not used because the cache file is corrupted.');
131135
}
132136

133-
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], []);
137+
return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], $currentFileHashes);
134138
}
135139

136140
$meta = $this->getMeta($allAnalysedFiles, $projectConfigArray);
@@ -139,15 +143,16 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
139143
$diffs = $this->getMetaKeyDifferences($data['meta'], $meta);
140144
$output->writeLineFormatted('Result cache not used because the metadata do not match: ' . implode(', ', $diffs));
141145
}
142-
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], []);
146+
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], [], $currentFileHashes);
143147
}
144148

145149
if (time() - $data['lastFullAnalysisTime'] >= 60 * 60 * 24 * 7) {
146150
if ($output->isVeryVerbose()) {
147151
$output->writeLineFormatted('Result cache not used because it\'s more than 7 days since last full analysis.');
148152
}
153+
149154
// run full analysis if the result cache is older than 7 days
150-
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], []);
155+
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], [], $currentFileHashes);
151156
}
152157

153158
/**
@@ -162,7 +167,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
162167
if ($output->isVeryVerbose()) {
163168
$output->writeLineFormatted(sprintf('Result cache not used because extension file %s was not found.', $extensionFile));
164169
}
165-
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], []);
170+
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], [], $currentFileHashes);
166171
}
167172

168173
if ($this->getFileHash($extensionFile) === $fileHash) {
@@ -173,7 +178,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
173178
$output->writeLineFormatted(sprintf('Result cache not used because extension file %s hash does not match.', $extensionFile));
174179
}
175180

176-
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], []);
181+
return new ResultCache($allAnalysedFiles, true, time(), $meta, [], [], [], [], [], [], [], [], $currentFileHashes);
177182
}
178183

179184
$invertedDependencies = $data['dependencies'];
@@ -234,7 +239,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
234239
$cachedFileHash = $analysedFileData['fileHash'];
235240
$dependentFiles = $analysedFileData['dependentFiles'];
236241
$invertedDependenciesToReturn[$analysedFile] = $dependentFiles;
237-
$currentFileHash = $this->getFileHash($analysedFile);
242+
$currentFileHash = $currentFileHashes[$analysedFile];
238243

239244
if ($cachedFileHash === $currentFileHash) {
240245
continue;
@@ -301,7 +306,7 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
301306
));
302307
}
303308

304-
return new ResultCache($filesToAnalyse, false, $data['lastFullAnalysisTime'], $meta, $filteredErrors, $filteredLocallyIgnoredErrors, $filteredLinesToIgnore, $filteredUnmatchedLineIgnores, $filteredCollectedData, $invertedDependenciesToReturn, $filteredExportedNodes, $data['projectExtensionFiles']);
309+
return new ResultCache($filesToAnalyse, false, $data['lastFullAnalysisTime'], $meta, $filteredErrors, $filteredLocallyIgnoredErrors, $filteredLinesToIgnore, $filteredUnmatchedLineIgnores, $filteredCollectedData, $invertedDependenciesToReturn, $filteredExportedNodes, $data['projectExtensionFiles'], $currentFileHashes);
305310
}
306311

307312
/**
@@ -445,7 +450,7 @@ public function process(AnalyserResult $analyserResult, ResultCache $resultCache
445450
}
446451
}
447452

448-
$this->save($resultCache->getLastFullAnalysisTime(), $errorsByFile, $locallyIgnoredErrorsByFile, $linesToIgnore, $unmatchedLineIgnores, $collectedDataByFile, $dependencies, $exportedNodes, $projectExtensionFiles, $meta);
453+
$this->save($resultCache->getLastFullAnalysisTime(), $errorsByFile, $locallyIgnoredErrorsByFile, $linesToIgnore, $unmatchedLineIgnores, $collectedDataByFile, $dependencies, $exportedNodes, $projectExtensionFiles, $resultCache->getCurrentFileHashes(), $meta);
449454

450455
if ($output->isVeryVerbose()) {
451456
$output->writeLineFormatted('Result cache is saved.');
@@ -702,6 +707,7 @@ private function mergeUnmatchedLineIgnores(ResultCache $resultCache, array $fres
702707
* @param array<string, array<string>> $dependencies
703708
* @param array<string, array<RootExportedNode>> $exportedNodes
704709
* @param array<string, array{string, bool, string}> $projectExtensionFiles
710+
* @param array<string, string> $currentFileHashes
705711
* @param mixed[] $meta
706712
*/
707713
private function save(
@@ -714,6 +720,7 @@ private function save(
714720
array $dependencies,
715721
array $exportedNodes,
716722
array $projectExtensionFiles,
723+
array $currentFileHashes,
717724
array $meta,
718725
): void
719726
{
@@ -723,7 +730,7 @@ private function save(
723730
foreach ($fileDependencies as $fileDep) {
724731
if (!array_key_exists($fileDep, $invertedDependencies)) {
725732
$invertedDependencies[$fileDep] = [
726-
'fileHash' => $this->getFileHash($fileDep),
733+
'fileHash' => $currentFileHashes[$fileDep] ?? $this->getFileHash($fileDep),
727734
'dependentFiles' => [],
728735
];
729736
unset($filesNoOneIsDependingOn[$fileDep]);
@@ -742,7 +749,7 @@ private function save(
742749
}
743750

744751
$invertedDependencies[$file] = [
745-
'fileHash' => $this->getFileHash($file),
752+
'fileHash' => $currentFileHashes[$file] ?? $this->getFileHash($file),
746753
'dependentFiles' => [],
747754
];
748755
}

0 commit comments

Comments
 (0)