]> granicus.if.org Git - php/commitdiff
Verify that all stubs have a return type
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 3 Apr 2020 14:49:11 +0000 (16:49 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 3 Apr 2020 15:59:30 +0000 (17:59 +0200)
27 files changed:
Zend/zend_closures.stub.php
Zend/zend_exceptions.stub.php
Zend/zend_generators.stub.php
Zend/zend_interfaces.stub.php
build/gen_stub.php
ext/com_dotnet/com_extension.stub.php
ext/com_dotnet/com_extension_arginfo.h
ext/dom/domimplementation.stub.php
ext/dom/xpath.stub.php
ext/gd/gd.stub.php
ext/gd/gd_arginfo.h
ext/intl/common/common.stub.php
ext/json/json.stub.php
ext/phar/phar_object.stub.php
ext/reflection/php_reflection.stub.php
ext/sockets/sockets.stub.php
ext/spl/spl_directory.stub.php
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/user_filters.stub.php
ext/xml/xml.stub.php
ext/xml/xml_arginfo.h
ext/xmlrpc/xmlrpc.stub.php
ext/xmlwriter/xmlwriter.stub.php
ext/xmlwriter/xmlwriter_arginfo.h
ext/zend_test/test.stub.php
ext/zend_test/test_arginfo.h

index ad15daa526a6c96a993ca976a077d43ab41bd170..0dc92789a00248458c4a1554e7ea83dc40d4fcb8 100644 (file)
@@ -10,6 +10,7 @@ Class Closure
     /** @return ?Closure */
     function bindTo(?object $newthis, $newscope = UNKNOWN) {}
 
+    /** @return mixed */
     function call(object $newthis, ...$parameters) {}
 
     /**
index 12255df3f6eeb89e3bd473e269bda7618b986ee0..cf631f3c2b00a5d116305f66d27ebcbb78d91353 100644 (file)
@@ -60,5 +60,6 @@ class ErrorException extends Exception
 {
     function __construct(string $message = UNKNOWN, int $code = 0, int $severity = E_ERROR, string $filename = UNKNOWN, int $lineno = 0, ?Throwable $previous = null) {}
 
+    /** @return int */
     final function getSeverity() {}
 }
index 759bd4cd4868cbfed7ba2d8a99b4ac2608d6762a..3599cc0e69c2bb4ff4b87d6cceb696ee2ea11889 100644 (file)
@@ -6,15 +6,20 @@ final class Generator implements Iterator
 
     function valid(): bool {}
 
+    /** @return mixed */
     function current() {}
 
+    /** @return mixed */
     function key() {}
 
     function next(): void {}
 
+    /** @return mixed */
     function send($value) {}
 
+    /** @return mixed */
     function throw(Throwable $exception) {}
 
+    /** @return mixed */
     function getReturn() {}
 }
index 3a908212a4631a2c2463ffae5e3257221320dcc1..b78257f53f0c66c0979863834cf235c5c500fbf8 100644 (file)
@@ -10,11 +10,13 @@ interface IteratorAggregate extends Traversable
 
 interface Iterator extends Traversable
 {
+    /** @return mixed */
     function current();
 
     /** @return void */
     function next();
 
+    /** @return mixed */
     function key();
 
     /** @return bool */
@@ -26,13 +28,17 @@ interface Iterator extends Traversable
 
 interface ArrayAccess
 {
+    /** @return bool */
     function offsetExists($offset);
 
     /* actually this should be return by ref but atm cannot be */
+    /** @return mixed */
     function offsetGet($offset);
 
+    /** @return void */
     function offsetSet($offset, $value);
 
+    /** @return void */
     function offsetUnset($offset);
 }
 
@@ -41,6 +47,7 @@ interface Serializable
     /** @return string */
     function serialize();
 
+    /** @return void */
     function unserialize(string $serialized);
 }
 
index e94399fbe3118109dc7ea1705fc56bad493c690b..2207a1348b90c63d01c571f3d72efcd463524e43 100644 (file)
@@ -385,25 +385,70 @@ class FileInfo {
     }
 }
 
