mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Fix #1475 - allow self params in traits
This commit is contained in:
parent
f5c6abb6a0
commit
f66af3e267
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -839,6 +839,18 @@ class TraitTest extends TestCase
|
||||
public function bar() { return []; }
|
||||
}'
|
||||
],
|
||||
'traitSelfParam' => [
|
||||
'<?php
|
||||
trait T {
|
||||
public function bar(self $object): self {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
use T;
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user