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

Fix trait method aliasing

This commit is contained in:
Matthew Brown 2018-03-21 16:55:31 -04:00
parent cb15f48406
commit 49c4dd8a5d
3 changed files with 96 additions and 31 deletions

View File

@ -275,13 +275,26 @@ class MethodCallChecker extends \Psalm\Checker\Statements\Expression\CallChecker
}
}
if ($var_id === '$this' &&
$context->self &&
$fq_class_name !== $context->self &&
$codebase->methodExists($context->self . '::' . $method_name_lc)
) {
$method_id = $context->self . '::' . $method_name_lc;
$fq_class_name = $context->self;
$source_source = $statements_checker->getSource();
/**
* @var \Psalm\Checker\ClassLikeChecker|null
*/
$classlike_source = $source_source->getSource();
$classlike_source_fqcln = $classlike_source ? $classlike_source->getFQCLN() : null;
if ($var_id === '$this' && $context->self && $classlike_source_fqcln) {
if ($fq_class_name !== $context->self
&& $codebase->methodExists($context->self . '::' . $method_name_lc)
) {
$method_id = $context->self . '::' . $method_name_lc;
$fq_class_name = $context->self;
} elseif ($classlike_source instanceof \Psalm\Checker\TraitChecker
&& $codebase->methodExists($classlike_source_fqcln . '::' . $method_name_lc)
) {
$method_id = $classlike_source_fqcln . '::' . $method_name_lc;
$fq_class_name = $classlike_source_fqcln;
}
}
if ($intersection_types && !$codebase->methodExists($method_id)) {

View File

@ -460,23 +460,25 @@ class Populator
// register where they appear (can never be in a trait)
foreach ($parent_storage->appearing_method_ids as $method_name => $appearing_method_id) {
$aliased_method_names = [$method_name];
if ($parent_storage->is_trait
&& $storage->trait_alias_map
&& isset($storage->trait_alias_map[$method_name])
) {
$aliased_method_name = $storage->trait_alias_map[$method_name];
} else {
$aliased_method_name = $method_name;
$aliased_method_names[] = $storage->trait_alias_map[$method_name];
}
if (isset($storage->appearing_method_ids[$aliased_method_name])) {
continue;
foreach ($aliased_method_names as $aliased_method_name) {
if (isset($storage->appearing_method_ids[$aliased_method_name])) {
continue;
}
$implemented_method_id = $fq_class_name . '::' . $aliased_method_name;
$storage->appearing_method_ids[$aliased_method_name] =
$parent_storage->is_trait ? $implemented_method_id : $appearing_method_id;
}
$implemented_method_id = $fq_class_name . '::' . $aliased_method_name;
$storage->appearing_method_ids[$aliased_method_name] =
$parent_storage->is_trait ? $implemented_method_id : $appearing_method_id;
}
// register where they're declared
@ -485,30 +487,32 @@ class Populator
$storage->overridden_method_ids[$method_name][] = $declaring_method_id;
}
$aliased_method_names = [$method_name];
if ($parent_storage->is_trait
&& $storage->trait_alias_map
&& isset($storage->trait_alias_map[$method_name])
) {
$aliased_method_name = $storage->trait_alias_map[$method_name];
} else {
$aliased_method_name = $method_name;
$aliased_method_names[] = $storage->trait_alias_map[$method_name];
}
if (isset($storage->declaring_method_ids[$aliased_method_name])) {
list($implementing_fq_class_name, $implementing_method_name) = explode(
'::',
$storage->declaring_method_ids[$aliased_method_name]
);
foreach ($aliased_method_names as $aliased_method_name) {
if (isset($storage->declaring_method_ids[$aliased_method_name])) {
list($implementing_fq_class_name, $implementing_method_name) = explode(
'::',
$storage->declaring_method_ids[$aliased_method_name]
);
$implementing_class_storage = $this->classlike_storage_provider->get($implementing_fq_class_name);
$implementing_class_storage = $this->classlike_storage_provider->get($implementing_fq_class_name);
if (!$implementing_class_storage->methods[$implementing_method_name]->abstract) {
continue;
if (!$implementing_class_storage->methods[$implementing_method_name]->abstract) {
continue;
}
}
}
$storage->declaring_method_ids[$aliased_method_name] = $declaring_method_id;
$storage->inheritable_method_ids[$aliased_method_name] = $declaring_method_id;
$storage->declaring_method_ids[$aliased_method_name] = $declaring_method_id;
$storage->inheritable_method_ids[$aliased_method_name] = $declaring_method_id;
}
}
}

View File

@ -450,6 +450,54 @@ class TraitTest extends TestCase
}
}',
],
'aliasedMethodInternalCallNoReplacement' => [
'<?php
trait T {
public function foo() : int {
return $this->bar();
}
public function bar() : int {
return 3;
}
}
class A {
use T {
bar as bat;
}
public function baz() : int {
return $this->bar();
}
}',
],
'aliasedMethodInternalCallWithLocalDefinition' => [
'<?php
trait T {
public function foo() : int {
return $this->bar();
}
public function bar() : int {
return 3;
}
}
class A {
use T {
bar as bat;
}
public function bar() : string {
return "hello";
}
public function baz() : string {
return $this->bar();
}
}',
],
];
}