+class DocCommentTag {
+    /** @var string */
+    public $name;
+    /** @var ?string */
+    public $value;
+
+    public function __construct(string $name, ?string $value) {
+        $this->name = $name;
+        $this->value = $value;
+    }
+
+    public function getValue(): string {
+        if ($this->value === null) {
+            throw new Exception("@$this->name does not have a value");
+        }
+
+        return $this->value;
+    }
+
+    public function getVariableName(): string {
+        $value = $this->getValue();
+        if ($value === null || strlen($value) === 0 || $value[0] !== '$') {
+            throw new Exception("@$this->name not followed by variable name");
+        }
+
+        return substr($value, 1);
+    }
+}
+
+/** @return DocCommentTag[] */
+function parseDocComment(DocComment $comment): array {
+    $commentText = substr($comment->getText(), 2, -2);
+    $tags = [];
+    foreach (explode("\n", $commentText) as $commentLine) {
+        $regex = '/^\*\s*@([a-z-]+)(?:\s+(.+))$/';
+        if (preg_match($regex, trim($commentLine), $matches, PREG_UNMATCHED_AS_NULL)) {
+            $tags[] = new DocCommentTag($matches[1], $matches[2]);
+        }
+    }
+
+    return $tags;
+}
+
 function parseFunctionLike(
     string $name, ?string $className, Node\FunctionLike $func, ?string $cond
 ): FuncInfo {
     $comment = $func->getDocComment();
     $paramMeta = [];
     $alias = null;
+    $haveDocReturnType = false;
 
     if ($comment) {
-        $commentText = substr($comment->getText(), 2, -2);
-
-        foreach (explode("\n", $commentText) as $commentLine) {
-            if (preg_match('/^\*\s*@prefer-ref\s+\$(.+)$/', trim($commentLine), $matches)) {
-                $varName = $matches[1];
+        $tags = parseDocComment($comment);
+        foreach ($tags as $tag) {
+            if ($tag->name === 'prefer-ref') {
+                $varName = $tag->getVariableName();
                 if (!isset($paramMeta[$varName])) {
                     $paramMeta[$varName] = [];
                 }
                 $paramMeta[$varName]['preferRef'] = true;
-            } else if (preg_match('/^\*\s*@alias\s+(.+)$/', trim($commentLine), $matches)) {
-                $alias = $matches[1];
+            } else if ($tag->name === 'alias') {
+                $alias = $tag->getValue();
+            } else if ($tag->name === 'return') {
+                $haveDocReturnType = true;
             }
         }
     }
@@ -455,6 +500,10 @@ function parseFunctionLike(
     }
 
     $returnType = $func->getReturnType();
+    if ($returnType === null && !$haveDocReturnType && substr($name, 0, 2) !== '__') {
+        throw new Exception("Missing return type for function $name()");
+    }
+
     $return = new ReturnInfo(
         $func->returnsByRef(),
         $returnType ? Type::fromNode($returnType) : null);
index 83cfc50350c35efcf329679b11577792690c0bfd..8e065fb2bafd258cba610e6c3f3db99eead9b88c 100644 (file)
@@ -40,7 +40,7 @@ function variant_not($left): variant {}
 
 function variant_round($left, int $decimals): ?variant {}
 
-function variant_cmp($left, $right, int $lcid = UNKNOWN, int $flags = 0) {}
+function variant_cmp($left, $right, int $lcid = UNKNOWN, int $flags = 0): int {}
 
 function variant_date_to_timestamp(variant $variant): ?int {}
 
@@ -63,4 +63,4 @@ function com_print_typeinfo($comobject, ?string $dispinterface = null, bool $wan
 
 function com_message_pump(int $timeoutms = 0): bool {}
 
-function com_load_typelib(string $typelib_name, bool $case_insensitive = true) {}
+function com_load_typelib(string $typelib_name, bool $case_insensitive = true): bool {}
index b8ffef8077430e52a1b6dbeffe399415d8d2de3a..b5eac32332392bba33491ed29fad170a844c66bd 100644 (file)
@@ -51,7 +51,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_variant_round, 0, 2, variant, 1)
        ZEND_ARG_TYPE_INFO(0, decimals, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_cmp, 0, 0, 2)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_variant_cmp, 0, 2, IS_LONG, 0)
        ZEND_ARG_INFO(0, left)
        ZEND_ARG_INFO(0, right)
        ZEND_ARG_TYPE_INFO(0, lcid, IS_LONG, 0)
@@ -104,7 +104,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_com_message_pump, 0, 0, _IS_BOOL
        ZEND_ARG_TYPE_INFO(0, timeoutms, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_com_load_typelib, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_com_load_typelib, 0, 1, _IS_BOOL, 0)
        ZEND_ARG_TYPE_INFO(0, typelib_name, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, case_insensitive, _IS_BOOL, 0)
 ZEND_END_ARG_INFO()
index c103d489b469c398eaa79ed24d3f0c43ffb8d8d4..86b28d196ed6b041da580497fcb4ec79dfad3a9c 100644 (file)
@@ -2,6 +2,7 @@
 
 class DOMImplementation
 {
+    /** @return void */
     public function getFeature(string $feature, string $version) {}
 
     /** @return bool */
index 167c5a94efb10010311854102099f0f92569cfe3..a7ea2bb7b02a50e170e410c41fb867dbf4e41ab8 100644 (file)
@@ -14,7 +14,10 @@ class DOMXPath
     /** @return bool */
     public function registerNamespace(string $prefix, string $namespaceURI) {}
 
-    /** @param string|array $restrict */
+    /**
+     * @param string|array $restrict
+     * @return bool|null
+     */
     public function registerPhpFunctions($restrict = null) {}
 }
 #endif
index 5138e2596a340725cd28baed7d886adeeedb7efc..18497cddfe517d189794dc63fa97604deaa33413 100644 (file)
@@ -209,7 +209,7 @@ function imagefttext(GdImage $im, float $size, float $angle, int $x, int $y, int
 
 function imagettfbbox(float $size, float $angle, string $font_file, string $text): array|false {}
 
-function imagettftext(GdImage $im, float $size, float $angle, int $x, int $y, int $col, string $font_file, string $text) {}
+function imagettftext(GdImage $im, float $size, float $angle, int $x, int $y, int $col, string $font_file, string $text): array|false {}
 #endif
 
 function imagefilter(GdImage $im, int $filtertype, $arg1 = UNKNOWN, $arg2 = UNKNOWN, $arg3 = UNKNOWN, $arg4 = UNKNOWN): bool {}
index 0d8554864d2cf973a263b66c95c4726f2df43b52..e829e3a4bc70695b40ff925db888e3e5039a1e66 100644 (file)
@@ -483,7 +483,7 @@ ZEND_END_ARG_INFO()
 #endif
 
 #if defined(HAVE_GD_FREETYPE)
-ZEND_BEGIN_ARG_INFO_EX(arginfo_imagettftext, 0, 0, 8)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imagettftext, 0, 8, MAY_BE_ARRAY|MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, im, GdImage, 0)
        ZEND_ARG_TYPE_INFO(0, size, IS_DOUBLE, 0)
        ZEND_ARG_TYPE_INFO(0, angle, IS_DOUBLE, 0)
index 5d7ef874d1a114d98e6ca5b5de9ff8b8645e2a65..8bb6e38ce8e1dcae5599cdaaf455cb049981378e 100644 (file)
@@ -2,13 +2,18 @@
 
 class IntlIterator implements Iterator
 {
+    /** @return mixed */
     public function current() {}
 
+    /** @return mixed */
     public function key() {}
 
+    /** @return void */
     public function next() {}
 
+    /** @return void */
     public function rewind() {}
 
+    /** @return bool */
     public function valid() {}
 }
index 90bedef91e431b5fda29199b4c867bdf8f7cfe68..c5713a7980d40671fadc26650c48dc0cca4d50aa 100644 (file)
@@ -11,5 +11,6 @@ function json_last_error_msg(): string {}
 
 interface JsonSerializable
 {
+    /** @return mixed */
     public function jsonSerialize();
 }
index 44ec4732da784fe1b3db089724d6b2b2aa9f4e54..af7d57cabc263e52c5fd8e064abdc6b0bcb58328 100644 (file)
@@ -381,6 +381,7 @@ class PharFileInfo extends SplFileInfo
     /** @return string */
     public function getContent() {}
 
+    /** @return mixed */
     public function getMetadata() {}
 
     /** @return int */
index 05e1b0490de5e7580ec67c63fe32355e44404e71..b96a4f65e9d05c2659a6fb95dcb2f9799c3618e8 100644 (file)
@@ -104,8 +104,10 @@ class ReflectionFunction extends ReflectionFunctionAbstract
     /** @return bool */
     public function isDisabled() {}
 
+    /** @return mixed */
     public function invoke(...$args) {}
 
+    /** @return mixed */
     public function invokeArgs(array $args) {}
 
     /** @return Closure */
@@ -172,8 +174,10 @@ class ReflectionMethod extends ReflectionFunctionAbstract
     /** @return int */
     public function getModifiers() {}
 
+    /** @return mixed */
     public function invoke(?object $object = null, ...$args) {}
 
+    /** @return mixed */
     public function invokeArgs(?object $object, array $args) {}
 
     /** @return ReflectionClass */
@@ -255,6 +259,7 @@ class ReflectionClass implements Reflector
     /** @return ReflectionClassConstant[] */
     public function getReflectionConstants() {}
 
+    /** @return mixed */
     public function getConstant(string $name) {}
 
     /** @return ReflectionClassConstant|false */
@@ -314,6 +319,7 @@ class ReflectionClass implements Reflector
     /** @return ?array */
     public function getStaticProperties() {}
 
+    /** @return mixed */
     public function getStaticPropertyValue(string $name, $default = UNKNOWN) {}
 
     /** @return void */
@@ -367,6 +373,7 @@ class ReflectionProperty implements Reflector
     /** @return string|false */
     public function getName() {}
 
+    /** @return mixed */
     public function getValue(?object $object = null) {}
 
     /** @return void */
@@ -426,6 +433,7 @@ class ReflectionClassConstant implements Reflector
     /** @return string|false */
     public function getName() {}
 
+    /** @return mixed */
     public function getValue() {}
 
     /** @return bool */
@@ -501,6 +509,7 @@ class ReflectionParameter implements Reflector
     /** @return bool */
     public function isDefaultValueAvailable() {}
 
+    /** @return mixed */
     public function getDefaultValue() {}
 
     /** @return bool */
index 86c4cd856e6f4c290551108fd6e214dc68f19614..bdff816f4622939800071c0ca196e00d1c22d298 100644 (file)
@@ -91,7 +91,10 @@ function socket_clear_error($socket = UNKNOWN): void {}
  */
 function socket_import_stream($stream) {}
 
-/** @param resource $socket */
+/**
+ * @param resource $socket
+ * @return resource|false
+ */
 function socket_export_stream($socket) {}
 
 /** @param resource $socket */
index de6cda349e161555f1a4750111c81cbb3a026799..c5a63ef1cd0d1d34c7b132c439975592f2f0dcc8 100755 (executable)
@@ -90,6 +90,7 @@ class SplFileInfo
 
     public function __toString(): string {}
 
+    /** @return void */
     final public function _bad_state_ex() {}
 }
 
index 4b39aa32f9d33e7aaa771ace52a2f0b270c20858..0c1c1ee380de5439c082e376aad4f256ebec70b4 100755 (executable)
@@ -238,6 +238,7 @@ function array_sum(array $arg): int|float {}
 
 function array_product(array $arg): int|float {}
 
+/** @return mixed */
 function array_reduce(array $arg, callable $callback, $initial = null) {}
 
 function array_filter(array $arg, callable $callback = UNKNOWN, int $use_keys = 0): array {}
@@ -1457,7 +1458,7 @@ function is_object($value): bool {}
 function is_scalar($value): bool {}
 
 /** @param mixed $value */
-function is_callable($value, bool $syntax_only = false, &$callable_name = null) {}
+function is_callable($value, bool $syntax_only = false, &$callable_name = null): bool {}
 
 /** @param mixed $value */
 function is_iterable($value): bool {}
@@ -1545,7 +1546,7 @@ function sapi_windows_cp_get(string $kind = UNKNOWN): int {}
  * @param int|string $in_codepage
  * @param int|string $out_codepage
  */
-function sapi_windows_cp_conv($in_codepage, $out_codepage, string $subject) {}
+function sapi_windows_cp_conv($in_codepage, $out_codepage, string $subject): ?string {}
 
 function sapi_windows_cp_is_utf8(): bool {}
 
index 9c1b0162b0da53e2190d89b768797082db00e7d4..7e0fbe84dcebe6acd241ca24fadd3a8d4a489dc6 100755 (executable)
@@ -2103,7 +2103,7 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_is_scalar arginfo_boolval
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_is_callable, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_callable, 0, 1, _IS_BOOL, 0)
        ZEND_ARG_INFO(0, value)
        ZEND_ARG_TYPE_INFO(0, syntax_only, _IS_BOOL, 0)
        ZEND_ARG_INFO(1, callable_name)
