diff --git a/src/Psalm/Internal/Algebra.php b/src/Psalm/Internal/Algebra.php index f60f76446b1..7b59a0af77e 100644 --- a/src/Psalm/Internal/Algebra.php +++ b/src/Psalm/Internal/Algebra.php @@ -136,6 +136,7 @@ public static function simplifyCNF(array $clauses): array if (!$clause_a->reconcilable || $clause_a->wedge) { continue; } + $clause_a_keys = array_keys($clause_a->possibilities); if (count($clause_a->possibilities) !== 1 || count(array_values($clause_a->possibilities)[0]) !== 1) { foreach ($cloned_clauses as $clause_b) { @@ -143,7 +144,7 @@ public static function simplifyCNF(array $clauses): array continue; } - if (array_keys($clause_a->possibilities) === array_keys($clause_b->possibilities)) { + if ($clause_a_keys === array_keys($clause_b->possibilities)) { $opposing_keys = []; foreach ($clause_a->possibilities as $key => $a_possibilities) { diff --git a/src/Psalm/Internal/Clause.php b/src/Psalm/Internal/Clause.php index f861487c2cf..7996923015e 100644 --- a/src/Psalm/Internal/Clause.php +++ b/src/Psalm/Internal/Clause.php @@ -10,15 +10,17 @@ use function array_unique; use function array_values; use function count; +use function hash; use function implode; use function ksort; -use function md5; use function reset; use function serialize; use function sort; use function strpos; use function substr; +use const PHP_VERSION_ID; + /** * @internal * @@ -106,11 +108,15 @@ public function __construct( } else { ksort($possibilities); - foreach ($possibilities as $i => $_) { + foreach ($possibilities as $i => $v) { + if (count($v) < 2) { + continue; + } sort($possibilities[$i]); } - $this->hash = md5(serialize($possibilities)); + $data = serialize($possibilities); + $this->hash = PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); } } @@ -120,8 +126,14 @@ public function contains(Clause $other_clause): bool return false; } + foreach ($other_clause->possibilities as $var => $_) { + if (!isset($this->possibilities[$var])) { + return false; + } + } + foreach ($other_clause->possibilities as $var => $possible_types) { - if (!isset($this->possibilities[$var]) || count(array_diff($possible_types, $this->possibilities[$var]))) { + if (count(array_diff($possible_types, $this->possibilities[$var]))) { return false; } } diff --git a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php index 0c79452a647..dae227f5520 100644 --- a/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php @@ -17,6 +17,7 @@ use function igbinary_serialize; use function igbinary_unserialize; use function is_dir; +use function is_null; use function mkdir; use function serialize; use function strtolower; @@ -75,9 +76,15 @@ public function writeToCache(ClassLikeStorage $storage, string $file_path, strin { $fq_classlike_name_lc = strtolower($storage->name); - $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true); $storage->hash = $this->getCacheHash($file_path, $file_contents); + // check if we have it in cache already + $cached_value = $this->loadFromCache($fq_classlike_name_lc, $file_path); + if (!is_null($cached_value) && $cached_value->hash === $storage->hash) { + return; + } + + $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true); if ($this->config->use_igbinary) { file_put_contents($cache_location, igbinary_serialize($storage)); } else { @@ -110,9 +117,9 @@ public function getLatestFromCache( return $cached_value; } - private function getCacheHash(?string $file_path, ?string $file_contents): string + private function getCacheHash(?string $_unused_file_path, ?string $file_contents): string { - $data = ($file_path ? $file_contents : '') . $this->modified_timestamps; + $data = $file_contents ? $file_contents : $this->modified_timestamps; return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); } diff --git a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php index 5d4a5b29b0d..d52b4165acf 100644 --- a/src/Psalm/Internal/Provider/FileStorageCacheProvider.php +++ b/src/Psalm/Internal/Provider/FileStorageCacheProvider.php @@ -117,9 +117,12 @@ public function removeCacheForFile(string $file_path): void } } - private function getCacheHash(string $file_path, string $file_contents): string + private function getCacheHash(string $_unused_file_path, string $file_contents): string { - $data = ($file_path ? $file_contents : '') . $this->modified_timestamps; + // do not concatenate, as $file_contents can be big and performance will be bad + // the timestamp is only needed if we don't have file contents + // as same contents should give same results, independent of when file was modified + $data = $file_contents ? $file_contents : $this->modified_timestamps; return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); }