2017-02-18 19:41:27 +01:00
|
|
|
|
<?php
|
2018-11-06 03:57:36 +01:00
|
|
|
|
namespace Psalm\Internal\Provider;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2019-06-26 22:52:29 +02:00
|
|
|
|
use function array_filter;
|
|
|
|
|
use function array_keys;
|
|
|
|
|
use function array_merge;
|
|
|
|
|
use function array_unique;
|
2019-07-05 22:24:00 +02:00
|
|
|
|
use function file_exists;
|
|
|
|
|
use Psalm\Codebase;
|
|
|
|
|
use Psalm\CodeLocation;
|
2020-02-17 00:24:40 +01:00
|
|
|
|
use Psalm\Internal\Analyzer\IssueData;
|
2019-07-05 22:24:00 +02:00
|
|
|
|
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-09-26 22:33:59 +02:00
|
|
|
|
/**
|
2020-05-15 06:16:20 +02:00
|
|
|
|
* @psalm-import-type FileMapType from \Psalm\Internal\Codebase\Analyzer
|
|
|
|
|
*
|
2017-02-18 23:49:34 +01:00
|
|
|
|
* Used to determine which files reference other files, necessary for using the --diff
|
|
|
|
|
* option from the command line.
|
|
|
|
|
*/
|
2017-02-18 19:41:27 +01:00
|
|
|
|
class FileReferenceProvider
|
|
|
|
|
{
|
2018-09-30 05:51:06 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
private $loaded_from_cache = false;
|
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
/**
|
2020-04-02 23:17:55 +02:00
|
|
|
|
* A lookup table used for getting all the references to a class not inside a method
|
|
|
|
|
* indexed by file
|
2017-02-18 19:41:27 +01:00
|
|
|
|
*
|
|
|
|
|
* @var array<string, array<string,bool>>
|
|
|
|
|
*/
|
2020-04-02 23:17:55 +02:00
|
|
|
|
private static $nonmethod_references_to_classes = [];
|
2019-04-16 22:07:48 +02:00
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* A lookup table used for getting all the methods that reference a class
|
|
|
|
|
*
|
|
|
|
|
* @var array<string, array<string,bool>>
|
|
|
|
|
*/
|
|
|
|
|
private static $method_references_to_classes = [];
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* A lookup table used for getting all the files that reference a class member
|
|
|
|
|
*
|
|
|
|
|
* @var array<string, array<string,bool>>
|
|
|
|
|
*/
|
|
|
|
|
private static $file_references_to_class_members = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A lookup table used for getting all the files that reference a missing class member
|
|
|
|
|
*
|
|
|
|
|
* @var array<string, array<string,bool>>
|
|
|
|
|
*/
|
|
|
|
|
private static $file_references_to_missing_class_members = [];
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
|
|
|
|
/**
|
2019-12-27 16:34:51 +01:00
|
|
|
|
* @var array<string, array<string, true>>
|
2017-02-18 19:41:27 +01:00
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
private static $files_inheriting_classes = [];
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A list of all files deleted since the last successful run
|
|
|
|
|
*
|
|
|
|
|
* @var array<int, string>|null
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
private static $deleted_files = null;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A lookup table used for getting all the files referenced by a file
|
|
|
|
|
*
|
|
|
|
|
* @var array<string, array{a:array<int, string>, i:array<int, string>}>
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
private static $file_references = [];
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<string, bool>>
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
private static $method_references_to_class_members = [];
|
2019-04-13 00:28:07 +02:00
|
|
|
|
|
|
|
|
|
/**
|
2019-04-16 22:07:48 +02:00
|
|
|
|
* @var array<string, array<string, bool>>
|
2019-04-13 00:28:07 +02:00
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
private static $method_references_to_missing_class_members = [];
|
2018-09-26 00:37:24 +02:00
|
|
|
|
|
2019-04-27 23:38:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<string, bool>>
|
|
|
|
|
*/
|
|
|
|
|
private static $references_to_mixed_member_names = [];
|
|
|
|
|
|
2019-04-13 00:28:07 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
private static $class_method_locations = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
private static $class_property_locations = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
private static $class_locations = [];
|
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, string>
|
|
|
|
|
*/
|
|
|
|
|
private static $classlike_files = [];
|
|
|
|
|
|
2018-09-30 05:51:06 +02:00
|
|
|
|
/**
|
2018-10-07 04:58:21 +02:00
|
|
|
|
* @var array<string, array<string, int>>
|
2018-09-30 05:51:06 +02:00
|
|
|
|
*/
|
2018-11-02 02:52:39 +01:00
|
|
|
|
private static $analyzed_methods = [];
|
2018-09-30 05:51:06 +02:00
|
|
|
|
|
2018-09-26 22:33:59 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<int, IssueData>>
|
|
|
|
|
*/
|
|
|
|
|
private static $issues = [];
|
|
|
|
|
|
2018-10-26 22:17:15 +02:00
|
|
|
|
/**
|
2020-05-15 06:16:20 +02:00
|
|
|
|
* @var array<string, FileMapType>
|
2018-10-26 22:17:15 +02:00
|
|
|
|
*/
|
|
|
|
|
private static $file_maps = [];
|
|
|
|
|
|
2019-03-23 14:50:47 +01:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array{int, int}>
|
|
|
|
|
*/
|
|
|
|
|
private static $mixed_counts = [];
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var array<string, array<int, array<string, bool>>>
|
|
|
|
|
*/
|
|
|
|
|
private static $method_param_uses = [];
|
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var ?FileReferenceCacheProvider
|
|
|
|
|
*/
|
|
|
|
|
public $cache;
|
|
|
|
|
|
|
|
|
|
public function __construct(FileReferenceCacheProvider $cache = null)
|
|
|
|
|
{
|
|
|
|
|
$this->cache = $cache;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string>
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function getDeletedReferencedFiles()
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
if (self::$deleted_files === null) {
|
|
|
|
|
self::$deleted_files = array_filter(
|
|
|
|
|
array_keys(self::$file_references),
|
|
|
|
|
/**
|
|
|
|
|
* @param string $file_name
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function ($file_name) {
|
|
|
|
|
return !file_exists($file_name);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self::$deleted_files;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-03-06 19:02:34 +01:00
|
|
|
|
* @param lowercase-string $fq_class_name_lc
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2020-04-02 23:17:55 +02:00
|
|
|
|
public function addNonMethodReferenceToClass(string $source_file, string $fq_class_name_lc)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes[$fq_class_name_lc][$source_file] = true;
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string,bool>>
|
|
|
|
|
*/
|
2020-04-02 23:17:55 +02:00
|
|
|
|
public function getAllNonMethodReferencesToClasses()
|
2019-04-16 22:07:48 +02:00
|
|
|
|
{
|
2020-04-02 23:17:55 +02:00
|
|
|
|
return self::$nonmethod_references_to_classes;
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2020-04-02 23:17:55 +02:00
|
|
|
|
public function addNonMethodReferencesToClasses(array $references)
|
2019-04-16 22:07:48 +02:00
|
|
|
|
{
|
2019-10-12 02:17:07 +02:00
|
|
|
|
foreach ($references as $key => $reference) {
|
2020-04-02 23:17:55 +02:00
|
|
|
|
if (isset(self::$nonmethod_references_to_classes[$key])) {
|
|
|
|
|
self::$nonmethod_references_to_classes[$key] = array_merge(
|
2019-10-12 02:17:07 +02:00
|
|
|
|
$reference,
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes[$key]
|
2019-10-12 02:17:07 +02:00
|
|
|
|
);
|
|
|
|
|
} else {
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes[$key] = $reference;
|
2019-10-12 02:17:07 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, string> $map
|
|
|
|
|
*/
|
|
|
|
|
public function addClassLikeFiles(array $map) : void
|
|
|
|
|
{
|
|
|
|
|
self::$classlike_files += $map;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addFileReferenceToClassMember(string $source_file, string $referenced_member_id)
|
|
|
|
|
{
|
|
|
|
|
self::$file_references_to_class_members[$referenced_member_id][$source_file] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addFileReferenceToMissingClassMember(string $source_file, string $referenced_member_id)
|
|
|
|
|
{
|
|
|
|
|
self::$file_references_to_missing_class_members[$referenced_member_id][$source_file] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string,bool>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllFileReferencesToClassMembers()
|
|
|
|
|
{
|
|
|
|
|
return self::$file_references_to_class_members;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 18:38:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string,bool>>
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function getAllFileReferencesToMissingClassMembers()
|
|
|
|
|
{
|
|
|
|
|
return self::$file_references_to_missing_class_members;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addFileReferencesToClassMembers(array $references)
|
2017-08-22 18:38:38 +02:00
|
|
|
|
{
|
2019-10-12 02:17:07 +02:00
|
|
|
|
foreach ($references as $key => $reference) {
|
|
|
|
|
if (isset(self::$file_references_to_class_members[$key])) {
|
|
|
|
|
self::$file_references_to_class_members[$key] = array_merge(
|
|
|
|
|
$reference,
|
|
|
|
|
self::$file_references_to_class_members[$key]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$file_references_to_class_members[$key] = $reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-22 18:38:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function addFileReferencesToMissingClassMembers(array $references)
|
2017-08-22 18:38:38 +02:00
|
|
|
|
{
|
2019-10-12 02:17:07 +02:00
|
|
|
|
foreach ($references as $key => $reference) {
|
|
|
|
|
if (isset(self::$file_references_to_missing_class_members[$key])) {
|
|
|
|
|
self::$file_references_to_missing_class_members[$key] = array_merge(
|
|
|
|
|
$reference,
|
|
|
|
|
self::$file_references_to_missing_class_members[$key]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$file_references_to_missing_class_members[$key] = $reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-22 18:38:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @param string $source_file
|
2017-07-25 22:11:02 +02:00
|
|
|
|
* @param string $fq_class_name_lc
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function addFileInheritanceToClass($source_file, $fq_class_name_lc)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
2017-07-25 22:11:02 +02:00
|
|
|
|
self::$files_inheriting_classes[$fq_class_name_lc][$source_file] = true;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addMethodParamUse(string $method_id, int $offset, string $referencing_method_id)
|
|
|
|
|
{
|
|
|
|
|
self::$method_param_uses[$method_id][$offset][$referencing_method_id] = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @param string $file
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2019-12-27 16:34:51 +01:00
|
|
|
|
* @return array<int, string>
|
2017-02-18 19:41:27 +01:00
|
|
|
|
*/
|
2018-10-07 02:11:19 +02:00
|
|
|
|
private function calculateFilesReferencingFile(Codebase $codebase, $file)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
$referenced_files = [];
|
|
|
|
|
|
2018-11-06 03:57:36 +01:00
|
|
|
|
$file_classes = ClassLikeAnalyzer::getClassesForFile($codebase, $file);
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-02-12 04:49:19 +01:00
|
|
|
|
foreach ($file_classes as $file_class_lc => $_) {
|
2020-04-02 23:17:55 +02:00
|
|
|
|
if (isset(self::$nonmethod_references_to_classes[$file_class_lc])) {
|
|
|
|
|
$new_files = array_keys(self::$nonmethod_references_to_classes[$file_class_lc]);
|
2020-02-11 22:39:33 +01:00
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
$referenced_files = array_merge(
|
|
|
|
|
$referenced_files,
|
2020-02-11 22:39:33 +01:00
|
|
|
|
$new_files
|
2017-02-18 19:41:27 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
2020-04-02 23:17:55 +02:00
|
|
|
|
|
|
|
|
|
if (isset(self::$method_references_to_classes[$file_class_lc])) {
|
|
|
|
|
$new_referencing_methods = array_keys(self::$method_references_to_classes[$file_class_lc]);
|
|
|
|
|
|
|
|
|
|
foreach ($new_referencing_methods as $new_referencing_method_id) {
|
|
|
|
|
$fq_class_name_lc = \explode('::', $new_referencing_method_id)[0];
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$referenced_files[] = $codebase->scanner->getClassLikeFilePath($fq_class_name_lc);
|
|
|
|
|
} catch (\UnexpectedValueException $e) {
|
|
|
|
|
if (isset(self::$classlike_files[$fq_class_name_lc])) {
|
|
|
|
|
$referenced_files[] = self::$classlike_files[$fq_class_name_lc];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array_unique($referenced_files);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $file
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2019-12-27 16:34:51 +01:00
|
|
|
|
* @return array<int, string>
|
2017-02-18 19:41:27 +01:00
|
|
|
|
*/
|
2018-10-07 02:11:19 +02:00
|
|
|
|
private function calculateFilesInheritingFile(Codebase $codebase, $file)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
$referenced_files = [];
|
|
|
|
|
|
2018-11-06 03:57:36 +01:00
|
|
|
|
$file_classes = ClassLikeAnalyzer::getClassesForFile($codebase, $file);
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-02-12 04:49:19 +01:00
|
|
|
|
foreach ($file_classes as $file_class_lc => $_) {
|
|
|
|
|
if (isset(self::$files_inheriting_classes[$file_class_lc])) {
|
2017-02-18 19:41:27 +01:00
|
|
|
|
$referenced_files = array_merge(
|
|
|
|
|
$referenced_files,
|
2018-02-12 04:49:19 +01:00
|
|
|
|
array_keys(self::$files_inheriting_classes[$file_class_lc])
|
2017-02-18 19:41:27 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array_unique($referenced_files);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function removeDeletedFilesFromReferences()
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
$deleted_files = self::getDeletedReferencedFiles();
|
|
|
|
|
|
|
|
|
|
if ($deleted_files) {
|
|
|
|
|
foreach ($deleted_files as $file) {
|
|
|
|
|
unset(self::$file_references[$file]);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
if ($this->cache) {
|
|
|
|
|
$this->cache->setCachedFileReferences(self::$file_references);
|
|
|
|
|
}
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $file
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return array<string>
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function getFilesReferencingFile($file)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
return isset(self::$file_references[$file]['a']) ? self::$file_references[$file]['a'] : [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $file
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return array<string>
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function getFilesInheritingFromFile($file)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
|
|
|
|
return isset(self::$file_references[$file]['i']) ? self::$file_references[$file]['i'] : [];
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
/**
|
2018-09-26 23:54:08 +02:00
|
|
|
|
* @return array<string, array<string, bool>>
|
2018-09-26 00:37:24 +02:00
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function getAllMethodReferencesToClassMembers()
|
2018-09-26 00:37:24 +02:00
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
return self::$method_references_to_class_members;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string, bool>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllMethodReferencesToClasses()
|
|
|
|
|
{
|
|
|
|
|
return self::$method_references_to_classes;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string, bool>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllMethodReferencesToMissingClassMembers()
|
|
|
|
|
{
|
|
|
|
|
return self::$method_references_to_missing_class_members;
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-27 23:38:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string,bool>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllReferencesToMixedMemberNames()
|
|
|
|
|
{
|
|
|
|
|
return self::$references_to_mixed_member_names;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<int, array<string, bool>>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllMethodParamUses()
|
|
|
|
|
{
|
|
|
|
|
return self::$method_param_uses;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 19:41:27 +01:00
|
|
|
|
/**
|
2018-10-17 17:03:32 +02:00
|
|
|
|
* @param bool $force_reload
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return bool
|
2019-08-18 22:10:12 +02:00
|
|
|
|
* @psalm-suppress MixedPropertyTypeCoercion
|
2017-02-18 19:41:27 +01:00
|
|
|
|
*/
|
2018-10-17 17:03:32 +02:00
|
|
|
|
public function loadReferenceCache($force_reload = true)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
2018-10-17 17:03:32 +02:00
|
|
|
|
if ($this->cache && (!$this->loaded_from_cache || $force_reload)) {
|
2018-09-30 05:51:06 +02:00
|
|
|
|
$this->loaded_from_cache = true;
|
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
$file_references = $this->cache->getCachedFileReferences();
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
if ($file_references === null) {
|
2018-09-26 00:37:24 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
self::$file_references = $file_references;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
$nonmethod_references_to_classes = $this->cache->getCachedNonMethodClassReferences();
|
2019-04-28 18:36:24 +02:00
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
if ($nonmethod_references_to_classes === null) {
|
2019-04-28 18:36:24 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes = $nonmethod_references_to_classes;
|
2019-04-28 18:36:24 +02:00
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
$method_references_to_classes = $this->cache->getCachedMethodClassReferences();
|
|
|
|
|
|
|
|
|
|
if ($method_references_to_classes === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$method_references_to_classes = $method_references_to_classes;
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
$method_references_to_class_members = $this->cache->getCachedMethodMemberReferences();
|
|
|
|
|
|
|
|
|
|
if ($method_references_to_class_members === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$method_references_to_class_members = $method_references_to_class_members;
|
|
|
|
|
|
|
|
|
|
$method_references_to_missing_class_members = $this->cache->getCachedMethodMissingMemberReferences();
|
|
|
|
|
|
|
|
|
|
if ($method_references_to_missing_class_members === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$method_references_to_missing_class_members = $method_references_to_missing_class_members;
|
|
|
|
|
|
|
|
|
|
$file_references_to_class_members = $this->cache->getCachedFileMemberReferences();
|
2017-05-25 04:07:49 +02:00
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
if ($file_references_to_class_members === null) {
|
2018-09-26 00:37:24 +02:00
|
|
|
|
return false;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
2018-09-26 00:37:24 +02:00
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
self::$file_references_to_class_members = $file_references_to_class_members;
|
|
|
|
|
|
|
|
|
|
$file_references_to_missing_class_members = $this->cache->getCachedFileMissingMemberReferences();
|
|
|
|
|
|
|
|
|
|
if ($file_references_to_missing_class_members === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$file_references_to_missing_class_members = $file_references_to_missing_class_members;
|
2018-09-26 00:37:24 +02:00
|
|
|
|
|
2019-04-27 23:38:24 +02:00
|
|
|
|
$references_to_mixed_member_names = $this->cache->getCachedMixedMemberNameReferences();
|
|
|
|
|
|
|
|
|
|
if ($references_to_mixed_member_names === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$references_to_mixed_member_names = $references_to_mixed_member_names;
|
|
|
|
|
|
2018-11-02 02:52:39 +01:00
|
|
|
|
$analyzed_methods = $this->cache->getAnalyzedMethodCache();
|
2018-10-07 02:11:19 +02:00
|
|
|
|
|
2018-11-02 02:52:39 +01:00
|
|
|
|
if ($analyzed_methods === false) {
|
2018-10-07 02:11:19 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 02:52:39 +01:00
|
|
|
|
self::$analyzed_methods = $analyzed_methods;
|
2018-10-07 02:11:19 +02:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
$issues = $this->cache->getCachedIssues();
|
2018-09-26 22:33:59 +02:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
if ($issues === null) {
|
2018-09-26 22:33:59 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
self::$issues = $issues;
|
2018-09-26 22:33:59 +02:00
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
$method_param_uses = $this->cache->getCachedMethodParamUses();
|
|
|
|
|
|
|
|
|
|
if ($method_param_uses === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$method_param_uses = $method_param_uses;
|
|
|
|
|
|
2019-03-23 14:50:47 +01:00
|
|
|
|
$mixed_counts = $this->cache->getTypeCoverage();
|
|
|
|
|
|
|
|
|
|
if ($mixed_counts === false) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$mixed_counts = $mixed_counts;
|
|
|
|
|
|
2020-04-02 23:17:55 +02:00
|
|
|
|
$classlike_files = $this->cache->getCachedClassLikeFiles();
|
|
|
|
|
|
|
|
|
|
if ($classlike_files === null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$classlike_files = $classlike_files;
|
|
|
|
|
|
2018-10-26 22:17:15 +02:00
|
|
|
|
self::$file_maps = $this->cache->getFileMapCache() ?: [];
|
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
return true;
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-09-28 22:18:45 +02:00
|
|
|
|
* @param array<string, string|bool> $visited_files
|
2017-05-27 02:16:18 +02:00
|
|
|
|
*
|
2017-02-18 19:41:27 +01:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-10-07 02:11:19 +02:00
|
|
|
|
public function updateReferenceCache(Codebase $codebase, array $visited_files)
|
2017-02-18 19:41:27 +01:00
|
|
|
|
{
|
2018-09-28 22:18:45 +02:00
|
|
|
|
foreach ($visited_files as $file => $_) {
|
|
|
|
|
$all_file_references = array_unique(
|
|
|
|
|
array_merge(
|
|
|
|
|
isset(self::$file_references[$file]['a']) ? self::$file_references[$file]['a'] : [],
|
2018-10-07 02:11:19 +02:00
|
|
|
|
$this->calculateFilesReferencingFile($codebase, $file)
|
2018-09-28 22:18:45 +02:00
|
|
|
|
)
|
|
|
|
|
);
|
2018-09-26 00:37:24 +02:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
$inheritance_references = array_unique(
|
|
|
|
|
array_merge(
|
|
|
|
|
isset(self::$file_references[$file]['i']) ? self::$file_references[$file]['i'] : [],
|
2018-10-07 02:11:19 +02:00
|
|
|
|
$this->calculateFilesInheritingFile($codebase, $file)
|
2018-09-28 22:18:45 +02:00
|
|
|
|
)
|
|
|
|
|
);
|
2018-09-26 00:37:24 +02:00
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
self::$file_references[$file] = [
|
|
|
|
|
'a' => $all_file_references,
|
|
|
|
|
'i' => $inheritance_references,
|
|
|
|
|
];
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 22:18:45 +02:00
|
|
|
|
if ($this->cache) {
|
|
|
|
|
$this->cache->setCachedFileReferences(self::$file_references);
|
2020-03-26 17:35:27 +01:00
|
|
|
|
$this->cache->setCachedMethodClassReferences(self::$method_references_to_classes);
|
2020-04-02 23:17:55 +02:00
|
|
|
|
$this->cache->setCachedNonMethodClassReferences(self::$nonmethod_references_to_classes);
|
2019-04-16 22:07:48 +02:00
|
|
|
|
$this->cache->setCachedMethodMemberReferences(self::$method_references_to_class_members);
|
|
|
|
|
$this->cache->setCachedFileMemberReferences(self::$file_references_to_class_members);
|
|
|
|
|
$this->cache->setCachedMethodMissingMemberReferences(self::$method_references_to_missing_class_members);
|
|
|
|
|
$this->cache->setCachedFileMissingMemberReferences(self::$file_references_to_missing_class_members);
|
2019-04-27 23:38:24 +02:00
|
|
|
|
$this->cache->setCachedMixedMemberNameReferences(self::$references_to_mixed_member_names);
|
2019-04-29 23:29:38 +02:00
|
|
|
|
$this->cache->setCachedMethodParamUses(self::$method_param_uses);
|
2018-09-28 22:18:45 +02:00
|
|
|
|
$this->cache->setCachedIssues(self::$issues);
|
2020-04-02 23:17:55 +02:00
|
|
|
|
$this->cache->setCachedClassLikeFiles(self::$classlike_files);
|
2018-10-26 22:17:15 +02:00
|
|
|
|
$this->cache->setFileMapCache(self::$file_maps);
|
2019-03-23 14:50:47 +01:00
|
|
|
|
$this->cache->setTypeCoverage(self::$mixed_counts);
|
2018-11-02 02:52:39 +01:00
|
|
|
|
$this->cache->setAnalyzedMethodCache(self::$analyzed_methods);
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @param lowercase-string $fq_class_name_lc
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addMethodReferenceToClass(string $calling_function_id, string $fq_class_name_lc)
|
|
|
|
|
{
|
|
|
|
|
if (!isset(self::$method_references_to_classes[$fq_class_name_lc])) {
|
|
|
|
|
self::$method_references_to_classes[$fq_class_name_lc] = [$calling_function_id => true];
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_references_to_classes[$fq_class_name_lc][$calling_function_id] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-12-29 00:37:55 +01:00
|
|
|
|
public function addMethodReferenceToClassMember(string $calling_function_id, string $referenced_member_id)
|
2018-09-26 00:37:24 +02:00
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
if (!isset(self::$method_references_to_class_members[$referenced_member_id])) {
|
2019-12-29 00:37:55 +01:00
|
|
|
|
self::$method_references_to_class_members[$referenced_member_id] = [$calling_function_id => true];
|
2018-09-26 00:37:24 +02:00
|
|
|
|
} else {
|
2019-12-29 00:37:55 +01:00
|
|
|
|
self::$method_references_to_class_members[$referenced_member_id][$calling_function_id] = true;
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-04-13 00:28:07 +02:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-12-29 00:37:55 +01:00
|
|
|
|
public function addMethodReferenceToMissingClassMember(string $calling_function_id, string $referenced_member_id)
|
2019-04-13 00:28:07 +02:00
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
if (!isset(self::$method_references_to_missing_class_members[$referenced_member_id])) {
|
2019-12-29 00:37:55 +01:00
|
|
|
|
self::$method_references_to_missing_class_members[$referenced_member_id] = [$calling_function_id => true];
|
2019-04-16 22:07:48 +02:00
|
|
|
|
} else {
|
2019-12-29 00:37:55 +01:00
|
|
|
|
self::$method_references_to_missing_class_members[$referenced_member_id][$calling_function_id] = true;
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addCallingLocationForClassMethod(CodeLocation $code_location, string $referenced_member_id)
|
|
|
|
|
{
|
|
|
|
|
if (!isset(self::$class_method_locations[$referenced_member_id])) {
|
|
|
|
|
self::$class_method_locations[$referenced_member_id] = [$code_location];
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_method_locations[$referenced_member_id][] = $code_location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return void
|
2018-09-26 00:37:24 +02:00
|
|
|
|
*/
|
2019-04-13 00:28:07 +02:00
|
|
|
|
public function addCallingLocationForClassProperty(CodeLocation $code_location, string $referenced_property_id)
|
|
|
|
|
{
|
|
|
|
|
if (!isset(self::$class_property_locations[$referenced_property_id])) {
|
|
|
|
|
self::$class_property_locations[$referenced_property_id] = [$code_location];
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_property_locations[$referenced_property_id][] = $code_location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addCallingLocationForClass(CodeLocation $code_location, string $referenced_class)
|
|
|
|
|
{
|
|
|
|
|
if (!isset(self::$class_locations[$referenced_class])) {
|
|
|
|
|
self::$class_locations[$referenced_class] = [$code_location];
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_locations[$referenced_class][] = $code_location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function isClassMethodReferenced(string $method_id) : bool
|
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
return !empty(self::$file_references_to_class_members[$method_id])
|
|
|
|
|
|| !empty(self::$method_references_to_class_members[$method_id]);
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function isClassPropertyReferenced(string $property_id) : bool
|
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
return !empty(self::$file_references_to_class_members[$property_id])
|
|
|
|
|
|| !empty(self::$method_references_to_class_members[$property_id]);
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 21:38:09 +02:00
|
|
|
|
public function isClassReferenced(string $fq_class_name_lc) : bool
|
|
|
|
|
{
|
2020-04-02 23:17:55 +02:00
|
|
|
|
return isset(self::$method_references_to_classes[$fq_class_name_lc])
|
|
|
|
|
|| isset(self::$nonmethod_references_to_classes[$fq_class_name_lc]);
|
2019-04-13 21:38:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
public function isMethodParamUsed(string $method_id, int $offset) : bool
|
|
|
|
|
{
|
|
|
|
|
return !empty(self::$method_param_uses[$method_id][$offset]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-28 18:59:36 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2020-04-02 23:17:55 +02:00
|
|
|
|
public function setNonMethodReferencesToClasses(array $references)
|
2019-04-28 18:59:36 +02:00
|
|
|
|
{
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes = $references;
|
2019-04-28 18:59:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 00:28:07 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllClassMethodLocations() : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_method_locations;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllClassPropertyLocations() : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_property_locations;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<int, CodeLocation>>
|
|
|
|
|
*/
|
|
|
|
|
public function getAllClassLocations() : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_locations;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, CodeLocation>
|
|
|
|
|
*/
|
|
|
|
|
public function getClassMethodLocations(string $method_id) : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_method_locations[$method_id] ?? [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, CodeLocation>
|
|
|
|
|
*/
|
|
|
|
|
public function getClassPropertyLocations(string $property_id) : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_property_locations[$property_id] ?? [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, CodeLocation>
|
|
|
|
|
*/
|
|
|
|
|
public function getClassLocations(string $fq_class_name_lc) : array
|
|
|
|
|
{
|
|
|
|
|
return self::$class_locations[$fq_class_name_lc] ?? [];
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function addMethodReferencesToClassMembers(array $references)
|
2018-09-26 00:37:24 +02:00
|
|
|
|
{
|
2019-10-12 02:17:07 +02:00
|
|
|
|
foreach ($references as $key => $reference) {
|
|
|
|
|
if (isset(self::$method_references_to_class_members[$key])) {
|
|
|
|
|
self::$method_references_to_class_members[$key] = array_merge(
|
|
|
|
|
$reference,
|
|
|
|
|
self::$method_references_to_class_members[$key]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_references_to_class_members[$key] = $reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addMethodReferencesToClasses(array $references)
|
|
|
|
|
{
|
|
|
|
|
foreach ($references as $key => $reference) {
|
|
|
|
|
if (isset(self::$method_references_to_classes[$key])) {
|
|
|
|
|
self::$method_references_to_classes[$key] = array_merge(
|
|
|
|
|
$reference,
|
|
|
|
|
self::$method_references_to_classes[$key]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_references_to_classes[$key] = $reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addMethodReferencesToMissingClassMembers(array $references)
|
|
|
|
|
{
|
2019-10-12 02:17:07 +02:00
|
|
|
|
foreach ($references as $key => $reference) {
|
|
|
|
|
if (isset(self::$method_references_to_missing_class_members[$key])) {
|
|
|
|
|
self::$method_references_to_missing_class_members[$key] = array_merge(
|
|
|
|
|
$reference,
|
|
|
|
|
self::$method_references_to_missing_class_members[$key]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_references_to_missing_class_members[$key] = $reference;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-16 22:07:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<int, array<string, bool>>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addMethodParamUses(array $references)
|
|
|
|
|
{
|
2019-06-09 23:02:21 +02:00
|
|
|
|
foreach ($references as $method_id => $method_param_uses) {
|
|
|
|
|
if (isset(self::$method_param_uses[$method_id])) {
|
|
|
|
|
foreach ($method_param_uses as $offset => $reference_map) {
|
|
|
|
|
if (isset(self::$method_param_uses[$method_id][$offset])) {
|
|
|
|
|
self::$method_param_uses[$method_id][$offset] = array_merge(
|
|
|
|
|
self::$method_param_uses[$method_id][$offset],
|
|
|
|
|
$reference_map
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_param_uses[$method_id][$offset] = $reference_map;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
self::$method_param_uses[$method_id] = $method_param_uses;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-29 23:29:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 17:35:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setCallingMethodReferencesToClasses(array $references)
|
|
|
|
|
{
|
|
|
|
|
self::$method_references_to_classes = $references;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 22:07:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setCallingMethodReferencesToClassMembers(array $references)
|
|
|
|
|
{
|
|
|
|
|
self::$method_references_to_class_members = $references;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setCallingMethodReferencesToMissingClassMembers(array $references)
|
|
|
|
|
{
|
|
|
|
|
self::$method_references_to_missing_class_members = $references;
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-04-16 22:07:48 +02:00
|
|
|
|
* @param array<string, array<string,bool>> $references
|
2019-04-13 00:28:07 +02:00
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function setFileReferencesToClassMembers(array $references)
|
2019-04-13 00:28:07 +02:00
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
self::$file_references_to_class_members = $references;
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-04-16 22:07:48 +02:00
|
|
|
|
* @param array<string, array<string,bool>> $references
|
2019-04-13 00:28:07 +02:00
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-04-16 22:07:48 +02:00
|
|
|
|
public function setFileReferencesToMissingClassMembers(array $references)
|
2019-04-13 00:28:07 +02:00
|
|
|
|
{
|
2019-04-16 22:07:48 +02:00
|
|
|
|
self::$file_references_to_missing_class_members = $references;
|
2019-04-13 00:28:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-27 23:38:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<string,bool>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setReferencesToMixedMemberNames(array $references)
|
|
|
|
|
{
|
|
|
|
|
self::$references_to_mixed_member_names = $references;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 23:29:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<int, array<string, bool>>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setMethodParamUses(array $references)
|
|
|
|
|
{
|
|
|
|
|
self::$method_param_uses = $references;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 00:28:07 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<int, CodeLocation>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addClassMethodLocations(array $references)
|
|
|
|
|
{
|
|
|
|
|
foreach ($references as $referenced_member_id => $locations) {
|
|
|
|
|
if (isset(self::$class_method_locations[$referenced_member_id])) {
|
|
|
|
|
self::$class_method_locations[$referenced_member_id] = array_merge(
|
|
|
|
|
self::$class_method_locations[$referenced_member_id],
|
|
|
|
|
$locations
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_method_locations[$referenced_member_id] = $locations;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<int, CodeLocation>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addClassPropertyLocations(array $references)
|
|
|
|
|
{
|
|
|
|
|
foreach ($references as $referenced_member_id => $locations) {
|
|
|
|
|
if (isset(self::$class_property_locations[$referenced_member_id])) {
|
|
|
|
|
self::$class_property_locations[$referenced_member_id] = array_merge(
|
|
|
|
|
self::$class_property_locations[$referenced_member_id],
|
|
|
|
|
$locations
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_property_locations[$referenced_member_id] = $locations;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array<int, CodeLocation>> $references
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function addClassLocations(array $references)
|
|
|
|
|
{
|
|
|
|
|
foreach ($references as $referenced_member_id => $locations) {
|
|
|
|
|
if (isset(self::$class_locations[$referenced_member_id])) {
|
|
|
|
|
self::$class_locations[$referenced_member_id] = array_merge(
|
|
|
|
|
self::$class_locations[$referenced_member_id],
|
|
|
|
|
$locations
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
self::$class_locations[$referenced_member_id] = $locations;
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 22:33:59 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<int, IssueData>>
|
|
|
|
|
*/
|
2018-09-28 22:18:45 +02:00
|
|
|
|
public function getExistingIssues() : array
|
2018-09-26 22:33:59 +02:00
|
|
|
|
{
|
|
|
|
|
return self::$issues;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-09-30 05:51:06 +02:00
|
|
|
|
* @param string $file_path
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2018-09-26 22:33:59 +02:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-09-30 05:51:06 +02:00
|
|
|
|
public function clearExistingIssuesForFile($file_path)
|
2018-09-26 22:33:59 +02:00
|
|
|
|
{
|
2018-09-30 05:51:06 +02:00
|
|
|
|
unset(self::$issues[$file_path]);
|
2018-09-26 22:33:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-09-27 19:32:08 +02:00
|
|
|
|
* @param string $file_path
|
2018-10-17 21:52:26 +02:00
|
|
|
|
* @param IssueData $issue
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2018-09-26 22:33:59 +02:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-10-26 22:17:15 +02:00
|
|
|
|
public function clearExistingFileMapsForFile($file_path)
|
|
|
|
|
{
|
|
|
|
|
unset(self::$file_maps[$file_path]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $file_path
|
2019-10-01 21:44:43 +02:00
|
|
|
|
* @param IssueData $issue
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2018-10-26 22:17:15 +02:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2020-02-17 00:24:40 +01:00
|
|
|
|
public function addIssue($file_path, IssueData $issue)
|
2018-09-26 22:33:59 +02:00
|
|
|
|
{
|
2018-10-17 21:52:26 +02:00
|
|
|
|
// don’t save parse errors ever, as they're not responsive to AST diffing
|
2020-02-17 00:24:40 +01:00
|
|
|
|
if ($issue->type === 'ParseError') {
|
2018-10-17 21:52:26 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 22:33:59 +02:00
|
|
|
|
if (!isset(self::$issues[$file_path])) {
|
|
|
|
|
self::$issues[$file_path] = [$issue];
|
|
|
|
|
} else {
|
|
|
|
|
self::$issues[$file_path][] = $issue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-30 05:51:06 +02:00
|
|
|
|
/**
|
2018-11-02 02:52:39 +01:00
|
|
|
|
* @param array<string, array<string, int>> $analyzed_methods
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2018-10-07 02:11:19 +02:00
|
|
|
|
* @return void
|
2018-09-30 05:51:06 +02:00
|
|
|
|
*/
|
2018-11-02 02:52:39 +01:00
|
|
|
|
public function setAnalyzedMethods(array $analyzed_methods)
|
2018-09-30 05:51:06 +02:00
|
|
|
|
{
|
2018-11-02 02:52:39 +01:00
|
|
|
|
self::$analyzed_methods = $analyzed_methods;
|
2018-09-30 05:51:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-26 22:17:15 +02:00
|
|
|
|
/**
|
2020-05-15 06:16:20 +02:00
|
|
|
|
* @param array<string, FileMapType> $file_maps
|
2018-10-26 22:17:15 +02:00
|
|
|
|
*/
|
2019-06-21 23:10:35 +02:00
|
|
|
|
public function setFileMaps(array $file_maps) : void
|
2018-10-26 22:17:15 +02:00
|
|
|
|
{
|
|
|
|
|
self::$file_maps = $file_maps;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 14:50:47 +01:00
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array{int, int}>
|
|
|
|
|
*/
|
|
|
|
|
public function getTypeCoverage()
|
|
|
|
|
{
|
|
|
|
|
return self::$mixed_counts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, array{int, int}> $mixed_counts
|
2019-07-05 22:24:00 +02:00
|
|
|
|
*
|
2019-03-23 14:50:47 +01:00
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setTypeCoverage(array $mixed_counts)
|
|
|
|
|
{
|
|
|
|
|
self::$mixed_counts = array_merge(self::$mixed_counts, $mixed_counts);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-30 05:51:06 +02:00
|
|
|
|
/**
|
2018-10-07 04:58:21 +02:00
|
|
|
|
* @return array<string, array<string, int>>
|
2018-09-30 05:51:06 +02:00
|
|
|
|
*/
|
2018-11-02 02:52:39 +01:00
|
|
|
|
public function getAnalyzedMethods()
|
2018-09-30 05:51:06 +02:00
|
|
|
|
{
|
2018-11-02 02:52:39 +01:00
|
|
|
|
return self::$analyzed_methods;
|
2018-09-30 05:51:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-26 22:17:15 +02:00
|
|
|
|
/**
|
2020-05-15 06:16:20 +02:00
|
|
|
|
* @return array<string, FileMapType>
|
2018-10-26 22:17:15 +02:00
|
|
|
|
*/
|
|
|
|
|
public function getFileMaps()
|
|
|
|
|
{
|
|
|
|
|
return self::$file_maps;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 00:37:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public static function clearCache()
|
|
|
|
|
{
|
|
|
|
|
self::$files_inheriting_classes = [];
|
|
|
|
|
self::$deleted_files = null;
|
|
|
|
|
self::$file_references = [];
|
2019-04-16 22:07:48 +02:00
|
|
|
|
self::$file_references_to_class_members = [];
|
|
|
|
|
self::$method_references_to_class_members = [];
|
2020-03-26 17:35:27 +01:00
|
|
|
|
self::$method_references_to_classes = [];
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$nonmethod_references_to_classes = [];
|
2019-04-16 22:07:48 +02:00
|
|
|
|
self::$file_references_to_missing_class_members = [];
|
|
|
|
|
self::$method_references_to_missing_class_members = [];
|
2019-04-27 23:38:24 +02:00
|
|
|
|
self::$references_to_mixed_member_names = [];
|
2019-04-13 00:28:07 +02:00
|
|
|
|
self::$class_method_locations = [];
|
|
|
|
|
self::$class_property_locations = [];
|
2020-08-23 16:32:07 +02:00
|
|
|
|
self::$class_locations = [];
|
2018-11-02 02:52:39 +01:00
|
|
|
|
self::$analyzed_methods = [];
|
2018-09-26 22:33:59 +02:00
|
|
|
|
self::$issues = [];
|
2018-10-26 22:17:15 +02:00
|
|
|
|
self::$file_maps = [];
|
2019-04-29 23:29:38 +02:00
|
|
|
|
self::$method_param_uses = [];
|
2020-04-02 23:17:55 +02:00
|
|
|
|
self::$classlike_files = [];
|
2020-08-23 16:32:07 +02:00
|
|
|
|
self::$mixed_counts = [];
|
2018-09-26 00:37:24 +02:00
|
|
|
|
}
|
2017-02-18 19:41:27 +01:00
|
|
|
|
}
|