@@ -2212,7 +2212,7 @@ ZEND_END_ARG_INFO()
 #endif
 
 #if defined(PHP_WIN32)
-ZEND_BEGIN_ARG_INFO_EX(arginfo_sapi_windows_cp_conv, 0, 0, 3)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_sapi_windows_cp_conv, 0, 3, IS_STRING, 1)
        ZEND_ARG_INFO(0, in_codepage)
        ZEND_ARG_INFO(0, out_codepage)
        ZEND_ARG_TYPE_INFO(0, subject, IS_STRING, 0)
index f789dc1f32cdb89b89d13dd600575c5bc9a01fdc..9481b0b663800a54d9382611839c564fb974e648 100755 (executable)
@@ -2,6 +2,7 @@
 
 class php_user_filter
 {
+    /** @return int */
     public function filter($in, $out, &$consumed, $closing) {}
 
     /** @return void */
index 0f6ed6b24c43d12b909b35ef2503d94bb80e05db..60eeaaae333b58f9282c3ff6f3a76e97aff980dd 100644 (file)
@@ -54,4 +54,4 @@ function xml_parser_free(XmlParser $parser): bool {}
 
 function xml_parser_set_option(XmlParser $parser, int $option, $value): bool {}
 
-function xml_parser_get_option(XmlParser $parser, int $option) {}
+function xml_parser_get_option(XmlParser $parser, int $option): string|int|false {}
index 06f6fde985e32c8280243375ec004f46bab570f5..463ad8b9eb406ade66e56e9c2362888c2c433efd 100644 (file)
@@ -76,7 +76,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xml_parser_set_option, 0, 3, _IS
        ZEND_ARG_INFO(0, value)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_parser_get_option, 0, 0, 2)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_xml_parser_get_option, 0, 2, MAY_BE_STRING|MAY_BE_LONG|MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, parser, XmlParser, 0)
        ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
 ZEND_END_ARG_INFO()
