1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-15 19:07:00 +01:00
psalm/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php

730 lines
20 KiB
PHP
Raw Normal View History

<?php
2018-11-06 03:57:36 +01:00
namespace Psalm\Internal\Provider;
use const DIRECTORY_SEPARATOR;
2019-07-05 22:24:00 +02:00
use function file_exists;
use function file_get_contents;
use function file_put_contents;
2019-07-05 22:24:00 +02:00
use function is_array;
use function is_readable;
2020-02-17 00:24:40 +01:00
use Psalm\Internal\Analyzer\IssueData;
2019-07-05 22:24:00 +02:00
use Psalm\Config;
use function serialize;
2019-07-05 22:24:00 +02:00
use function unserialize;
/**
* @psalm-type TaggedCodeType = array<int, array{0: int, 1: string}>
*/
/**
* Used to determine which files reference other files, necessary for using the --diff
* option from the command line.
*/
class FileReferenceCacheProvider
{
const REFERENCE_CACHE_NAME = 'references';
const CLASSLIKE_FILE_CACHE_NAME = 'classlike_files';
const NONMETHOD_CLASS_REFERENCE_CACHE_NAME = 'file_class_references';
const METHOD_CLASS_REFERENCE_CACHE_NAME = 'method_class_references';
2018-11-02 02:52:39 +01:00
const ANALYZED_METHODS_CACHE_NAME = 'analyzed_methods';
const CLASS_METHOD_CACHE_NAME = 'class_method_references';
const FILE_CLASS_MEMBER_CACHE_NAME = 'file_class_member_references';
const ISSUES_CACHE_NAME = 'issues';
const FILE_MAPS_CACHE_NAME = 'file_maps';
const TYPE_COVERAGE_CACHE_NAME = 'type_coverage';
const CONFIG_HASH_CACHE_NAME = 'config';
const METHOD_MISSING_MEMBER_CACHE_NAME = 'method_missing_member';
const FILE_MISSING_MEMBER_CACHE_NAME = 'file_missing_member';
2019-04-27 23:38:24 +02:00
const UNKNOWN_MEMBER_CACHE_NAME = 'unknown_member_references';
const METHOD_PARAM_USE_CACHE_NAME = 'method_param_uses';
/**
* @var Config
*/
private $config;
/**
* @var bool
*/
public $config_changed;
public function __construct(Config $config)
{
$this->config = $config;
$this->config_changed = $config->hash !== $this->getConfigHashCache();
$this->setConfigHashCache($config->hash);
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedFileReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory || $this->config_changed) {
return null;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME;
if (!is_readable($reference_cache_location)) {
return null;
}
$reference_cache = unserialize((string) file_get_contents($reference_cache_location));
if (!is_array($reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedClassLikeFiles()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory || $this->config_changed) {
return null;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME;
if (!is_readable($reference_cache_location)) {
return null;
}
$reference_cache = unserialize((string) file_get_contents($reference_cache_location));
if (!is_array($reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedNonMethodClassReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME;
if (!is_readable($reference_cache_location)) {
return null;
}
$reference_cache = unserialize((string) file_get_contents($reference_cache_location));
if (!is_array($reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedMethodClassReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME;
if (!is_readable($cache_location)) {
return null;
}
$reference_cache = unserialize((string) file_get_contents($cache_location));
if (!is_array($reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedMethodMemberReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME;
if (!is_readable($class_member_cache_location)) {
return null;
}
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
if (!is_array($class_member_reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $class_member_reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedMethodMissingMemberReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME;
if (!is_readable($class_member_cache_location)) {
return null;
}
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
if (!is_array($class_member_reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $class_member_reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedFileMemberReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$file_class_member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME;
if (!is_readable($file_class_member_cache_location)) {
return null;
}
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
if (!is_array($file_class_member_reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $file_class_member_reference_cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedFileMissingMemberReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$file_class_member_cache_location
= $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME;
if (!is_readable($file_class_member_cache_location)) {
return null;
}
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
if (!is_array($file_class_member_reference_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $file_class_member_reference_cache;
}
2019-04-27 23:38:24 +02:00
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedMixedMemberNameReferences()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
if (!is_readable($cache_location)) {
return null;
}
$cache = unserialize((string) file_get_contents($cache_location));
if (!is_array($cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedMethodParamUses()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
if (!is_readable($cache_location)) {
return null;
}
$cache = unserialize((string) file_get_contents($cache_location));
if (!is_array($cache)) {
throw new \UnexpectedValueException('The method param use cache must be an array');
}
return $cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
*/
public function getCachedIssues()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME;
if (!is_readable($issues_cache_location)) {
return null;
}
$issues_cache = unserialize((string) file_get_contents($issues_cache_location));
if (!is_array($issues_cache)) {
throw new \UnexpectedValueException('The reference cache must be an array');
}
return $issues_cache;
}
/**
* @return void
*/
public function setCachedFileReferences(array $file_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME;
file_put_contents($reference_cache_location, serialize($file_references));
}
/**
* @return void
*/
public function setCachedClassLikeFiles(array $file_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME;
file_put_contents($reference_cache_location, serialize($file_references));
}
/**
* @return void
*/
public function setCachedNonMethodClassReferences(array $file_class_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME;
file_put_contents($reference_cache_location, serialize($file_class_references));
}
/**
* @return void
*/
public function setCachedMethodClassReferences(array $method_class_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME;
file_put_contents($reference_cache_location, serialize($method_class_references));
}
/**
* @return void
*/
public function setCachedMethodMemberReferences(array $member_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME;
file_put_contents($member_cache_location, serialize($member_references));
}
/**
* @return void
*/
public function setCachedMethodMissingMemberReferences(array $member_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME;
file_put_contents($member_cache_location, serialize($member_references));
}
/**
* @return void
*/
public function setCachedFileMemberReferences(array $member_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME;
file_put_contents($member_cache_location, serialize($member_references));
}
/**
* @return void
*/
public function setCachedFileMissingMemberReferences(array $member_references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME;
file_put_contents($member_cache_location, serialize($member_references));
}
2019-04-27 23:38:24 +02:00
/**
* @return void
*/
public function setCachedMixedMemberNameReferences(array $references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
file_put_contents($cache_location, serialize($references));
}
/**
* @return void
*/
public function setCachedMethodParamUses(array $references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
2019-04-27 23:38:24 +02:00
file_put_contents($cache_location, serialize($references));
}
/**
* @return void
*/
public function setCachedIssues(array $issues)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME;
file_put_contents($issues_cache_location, serialize($issues));
}
/**
* @return array<string, array<string, int>>|false
*/
2018-11-02 02:52:39 +01:00
public function getAnalyzedMethodCache()
{
2018-10-07 02:11:19 +02:00
$cache_directory = $this->config->getCacheDirectory();
2018-11-02 02:52:39 +01:00
$analyzed_methods_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ANALYZED_METHODS_CACHE_NAME;
if ($cache_directory
2018-11-02 02:52:39 +01:00
&& file_exists($analyzed_methods_cache_location)
&& !$this->config_changed
) {
/** @var array<string, array<string, int>> */
2018-11-02 02:52:39 +01:00
return unserialize(file_get_contents($analyzed_methods_cache_location));
}
2018-10-07 02:11:19 +02:00
return false;
}
/**
2018-11-02 02:52:39 +01:00
* @param array<string, array<string, int>> $analyzed_methods
2019-07-05 22:24:00 +02:00
*
* @return void
*/
2018-11-02 02:52:39 +01:00
public function setAnalyzedMethodCache(array $analyzed_methods)
{
$cache_directory = Config::getInstance()->getCacheDirectory();
if ($cache_directory) {
2018-11-02 02:52:39 +01:00
$analyzed_methods_cache_location = $cache_directory
. DIRECTORY_SEPARATOR
. self::ANALYZED_METHODS_CACHE_NAME;
file_put_contents(
2018-11-02 02:52:39 +01:00
$analyzed_methods_cache_location,
serialize($analyzed_methods)
);
}
}
/**
* @return array<
* string,
* array{
* 0: TaggedCodeType,
* 1: TaggedCodeType,
* 2: array<int, array{0: int, 1: string, 2: int}>
* }
* >|false
*/
public function getFileMapCache()
{
$cache_directory = $this->config->getCacheDirectory();
$file_maps_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MAPS_CACHE_NAME;
if ($cache_directory
&& file_exists($file_maps_cache_location)
&& !$this->config_changed
) {
/**
* @var array<
* string,
* array{
* 0: TaggedCodeType,
* 1: TaggedCodeType,
* 2: array<int, array{0: int, 1: string, 2: int}>
* }
* >
*/
$file_maps_cache = unserialize(file_get_contents($file_maps_cache_location));
2019-07-05 22:24:00 +02:00
return $file_maps_cache;
}
return false;
}
/**
* @param array<
* string,
* array{
* 0: TaggedCodeType,
* 1: TaggedCodeType,
* 2: array<int, array{0: int, 1: string, 2: int}>
* }
* > $file_maps
2019-07-05 22:24:00 +02:00
*
* @return void
*/
public function setFileMapCache(array $file_maps)
{
$cache_directory = Config::getInstance()->getCacheDirectory();
if ($cache_directory) {
$file_maps_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MAPS_CACHE_NAME;
file_put_contents(
$file_maps_cache_location,
serialize($file_maps)
);
}
}
/**
* @return array<string, array{int, int}>|false
*/
public function getTypeCoverage()
{
$cache_directory = Config::getInstance()->getCacheDirectory();
$type_coverage_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::TYPE_COVERAGE_CACHE_NAME;
if ($cache_directory
&& file_exists($type_coverage_cache_location)
&& !$this->config_changed
) {
/** @var array<string, array{int, int}> */
$type_coverage_cache = unserialize(file_get_contents($type_coverage_cache_location));
2019-07-05 22:24:00 +02:00
return $type_coverage_cache;
}
return false;
}
/**
* @param array<string, array{int, int}> $mixed_counts
2019-07-05 22:24:00 +02:00
*
* @return void
*/
public function setTypeCoverage(array $mixed_counts)
{
$cache_directory = Config::getInstance()->getCacheDirectory();
if ($cache_directory) {
$type_coverage_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::TYPE_COVERAGE_CACHE_NAME;
file_put_contents(
$type_coverage_cache_location,
serialize($mixed_counts)
);
}
}
/**
* @return string|false
*/
public function getConfigHashCache()
{
$cache_directory = $this->config->getCacheDirectory();
$config_hash_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CONFIG_HASH_CACHE_NAME;
if ($cache_directory
&& file_exists($config_hash_cache_location)
) {
/** @var string */
$file_maps_cache = unserialize(file_get_contents($config_hash_cache_location));
2019-07-05 22:24:00 +02:00
return $file_maps_cache;
}
return false;
}
/**
* @return void
*/
public function setConfigHashCache(string $hash)
{
$cache_directory = Config::getInstance()->getCacheDirectory();
if ($cache_directory) {
2019-07-11 17:07:39 +02:00
if (!file_exists($cache_directory)) {
\mkdir($cache_directory, 0777, true);
}
$config_hash_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CONFIG_HASH_CACHE_NAME;
file_put_contents(
$config_hash_cache_location,
serialize($hash)
);
}
}
}