diff --git a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php index 3842dce76..57ba7d23c 100644 --- a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php @@ -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, diff --git a/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php b/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php index fc798e443..d7092e97b 100644 --- a/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php @@ -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); diff --git a/src/Psalm/Internal/Analyzer/MethodComparator.php b/src/Psalm/Internal/Analyzer/MethodComparator.php index a750940a2..50f34758a 100644 --- a/src/Psalm/Internal/Analyzer/MethodComparator.php +++ b/src/Psalm/Internal/Analyzer/MethodComparator.php @@ -238,6 +238,53 @@ final class MethodComparator return null; } + /** + * @param array $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 */ diff --git a/tests/MagicMethodAnnotationTest.php b/tests/MagicMethodAnnotationTest.php index 88f5a2a47..ea2f6e8f7 100644 --- a/tests/MagicMethodAnnotationTest.php +++ b/tests/MagicMethodAnnotationTest.php @@ -1164,6 +1164,62 @@ class MagicMethodAnnotationTest extends TestCase }', 'error_message' => 'UndefinedVariable', ], + 'MagicMethodReturnTypesCheckedForClasses' => [ + 'code' => ' 'ImplementedReturnTypeMismatch', + ], + 'MagicMethodParamTypesCheckedForClasses' => [ + 'code' => ' 'ImplementedParamTypeMismatch', + ], + 'MagicMethodReturnTypesCheckedForInterfaces' => [ + 'code' => ' 'ImplementedReturnTypeMismatch', + ], + 'MagicMethodParamTypesCheckedForInterfaces' => [ + 'code' => ' 'ImplementedParamTypeMismatch', + ], ]; }