Verify that all stubs have a return type

This commit is contained in:
Nikita Popov 2020-04-03 16:49:11 +02:00
parent d2c92d7fd3
commit 2bcc4ab8f4
27 changed files with 121 additions and 26 deletions

View file

@ -10,6 +10,7 @@ Class Closure
/** @return ?Closure */ /** @return ?Closure */
function bindTo(?object $newthis, $newscope = UNKNOWN) {} function bindTo(?object $newthis, $newscope = UNKNOWN) {}
/** @return mixed */
function call(object $newthis, ...$parameters) {} function call(object $newthis, ...$parameters) {}
/** /**

View 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) {} 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() {} final function getSeverity() {}
} }

View file

@ -6,15 +6,20 @@ final class Generator implements Iterator
function valid(): bool {} function valid(): bool {}
/** @return mixed */
function current() {} function current() {}
/** @return mixed */
function key() {} function key() {}
function next(): void {} function next(): void {}
/** @return mixed */
function send($value) {} function send($value) {}
/** @return mixed */
function throw(Throwable $exception) {} function throw(Throwable $exception) {}
/** @return mixed */
function getReturn() {} function getReturn() {}
} }

View file

@ -10,11 +10,13 @@ interface IteratorAggregate extends Traversable
interface Iterator extends Traversable interface Iterator extends Traversable
{ {
/** @return mixed */
function current(); function current();
/** @return void */ /** @return void */
function next(); function next();
/** @return mixed */
function key(); function key();
/** @return bool */ /** @return bool */
@ -26,13 +28,17 @@ interface Iterator extends Traversable
interface ArrayAccess interface ArrayAccess
{ {
/** @return bool */
function offsetExists($offset); function offsetExists($offset);
/* actually this should be return by ref but atm cannot be */ /* actually this should be return by ref but atm cannot be */
/** @return mixed */
function offsetGet($offset); function offsetGet($offset);
/** @return void */
function offsetSet($offset, $value); function offsetSet($offset, $value);
/** @return void */
function offsetUnset($offset); function offsetUnset($offset);
} }
@ -41,6 +47,7 @@ interface Serializable
/** @return string */ /** @return string */
function serialize(); function serialize();
/** @return void */
function unserialize(string $serialized); function unserialize(string $serialized);
} }

View 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( function parseFunctionLike(
string $name, ?string $className, Node\FunctionLike $func, ?string $cond string $name, ?string $className, Node\FunctionLike $func, ?string $cond
): FuncInfo { ): FuncInfo {
$comment = $func->getDocComment(); $comment = $func->getDocComment();
$paramMeta = []; $paramMeta = [];
$alias = null; $alias = null;
$haveDocReturnType = false;
if ($comment) { if ($comment) {
$commentText = substr($comment->getText(), 2, -2); $tags = parseDocComment($comment);
foreach ($tags as $tag) {
foreach (explode("\n", $commentText) as $commentLine) { if ($tag->name === 'prefer-ref') {
if (preg_match('/^\*\s*@prefer-ref\s+\$(.+)$/', trim($commentLine), $matches)) { $varName = $tag->getVariableName();
$varName = $matches[1];
if (!isset($paramMeta[$varName])) { if (!isset($paramMeta[$varName])) {
$paramMeta[$varName] = []; $paramMeta[$varName] = [];
} }
$paramMeta[$varName]['preferRef'] = true; $paramMeta[$varName]['preferRef'] = true;
} else if (preg_match('/^\*\s*@alias\s+(.+)$/', trim($commentLine), $matches)) { } else if ($tag->name === 'alias') {
$alias = $matches[1]; $alias = $tag->getValue();
} else if ($tag->name === 'return') {
$haveDocReturnType = true;
} }
} }
} }
@ -455,6 +500,10 @@ function parseFunctionLike(
} }
$returnType = $func->getReturnType(); $returnType = $func->getReturnType();
if ($returnType === null && !$haveDocReturnType && substr($name, 0, 2) !== '__') {
throw new Exception("Missing return type for function $name()");
}
$return = new ReturnInfo( $return = new ReturnInfo(
$func->returnsByRef(), $func->returnsByRef(),
$returnType ? Type::fromNode($returnType) : null); $returnType ? Type::fromNode($returnType) : null);

View file

@ -40,7 +40,7 @@ function variant_not($left): variant {}
function variant_round($left, int $decimals): ?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 {} 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_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 {}

View 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_ARG_TYPE_INFO(0, decimals, IS_LONG, 0)
ZEND_END_ARG_INFO() 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, left)
ZEND_ARG_INFO(0, right) ZEND_ARG_INFO(0, right)
ZEND_ARG_TYPE_INFO(0, lcid, IS_LONG, 0) 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_ARG_TYPE_INFO(0, timeoutms, IS_LONG, 0)
ZEND_END_ARG_INFO() 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, typelib_name, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, case_insensitive, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, case_insensitive, _IS_BOOL, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()

