mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
parent
b775d297bb
commit
61f02d8889
@ -258,8 +258,6 @@ final class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
IssueBuffer::maybeAdd($docblock_issue);
|
||||
}
|
||||
|
||||
$classlike_storage_provider = $codebase->classlike_storage_provider;
|
||||
|
||||
$parent_fq_class_name = $this->parent_fq_class_name;
|
||||
|
||||
if ($class instanceof PhpParser\Node\Stmt\Class_ && $class->extends && $parent_fq_class_name) {
|
||||
@ -626,43 +624,7 @@ final class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
}
|
||||
|
||||
$pseudo_methods = $storage->pseudo_methods + $storage->pseudo_static_methods;
|
||||
|
||||
foreach ($pseudo_methods as $pseudo_method_name => $pseudo_method_storage) {
|
||||
$pseudo_method_id = new MethodIdentifier(
|
||||
$this->fq_class_name,
|
||||
$pseudo_method_name,
|
||||
);
|
||||
|
||||
$overridden_method_ids = $codebase->methods->getOverriddenMethodIds($pseudo_method_id);
|
||||
|
||||
if ($overridden_method_ids
|
||||
&& $pseudo_method_name !== '__construct'
|
||||
&& $pseudo_method_storage->location
|
||||
) {
|
||||
foreach ($overridden_method_ids as $overridden_method_id) {
|
||||
$parent_method_storage = $codebase->methods->getStorage($overridden_method_id);
|
||||
|
||||
$overridden_fq_class_name = $overridden_method_id->fq_class_name;
|
||||
|
||||
$parent_storage = $classlike_storage_provider->get($overridden_fq_class_name);
|
||||
|
||||
MethodComparator::compare(
|
||||
$codebase,
|
||||
null,
|
||||
$storage,
|
||||
$parent_storage,
|
||||
$pseudo_method_storage,
|
||||
$parent_method_storage,
|
||||
$this->fq_class_name,
|
||||
$pseudo_method_storage->visibility ?: 0,
|
||||
$storage->location ?: $pseudo_method_storage->location,
|
||||
$storage->suppressed_issues,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
MethodComparator::comparePseudoMethods($pseudo_methods, $this->fq_class_name, $codebase, $storage);
|
||||
|
||||
$event = new AfterClassLikeAnalysisEvent(
|
||||
$class,
|
||||
|
@ -217,6 +217,10 @@ final class InterfaceAnalyzer extends ClassLikeAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
$pseudo_methods = $class_storage->pseudo_methods + $class_storage->pseudo_static_methods;
|
||||
|
||||
MethodComparator::comparePseudoMethods($pseudo_methods, $this->fq_class_name, $codebase, $class_storage);
|
||||
|
||||
$statements_analyzer = new StatementsAnalyzer($this, new NodeDataProvider());
|
||||
$statements_analyzer->analyze($member_stmts, $interface_context, null, true);
|
||||
|
||||
|
@ -238,6 +238,53 @@ final class MethodComparator
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<lowercase-string, MethodStorage> $pseudo_methods
|
||||
*/
|
||||
public static function comparePseudoMethods(
|
||||
array $pseudo_methods,
|
||||
string $fq_class_name,
|
||||
Codebase $codebase,
|
||||
ClassLikeStorage $class_storage,
|
||||
): void {
|
||||
foreach ($pseudo_methods as $pseudo_method_name => $pseudo_method_storage) {
|
||||
$pseudo_method_id = new MethodIdentifier(
|
||||
$fq_class_name,
|
||||
$pseudo_method_name,
|
||||
);
|
||||
|
||||
$overridden_method_ids = $codebase->methods->getOverriddenMethodIds($pseudo_method_id);
|
||||
|
||||
if ($overridden_method_ids
|
||||
&& $pseudo_method_name !== '__construct'
|
||||
&& $pseudo_method_storage->location
|
||||
) {
|
||||
foreach ($overridden_method_ids as $overridden_method_id) {
|
||||
$parent_method_storage = $codebase->methods->getStorage($overridden_method_id);
|
||||
|
||||
$overridden_fq_class_name = $overridden_method_id->fq_class_name;
|
||||
|
||||
$parent_storage = $codebase->classlike_storage_provider->get($overridden_fq_class_name);
|
||||
|
||||
self::compare(
|
||||
$codebase,
|
||||
null,
|
||||
$class_storage,
|
||||
$parent_storage,
|
||||
$pseudo_method_storage,
|
||||
$parent_method_storage,
|
||||
$fq_class_name,
|
||||
$pseudo_method_storage->visibility ?: 0,
|
||||
$class_storage->location ?: $pseudo_method_storage->location,
|
||||
$class_storage->suppressed_issues,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $suppressed_issues
|
||||
*/
|
||||
|
@ -1164,6 +1164,62 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'UndefinedVariable',
|
||||
],
|
||||
'MagicMethodReturnTypesCheckedForClasses' => [
|
||||
'code' => '<?php
|
||||
class A
|
||||
{
|
||||
public function a(int $className): int { return 0; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @method stdClass a(int $a)
|
||||
*/
|
||||
class B extends A {}
|
||||
',
|
||||
'error_message' => 'ImplementedReturnTypeMismatch',
|
||||
],
|
||||
'MagicMethodParamTypesCheckedForClasses' => [
|
||||
'code' => '<?php
|
||||
class A
|
||||
{
|
||||
public function a(int $className): int { return 0; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @method int a(string $a)
|
||||
*/
|
||||
class B extends A {}
|
||||
',
|
||||
'error_message' => 'ImplementedParamTypeMismatch',
|
||||
],
|
||||
'MagicMethodReturnTypesCheckedForInterfaces' => [
|
||||
'code' => '<?php
|
||||
interface A
|
||||
{
|
||||
public function a(int $className): int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @method stdClass a(int $a)
|
||||
*/
|
||||
interface B extends A {}
|
||||
',
|
||||
'error_message' => 'ImplementedReturnTypeMismatch',
|
||||
],
|
||||
'MagicMethodParamTypesCheckedForInterfaces' => [
|
||||
'code' => '<?php
|
||||
interface A
|
||||
{
|
||||
public function a(string $className): int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @method int a(int $a)
|
||||
*/
|
||||
interface B extends A {}
|
||||
',
|
||||
'error_message' => 'ImplementedParamTypeMismatch',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user