index 751aa7c32535c2958af84f58c2eead785f3704bb..e2805bd43f1861123acfdef95a04b4fa24244bd5 100644 (file)
@@ -2,8 +2,10 @@
 
 function xmlrpc_encode($value): ?string {}
 
+/** @return mixed */
 function xmlrpc_decode(string $xml, string $encoding = "iso-8859-1") {}
 
+/** @return mixed */
 function xmlrpc_decode_request(string $xml, &$method, string $encoding = "iso-8859-1") {}
 
 function xmlrpc_encode_request(?string $method, $params, array $output_options = UNKNOWN): ?string {}
@@ -21,9 +23,13 @@ function xmlrpc_server_destroy($server): bool {}
 /** @param resource $server */
 function xmlrpc_server_register_method($server, string $method_name, $function): bool {}
 
-/** @param resource $server */
+/**
+ * @param resource $server
+ * @return mixed
+ */
 function xmlrpc_server_call_method($server, string $xml, $user_data, array $output_options = UNKNOWN) {}
 
+/** @return mixed */
 function xmlrpc_parse_method_descriptions(string $xml) {}
 
 /** @param resource $server */
index ce476c0705bd5a6541158e0b11d416a50060affb..35a0dec65885c9ccc6f4e7e281c4042d1bfaef39 100644 (file)
@@ -50,7 +50,7 @@ function xmlwriter_text(XMLWriter $xmlwriter, string $content): bool {}
 
 function xmlwriter_write_raw(XMLWriter $xmlwriter, string $content): bool {}
 