View file

@ -2,6 +2,7 @@
class DOMImplementation class DOMImplementation
{ {
/** @return void */
public function getFeature(string $feature, string $version) {} public function getFeature(string $feature, string $version) {}
/** @return bool */ /** @return bool */

View file

@ -14,7 +14,10 @@ class DOMXPath
/** @return bool */ /** @return bool */
public function registerNamespace(string $prefix, string $namespaceURI) {} public function registerNamespace(string $prefix, string $namespaceURI) {}
/** @param string|array $restrict */ /**
* @param string|array $restrict
* @return bool|null
*/
public function registerPhpFunctions($restrict = null) {} public function registerPhpFunctions($restrict = null) {}
} }
#endif #endif

View 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 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 #endif
function imagefilter(GdImage $im, int $filtertype, $arg1 = UNKNOWN, $arg2 = UNKNOWN, $arg3 = UNKNOWN, $arg4 = UNKNOWN): bool {} function imagefilter(GdImage $im, int $filtertype, $arg1 = UNKNOWN, $arg2 = UNKNOWN, $arg3 = UNKNOWN, $arg4 = UNKNOWN): bool {}

View file

@ -483,7 +483,7 @@ ZEND_END_ARG_INFO()
#endif #endif
#if defined(HAVE_GD_FREETYPE) #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_OBJ_INFO(0, im, GdImage, 0)
ZEND_ARG_TYPE_INFO(0, size, IS_DOUBLE, 0) ZEND_ARG_TYPE_INFO(0, size, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, angle, IS_DOUBLE, 0) ZEND_ARG_TYPE_INFO(0, angle, IS_DOUBLE, 0)

View file

@ -2,13 +2,18 @@
class IntlIterator implements Iterator class IntlIterator implements Iterator
{ {
/** @return mixed */
public function current() {} public function current() {}
/** @return mixed */
public function key() {} public function key() {}
/** @return void */
public function next() {} public function next() {}
/** @return void */
public function rewind() {} public function rewind() {}
/** @return bool */
public function valid() {} public function valid() {}
} }

View file

@ -11,5 +11,6 @@ function json_last_error_msg(): string {}
interface JsonSerializable interface JsonSerializable
{ {
/** @return mixed */
public function jsonSerialize(); public function jsonSerialize();
} }

View file

@ -381,6 +381,7 @@ class PharFileInfo extends SplFileInfo
/** @return string */ /** @return string */
public function getContent() {} public function getContent() {}
/** @return mixed */
public function getMetadata() {} public function getMetadata() {}
/** @return int */ /** @return int */

View file

@ -104,8 +104,10 @@ class ReflectionFunction extends ReflectionFunctionAbstract
/** @return bool */ /** @return bool */
public function isDisabled() {} public function isDisabled() {}
/** @return mixed */
public function invoke(...$args) {} public function invoke(...$args) {}
/** @return mixed */
public function invokeArgs(array $args) {} public function invokeArgs(array $args) {}
/** @return Closure */ /** @return Closure */
@ -172,8 +174,10 @@ class ReflectionMethod extends ReflectionFunctionAbstract
/** @return int */ /** @return int */
public function getModifiers() {} public function getModifiers() {}
/** @return mixed */
public function invoke(?object $object = null, ...$args) {} public function invoke(?object $object = null, ...$args) {}
/** @return mixed */
public function invokeArgs(?object $object, array $args) {} public function invokeArgs(?object $object, array $args) {}
/** @return ReflectionClass */ /** @return ReflectionClass */
@ -255,6 +259,7 @@ class ReflectionClass implements Reflector
/** @return ReflectionClassConstant[] */ /** @return ReflectionClassConstant[] */
public function getReflectionConstants() {} public function getReflectionConstants() {}
/** @return mixed */
public function getConstant(string $name) {} public function getConstant(string $name) {}
/** @return ReflectionClassConstant|false */ /** @return ReflectionClassConstant|false */
@ -314,6 +319,7 @@ class ReflectionClass implements Reflector
/** @return ?array */ /** @return ?array */
public function getStaticProperties() {} public function getStaticProperties() {}
/** @return mixed */
public function getStaticPropertyValue(string $name, $default = UNKNOWN) {} public function getStaticPropertyValue(string $name, $default = UNKNOWN) {}
/** @return void */ /** @return void */
@ -367,6 +373,7 @@ class ReflectionProperty implements Reflector
/** @return string|false */ /** @return string|false */
public function getName() {} public function getName() {}
/** @return mixed */
public function getValue(?object $object = null) {} public function getValue(?object $object = null) {}
/** @return void */ /** @return void */
@ -426,6 +433,7 @@ class ReflectionClassConstant implements Reflector
/** @return string|false */ /** @return string|false */
public function getName() {} public function getName() {}
/** @return mixed */
public function getValue() {} public function getValue() {}
/** @return bool */ /** @return bool */
@ -501,6 +509,7 @@ class ReflectionParameter implements Reflector
/** @return bool */ /** @return bool */
public function isDefaultValueAvailable() {} public function isDefaultValueAvailable() {}
/** @return mixed */
public function getDefaultValue() {} public function getDefaultValue() {}
/** @return bool */ /** @return bool */

