mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Fix #1548 - allow parallel execution with --find-dead-code
This commit is contained in:
parent
d377bbde2b
commit
d145f17782
@ -1079,6 +1079,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
$previous_context_include_location = $class_context->include_location;
|
||||
|
||||
foreach ($stmt->traits as $trait_name) {
|
||||
$trait_location = new CodeLocation($this, $trait_name, null, true);
|
||||
$class_context->include_location = new CodeLocation($this, $trait_name, null, true);
|
||||
|
||||
$fq_trait_name = self::getFQCLNFromNameObject(
|
||||
@ -1086,7 +1087,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
$aliases
|
||||
);
|
||||
|
||||
if (!$codebase->classlikes->hasFullyQualifiedTraitName($fq_trait_name)) {
|
||||
if (!$codebase->classlikes->hasFullyQualifiedTraitName($fq_trait_name, $trait_location)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UndefinedTrait(
|
||||
'Trait ' . $fq_trait_name . ' does not exist',
|
||||
|
@ -231,11 +231,17 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_exists = $codebase->classExists($fq_class_name);
|
||||
$interface_exists = $codebase->interfaceExists($fq_class_name);
|
||||
$class_exists = $codebase->classlikes->classExists(
|
||||
$fq_class_name,
|
||||
!$inferred ? $code_location : null
|
||||
);
|
||||
$interface_exists = $codebase->classlikes->interfaceExists(
|
||||
$fq_class_name,
|
||||
!$inferred ? $code_location : null
|
||||
);
|
||||
|
||||
if (!$class_exists && !$interface_exists) {
|
||||
if (!$allow_trait || !$codebase->classlikes->traitExists($fq_class_name)) {
|
||||
if (!$allow_trait || !$codebase->classlikes->traitExists($fq_class_name, $code_location)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UndefinedClass(
|
||||
'Class or interface ' . $fq_class_name . ' does not exist',
|
||||
@ -290,13 +296,6 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou
|
||||
}
|
||||
}
|
||||
|
||||
if ($codebase->collect_locations && !$inferred) {
|
||||
$codebase->file_reference_provider->addCallingLocationForClass(
|
||||
$code_location,
|
||||
$aliased_name_lc
|
||||
);
|
||||
}
|
||||
|
||||
if (($class_exists && !$codebase->classHasCorrectCasing($fq_class_name)) ||
|
||||
($interface_exists && !$codebase->interfaceHasCorrectCasing($fq_class_name))
|
||||
) {
|
||||
@ -314,11 +313,6 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou
|
||||
}
|
||||
}
|
||||
|
||||
$codebase->file_reference_provider->addFileReferenceToClass(
|
||||
$code_location->file_path,
|
||||
$aliased_name_lc
|
||||
);
|
||||
|
||||
if (!$inferred) {
|
||||
$plugin_classes = $codebase->config->after_classlike_exists_checks;
|
||||
|
||||
|
@ -41,7 +41,12 @@ use Psalm\Internal\Provider\FileStorageProvider;
|
||||
* file_maps: array<
|
||||
* string,
|
||||
* array{0: TaggedCodeType, 1: TaggedCodeType}
|
||||
* >
|
||||
* >,
|
||||
* class_locations: array<string, array<int, \Psalm\CodeLocation>>,
|
||||
* class_method_locations: array<string, array<int, \Psalm\CodeLocation>>,
|
||||
* class_property_locations: array<string, array<int, \Psalm\CodeLocation>>,
|
||||
* class_method_references: array<string, bool>,
|
||||
* class_property_references: array<string, bool>
|
||||
* }
|
||||
*/
|
||||
|
||||
@ -236,6 +241,11 @@ class Analyzer
|
||||
'mixed_counts' => $analyzer->getMixedCounts(),
|
||||
'analyzed_methods' => $analyzer->getAnalyzedMethods(),
|
||||
'file_maps' => $analyzer->getFileMaps(),
|
||||
'class_locations' => $file_reference_provider->getAllClassLocations(),
|
||||
'class_method_locations' => $file_reference_provider->getAllClassMethodLocations(),
|
||||
'class_property_locations' => $file_reference_provider->getAllClassPropertyLocations(),
|
||||
'class_method_references' => $file_reference_provider->getAllClassMethodReferences(),
|
||||
'class_property_references' => $file_reference_provider->getAllClassPropertyReferences(),
|
||||
];
|
||||
}
|
||||
);
|
||||
@ -259,6 +269,22 @@ class Analyzer
|
||||
$codebase->file_reference_provider->addCallingMethodReferencesToClassMember(
|
||||
$pool_data['member_references']
|
||||
);
|
||||
$codebase->file_reference_provider->addClassLocations(
|
||||
$pool_data['class_locations']
|
||||
);
|
||||
$codebase->file_reference_provider->addClassMethodLocations(
|
||||
$pool_data['class_method_locations']
|
||||
);
|
||||
$codebase->file_reference_provider->addClassPropertyLocations(
|
||||
$pool_data['class_property_locations']
|
||||
);
|
||||
$codebase->file_reference_provider->addClassMethodReferences(
|
||||
$pool_data['class_method_references']
|
||||
);
|
||||
$codebase->file_reference_provider->addClassPropertyReferences(
|
||||
$pool_data['class_property_references']
|
||||
);
|
||||
|
||||
$this->analyzed_methods = array_merge($pool_data['analyzed_methods'], $this->analyzed_methods);
|
||||
|
||||
foreach ($pool_data['mixed_counts'] as $file_path => list($mixed_count, $nonmixed_count)) {
|
||||
|
@ -82,11 +82,6 @@ class ClassLikes
|
||||
*/
|
||||
private $trait_aliases = [];
|
||||
|
||||
/**
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private $classlike_references = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
@ -252,7 +247,7 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFullyQualifiedClassName($fq_class_name)
|
||||
public function hasFullyQualifiedClassName($fq_class_name, CodeLocation $code_location = null)
|
||||
{
|
||||
$fq_class_name_lc = strtolower($fq_class_name);
|
||||
|
||||
@ -282,12 +277,18 @@ class ClassLikes
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->collect_references) {
|
||||
if (!isset($this->classlike_references[$fq_class_name_lc])) {
|
||||
$this->classlike_references[$fq_class_name_lc] = 0;
|
||||
if ($this->collect_references && $code_location) {
|
||||
$this->file_reference_provider->addFileReferenceToClass(
|
||||
$code_location->file_path,
|
||||
$fq_class_name_lc
|
||||
);
|
||||
}
|
||||
|
||||
++$this->classlike_references[$fq_class_name_lc];
|
||||
if ($this->collect_locations && $code_location) {
|
||||
$this->file_reference_provider->addCallingLocationForClass(
|
||||
$code_location,
|
||||
strtolower($fq_class_name)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -298,7 +299,7 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFullyQualifiedInterfaceName($fq_class_name)
|
||||
public function hasFullyQualifiedInterfaceName($fq_class_name, CodeLocation $code_location = null)
|
||||
{
|
||||
$fq_class_name_lc = strtolower($fq_class_name);
|
||||
|
||||
@ -328,12 +329,18 @@ class ClassLikes
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->collect_references) {
|
||||
if (!isset($this->classlike_references[$fq_class_name_lc])) {
|
||||
$this->classlike_references[$fq_class_name_lc] = 0;
|
||||
if ($this->collect_references && $code_location) {
|
||||
$this->file_reference_provider->addFileReferenceToClass(
|
||||
$code_location->file_path,
|
||||
$fq_class_name_lc
|
||||
);
|
||||
}
|
||||
|
||||
++$this->classlike_references[$fq_class_name_lc];
|
||||
if ($this->collect_locations && $code_location) {
|
||||
$this->file_reference_provider->addCallingLocationForClass(
|
||||
$code_location,
|
||||
strtolower($fq_class_name)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -344,7 +351,7 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFullyQualifiedTraitName($fq_class_name)
|
||||
public function hasFullyQualifiedTraitName($fq_class_name, CodeLocation $code_location = null)
|
||||
{
|
||||
$fq_class_name_lc = strtolower($fq_class_name);
|
||||
|
||||
@ -358,12 +365,11 @@ class ClassLikes
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->collect_references) {
|
||||
if (!isset($this->classlike_references[$fq_class_name_lc])) {
|
||||
$this->classlike_references[$fq_class_name_lc] = 0;
|
||||
}
|
||||
|
||||
++$this->classlike_references[$fq_class_name_lc];
|
||||
if ($this->collect_references && $code_location) {
|
||||
$this->file_reference_provider->addFileReferenceToClass(
|
||||
$code_location->file_path,
|
||||
$fq_class_name_lc
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -381,17 +387,12 @@ class ClassLikes
|
||||
$fq_class_name,
|
||||
CodeLocation $code_location = null
|
||||
) {
|
||||
if (!$this->classExists($fq_class_name) && !$this->interfaceExists($fq_class_name)) {
|
||||
if (!$this->classExists($fq_class_name, $code_location)
|
||||
&& !$this->interfaceExists($fq_class_name, $code_location)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->collect_locations && $code_location) {
|
||||
$this->file_reference_provider->addCallingLocationForClass(
|
||||
$code_location,
|
||||
strtolower($fq_class_name)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -402,7 +403,7 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function classExists($fq_class_name)
|
||||
public function classExists($fq_class_name, CodeLocation $code_location = null)
|
||||
{
|
||||
if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[$fq_class_name])) {
|
||||
return false;
|
||||
@ -412,7 +413,7 @@ class ClassLikes
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasFullyQualifiedClassName($fq_class_name);
|
||||
return $this->hasFullyQualifiedClassName($fq_class_name, $code_location);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -490,13 +491,13 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function interfaceExists($fq_interface_name)
|
||||
public function interfaceExists($fq_interface_name, CodeLocation $code_location = null)
|
||||
{
|
||||
if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[strtolower($fq_interface_name)])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->hasFullyQualifiedInterfaceName($fq_interface_name);
|
||||
return $this->hasFullyQualifiedInterfaceName($fq_interface_name, $code_location);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -529,9 +530,9 @@ class ClassLikes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function traitExists($fq_trait_name)
|
||||
public function traitExists($fq_trait_name, CodeLocation $code_location = null)
|
||||
{
|
||||
return $this->hasFullyQualifiedTraitName($fq_trait_name);
|
||||
return $this->hasFullyQualifiedTraitName($fq_trait_name, $code_location);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -676,7 +677,7 @@ class ClassLikes
|
||||
&& $this->config->isInProjectDirs($classlike_storage->location->file_path)
|
||||
&& !$classlike_storage->is_trait
|
||||
) {
|
||||
if (!isset($this->classlike_references[$fq_class_name_lc])) {
|
||||
if (!$this->file_reference_provider->isClassReferenced($fq_class_name_lc)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UnusedClass(
|
||||
'Class ' . $classlike_storage->name . ' is never used',
|
||||
@ -969,8 +970,7 @@ class ClassLikes
|
||||
$this->existing_interfaces[$fq_class_name],
|
||||
$this->existing_classes[$fq_class_name],
|
||||
$this->trait_nodes[$fq_class_name_lc],
|
||||
$this->trait_aliases[$fq_class_name_lc],
|
||||
$this->classlike_references[$fq_class_name_lc]
|
||||
$this->trait_aliases[$fq_class_name_lc]
|
||||
);
|
||||
|
||||
$this->scanner->removeClassLike($fq_class_name_lc);
|
||||
@ -986,8 +986,7 @@ class ClassLikes
|
||||
* 5: array<string, bool>,
|
||||
* 6: array<string, bool>,
|
||||
* 7: array<string, \PhpParser\Node\Stmt\Trait_>,
|
||||
* 8: array<string, \Psalm\Aliases>,
|
||||
* 9: array<string, int>
|
||||
* 8: array<string, \Psalm\Aliases>
|
||||
* }
|
||||
*/
|
||||
public function getThreadData()
|
||||
@ -1002,7 +1001,6 @@ class ClassLikes
|
||||
$this->existing_classes,
|
||||
$this->trait_nodes,
|
||||
$this->trait_aliases,
|
||||
$this->classlike_references
|
||||
];
|
||||
}
|
||||
|
||||
@ -1016,8 +1014,7 @@ class ClassLikes
|
||||
* 5: array<string, bool>,
|
||||
* 6: array<string, bool>,
|
||||
* 7: array<string, \PhpParser\Node\Stmt\Trait_>,
|
||||
* 8: array<string, \Psalm\Aliases>,
|
||||
* 9: array<string, int>
|
||||
* 8: array<string, \Psalm\Aliases>
|
||||
* } $thread_data
|
||||
*
|
||||
* @return void
|
||||
@ -1034,7 +1031,6 @@ class ClassLikes
|
||||
$existing_classes,
|
||||
$trait_nodes,
|
||||
$trait_aliases,
|
||||
$classlike_references
|
||||
) = $thread_data;
|
||||
|
||||
$this->existing_classlikes_lc = array_merge($existing_classlikes_lc, $this->existing_classlikes_lc);
|
||||
@ -1046,6 +1042,5 @@ class ClassLikes
|
||||
$this->existing_classes = array_merge($existing_classes, $this->existing_classes);
|
||||
$this->trait_nodes = array_merge($trait_nodes, $this->trait_nodes);
|
||||
$this->trait_aliases = array_merge($trait_aliases, $this->trait_aliases);
|
||||
$this->classlike_references = array_merge($classlike_references, $this->classlike_references);
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,7 @@ use Psalm\Internal\Scanner\FileScanner;
|
||||
* 5:array<string, bool>,
|
||||
* 6:array<string, bool>,
|
||||
* 7:array<string, \PhpParser\Node\Stmt\Trait_>,
|
||||
* 8:array<string, \Psalm\Aliases>,
|
||||
* 9:array<string, int>
|
||||
* 8:array<string, \Psalm\Aliases>
|
||||
* },
|
||||
* scanner_data:array{
|
||||
* 0:array<string, string>,
|
||||
|
@ -469,6 +469,11 @@ class FileReferenceProvider
|
||||
return isset(self::$class_property_references[$property_id]);
|
||||
}
|
||||
|
||||
public function isClassReferenced(string $fq_class_name_lc) : bool
|
||||
{
|
||||
return isset(self::$file_references_to_class[$fq_class_name_lc]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<int, CodeLocation>>
|
||||
*/
|
||||
|
@ -578,13 +578,7 @@ if ($paths_to_check === null) {
|
||||
if ($find_references_to) {
|
||||
$project_analyzer->findReferencesTo($find_references_to);
|
||||
} elseif (($find_unused_code === 'always') || ($find_unused_code === 'auto' && !$paths_to_check && !$is_diff)) {
|
||||
if ($threads > 1) {
|
||||
if ($output_format === ProjectAnalyzer::TYPE_CONSOLE) {
|
||||
echo 'Unused classes and methods cannot currently be found in multithreaded mode' . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
$project_analyzer->checkClassReferences();
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['set-baseline']) && is_string($options['set-baseline'])) {
|
||||
|
Loading…
Reference in New Issue
Block a user