Skip to content

Commit 3e2db51

Browse files
ondrejmirtesclaude
andcommitted
Do not parse a changed file when the outcome cannot add anything
restore() parses every changed file to compare its exported nodes with the cached ones, which decides whether its dependents, the classes using a trait it declares, and the files with errors are re-analysed too. When all of those files changed themselves and are re-analysed anyway, the answer cannot add anything, so the file is not parsed. After a branch switch or a formatting run that touched most of the project that is most of the changed files. On Drupal core with every file edited, restoring took 9 seconds of parsing in the main process, and the workers forked from it were slower too. The files re-analysed stay the same. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdwtgiEHwkF5BTz73jgHQQ
1 parent f8a929c commit 3e2db51

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

‎src/Analyser/ResultCache/ResultCacheManager.php‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,36 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
721721
$filteredErrors[$stubFile] = $errors[$stubFile];
722722
}
723723

724+
// Whether a changed file's exported nodes changed decides what else has to be re-analysed with
725+
// it: its dependents, the classes using a trait it declares, and - when a symbol appeared or
726+
// disappeared - the files with errors. Finding out means parsing the file, serially here in
727+
// the main process. When all of those files are re-analysed anyway, because they changed
728+
// themselves, the answer cannot add anything and the file is not parsed. After a branch switch
729+
// or a formatting run that touched most of the project, that is most of the changed files -
730+
// on Drupal core with every file edited, 9 seconds of parsing, and workers forked from a main
731+
// process bloated by the parsed files.
732+
$changedAnalysedFiles = [];
733+
foreach ($allAnalysedFiles as $analysedFile) {
734+
if (
735+
array_key_exists($analysedFile, $invertedDependencies)
736+
&& $invertedDependencies[$analysedFile]['fileHash'] === $currentFileHashes[$analysedFile]
737+
) {
738+
continue;
739+
}
740+
741+
$changedAnalysedFiles[$analysedFile] = true;
742+
}
743+
// only the stub files with errors so far, which are never analysed
744+
$filesWithErrorsAllChanged = $filteredErrors === [];
745+
foreach ($allAnalysedFiles as $analysedFile) {
746+
if (!array_key_exists($analysedFile, $errors) || array_key_exists($analysedFile, $changedAnalysedFiles)) {
747+
continue;
748+
}
749+
750+
$filesWithErrorsAllChanged = false;
751+
break;
752+
}
753+
724754
foreach ($allAnalysedFiles as $analysedFile) {
725755
if (array_key_exists($analysedFile, $errors)) {
726756
$filteredErrors[$analysedFile] = $errors[$analysedFile];
@@ -766,6 +796,14 @@ public function restore(array $allAnalysedFiles, bool $debug, bool $onlyFiles, ?
766796
}
767797

768798
$filesToAnalyse[] = $analysedFile;
799+
if (
800+
($filesWithErrorsAllChanged || $newFileAppeared)
801+
&& $this->areAllChanged($dependentFiles, $changedAnalysedFiles)
802+
&& $this->areAllChanged($usedTraitDependentFiles, $changedAnalysedFiles)
803+
) {
804+
continue;
805+
}
806+
769807
// A file that declared nothing has no entry at all - save() only writes one for a file with
770808
// at least one exported node - and a missing entry is not the same as nothing to propagate:
771809
// the file may have gained its first symbol, which is exactly what the files with errors are
@@ -1044,6 +1082,21 @@ private function getMetaKeyDifferences(array $cachedMeta, array $currentMeta): a
10441082
return $diffs;
10451083
}
10461084

1085+
/**
1086+
* @param list<string> $files
1087+
* @param array<string, true> $changedFiles
1088+
*/
1089+
private function areAllChanged(array $files, array $changedFiles): bool
1090+
{
1091+
foreach ($files as $file) {
1092+
if (!array_key_exists($file, $changedFiles)) {
1093+
return false;
1094+
}
1095+
}
1096+
1097+
return true;
1098+
}
1099+
10471100
/**
10481101
* @param array<int, RootExportedNode> $cachedFileExportedNodes
10491102
* @return bool|null null means nothing changed, true means new root symbol appeared, false means nested node changed

0 commit comments

Comments
 (0)