Skip to content

Commit 549ce7c

Browse files
committed
Add warning for arguments in stubs that doesn't have any type info
1 parent ca35800 commit 549ce7c

9 files changed

+73
-29
lines changed

Zend/zend_builtin_functions.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,16 @@ ZEND_FUNCTION(error_reporting)
385385
{
386386
zval *err = NULL;
387387
int old_error_reporting;
388+
zend_long err;
389+
zend_bool err_is_null = 1;
388390

389391
ZEND_PARSE_PARAMETERS_START(0, 1)
390392
Z_PARAM_OPTIONAL
391-
Z_PARAM_ZVAL(err)
393+
Z_PARAM_LONG_OR_NULL(err, err_is_null)
392394
ZEND_PARSE_PARAMETERS_END();
393395

394396
old_error_reporting = EG(error_reporting);
395-
if (ZEND_NUM_ARGS() != 0) {
397+
if (!err_is_null) {
396398
zend_string *new_val = zval_try_get_string(err);
397399
if (UNEXPECTED(!new_val)) {
398400
RETURN_THROWS();
@@ -424,11 +426,7 @@ ZEND_FUNCTION(error_reporting)
424426
}
425427

426428
p->value = new_val;
427-
if (Z_TYPE_P(err) == IS_LONG) {
428-
EG(error_reporting) = Z_LVAL_P(err);
429-
} else {
430-
EG(error_reporting) = atoi(ZSTR_VAL(p->value));
431-
}
429+
G(error_reporting) = err;
432430
} while (0);
433431
}
434432

@@ -638,11 +636,11 @@ ZEND_FUNCTION(get_parent_class)
638636
zval *arg;
639637
zend_class_entry *ce = NULL;
640638

641-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
639+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &arg) == FAILURE) {
642640
RETURN_THROWS();
643641
}
644642

645-
if (!ZEND_NUM_ARGS()) {
643+
if (!arg) {
646644
ce = zend_get_executed_scope();
647645
if (ce && ce->parent) {
648646
RETURN_STR_COPY(ce->parent->name);
@@ -655,6 +653,8 @@ ZEND_FUNCTION(get_parent_class)
655653
ce = Z_OBJ_P(arg)->ce;
656654
} else if (Z_TYPE_P(arg) == IS_STRING) {
657655
ce = zend_lookup_class(Z_STR_P(arg));
656+
} else {
657+
zend_argument_type_error(1, "must be type of object|string|null, %s given", zend_zval_type_name(arg));
658658
}
659659

660660
if (ce && ce->parent) {
@@ -695,7 +695,7 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass) /*
695695
} else if (Z_TYPE_P(obj) == IS_OBJECT) {
696696
instance_ce = Z_OBJCE_P(obj);
697697
} else {
698-
RETURN_FALSE;
698+
zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(obj));
699699
}
700700

701701
if (!only_subclass && EXPECTED(zend_string_equals(instance_ce->name, class_name))) {
@@ -940,6 +940,8 @@ ZEND_FUNCTION(get_class_methods)
940940
ce = Z_OBJCE_P(klass);
941941
} else if (Z_TYPE_P(klass) == IS_STRING) {
942942
ce = zend_lookup_class(Z_STR_P(klass));
943+
} else {
944+
zend_argument_type_error(1, "must be of type object|string. %s given", zend_zval_type_name(klass));
943945
}
944946

945947
if (!ce) {

Zend/zend_builtin_functions.stub.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ function strcasecmp(string $str1, string $str2): int {}
2020

2121
function strncasecmp(string $str1, string $str2, int $len): int {}
2222

23-
function error_reporting($new_error_level = UNKNOWN): int {}
23+
function error_reporting(?int $new_error_level = null): int {}
2424

25+
/** @param bool|int|float|string|array|resource|object|null $value */
2526
function define(string $constant_name, $value, bool $case_insensitive = false): bool {}
2627

2728
function defined(string $constant_name): bool {}
@@ -30,10 +31,13 @@ function get_class(object $object = UNKNOWN): string {}
3031

3132
function get_called_class(): string {}
3233

33-
function get_parent_class($object = UNKNOWN): string|false {}
34+
/** @param object|string|null $object */
35+
function get_parent_class($object = null): string|false {}
3436

37+
/** @param object|string $object */
3538
function is_subclass_of($object, string $class_name, bool $allow_string = true): bool {}
3639

40+
/** @param object|string $object */
3741
function is_a($object, string $class_name, bool $allow_string = false): bool {}
3842

3943
function get_class_vars(string $class_name): array|false {}
@@ -42,6 +46,7 @@ function get_object_vars(object $obj): array {}
4246

4347
function get_mangled_object_vars(object $obj): array {}
4448

49+
/** @param object|string $class */
4550
function get_class_methods($class): ?array {}
4651

4752
function method_exists($object_or_class, string $method): bool {}

Zend/zend_builtin_functions_arginfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ ZEND_END_ARG_INFO()
3333
#define arginfo_strncasecmp arginfo_strncmp
3434

3535
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_error_reporting, 0, 0, IS_LONG, 0)
36-
ZEND_ARG_INFO(0, new_error_level)
36+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, new_error_level, IS_LONG, 1, "null")
3737
ZEND_END_ARG_INFO()
3838

3939
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_define, 0, 2, _IS_BOOL, 0)
@@ -53,7 +53,7 @@ ZEND_END_ARG_INFO()
5353
#define arginfo_get_called_class arginfo_zend_version
5454

5555
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_get_parent_class, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
56-
ZEND_ARG_INFO(0, object)
56+
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, object, "null")
5757
ZEND_END_ARG_INFO()
5858

5959
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_subclass_of, 0, 2, _IS_BOOL, 0)

