1
0
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:
Matthew Brown 2019-04-13 15:38:09 -04:00
parent d377bbde2b
commit d145f17782
7 changed files with 88 additions and 74 deletions

View File

@ -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',

View File

@ -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;

View File

@ -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)) {

View File

@ -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);
}
}

View File

@ -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>,

View File

@ -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>>
*/

View File

@ -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'])) {