diff --git a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index 84ae09bc0..281710737 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -359,19 +359,16 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements ); } - if ($function_param->type) { - if ($function_param->type_location) { - if ($function_param->type->check( - $this, - $function_param->type_location, - $storage->suppressed_issues, - [], - false - ) === false) { - $check_stmts = false; - } - } + if ($signature_type) { + $signature_type = ExpressionAnalyzer::fleshOutType( + $codebase, + $signature_type, + $context->self, + $context->self + ); + } + if ($function_param->type) { $is_signature_type = $function_param->type === $function_param->signature_type; if ($is_signature_type @@ -390,6 +387,18 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements $context->self, $context->self ); + + if ($function_param->type_location) { + if ($param_type->check( + $this, + $function_param->type_location, + $storage->suppressed_issues, + [], + false + ) === false) { + $check_stmts = false; + } + } } else { if (!$non_null_param_types && isset($implemented_docblock_param_types[$offset])) { $param_type = clone $implemented_docblock_param_types[$offset]; diff --git a/src/Psalm/Internal/Analyzer/MethodAnalyzer.php b/src/Psalm/Internal/Analyzer/MethodAnalyzer.php index 066ad3f7c..59a8af41c 100644 --- a/src/Psalm/Internal/Analyzer/MethodAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/MethodAnalyzer.php @@ -727,22 +727,42 @@ class MethodAnalyzer extends FunctionLikeAnalyzer if ($prevent_method_signature_mismatch && $guide_classlike_storage->user_defined && $implementer_param->signature_type - && !TypeAnalyzer::isContainedByInPhp($guide_param->signature_type, $implementer_param->signature_type) ) { - if (IssueBuffer::accepts( - new MethodSignatureMismatch( - 'Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . - $implementer_param->signature_type . '\', expecting \'' . - $guide_param->signature_type . '\' as defined by ' . - $cased_guide_method_id, - $implementer_method_storage->params[$i]->location - ?: $code_location + $guide_param_signature_type = $guide_param->signature_type + ? ExpressionAnalyzer::fleshOutType( + $codebase, + $guide_param->signature_type, + $guide_classlike_storage->name, + $guide_classlike_storage->name ) - )) { - return false; - } + : null; - return null; + $implementer_param_signature_type = ExpressionAnalyzer::fleshOutType( + $codebase, + $implementer_param->signature_type, + $implementer_classlike_storage->name, + $implementer_classlike_storage->name + ); + + if (!TypeAnalyzer::isContainedByInPhp( + $guide_param_signature_type, + $implementer_param_signature_type + )) { + if (IssueBuffer::accepts( + new MethodSignatureMismatch( + 'Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . + $implementer_param_signature_type . '\', expecting \'' . + $guide_param_signature_type . '\' as defined by ' . + $cased_guide_method_id, + $implementer_method_storage->params[$i]->location + ?: $code_location + ) + )) { + return false; + } + + return null; + } } if ($guide_classlike_storage->user_defined diff --git a/src/Psalm/Internal/Visitor/ReflectorVisitor.php b/src/Psalm/Internal/Visitor/ReflectorVisitor.php index 1f1e06ab6..93a7a0f1c 100644 --- a/src/Psalm/Internal/Visitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/Visitor/ReflectorVisitor.php @@ -2139,10 +2139,15 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse } elseif ($param_typehint instanceof PhpParser\Node\Name\FullyQualified) { $param_type_string = (string)$param_typehint; $this->codebase->scanner->queueClassLikeForScanning($param_type_string, $this->file_path); - } elseif (strtolower($param_typehint->parts[0]) === 'self') { - $param_type_string = $this->fq_classlike_names[count($this->fq_classlike_names) - 1]; } else { - $param_type_string = ClassLikeAnalyzer::getFQCLNFromNameObject($param_typehint, $this->aliases); + if ($this->classlike_storages + && strtolower($param_typehint->parts[0]) === 'self' + && !end($this->classlike_storages)->is_trait + ) { + $param_type_string = $this->fq_classlike_names[count($this->fq_classlike_names) - 1]; + } else { + $param_type_string = ClassLikeAnalyzer::getFQCLNFromNameObject($param_typehint, $this->aliases); + } if (!in_array(strtolower($param_type_string), ['self', 'static', 'parent'], true)) { $this->codebase->scanner->queueClassLikeForScanning($param_type_string, $this->file_path); diff --git a/tests/TraitTest.php b/tests/TraitTest.php index 66202c342..b1bba0726 100644 --- a/tests/TraitTest.php +++ b/tests/TraitTest.php @@ -839,6 +839,18 @@ class TraitTest extends TestCase public function bar() { return []; } }' ], + 'traitSelfParam' => [ + '