From 01177ee41cf94a08643ac129454f828969746a69 Mon Sep 17 00:00:00 2001 From: IanDelMar <42134098+IanDelMar@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:36:16 +0200 Subject: [PATCH] Add cond. return type and param type for absint() (#225) --- functionMap.php | 1 + tests/TypeInferenceTest.php | 1 + tests/data/absint.php | 54 +++++++++++++++++++++++++++++++++++++ wordpress-stubs.php | 3 +++ 4 files changed, 59 insertions(+) create mode 100644 tests/data/absint.php diff --git a/functionMap.php b/functionMap.php index 81da25a..c344817 100644 --- a/functionMap.php +++ b/functionMap.php @@ -34,6 +34,7 @@ return [ '_wp_json_sanity_check' => ['T', '@phpstan-template' => 'T', 'value' => 'T', 'depth' => 'positive-int'], '_get_list_table' => ["(\$class_name is 'WP_Posts_List_Table'|'WP_Media_List_Table'|'WP_Terms_List_Table'|'WP_Users_List_Table'|'WP_Comments_List_Table'|'WP_Post_Comments_List_Table'|'WP_Links_List_Table'|'WP_Plugin_Install_List_Table'|'WP_Themes_List_Table'|'WP_Theme_Install_List_Table'|'WP_Plugins_List_Table'|'WP_Application_Passwords_List_Table'|'WP_MS_Sites_List_Table'|'WP_MS_Users_List_Table'|'WP_MS_Themes_List_Table'|'WP_Privacy_Data_Export_Requests_List_Table'|'WP_Privacy_Data_Removal_Requests_List_Table' ? T : false)", '@phpstan-template' => 'T', 'class_name' => 'class-string', 'args' => 'array{screen?: string}'], + 'absint' => ['($maybeint is T&non-negative-int ? T : ($maybeint is negative-int ? positive-int : ($maybeint is empty ? 0 : ($maybeint is numeric-string ? non-negative-int : ($maybeint is string ? 0 : ($maybeint is true|non-empty-array ? 1 : ($maybeint is bool ? 0|1 : non-negative-int)))))))', '@template T' => 'of int', 'maybeint' => 'T|scalar|array|resource|null'], 'addslashes_gpc' => ['T', '@phpstan-template' => 'T', 'gpc' => 'T'], 'add_submenu_page' => [null, 'callback' => "''|callable"], 'have_posts' => [null, '@phpstan-impure' => ''], diff --git a/tests/TypeInferenceTest.php b/tests/TypeInferenceTest.php index 1ef79bc..8a2c580 100644 --- a/tests/TypeInferenceTest.php +++ b/tests/TypeInferenceTest.php @@ -11,6 +11,7 @@ public function dataFileAsserts(): iterable { yield from $this->gatherAssertTypes(__DIR__ . '/data/_get_list_table.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/_wp_json_sanity_check.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/absint.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/current_time.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/echo_parameter.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_approved_comments.php'); diff --git a/tests/data/absint.php b/tests/data/absint.php new file mode 100644 index 0000000..ec11e6d --- /dev/null +++ b/tests/data/absint.php @@ -0,0 +1,54 @@ + $posInt */ +$posInt = $_GET['posInt']; + +/** @var int<0, max> $nonNegInt */ +$nonNegInt = $_GET['nonNegInt']; + +/** @var resource $resource */ +$resource = $_GET['resource']; + +// Returns input for non-negative integers +assertType('0', absint(0)); +assertType('1', absint(1)); +assertType('10', absint(10)); +assertType('int<1, max>', absint($posInt)); +assertType('int<0, max>', absint($nonNegInt)); + +// Returns 0 for "empty" input +assertType('0', absint(null)); +assertType('0', absint(false)); +assertType('0', absint(0.0)); +assertType('0', absint('')); +assertType('0', absint([])); +// and non-numeric string +assertType('0', absint('nonNumericString')); +assertType('0', absint(' ')); + +// Returns 1 for true and non-empty array +assertType('1', absint(true)); +assertType('1', absint(['key' => 'value'])); + +// Returns 0 or 1 for booleans +assertType('0|1', absint((bool)$_GET['bool'])); + +// Returns positive integer for strictly negative integer input +assertType('int<1, max>', absint(-1)); +assertType('int<1, max>', absint(-10)); + +// Returns non-negative integer for floats, numeric strings, ressources +assertType('int<0, max>', absint(1.0)); +assertType('int<0, max>', absint('-10')); +assertType('int<0, max>', absint($resource)); +// and any other type that is not a subtype of `$maybeint` +assertType('int<0, max>', absint(new stdClass())); diff --git a/wordpress-stubs.php b/wordpress-stubs.php index 0e980b9..4262d47 100644 --- a/wordpress-stubs.php +++ b/wordpress-stubs.php @@ -109500,6 +109500,9 @@ function dead_db() * * @param mixed $maybeint Data you wish to have converted to a non-negative integer. * @return int A non-negative integer. + * @template T of int + * @phpstan-param T|scalar|array|resource|null $maybeint + * @phpstan-return ($maybeint is T&non-negative-int ? T : ($maybeint is negative-int ? positive-int : ($maybeint is empty ? 0 : ($maybeint is numeric-string ? non-negative-int : ($maybeint is string ? 0 : ($maybeint is true|non-empty-array ? 1 : ($maybeint is bool ? 0|1 : non-negative-int))))))) */ function absint($maybeint) {