1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix #416 - make sure trait methods are treated better by dead code detection

This commit is contained in:
Matthew Brown 2018-06-09 23:10:42 -04:00
parent 04cc920101
commit d47980df13
3 changed files with 79 additions and 19 deletions

View File

@ -77,8 +77,6 @@
<PossiblyUnusedMethod>
<errorLevel type="suppress">
<directory name="tests" />
<file name="src/Psalm/Type/Atomic/CallableTrait.php" />
<file name="src/Psalm/Type/Atomic/GenericTrait.php" />
<file name="src/Psalm/Plugin.php" />
<referencedMethod name="Psalm\Codebase::getParentInterfaces" />
<referencedMethod name="Psalm\Codebase::getMethodParams" />

View File

@ -628,9 +628,10 @@ class ClassLikes
continue;
}
if ($classlike_storage->location &&
$this->config &&
$this->config->isInProjectDirs($classlike_storage->location->file_path)
if ($classlike_storage->location
&& $this->config
&& $this->config->isInProjectDirs($classlike_storage->location->file_path)
&& !$classlike_storage->is_trait
) {
if (!isset($this->classlike_references[$fq_class_name_lc])) {
if (IssueBuffer::accepts(
@ -712,7 +713,29 @@ class ClassLikes
*/
private function checkMethodReferences(ClassLikeStorage $classlike_storage)
{
foreach ($classlike_storage->methods as $method_name => $method_storage) {
foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) {
list($appearing_fq_classlike_name) = explode('::', $appearing_method_id);
if ($appearing_fq_classlike_name !== $classlike_storage->name) {
continue;
}
if (isset($classlike_storage->methods[$method_name])) {
$method_storage = $classlike_storage->methods[$method_name];
} else {
$declaring_method_id = $classlike_storage->declaring_method_ids[$method_name];
list($declaring_fq_classlike_name) = explode('::', $declaring_method_id);
try {
$declaring_classlike_storage = $this->classlike_storage_provider->get($declaring_fq_classlike_name);
} catch (\InvalidArgumentException $e) {
continue;
}
$method_storage = $declaring_classlike_storage->methods[$method_name];
}
if (($method_storage->referencing_locations === null
|| count($method_storage->referencing_locations) === 0)
&& (substr($method_name, 0, 2) !== '__' || $method_name === '__construct')
@ -727,6 +750,7 @@ class ClassLikes
$has_parent_references = false;
if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) {
foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) {
$parent_method_storage = $this->methods->getStorage($parent_method_id);
@ -735,6 +759,7 @@ class ClassLikes
break;
}
}
}
foreach ($classlike_storage->class_implements as $fq_interface_name) {
$interface_storage = $this->classlike_storage_provider->get($fq_interface_name);
@ -777,6 +802,7 @@ class ClassLikes
$method_name_lc = strtolower($method_name);
if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) {
foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) {
$parent_method_storage = $this->methods->getStorage($parent_method_id);
@ -787,6 +813,7 @@ class ClassLikes
break;
}
}
}
if (!$has_parent_references && !isset($method_storage->used_params[$offset])) {
if (IssueBuffer::accepts(

View File

@ -229,7 +229,7 @@ class UnusedCodeTest extends TestCase
$m->modifyFoo("value2");
echo $m->getFoo();',
],
'usedTraitMethod' => [
'usedTraitMethodWithExplicitCall' => [
'<?php
class A {
public function foo(): void {
@ -717,6 +717,22 @@ class UnusedCodeTest extends TestCase
class A { }
new A();',
],
'usedTraitMethodWithImplicitCall' => [
'<?php
class A {
public function foo() : void {}
}
trait T {
public function foo() : void {}
}
class B extends A {
use T;
}
function takesA(A $a) : void {
$a->foo();
}
takesA(new B);'
],
];
}
@ -1067,6 +1083,25 @@ class UnusedCodeTest extends TestCase
}',
'error_message' => 'UnevaluatedCode',
],
'unusedTraitMethodInParent' => [
'<?php
class A {
public function foo() : void {}
}
trait T {
public function foo() : void {}
public function bar() : void {}
}
class B extends A {
use T;
}
function takesA(A $a) : void {
$a->foo();
}
takesA(new B);',
'error_message' => 'PossiblyUnusedMethod',
],
];
}
}