mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Merge branch '4.x' into update-master
This commit is contained in:
commit
e0acf22e40
@ -36,8 +36,7 @@
|
||||
"sebastian/diff": "^4.0",
|
||||
"symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0",
|
||||
"symfony/filesystem": "^5.4 || ^6.0",
|
||||
"symfony/polyfill-php80": "^1.25",
|
||||
"webmozart/path-util": "^2.3"
|
||||
"symfony/polyfill-php80": "^1.25"
|
||||
},
|
||||
"provide": {
|
||||
"psalm/psalm": "self.version"
|
||||
|
@ -418,7 +418,9 @@ return [
|
||||
'array_uintersect_assoc\'1' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'],
|
||||
'array_uintersect_uassoc' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'],
|
||||
'array_uintersect_uassoc\'1' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'],
|
||||
'array_unique' => ['associative-array', 'array'=>'array', 'flags='=>'int'],
|
||||
'array_unique' => ['array', 'array'=>'array', 'flags='=>'0'],
|
||||
'array_unique\'1' => ['array<int|float|string|null>', 'array'=>'array<int|float|string|null>', 'flags='=>'1'],
|
||||
'array_unique\'2' => ['array<int|float|string|bool|\Stringable|null>', 'array'=>'array<int|float|string|bool|\Stringable|null>', 'flags='=>'2|5'],
|
||||
'array_unshift' => ['int', '&rw_array'=>'array', 'values'=>'mixed', '...vars='=>'mixed'],
|
||||
'array_values' => ['list<mixed>', 'array'=>'array'],
|
||||
'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'],
|
||||
|
@ -9561,7 +9561,9 @@ return [
|
||||
'array_uintersect_assoc\'1' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'],
|
||||
'array_uintersect_uassoc' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'],
|
||||
'array_uintersect_uassoc\'1' => ['associative-array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'],
|
||||
'array_unique' => ['associative-array', 'array'=>'array', 'flags='=>'int'],
|
||||
'array_unique' => ['array', 'array'=>'array', 'flags='=>'0'],
|
||||
'array_unique\'1' => ['array<int|float|string|null>', 'array'=>'array<int|float|string|null>', 'flags='=>'1'],
|
||||
'array_unique\'2' => ['array<int|float|string|bool|\Stringable|null>', 'array'=>'array<int|float|string|bool|\Stringable|null>', 'flags='=>'2|5'],
|
||||
'array_unshift' => ['int', '&rw_array'=>'array', 'values'=>'mixed', '...vars='=>'mixed'],
|
||||
'array_values' => ['list<mixed>', 'array'=>'array'],
|
||||
'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'],
|
||||
|
@ -2130,6 +2130,11 @@ class Config
|
||||
$this->internal_stubs[] = $ext_phpredis_path;
|
||||
}
|
||||
|
||||
if (extension_loaded('apcu')) {
|
||||
$ext_apcu_path = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'ext-apcu.phpstub';
|
||||
$this->internal_stubs[] = $ext_apcu_path;
|
||||
}
|
||||
|
||||
foreach ($this->internal_stubs as $stub_path) {
|
||||
if (!file_exists($stub_path)) {
|
||||
throw new UnexpectedValueException('Cannot locate ' . $stub_path);
|
||||
|
@ -192,22 +192,42 @@ class CastAnalyzer
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) {
|
||||
$was_inside_general_use = $context->inside_general_use;
|
||||
$context->inside_general_use = true;
|
||||
if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === false) {
|
||||
$context->inside_general_use = $was_inside_general_use;
|
||||
|
||||
if (!self::checkExprGeneralUse($statements_analyzer, $stmt, $context)) {
|
||||
return false;
|
||||
}
|
||||
$context->inside_general_use = $was_inside_general_use;
|
||||
|
||||
$type = new Union([new TNamedObject('stdClass')]);
|
||||
$permissible_atomic_types = [];
|
||||
$all_permissible = false;
|
||||
|
||||
$maybe_type = $statements_analyzer->node_data->getType($stmt->expr);
|
||||
if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) {
|
||||
if ($stmt_expr_type->isObjectType()) {
|
||||
self::handleRedundantCast($stmt_expr_type, $statements_analyzer, $stmt);
|
||||
}
|
||||
|
||||
$all_permissible = true;
|
||||
|
||||
foreach ($stmt_expr_type->getAtomicTypes() as $type) {
|
||||
if ($type instanceof Scalar) {
|
||||
$objWithProps = new TObjectWithProperties(['scalar' => new Union([$type])]);
|
||||
$permissible_atomic_types[] = $objWithProps;
|
||||
} elseif ($type instanceof TKeyedArray) {
|
||||
$permissible_atomic_types[] = new TObjectWithProperties($type->properties);
|
||||
} else {
|
||||
$all_permissible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($permissible_atomic_types && $all_permissible) {
|
||||
$type = TypeCombiner::combine($permissible_atomic_types);
|
||||
} else {
|
||||
$type = Type::getObject();
|
||||
}
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph
|
||||
) {
|
||||
$type->parent_nodes = $maybe_type->parent_nodes ?? [];
|
||||
$type->parent_nodes = $stmt_expr_type->parent_nodes ?? [];
|
||||
}
|
||||
|
||||
$statements_analyzer->node_data->setType($stmt, $type);
|
||||
@ -216,14 +236,9 @@ class CastAnalyzer
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) {
|
||||
$was_inside_general_use = $context->inside_general_use;
|
||||
$context->inside_general_use = true;
|
||||
if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === false) {
|
||||
$context->inside_general_use = $was_inside_general_use;
|
||||
|
||||
if (!self::checkExprGeneralUse($statements_analyzer, $stmt, $context)) {
|
||||
return false;
|
||||
}
|
||||
$context->inside_general_use = $was_inside_general_use;
|
||||
|
||||
$permissible_atomic_types = [];
|
||||
$all_permissible = false;
|
||||
@ -466,6 +481,18 @@ class CastAnalyzer
|
||||
return $str_type;
|
||||
}
|
||||
|
||||
private static function checkExprGeneralUse(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Expr\Cast $stmt,
|
||||
Context $context
|
||||
): bool {
|
||||
$was_inside_general_use = $context->inside_general_use;
|
||||
$context->inside_general_use = true;
|
||||
$retVal = ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context);
|
||||
$context->inside_general_use = $was_inside_general_use;
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
private static function handleRedundantCast(
|
||||
Union $maybe_type,
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
|
@ -9,7 +9,6 @@ use Psalm\Internal\PluginManager\Command\EnableCommand;
|
||||
use Psalm\Internal\PluginManager\Command\ShowCommand;
|
||||
use Psalm\Internal\PluginManager\PluginListFactory;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function dirname;
|
||||
use function getcwd;
|
||||
@ -44,10 +43,6 @@ final class Plugin
|
||||
new DisableCommand($plugin_list_factory),
|
||||
]);
|
||||
|
||||
$app->getDefinition()->addOption(
|
||||
new InputOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')
|
||||
);
|
||||
|
||||
$app->setDefaultCommand('show');
|
||||
$app->run();
|
||||
}
|
||||
|
@ -380,7 +380,6 @@ class TextDocument
|
||||
$indentation = $matches[1] ?? '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Suppress Psalm because ther are bugs in how
|
||||
* LanguageServer's signature of WorkspaceEdit is declared:
|
||||
|
@ -7,6 +7,7 @@ use Psalm\Internal\PluginManager\PluginListFactory;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use UnexpectedValueException;
|
||||
@ -41,6 +42,7 @@ class DisableCommand extends Command
|
||||
InputArgument::REQUIRED,
|
||||
'Plugin name (fully qualified class name or composer package name)'
|
||||
)
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')
|
||||
->addUsage('vendor/plugin-package-name [-c path/to/psalm.xml]');
|
||||
$this->addUsage('\'Plugin\Class\Name\' [-c path/to/psalm.xml]');
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use Psalm\Internal\PluginManager\PluginListFactory;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use UnexpectedValueException;
|
||||
@ -41,6 +42,7 @@ class EnableCommand extends Command
|
||||
InputArgument::REQUIRED,
|
||||
'Plugin name (fully qualified class name or composer package name)'
|
||||
)
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')
|
||||
->addUsage('vendor/plugin-package-name [-c path/to/psalm.xml]');
|
||||
$this->addUsage('\'Plugin\Class\Name\' [-c path/to/psalm.xml]');
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace Psalm\Internal\PluginManager\Command;
|
||||
use Psalm\Internal\PluginManager\PluginListFactory;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use UnexpectedValueException;
|
||||
@ -37,6 +38,7 @@ class ShowCommand extends Command
|
||||
$this
|
||||
->setName('show')
|
||||
->setDescription('Lists enabled and available plugins')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')
|
||||
->addUsage('[-c path/to/psalm.xml]');
|
||||
}
|
||||
|
||||
|
@ -13,17 +13,18 @@ use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function get_class;
|
||||
use function hash;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
use function strtolower;
|
||||
use function unlink;
|
||||
use function unserialize;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -111,7 +112,8 @@ class ClassLikeStorageCacheProvider
|
||||
|
||||
private function getCacheHash(?string $file_path, ?string $file_contents): string
|
||||
{
|
||||
return sha1(($file_path ? $file_contents : '') . $this->modified_timestamps);
|
||||
$data = ($file_path ? $file_contents : '') . $this->modified_timestamps;
|
||||
return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,9 +163,13 @@ class ClassLikeStorageCacheProvider
|
||||
mkdir($parser_cache_directory, 0777, true);
|
||||
}
|
||||
|
||||
$data = $file_path ? strtolower($file_path) . ' ' : '';
|
||||
$data .= $fq_classlike_name_lc;
|
||||
$file_path_sha = PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data);
|
||||
|
||||
return $parser_cache_directory
|
||||
. DIRECTORY_SEPARATOR
|
||||
. sha1(($file_path ? strtolower($file_path) . ' ' : '') . $fq_classlike_name_lc)
|
||||
. $file_path_sha
|
||||
. ($this->config->use_igbinary ? '-igbinary' : '');
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ namespace Psalm\Internal\Provider;
|
||||
|
||||
use function microtime;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -28,8 +27,8 @@ class FakeFileProvider extends FileProvider
|
||||
|
||||
public function getContents(string $file_path, bool $go_to_source = false): string
|
||||
{
|
||||
if (!$go_to_source && isset($this->temp_files[strtolower($file_path)])) {
|
||||
return $this->temp_files[strtolower($file_path)];
|
||||
if (!$go_to_source && isset($this->temp_files[$file_path])) {
|
||||
return $this->temp_files[$file_path];
|
||||
}
|
||||
|
||||
return $this->fake_files[$file_path] ?? parent::getContents($file_path);
|
||||
@ -42,8 +41,8 @@ class FakeFileProvider extends FileProvider
|
||||
|
||||
public function setOpenContents(string $file_path, string $file_contents): void
|
||||
{
|
||||
if (isset($this->fake_files[strtolower($file_path)])) {
|
||||
$this->fake_files[strtolower($file_path)] = $file_contents;
|
||||
if (isset($this->fake_files[$file_path])) {
|
||||
$this->fake_files[$file_path] = $file_contents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +68,7 @@ class FakeFileProvider extends FileProvider
|
||||
$file_paths = parent::getFilesInDir($dir_path, $file_extensions, $filter);
|
||||
|
||||
foreach ($this->fake_files as $file_path => $_) {
|
||||
if (strpos(strtolower($file_path), strtolower($dir_path)) === 0) {
|
||||
if (strpos($file_path, $dir_path) === 0) {
|
||||
$file_paths[] = $file_path;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function in_array;
|
||||
use function is_dir;
|
||||
use function strtolower;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
@ -25,24 +24,23 @@ use const DIRECTORY_SEPARATOR;
|
||||
class FileProvider
|
||||
{
|
||||
/**
|
||||
* @var array<lowercase-string, string>
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $temp_files = [];
|
||||
|
||||
/**
|
||||
* @var array<lowercase-string, string>
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $open_files = [];
|
||||
protected static $open_files = [];
|
||||
|
||||
public function getContents(string $file_path, bool $go_to_source = false): string
|
||||
{
|
||||
$file_path_lc = strtolower($file_path);
|
||||
if (!$go_to_source && isset($this->temp_files[$file_path_lc])) {
|
||||
return $this->temp_files[$file_path_lc];
|
||||
if (!$go_to_source && isset($this->temp_files[$file_path])) {
|
||||
return $this->temp_files[$file_path];
|
||||
}
|
||||
|
||||
if (isset($this->open_files[$file_path_lc])) {
|
||||
return $this->open_files[$file_path_lc];
|
||||
if (isset(self::$open_files[$file_path])) {
|
||||
return self::$open_files[$file_path];
|
||||
}
|
||||
|
||||
if (!file_exists($file_path)) {
|
||||
@ -53,18 +51,21 @@ class FileProvider
|
||||
throw new UnexpectedValueException('File ' . $file_path . ' is a directory');
|
||||
}
|
||||
|
||||
return (string)file_get_contents($file_path);
|
||||
$file_contents = (string) file_get_contents($file_path);
|
||||
|
||||
self::$open_files[$file_path] = $file_contents;
|
||||
|
||||
return $file_contents;
|
||||
}
|
||||
|
||||
public function setContents(string $file_path, string $file_contents): void
|
||||
{
|
||||
$file_path_lc = strtolower($file_path);
|
||||
if (isset($this->open_files[$file_path_lc])) {
|
||||
$this->open_files[$file_path_lc] = $file_contents;
|
||||
if (isset(self::$open_files[$file_path])) {
|
||||
self::$open_files[$file_path] = $file_contents;
|
||||
}
|
||||
|
||||
if (isset($this->temp_files[$file_path_lc])) {
|
||||
$this->temp_files[$file_path_lc] = $file_contents;
|
||||
if (isset($this->temp_files[$file_path])) {
|
||||
$this->temp_files[$file_path] = $file_contents;
|
||||
}
|
||||
|
||||
file_put_contents($file_path, $file_contents);
|
||||
@ -72,9 +73,8 @@ class FileProvider
|
||||
|
||||
public function setOpenContents(string $file_path, string $file_contents): void
|
||||
{
|
||||
$file_path_lc = strtolower($file_path);
|
||||
if (isset($this->open_files[$file_path_lc])) {
|
||||
$this->open_files[$file_path_lc] = $file_contents;
|
||||
if (isset(self::$open_files[$file_path])) {
|
||||
self::$open_files[$file_path] = $file_contents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,34 +84,32 @@ class FileProvider
|
||||
throw new UnexpectedValueException('File should exist to get modified time');
|
||||
}
|
||||
|
||||
return (int)filemtime($file_path);
|
||||
return (int) filemtime($file_path);
|
||||
}
|
||||
|
||||
public function addTemporaryFileChanges(string $file_path, string $new_content): void
|
||||
{
|
||||
$this->temp_files[strtolower($file_path)] = $new_content;
|
||||
$this->temp_files[$file_path] = $new_content;
|
||||
}
|
||||
|
||||
public function removeTemporaryFileChanges(string $file_path): void
|
||||
{
|
||||
unset($this->temp_files[strtolower($file_path)]);
|
||||
unset($this->temp_files[$file_path]);
|
||||
}
|
||||
|
||||
public function openFile(string $file_path): void
|
||||
{
|
||||
$this->open_files[strtolower($file_path)] = $this->getContents($file_path, true);
|
||||
self::$open_files[$file_path] = $this->getContents($file_path, true);
|
||||
}
|
||||
|
||||
public function isOpen(string $file_path): bool
|
||||
{
|
||||
$file_path_lc = strtolower($file_path);
|
||||
return isset($this->temp_files[$file_path_lc]) || isset($this->open_files[$file_path_lc]);
|
||||
return isset($this->temp_files[$file_path]) || isset(self::$open_files[$file_path]);
|
||||
}
|
||||
|
||||
public function closeFile(string $file_path): void
|
||||
{
|
||||
$file_path_lc = strtolower($file_path);
|
||||
unset($this->temp_files[$file_path_lc], $this->open_files[$file_path_lc]);
|
||||
unset($this->temp_files[$file_path], self::$open_files[$file_path]);
|
||||
}
|
||||
|
||||
public function fileExists(string $file_path): bool
|
||||
|
@ -9,6 +9,8 @@ use UnexpectedValueException;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
use function is_array;
|
||||
use function is_readable;
|
||||
use function mkdir;
|
||||
@ -83,7 +85,11 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$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');
|
||||
@ -109,7 +115,11 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$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');
|
||||
@ -135,7 +145,11 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$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');
|
||||
@ -155,13 +169,17 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME;
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME;
|
||||
|
||||
if (!is_readable($cache_location)) {
|
||||
if (!is_readable($reference_cache_location)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$reference_cache = unserialize((string) file_get_contents($cache_location));
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$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');
|
||||
@ -187,7 +205,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
|
||||
$class_member_reference_cache = (string) file_get_contents($class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$class_member_reference_cache = igbinary_unserialize($class_member_reference_cache);
|
||||
} else {
|
||||
$class_member_reference_cache = unserialize($class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -214,7 +237,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$method_dependencies_cache = unserialize((string) file_get_contents($method_dependencies_cache_location));
|
||||
$method_dependencies_cache = (string) file_get_contents($method_dependencies_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$method_dependencies_cache = igbinary_unserialize($method_dependencies_cache);
|
||||
} else {
|
||||
$method_dependencies_cache = unserialize($method_dependencies_cache);
|
||||
}
|
||||
|
||||
if (!is_array($method_dependencies_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -240,7 +268,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
|
||||
$class_member_reference_cache = (string) file_get_contents($class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$class_member_reference_cache = igbinary_unserialize($class_member_reference_cache);
|
||||
} else {
|
||||
$class_member_reference_cache = unserialize($class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -266,7 +299,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
|
||||
$class_member_reference_cache = (string) file_get_contents($class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$class_member_reference_cache = igbinary_unserialize($class_member_reference_cache);
|
||||
} else {
|
||||
$class_member_reference_cache = unserialize($class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -292,7 +330,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_member_reference_cache = unserialize((string) file_get_contents($class_member_cache_location));
|
||||
$class_member_reference_cache = (string) file_get_contents($class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$class_member_reference_cache = igbinary_unserialize($class_member_reference_cache);
|
||||
} else {
|
||||
$class_member_reference_cache = unserialize($class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -318,7 +361,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
|
||||
$file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache);
|
||||
} else {
|
||||
$file_class_member_reference_cache = unserialize($file_class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($file_class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -346,7 +394,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
|
||||
$file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache);
|
||||
} else {
|
||||
$file_class_member_reference_cache = unserialize($file_class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($file_class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -374,7 +427,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
|
||||
$file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache);
|
||||
} else {
|
||||
$file_class_member_reference_cache = unserialize($file_class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($file_class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -401,7 +459,12 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$file_class_member_reference_cache = unserialize((string) file_get_contents($file_class_member_cache_location));
|
||||
$file_class_member_reference_cache = (string) file_get_contents($file_class_member_cache_location);
|
||||
if ($this->config->use_igbinary) {
|
||||
$file_class_member_reference_cache = igbinary_unserialize($file_class_member_reference_cache);
|
||||
} else {
|
||||
$file_class_member_reference_cache = unserialize($file_class_member_reference_cache);
|
||||
}
|
||||
|
||||
if (!is_array($file_class_member_reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
@ -421,19 +484,23 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
|
||||
|
||||
if (!is_readable($cache_location)) {
|
||||
if (!is_readable($reference_cache_location)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache = unserialize((string) file_get_contents($cache_location));
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$reference_cache = unserialize((string) file_get_contents($reference_cache_location));
|
||||
}
|
||||
|
||||
if (!is_array($cache)) {
|
||||
if (!is_array($reference_cache)) {
|
||||
throw new UnexpectedValueException('The reference cache must be an array');
|
||||
}
|
||||
|
||||
return $cache;
|
||||
return $reference_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -447,19 +514,23 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
|
||||
|
||||
if (!is_readable($cache_location)) {
|
||||
if (!is_readable($reference_cache_location)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache = unserialize((string) file_get_contents($cache_location));
|
||||
if ($this->config->use_igbinary) {
|
||||
$reference_cache = igbinary_unserialize((string) file_get_contents($reference_cache_location));
|
||||
} else {
|
||||
$reference_cache = unserialize((string) file_get_contents($reference_cache_location));
|
||||
}
|
||||
|
||||
if (!is_array($cache)) {
|
||||
if (!is_array($reference_cache)) {
|
||||
throw new UnexpectedValueException('The method param use cache must be an array');
|
||||
}
|
||||
|
||||
return $cache;
|
||||
return $reference_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,7 +550,11 @@ class FileReferenceCacheProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
$issues_cache = igbinary_unserialize((string) file_get_contents($issues_cache_location));
|
||||
} else {
|
||||
$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');
|
||||
@ -498,8 +573,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::REFERENCE_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($file_references));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($file_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedClassLikeFiles(array $file_references): void
|
||||
{
|
||||
@ -511,8 +590,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASSLIKE_FILE_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($file_references));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($file_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedNonMethodClassReferences(array $file_class_references): void
|
||||
{
|
||||
@ -524,8 +607,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($file_class_references));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($file_class_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodClassReferences(array $method_class_references): void
|
||||
{
|
||||
@ -537,8 +624,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_CLASS_REFERENCE_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($method_class_references));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($method_class_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodMemberReferences(array $member_references): void
|
||||
{
|
||||
@ -550,8 +641,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($member_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($member_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodDependencies(array $member_references): void
|
||||
{
|
||||
@ -563,8 +658,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_DEPENDENCIES_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($member_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($member_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodPropertyReferences(array $property_references): void
|
||||
{
|
||||
@ -576,8 +675,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_PROPERTY_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($property_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($property_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodMethodReturnReferences(array $method_return_references): void
|
||||
{
|
||||
@ -589,8 +692,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CLASS_METHOD_RETURN_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($method_return_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($method_return_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodMissingMemberReferences(array $member_references): void
|
||||
{
|
||||
@ -602,8 +709,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_MISSING_MEMBER_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($member_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($member_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedFileMemberReferences(array $member_references): void
|
||||
{
|
||||
@ -615,8 +726,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_MEMBER_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($member_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($member_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedFilePropertyReferences(array $property_references): void
|
||||
{
|
||||
@ -628,8 +743,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_CLASS_PROPERTY_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($property_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($property_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedFileMethodReturnReferences(array $method_return_references): void
|
||||
{
|
||||
@ -641,8 +760,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_METHOD_RETURN_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($method_return_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($method_return_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedFileMissingMemberReferences(array $member_references): void
|
||||
{
|
||||
@ -654,8 +777,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$member_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::FILE_MISSING_MEMBER_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($member_cache_location, igbinary_serialize($member_references));
|
||||
} else {
|
||||
file_put_contents($member_cache_location, serialize($member_references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMixedMemberNameReferences(array $references): void
|
||||
{
|
||||
@ -665,9 +792,13 @@ class FileReferenceCacheProvider
|
||||
return;
|
||||
}
|
||||
|
||||
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::UNKNOWN_MEMBER_CACHE_NAME;
|
||||
|
||||
file_put_contents($cache_location, serialize($references));
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($references));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($references));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedMethodParamUses(array $uses): void
|
||||
@ -678,9 +809,13 @@ class FileReferenceCacheProvider
|
||||
return;
|
||||
}
|
||||
|
||||
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
|
||||
$reference_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
|
||||
|
||||
file_put_contents($cache_location, serialize($uses));
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($reference_cache_location, igbinary_serialize($uses));
|
||||
} else {
|
||||
file_put_contents($reference_cache_location, serialize($uses));
|
||||
}
|
||||
}
|
||||
|
||||
public function setCachedIssues(array $issues): void
|
||||
@ -693,8 +828,12 @@ class FileReferenceCacheProvider
|
||||
|
||||
$issues_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::ISSUES_CACHE_NAME;
|
||||
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($issues_cache_location, igbinary_serialize($issues));
|
||||
} else {
|
||||
file_put_contents($issues_cache_location, serialize($issues));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<string, int>>|false
|
||||
@ -708,9 +847,14 @@ class FileReferenceCacheProvider
|
||||
if ($cache_directory
|
||||
&& file_exists($analyzed_methods_cache_location)
|
||||
) {
|
||||
if ($this->config->use_igbinary) {
|
||||
/** @var array<string, array<string, int>> */
|
||||
return igbinary_unserialize(file_get_contents($analyzed_methods_cache_location));
|
||||
} else {
|
||||
/** @var array<string, array<string, int>> */
|
||||
return unserialize(file_get_contents($analyzed_methods_cache_location));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -727,10 +871,11 @@ class FileReferenceCacheProvider
|
||||
. DIRECTORY_SEPARATOR
|
||||
. self::ANALYZED_METHODS_CACHE_NAME;
|
||||
|
||||
file_put_contents(
|
||||
$analyzed_methods_cache_location,
|
||||
serialize($analyzed_methods)
|
||||
);
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($analyzed_methods_cache_location, igbinary_serialize($analyzed_methods));
|
||||
} else {
|
||||
file_put_contents($analyzed_methods_cache_location, serialize($analyzed_methods));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,10 +891,17 @@ class FileReferenceCacheProvider
|
||||
if ($cache_directory
|
||||
&& file_exists($file_maps_cache_location)
|
||||
) {
|
||||
if ($this->config->use_igbinary) {
|
||||
/**
|
||||
* @var array<string, FileMapType>
|
||||
*/
|
||||
$file_maps_cache = igbinary_unserialize(file_get_contents($file_maps_cache_location));
|
||||
} else {
|
||||
/**
|
||||
* @var array<string, FileMapType>
|
||||
*/
|
||||
$file_maps_cache = unserialize(file_get_contents($file_maps_cache_location));
|
||||
}
|
||||
|
||||
return $file_maps_cache;
|
||||
}
|
||||
@ -767,10 +919,11 @@ class FileReferenceCacheProvider
|
||||
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)
|
||||
);
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($file_maps_cache_location, igbinary_serialize($file_maps));
|
||||
} else {
|
||||
file_put_contents($file_maps_cache_location, serialize($file_maps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -786,8 +939,13 @@ class FileReferenceCacheProvider
|
||||
if ($cache_directory
|
||||
&& file_exists($type_coverage_cache_location)
|
||||
) {
|
||||
if ($this->config->use_igbinary) {
|
||||
/** @var array<string, array{int, int}> */
|
||||
$type_coverage_cache = igbinary_unserialize(file_get_contents($type_coverage_cache_location));
|
||||
} else {
|
||||
/** @var array<string, array{int, int}> */
|
||||
$type_coverage_cache = unserialize(file_get_contents($type_coverage_cache_location));
|
||||
}
|
||||
|
||||
return $type_coverage_cache;
|
||||
}
|
||||
@ -805,10 +963,11 @@ class FileReferenceCacheProvider
|
||||
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)
|
||||
);
|
||||
if ($this->config->use_igbinary) {
|
||||
file_put_contents($type_coverage_cache_location, igbinary_serialize($mixed_counts));
|
||||
} else {
|
||||
file_put_contents($type_coverage_cache_location, serialize($mixed_counts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,17 +13,18 @@ use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function get_class;
|
||||
use function hash;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
use function strtolower;
|
||||
use function unlink;
|
||||
use function unserialize;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -118,7 +119,8 @@ class FileStorageCacheProvider
|
||||
|
||||
private function getCacheHash(string $file_path, string $file_contents): string
|
||||
{
|
||||
return sha1(strtolower($file_path) . ' ' . $file_contents . $this->modified_timestamps);
|
||||
$data = ($file_path ? $file_contents : '') . $this->modified_timestamps;
|
||||
return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,9 +167,15 @@ class FileStorageCacheProvider
|
||||
mkdir($parser_cache_directory, 0777, true);
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID >= 80100) {
|
||||
$hash = hash('xxh128', $file_path);
|
||||
} else {
|
||||
$hash = hash('md4', $file_path);
|
||||
}
|
||||
|
||||
return $parser_cache_directory
|
||||
. DIRECTORY_SEPARATOR
|
||||
. sha1($file_path)
|
||||
. $hash
|
||||
. ($this->config->use_igbinary ? '-igbinary' : '');
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,12 @@ use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function hash;
|
||||
use function mkdir;
|
||||
use function sha1;
|
||||
use function touch;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* Used to determine which files reference other files, necessary for using the --diff
|
||||
@ -93,11 +94,15 @@ class ProjectCacheProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
$sha1 = sha1($lockfile_contents);
|
||||
if (PHP_VERSION_ID >= 80100) {
|
||||
$hash = hash('xxh128', $lockfile_contents);
|
||||
} else {
|
||||
$hash = hash('md4', $lockfile_contents);
|
||||
}
|
||||
|
||||
$changed = $sha1 !== $this->getComposerLockHash();
|
||||
$changed = $hash !== $this->getComposerLockHash();
|
||||
|
||||
$this->composer_lock_hash = $sha1;
|
||||
$this->composer_lock_hash = $hash;
|
||||
|
||||
return $changed;
|
||||
}
|
||||
|
@ -895,6 +895,12 @@ class TypeParser
|
||||
);
|
||||
}
|
||||
|
||||
if (is_int($min_bound) && is_int($max_bound) && $min_bound > $max_bound) {
|
||||
throw new TypeParseTreeException(
|
||||
"Min bound can't be greater than max bound, int<$min_bound, $max_bound> given"
|
||||
);
|
||||
}
|
||||
|
||||
return new TIntRange($min_bound, $max_bound);
|
||||
}
|
||||
|
||||
|
@ -195,9 +195,10 @@ function array_search($needle, array $haystack, bool $strict = false)
|
||||
|
||||
/**
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<T>
|
||||
*
|
||||
* @param T[] $array
|
||||
* @param-out list<T> $array
|
||||
* @param TArray $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-list<T> : list<T>) $array
|
||||
*/
|
||||
function shuffle(array &$array): bool
|
||||
{
|
||||
@ -205,9 +206,10 @@ function shuffle(array &$array): bool
|
||||
|
||||
/**
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<T>
|
||||
*
|
||||
* @param T[] $array
|
||||
* @param-out list<T> $array
|
||||
* @param TArray $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-list<T> : list<T>) $array
|
||||
*/
|
||||
function sort(array &$array, int $flags = SORT_REGULAR): bool
|
||||
{
|
||||
@ -215,9 +217,10 @@ function sort(array &$array, int $flags = SORT_REGULAR): bool
|
||||
|
||||
/**
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<T>
|
||||
*
|
||||
* @param T[] $array
|
||||
* @param-out list<T> $array
|
||||
* @param TArray $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-list<T> : list<T>) $array
|
||||
*/
|
||||
function rsort(array &$array, int $flags = SORT_REGULAR): bool
|
||||
{
|
||||
@ -225,10 +228,11 @@ function rsort(array &$array, int $flags = SORT_REGULAR): bool
|
||||
|
||||
/**
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<T>
|
||||
*
|
||||
* @param T[] $array
|
||||
* @param TArray $array
|
||||
* @param callable(T,T):int $callback
|
||||
* @param-out list<T> $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-list<T> : list<T>) $array
|
||||
*/
|
||||
function usort(array &$array, callable $callback): bool
|
||||
{
|
||||
@ -237,10 +241,11 @@ function usort(array &$array, callable $callback): bool
|
||||
/**
|
||||
* @psalm-template TKey
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<TKey,T>
|
||||
*
|
||||
* @param array<TKey,T> $array
|
||||
* @param TArray $array
|
||||
* @param callable(T,T):int $callback
|
||||
* @param-out array<TKey,T> $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-array<TKey,T> : array<TKey,T>) $array
|
||||
*/
|
||||
function uasort(array &$array, callable $callback): bool
|
||||
{
|
||||
@ -249,10 +254,11 @@ function uasort(array &$array, callable $callback): bool
|
||||
/**
|
||||
* @psalm-template TKey
|
||||
* @psalm-template T
|
||||
* @psalm-template TArray as array<TKey,T>
|
||||
*
|
||||
* @param array<TKey,T> $array
|
||||
* @param TArray $array
|
||||
* @param callable(TKey,TKey):int $callback
|
||||
* @param-out array<TKey,T> $array
|
||||
* @param-out (TArray is non-empty-array ? non-empty-array<TKey,T> : array<TKey,T>) $array
|
||||
*/
|
||||
function uksort(array &$array, callable $callback): bool
|
||||
{
|
||||
@ -585,8 +591,13 @@ function rtrim(string $string, string $characters = " \t\n\r\0\x0B") : string {}
|
||||
* : non-empty-string
|
||||
* )
|
||||
* : string)
|
||||
* : ($array is non-empty-array
|
||||
* ? ($array is array<non-empty-literal-string|non-empty-string>
|
||||
* ? ($array is array<non-empty-literal-string> ? non-empty-literal-string : non-empty-string)
|
||||
* : string
|
||||
* )
|
||||
* : string)
|
||||
* )
|
||||
*
|
||||
* @psalm-flow ($separator) -> return
|
||||
* @psalm-flow ($array) -(array-fetch)-> return
|
||||
@ -607,8 +618,13 @@ function implode($separator, array $array = []) : string {}
|
||||
* : non-empty-string
|
||||
* )
|
||||
* : string)
|
||||
* : ($array is non-empty-array
|
||||
* ? ($array is array<non-empty-literal-string|non-empty-string>
|
||||
* ? ($array is array<non-empty-literal-string> ? non-empty-literal-string : non-empty-string)
|
||||
* : string
|
||||
* )
|
||||
* : string)
|
||||
* )
|
||||
*
|
||||
* @psalm-flow ($separator) -> return
|
||||
* @psalm-flow ($array) -(array-fetch)-> return
|
||||
@ -1336,6 +1352,7 @@ function get_defined_constants(bool $categorize = false): array {}
|
||||
/**
|
||||
* @param mixed $object_or_class
|
||||
* @param class-string $class
|
||||
* @param bool $allow_string
|
||||
* @return ($allow_string is false ? ($object_or_class is object ? bool : false) : bool)
|
||||
*/
|
||||
function is_a($object_or_class, string $class, $allow_string = false): bool{}
|
||||
|
92
stubs/ext-apcu.phpstub
Normal file
92
stubs/ext-apcu.phpstub
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
define('APC_LIST_ACTIVE', 1);
|
||||
define('APC_LIST_DELETED', 2);
|
||||
define('APC_ITER_TYPE', 1);
|
||||
define('APC_ITER_KEY', 2);
|
||||
define('APC_ITER_FILENAME', 4);
|
||||
define('APC_ITER_DEVICE', 8);
|
||||
define('APC_ITER_INODE', 16);
|
||||
define('APC_ITER_VALUE', 32);
|
||||
define('APC_ITER_MD5', 64);
|
||||
define('APC_ITER_NUM_HITS', 128);
|
||||
define('APC_ITER_MTIME', 256);
|
||||
define('APC_ITER_CTIME', 512);
|
||||
define('APC_ITER_DTIME', 1024);
|
||||
define('APC_ITER_ATIME', 2048);
|
||||
define('APC_ITER_REFCOUNT', 4096);
|
||||
define('APC_ITER_MEM_SIZE', 8192);
|
||||
define('APC_ITER_TTL', 16384);
|
||||
define('APC_ITER_NONE', 0);
|
||||
define('APC_ITER_ALL', -1);
|
||||
|
||||
class APCUIterator implements Iterator
|
||||
{
|
||||
/**
|
||||
* @param array<string>|null|string $search
|
||||
* @param int $format
|
||||
* @param int $chunk_size
|
||||
* @param int $list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($search, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalHits()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalSize()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalCount()
|
||||
{
|
||||
}
|
||||
}
|
@ -116,10 +116,13 @@ class ArgTest extends TestCase
|
||||
ksort($a);
|
||||
$b = ["b" => 5, "a" => 8];
|
||||
sort($b);
|
||||
$c = [];
|
||||
sort($c);
|
||||
',
|
||||
'assertions' => [
|
||||
'$a' => 'array{a: int, b: int}',
|
||||
'$b' => 'list<int>',
|
||||
'$b' => 'non-empty-list<int>',
|
||||
'$c' => 'list<empty>',
|
||||
],
|
||||
],
|
||||
'arrayModificationFunctions' => [
|
||||
@ -690,6 +693,19 @@ class ArgTest extends TestCase
|
||||
',
|
||||
'error_message' => 'ArgumentTypeCoercion',
|
||||
],
|
||||
'objectRedundantCast' => [
|
||||
'<?php
|
||||
|
||||
function makeObj(): object {
|
||||
return (object)["a" => 42];
|
||||
}
|
||||
|
||||
function takesObject(object $_o): void {}
|
||||
|
||||
takesObject((object)makeObj()); // expected: RedundantCast
|
||||
',
|
||||
'error_message' => 'RedundantCast',
|
||||
],
|
||||
'MissingMandatoryParamWithNamedParams' => [
|
||||
'code' => '<?php
|
||||
class User
|
||||
|
@ -666,28 +666,44 @@ class ArrayFunctionCallTest extends TestCase
|
||||
],
|
||||
'uasort' => [
|
||||
'code' => '<?php
|
||||
function foo (int $a, int $b): int {
|
||||
return $a > $b ? 1 : -1;
|
||||
}
|
||||
$manifest = ["a" => 1, "b" => 2];
|
||||
uasort(
|
||||
$manifest,
|
||||
function (int $a, int $b) {
|
||||
return $a > $b ? 1 : -1;
|
||||
}
|
||||
);',
|
||||
"foo"
|
||||
);
|
||||
$emptyManifest = [];
|
||||
uasort(
|
||||
$emptyManifest,
|
||||
"foo"
|
||||
);
|
||||
',
|
||||
'assertions' => [
|
||||
'$manifest' => 'array<string, int>'
|
||||
'$manifest' => 'non-empty-array<string, int>',
|
||||
'$emptyManifest' => 'array<empty, empty>',
|
||||
],
|
||||
],
|
||||
'uksort' => [
|
||||
'code' => '<?php
|
||||
function foo (string $a, string $b): int {
|
||||
return $a <=> $b;
|
||||
}
|
||||
|
||||
$array = ["b" => 1, "a" => 2];
|
||||
uksort(
|
||||
$array,
|
||||
function (string $a, string $b) {
|
||||
return $a <=> $b;
|
||||
}
|
||||
"foo"
|
||||
);
|
||||
$emptyArray = [];
|
||||
uksort(
|
||||
$emptyArray,
|
||||
"foo"
|
||||
);',
|
||||
'assertions' => [
|
||||
'$array' => 'array<string, int>',
|
||||
'$array' => 'non-empty-array<string, int>',
|
||||
'$emptyArray' => 'array<empty, empty>',
|
||||
],
|
||||
],
|
||||
'arrayMergeTKeyedArray' => [
|
||||
@ -1040,6 +1056,31 @@ class ArrayFunctionCallTest extends TestCase
|
||||
'$b===' => 'non-empty-literal-string',
|
||||
]
|
||||
],
|
||||
'implodeArrayOfNonEmptyStringAndEmptyString' => [
|
||||
'code' => '<?php
|
||||
class Foo {
|
||||
const DIR = __DIR__;
|
||||
}
|
||||
$l = ["a", "b"];
|
||||
$k = [Foo::DIR];
|
||||
$a = implode("", $l);
|
||||
$b = implode("", $k);',
|
||||
'assertions' => [
|
||||
'$a===' => 'non-empty-literal-string',
|
||||
'$b===' => 'non-empty-string',
|
||||
]
|
||||
],
|
||||
'implodeEmptyArrayAndString' => [
|
||||
'code' => '<?php
|
||||
$l = [""];
|
||||
$k = [];
|
||||
$a = implode("", $l);
|
||||
$b = implode("", $k);',
|
||||
'assertions' => [
|
||||
'$a===' => 'string',
|
||||
'$b===' => 'string',
|
||||
]
|
||||
],
|
||||
'key' => [
|
||||
'code' => '<?php
|
||||
$a = ["one" => 1, "two" => 3];
|
||||
@ -1762,33 +1803,46 @@ class ArrayFunctionCallTest extends TestCase
|
||||
'shuffle' => [
|
||||
'code' => '<?php
|
||||
$array = ["foo" => 123, "bar" => 456];
|
||||
shuffle($array);',
|
||||
shuffle($array);
|
||||
$emptyArray = [];
|
||||
shuffle($emptyArray);',
|
||||
'assertions' => [
|
||||
'$array' => 'list<int>',
|
||||
'$array' => 'non-empty-list<int>',
|
||||
'$emptyArray' => 'list<empty>',
|
||||
],
|
||||
],
|
||||
'sort' => [
|
||||
'code' => '<?php
|
||||
$array = ["foo" => 123, "bar" => 456];
|
||||
sort($array);',
|
||||
sort($array);
|
||||
$emptyArray = [];
|
||||
sort($emptyArray);',
|
||||
'assertions' => [
|
||||
'$array' => 'list<int>',
|
||||
'$array' => 'non-empty-list<int>',
|
||||
'$emptyArray' => 'list<empty>',
|
||||
],
|
||||
],
|
||||
'rsort' => [
|
||||
'code' => '<?php
|
||||
$array = ["foo" => 123, "bar" => 456];
|
||||
sort($array);',
|
||||
rsort($array);
|
||||
$emptyArray = [];
|
||||
rsort($emptyArray);',
|
||||
'assertions' => [
|
||||
'$array' => 'list<int>',
|
||||
'$array' => 'non-empty-list<int>',
|
||||
'$emptyArray' => 'list<empty>',
|
||||
],
|
||||
],
|
||||
'usort' => [
|
||||
'code' => '<?php
|
||||
function baz (int $a, int $b): int { return $a <=> $b; }
|
||||
$array = ["foo" => 123, "bar" => 456];
|
||||
usort($array, function (int $a, int $b) { return $a <=> $b; });',
|
||||
usort($array, "baz");
|
||||
$emptyArray = [];
|
||||
usort($emptyArray, "baz");',
|
||||
'assertions' => [
|
||||
'$array' => 'list<int>',
|
||||
'$array' => 'non-empty-list<int>',
|
||||
'$emptyArray' => 'list<empty>',
|
||||
],
|
||||
],
|
||||
'closureParamConstraintsMet' => [
|
||||
|
@ -90,10 +90,14 @@ class GetObjectVarsTest extends TestCase
|
||||
'assertions' => [],
|
||||
];
|
||||
|
||||
yield 'propertiesOfCastScalar' => [
|
||||
'code' => '<?php $ret = get_object_vars((object)true);',
|
||||
'assertions' => ['$ret' => 'array{scalar: true}'],
|
||||
];
|
||||
|
||||
yield 'propertiesOfPOPO' => [
|
||||
// todo: fix object cast so that it results in `object{a:1}` instead
|
||||
'code' => '<?php $ret = get_object_vars((object)["a" => 1]);',
|
||||
'assertions' => ['$ret' => 'array<string, mixed>'],
|
||||
'assertions' => ['$ret' => 'array{a: int}'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -855,6 +855,33 @@ class ReturnTypeTest extends TestCase
|
||||
'$res===' => 'iterable<int, numeric-string>',
|
||||
],
|
||||
],
|
||||
'infersObjectShapeOfCastScalar' => [
|
||||
'<?php
|
||||
function returnsInt(): int {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$obj = (object)returnsInt();
|
||||
',
|
||||
'assertions' => [
|
||||
'$obj' => 'object{scalar:int}',
|
||||
],
|
||||
],
|
||||
'infersObjectShapeOfCastArray' => [
|
||||
'<?php
|
||||
/**
|
||||
* @return array{a:1}
|
||||
*/
|
||||
function returnsArray(): array {
|
||||
return ["a" => 1];
|
||||
}
|
||||
|
||||
$obj = (object)returnsArray();
|
||||
',
|
||||
'assertions' => [
|
||||
'$obj' => 'object{a:int}',
|
||||
],
|
||||
],
|
||||
'mixedAssignmentWithUnderscore' => [
|
||||
'code' => '<?php
|
||||
$gen = (function (): Generator {
|
||||
@ -1542,6 +1569,17 @@ class ReturnTypeTest extends TestCase
|
||||
',
|
||||
'error_message' => 'LessSpecificReturnStatement',
|
||||
],
|
||||
'objectCastFromArrayWithMissingKey' => [
|
||||
'<?php
|
||||
/** @return object{status: string} */
|
||||
function foo(): object {
|
||||
return (object) [
|
||||
"notstatus" => "failed",
|
||||
];
|
||||
}
|
||||
',
|
||||
'error_message' => 'InvalidReturnStatement',
|
||||
],
|
||||
'lessSpecificImplementedReturnTypeFromTemplatedTraitMethod' => [
|
||||
'code' => '<?php
|
||||
/** @template T */
|
||||
|
@ -1608,7 +1608,6 @@ class FunctionTemplateTest extends TestCase
|
||||
],
|
||||
'dontScreamForArithmeticsOnFloatTemplates' => [
|
||||
'code' => '<?php
|
||||
|
||||
/**
|
||||
* @template T of ?float
|
||||
* @param T $p
|
||||
|
Loading…
Reference in New Issue
Block a user