1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #3897 - support aliasing final methods

This commit is contained in:
Brown 2020-07-26 14:46:52 -04:00
parent eddd7b8c11
commit 23f5d66516
3 changed files with 67 additions and 3 deletions

View File

@ -45,7 +45,7 @@ class CallAnalyzer
*/
public static function collectSpecialInformation(
FunctionLikeAnalyzer $source,
$method_name,
string $method_name,
Context $context
) {
$fq_class_name = (string)$source->getFQCLN();
@ -167,11 +167,27 @@ class CallAnalyzer
$class_analyzer = $source->getSource();
$is_final = $method_storage->final;
if ($method_name !== $declaring_method_id->method_name) {
$appearing_method_id = $codebase->methods->getAppearingMethodId($method_id);
if ($appearing_method_id) {
$appearing_class_storage = $codebase->classlike_storage_provider->get(
$appearing_method_id->fq_class_name
);
if (isset($appearing_class_storage->trait_final_map[strtolower($method_name)])) {
$is_final = true;
}
}
}
if ($class_analyzer instanceof ClassLikeAnalyzer
&& !$method_storage->is_static
&& ($context->collect_nonprivate_initializations
|| $method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE
|| $method_storage->final)
|| $is_final)
) {
$local_vars_in_scope = [];
$local_vars_possibly_in_scope = [];
@ -191,7 +207,7 @@ class CallAnalyzer
$old_calling_method_id = $context->calling_method_id;
if ($fq_class_name === $source->getFQCLN()) {
$class_analyzer->getMethodMutations(strtolower($method_name), $context);
$class_analyzer->getMethodMutations(strtolower($declaring_method_id->method_name), $context);
} else {
$declaring_fq_class_name = $declaring_method_id->fq_class_name;

View File

@ -373,6 +373,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$method_map = $storage->trait_alias_map ?: [];
$visibility_map = $storage->trait_visibility_map ?: [];
$final_map = $storage->trait_visibility_map ?: [];
foreach ($node->adaptations as $adaptation) {
if ($adaptation instanceof PhpParser\Node\Stmt\TraitUseAdaptation\Alias) {
@ -400,6 +401,14 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
case 4:
$visibility_map[$new_name] = ClassLikeAnalyzer::VISIBILITY_PRIVATE;
break;
case 4:
$visibility_map[$new_name] = ClassLikeAnalyzer::VISIBILITY_PRIVATE;
break;
case 32:
$final_map[$new_name] = true;
break;
}
}
}
@ -407,6 +416,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->trait_alias_map = $method_map;
$storage->trait_visibility_map = $visibility_map;
$storage->trait_final_map = $final_map;
foreach ($node->traits as $trait) {
$trait_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($trait, $this->aliases);

View File

@ -1985,6 +1985,44 @@ class PropertyTypeTest extends TestCase
}
}'
],
'aliasedFinalMethod' => [
'<?php
trait A {
private int $prop;
public final function setProp(int $prop): void {
$this->prop = $prop;
}
}
class B {
use A {
setProp as setPropFinal;
}
public function __construct() {
$this->setPropFinal(1);
}
}'
],
'aliasedAsFinalMethod' => [
'<?php
trait A {
private int $prop;
public function setProp(int $prop): void {
$this->prop = $prop;
}
}
class B {
use A {
setProp as final setPropFinal;
}
public function __construct() {
$this->setPropFinal(1);
}
}'
],
];
}