View file

@ -91,7 +91,10 @@ function socket_clear_error($socket = UNKNOWN): void {}
*/ */
function socket_import_stream($stream) {} function socket_import_stream($stream) {}
/** @param resource $socket */ /**
* @param resource $socket
* @return resource|false
*/
function socket_export_stream($socket) {} function socket_export_stream($socket) {}
/** @param resource $socket */ /** @param resource $socket */

View file

@ -90,6 +90,7 @@ class SplFileInfo
public function __toString(): string {} public function __toString(): string {}
/** @return void */
final public function _bad_state_ex() {} final public function _bad_state_ex() {}
} }

View file

@ -238,6 +238,7 @@ function array_sum(array $arg): int|float {}
function array_product(array $arg): int|float {} function array_product(array $arg): int|float {}
/** @return mixed */
function array_reduce(array $arg, callable $callback, $initial = null) {} function array_reduce(array $arg, callable $callback, $initial = null) {}
function array_filter(array $arg, callable $callback = UNKNOWN, int $use_keys = 0): array {} 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 {} function is_scalar($value): bool {}
/** @param mixed $value */ /** @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 */ /** @param mixed $value */
function is_iterable($value): bool {} 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 $in_codepage
* @param int|string $out_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 {} function sapi_windows_cp_is_utf8(): bool {}

View file

@ -2103,7 +2103,7 @@ ZEND_END_ARG_INFO()
#define arginfo_is_scalar arginfo_boolval #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_INFO(0, value)
ZEND_ARG_TYPE_INFO(0, syntax_only, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, syntax_only, _IS_BOOL, 0)
ZEND_ARG_INFO(1, callable_name) ZEND_ARG_INFO(1, callable_name)
@ -2212,7 +2212,7 @@ ZEND_END_ARG_INFO()
#endif #endif
#if defined(PHP_WIN32) #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, in_codepage)
ZEND_ARG_INFO(0, out_codepage) ZEND_ARG_INFO(0, out_codepage)
ZEND_ARG_TYPE_INFO(0, subject, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, subject, IS_STRING, 0)

View file

@ -2,6 +2,7 @@
class php_user_filter class php_user_filter
{ {
/** @return int */
public function filter($in, $out, &$consumed, $closing) {} public function filter($in, $out, &$consumed, $closing) {}
/** @return void */ /** @return void */

View 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_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 {}

View 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_ARG_INFO(0, value)
ZEND_END_ARG_INFO() 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_OBJ_INFO(0, parser, XmlParser, 0)
ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()

View file

@ -2,8 +2,10 @@
function xmlrpc_encode($value): ?string {} function xmlrpc_encode($value): ?string {}
/** @return mixed */
function xmlrpc_decode(string $xml, string $encoding = "iso-8859-1") {} 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_decode_request(string $xml, &$method, string $encoding = "iso-8859-1") {}
function xmlrpc_encode_request(?string $method, $params, array $output_options = UNKNOWN): ?string {} 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 */ /** @param resource $server */
function xmlrpc_server_register_method($server, string $method_name, $function): bool {} 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) {} function xmlrpc_server_call_method($server, string $xml, $user_data, array $output_options = UNKNOWN) {}
/** @return mixed */
function xmlrpc_parse_method_descriptions(string $xml) {} function xmlrpc_parse_method_descriptions(string $xml) {}
/** @param resource $server */ /** @param resource $server */

View file

@ -50,7 +50,7 @@ function xmlwriter_text(XMLWriter $xmlwriter, string $content): bool {}
function xmlwriter_write_raw(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 {} function xmlwriter_end_document(XMLWriter $xmlwriter): bool {}

View file

@ -104,7 +104,7 @@ ZEND_END_ARG_INFO()
#define arginfo_xmlwriter_write_raw arginfo_xmlwriter_write_cdata #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_OBJ_INFO(0, xmlwriter, XMLWriter, 0)
ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 1)
ZEND_ARG_TYPE_INFO(0, encoding, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, encoding, IS_STRING, 1)

View file

@ -20,7 +20,7 @@ function zend_test_deprecated(): void {}
function zend_create_unterminated_string(string $str): string {} function zend_create_unterminated_string(string $str): string {}
function zend_terminate_string(string &$str) {} function zend_terminate_string(string &$str): string {}
/** @param mixed $variable */ /** @param mixed $variable */
function zend_leak_variable($variable): void {} function zend_leak_variable($variable): void {}

View 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_ARG_TYPE_INFO(0, str, IS_STRING, 0)
ZEND_END_ARG_INFO() 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_ARG_TYPE_INFO(1, str, IS_STRING, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()