From ef35cfc6fec4a6fa81e92bd317b319b2443618d0 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 13 Mar 2018 12:52:00 -0400 Subject: [PATCH] Fix #566 - check for abstract methods inheriting from non-abstract ones --- src/Psalm/Checker/ClassChecker.php | 5 ++++- src/Psalm/Checker/MethodChecker.php | 17 +++++++++++++++++ src/Psalm/Provider/FileStorageCacheProvider.php | 2 ++ src/Psalm/Storage/FunctionLikeStorage.php | 5 ----- src/Psalm/Storage/MethodStorage.php | 5 +++++ src/psalter.php | 3 +++ tests/MethodSignatureTest.php | 11 +++++++++++ 7 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/Psalm/Checker/ClassChecker.php b/src/Psalm/Checker/ClassChecker.php index db7091159..55b55e369 100644 --- a/src/Psalm/Checker/ClassChecker.php +++ b/src/Psalm/Checker/ClassChecker.php @@ -782,7 +782,10 @@ class ClassChecker extends ClassLikeChecker $global_context ? clone $global_context : null ); - if ($stmt->name !== '__construct' && $config->reportIssueInFile('InvalidReturnType', $source->getFilePath())) { + if ($stmt->name !== '__construct' + && $config->reportIssueInFile('InvalidReturnType', $source->getFilePath()) + && $stmt->stmts !== null + ) { $return_type_location = null; $secondary_return_type_location = null; diff --git a/src/Psalm/Checker/MethodChecker.php b/src/Psalm/Checker/MethodChecker.php index 5ffd6b042..27b15032f 100644 --- a/src/Psalm/Checker/MethodChecker.php +++ b/src/Psalm/Checker/MethodChecker.php @@ -392,6 +392,23 @@ class MethodChecker extends FunctionLikeChecker return null; } + if (!$guide_method_storage->abstract + && $implementer_method_storage->abstract + && !$implementer_classlike_storage->abstract + ) { + if (IssueBuffer::accepts( + new MethodSignatureMismatch( + 'Method ' . $cased_implementer_method_id . ' cannot be abstract when inherited method ' + . $cased_guide_method_id . ' is non-abstract', + $code_location + ) + )) { + return false; + } + + return null; + } + if ($guide_method_storage->signature_return_type) { $guide_signature_return_type = ExpressionChecker::fleshOutType( $project_checker, diff --git a/src/Psalm/Provider/FileStorageCacheProvider.php b/src/Psalm/Provider/FileStorageCacheProvider.php index dac8aa24f..15c8f29fa 100644 --- a/src/Psalm/Provider/FileStorageCacheProvider.php +++ b/src/Psalm/Provider/FileStorageCacheProvider.php @@ -27,6 +27,8 @@ class FileStorageCacheProvider $dependent_files = [ $storage_dir . 'FileStorage.php', $storage_dir . 'FunctionLikeStorage.php', + $storage_dir . 'ClassLikeStorage.php', + $storage_dir . 'MethodStorage.php', ]; foreach ($dependent_files as $dependent_file_path) { diff --git a/src/Psalm/Storage/FunctionLikeStorage.php b/src/Psalm/Storage/FunctionLikeStorage.php index dc9b28d8f..d11f3d94e 100644 --- a/src/Psalm/Storage/FunctionLikeStorage.php +++ b/src/Psalm/Storage/FunctionLikeStorage.php @@ -67,11 +67,6 @@ class FunctionLikeStorage */ public $returns_by_ref = false; - /** - * @var bool - */ - public $abstract = false; - /** * @var int */ diff --git a/src/Psalm/Storage/MethodStorage.php b/src/Psalm/Storage/MethodStorage.php index 1be3c8fe3..c9172082e 100644 --- a/src/Psalm/Storage/MethodStorage.php +++ b/src/Psalm/Storage/MethodStorage.php @@ -20,6 +20,11 @@ class MethodStorage extends FunctionLikeStorage */ public $final; + /** + * @var bool + */ + public $abstract; + /** * @var array */ diff --git a/src/psalter.php b/src/psalter.php index 0a1244fff..de841f1b8 100644 --- a/src/psalter.php +++ b/src/psalter.php @@ -102,6 +102,9 @@ $vendor_dir = getVendorDir($current_dir); $first_autoloader = requireAutoloaders($current_dir, isset($options['r']), $vendor_dir); +// If XDebug is enabled, restart without it +(new \Composer\XdebugHandler\XdebugHandler('PSALTER'))->check(); + $paths_to_check = getPathsToCheck(isset($options['f']) ? $options['f'] : null); if ($paths_to_check && count($paths_to_check) > 1) { diff --git a/tests/MethodSignatureTest.php b/tests/MethodSignatureTest.php index 00a75b361..1348cb4be 100644 --- a/tests/MethodSignatureTest.php +++ b/tests/MethodSignatureTest.php @@ -430,6 +430,17 @@ class MethodSignatureTest extends TestCase }', 'error_message' => 'MethodSignatureMismatch', ], + 'abstractExtendsNonAbstractWithMethod' => [ + ' 'MethodSignatureMismatch', + ], ]; } }