Skip to content

Commit

Permalink
Fix #1548 - allow parallel execution with --find-dead-code
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Apr 13, 2019
1 parent d377bbd commit d145f17
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 74 deletions.
3 changes: 2 additions & 1 deletion src/Psalm/Internal/Analyzer/ClassAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -1079,14 +1079,15 @@ private function analyzeTraitUse(
$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(
$trait_name,
$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',
Expand Down
24 changes: 9 additions & 15 deletions src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,17 @@ public static function checkFullyQualifiedClassLikeName(
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',
Expand Down Expand Up @@ -290,13 +296,6 @@ public static function checkFullyQualifiedClassLikeName(
}
}

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))
) {
Expand All @@ -314,11 +313,6 @@ public static function checkFullyQualifiedClassLikeName(
}
}

$codebase->file_reference_provider->addFileReferenceToClass(
$code_location->file_path,
$aliased_name_lc
);

if (!$inferred) {
$plugin_classes = $codebase->config->after_classlike_exists_checks;

Expand Down
28 changes: 27 additions & 1 deletion src/Psalm/Internal/Codebase/Analyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@
* 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>
* }
*/

Expand Down Expand Up @@ -236,6 +241,11 @@ function () {
'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(),
];
}
);
Expand All @@ -259,6 +269,22 @@ function () {
$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)) {
Expand Down
91 changes: 43 additions & 48 deletions src/Psalm/Internal/Codebase/ClassLikes.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ class ClassLikes
*/
private $trait_aliases = [];

/**
* @var array<string, int>
*/
private $classlike_references = [];

/**
* @var array<string, string>
*/
Expand Down Expand Up @@ -252,7 +247,7 @@ public function hasFullyQualifiedClassLikeName($fq_class_name_lc)
*
* @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);

Expand Down Expand Up @@ -282,12 +277,18 @@ public function hasFullyQualifiedClassName($fq_class_name)
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;
Expand All @@ -298,7 +299,7 @@ public function hasFullyQualifiedClassName($fq_class_name)
*
* @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);

Expand Down Expand Up @@ -328,12 +329,18 @@ public function hasFullyQualifiedInterfaceName($fq_class_name)
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;
Expand All @@ -344,7 +351,7 @@ public function hasFullyQualifiedInterfaceName($fq_class_name)
*
* @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);

Expand All @@ -358,12 +365,11 @@ public function hasFullyQualifiedTraitName($fq_class_name)
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;
Expand All @@ -381,17 +387,12 @@ public function classOrInterfaceExists(
$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;
}

Expand All @@ -402,7 +403,7 @@ public function classOrInterfaceExists(
*
* @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;
Expand All @@ -412,7 +413,7 @@ public function classExists($fq_class_name)
return true;
}

return $this->hasFullyQualifiedClassName($fq_class_name);
return $this->hasFullyQualifiedClassName($fq_class_name, $code_location);
}

/**
Expand Down Expand Up @@ -490,13 +491,13 @@ public function classImplements($fq_class_name, $interface)
*
* @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);
}

/**
Expand Down Expand Up @@ -529,9 +530,9 @@ public function getParentInterfaces($fq_interface_name)
*
* @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);
}

/**
Expand Down Expand Up @@ -676,7 +677,7 @@ public function checkClassReferences(Methods $methods)
&& $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',
Expand Down Expand Up @@ -969,8 +970,7 @@ public function removeClassLike($fq_class_name)
$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);
Expand All @@ -986,8 +986,7 @@ public function removeClassLike($fq_class_name)
* 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()
Expand All @@ -1002,7 +1001,6 @@ public function getThreadData()
$this->existing_classes,
$this->trait_nodes,
$this->trait_aliases,
$this->classlike_references
];
}

Expand All @@ -1016,8 +1014,7 @@ public function getThreadData()
* 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
Expand All @@ -1034,7 +1031,6 @@ public function addThreadData(array $thread_data)
$existing_classes,
$trait_nodes,
$trait_aliases,
$classlike_references
) = $thread_data;

$this->existing_classlikes_lc = array_merge($existing_classlikes_lc, $this->existing_classlikes_lc);
Expand All @@ -1046,6 +1042,5 @@ public function addThreadData(array $thread_data)
$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);
}
}
3 changes: 1 addition & 2 deletions src/Psalm/Internal/Codebase/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
* 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>,
Expand Down
5 changes: 5 additions & 0 deletions src/Psalm/Internal/Provider/FileReferenceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,11 @@ public function isClassPropertyReferenced(string $property_id) : bool
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>>
*/
Expand Down
8 changes: 1 addition & 7 deletions src/psalm.php
Original file line number Diff line number Diff line change
Expand Up @@ -578,13 +578,7 @@ function ($arg) {
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();
}
$project_analyzer->checkClassReferences();
}

if (isset($options['set-baseline']) && is_string($options['set-baseline'])) {
Expand Down

0 comments on commit d145f17

Please sign in to comment.