Zend/zend_interfaces.stub.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,30 @@ public function rewind();
3030

3131
interface ArrayAccess
3232
{
33-
/** @return bool */
33+
/**
34+
* @param mixed $offset
35+
* @return bool
36+
*/
3437
public function offsetExists($offset);
3538

36-
/* actually this should be return by ref but atm cannot be */
37-
/** @return mixed */
39+
/**
40+
* Actually this should be return by ref but atm cannot be.
41+
* @param mixed $offset
42+
* @return mixed
43+
*/
3844
public function offsetGet($offset);
3945

40-
/** @return void */
46+
/**
47+
* @param mixed $offset
48+
* @param mixed $value
49+
* @return void
50+
*/
4151
public function offsetSet($offset, $value);
4252

43-
/** @return void */
53+
/**
54+
* @param mixed $offset
55+
* @return void
56+
*/
4457
public function offsetUnset($offset);
4558
}
4659

build/gen_stub.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,15 @@ public function getDeclaration(): string
321321
return "ZEND_FUNCTION($this->name);\n";
322322
}
323323

324-
public function __toString()
324+
public function getName(): string
325325
{
326326
return $this->className ? "$this->className::$this->name" : $this->name;
327327
}
328+
329+
public function __toString()
330+
{
331+
return $this->getName();
332+
}
328333
}
329334

330335
class ReturnInfo {
@@ -561,8 +566,19 @@ public function getValue(): string {
561566

562567
public function getVariableName(): string {
563568
$value = $this->getValue();
564-
if ($value === null || strlen($value) === 0 || $value[0] !== '$') {
565-
throw new Exception("@$this->name not followed by variable name");
569+
if ($value === null || strlen($value) === 0) {
570+
throw new Exception("@$this->name doesn't have any value");
571+
}
572+
573+
if ($this->name === "param") {
574+
$pos = strpos($value, " ");
575+
if ($pos !== false) {
576+
$value = substr($value, $pos + 1);
577+
}
578+
}
579+
580+
if ($value[0] !== '$') {
581+
throw new Exception("@$this->name doesn't contain variable name");
566582
}
567583

568584
return substr($value, 1);
@@ -595,6 +611,7 @@ function parseFunctionLike(
595611
$alias = null;
596612
$isDeprecated = false;
597613
$haveDocReturnType = false;
614+
$docParamTypes = [];
598615

599616
if ($comment) {
600617
$tags = parseDocComment($comment);
@@ -616,13 +633,16 @@ function parseFunctionLike(
616633
$isDeprecated = true;
617634
} else if ($tag->name === 'return') {
618635
$haveDocReturnType = true;
636+
} else if ($tag->name === 'param') {
637+
$docParamTypes[$tag->getVariableName()] = true;
619638
}
620639
}
621640
}
622641

623642
$args = [];
624643
$numRequiredArgs = 0;
625644
$foundVariadic = false;
645+
static $warnings = [];
626646
foreach ($func->getParams() as $i => $param) {
627647
$varName = $param->var->name;
628648
$preferRef = !empty($paramMeta[$varName]['preferRef']);
@@ -641,6 +661,12 @@ function parseFunctionLike(
641661
}
642662

643663
$type = $param->type ? Type::fromNode($param->type) : null;
664+
if ($type === null && !isset($docParamTypes[$varName]) && !isset($warnings[$name->getName()])) {
665+
$warnings[$name->getName()] = true;
666+
//throw new Exception("Missing argument type for function $name()");
667+
echo "Warning: Missing argument type for function $name()\n";
668+
}
669+
644670
if ($param->default instanceof Expr\ConstFetch &&
645671
$param->default->name->toLowerString() === "null" &&
646672
$type && !$type->isNullable()

ext/hash/hash.stub.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function hash_hmac_algos(): array {}
3131
function hash_pbkdf2(string $algo, string $password, string $salt, int $iterations, int $length = 0, bool $raw_output = false): string {}
3232

3333
/**
34-
* @param $known_string no type juggling is performed
35-
* @param $user_string no type juggling is performed
34+
* @param string $known_string no type juggling is performed
35+
* @param string $user_string no type juggling is performed
3636
*/
3737
function hash_equals(string $known_string, string $user_string): bool {}
3838

ext/intl/php_intl.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ function transliterator_list_ids(): array|false {}
414414

415415
function transliterator_create_inverse(Transliterator $orig_trans): ?Transliterator {}
416416

417-
/** @param Transliterator|string */
417+
/** @param Transliterator|string $transliterator */
418418
function transliterator_transliterate($transliterator, string $subject, int $start = 0, int $end = -1): string|false {}
419419

420420
function transliterator_get_error_code(Transliterator $trans): int|false {}

ext/mysqli/mysqli.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ function mysqli_stmt_attr_set(mysqli_stmt $mysql_stmt, int $attr, int $mode_in):
683683

684684
function mysqli_stmt_bind_param(mysqli_stmt $mysql_stmt, string $types, mixed &...$vars): bool {}
685685

686-
/** @param mixed &...$vars */
686+
/** @param mixed $vars */
687687
function mysqli_stmt_bind_result(mysqli_stmt $mysql_stmt, &...$vars): bool {}
688688

689689
function mysqli_stmt_close(mysqli_stmt $mysql_stmt): bool {}

ext/reflection/php_reflection.stub.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,9 +471,7 @@ class ReflectionParameter implements Reflector
471471
/** @alias ReflectionClass::__clone */
472472
final private function __clone() {}
473473

474-
/**
475-
* @param $function string|array|object
476-
*/
474+
/** @param string|array|object $function */
477475
public function __construct($function, int|string $parameter) {}
478476

479477
public function __toString(): string {}

0 commit comments

Comments
 (0)