-function xmlwriter_start_document(XMLWriter $xmlwriter, ?string $version = '1.0', ?string $encoding = null, ?string $standalone = null) {}
+function xmlwriter_start_document(XMLWriter $xmlwriter, ?string $version = '1.0', ?string $encoding = null, ?string $standalone = null): bool {}
 
 function xmlwriter_end_document(XMLWriter $xmlwriter): bool {}
 
index 54f571cb341b0680e182724108a915fdcd2c6cb3..e759a32e1044ae664400af164f910447114bbd5f 100644 (file)
@@ -104,7 +104,7 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_xmlwriter_write_raw arginfo_xmlwriter_write_cdata
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlwriter_start_document, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlwriter_start_document, 0, 1, _IS_BOOL, 0)
        ZEND_ARG_OBJ_INFO(0, xmlwriter, XMLWriter, 0)
        ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 1)
        ZEND_ARG_TYPE_INFO(0, encoding, IS_STRING, 1)
index b823116742ae231007855ad777ba68c5a831b833..85c733ad3cc103d59c03af10a2148d0d4de449b6 100644 (file)
@@ -20,7 +20,7 @@ function zend_test_deprecated(): void {}
 
 function zend_create_unterminated_string(string $str): string {}
 
-function zend_terminate_string(string &$str) {}
+function zend_terminate_string(string &$str): string {}
 
 /** @param mixed $variable */
 function zend_leak_variable($variable): void {}
index 89a72f63ae688517a7f9330d326312502e2adfa7..e0cb219e37dd510b2b117b20acbcfe72c310758b 100644 (file)
@@ -15,7 +15,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_create_unterminated_string,
        ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_terminate_string, 0, 0, 1)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_terminate_string, 0, 1, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(1, str, IS_STRING, 0)
 ZEND_END_ARG_INFO()