diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php index cc99d748ec5..c4779156a9e 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php @@ -2,6 +2,8 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Call\Method; +use Exception; +use PDOException; use PhpParser; use Psalm\CodeLocation; use Psalm\Codebase; @@ -27,6 +29,7 @@ use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; +use Throwable; use UnexpectedValueException; use function array_filter; @@ -92,6 +95,16 @@ public static function fetch( } } + if ($premixin_method_id->method_name === 'getcode' + && $premixin_method_id->fq_class_name !== Exception::class + && in_array(Throwable::class, $class_storage->class_implements)) { + if ($premixin_method_id->fq_class_name === PDOException::class) { + return Type::getString(); + } else { + return Type::getInt(true); // TODO: Remove the flag in Psalm 5 + } + } + if ($declaring_method_id && $declaring_method_id !== $method_id) { $declaring_fq_class_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; diff --git a/tests/ReturnTypeProvider/ExceptionCodeTest.php b/tests/ReturnTypeProvider/ExceptionCodeTest.php new file mode 100644 index 00000000000..ccc8ea10db5 --- /dev/null +++ b/tests/ReturnTypeProvider/ExceptionCodeTest.php @@ -0,0 +1,53 @@ + [ + 'getCode(); + } + ', + [], + ]; + yield 'LogicException' => [ + 'getCode(); + } + ', + [], + ]; + yield 'PDOException' => [ + 'getCode(); + } + ', + [], + ]; + yield 'Exception' => [ + 'getCode(); + ', + ['$code' => 'int|string'], + ]; + yield 'Throwable' => [ + 'getCode(); + ', + ['$code' => 'int|string'], + ]; + } +}