Skip to content

Commit

Permalink
functionMap: additions, improvement, corrections (#127)
Browse files Browse the repository at this point in the history
* Improve return type of get_comment() and get_post()

* Add wpdb::get_row() to functions map

* Add tests for wp_clear_scheduled_hook()

* Add wpdb::get_results() to the functions map

* Add get_bookmark() to function map

* Add get_category() to function map

* Add argument type to get_term()

* Use fully qualified name

* Add get_category_by_path() to function map

* Remove types already added without function map

* Add spaces around array assignment operator

* Regenerate function map

* Add trailing comma to last array item
  • Loading branch information
IanDelMar committed Nov 2, 2023
1 parent e6ec1f4 commit 5e28d4b
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 62 deletions.
77 changes: 40 additions & 37 deletions functionMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,37 @@
/**
* This array is in the same format as the function map array in PHPStan:
*
* '<function_name>' => ['<return_type>', '<arg_name>'=>'<arg_type>']
* '<function_name>' => ['<return_type>', '<arg_name>' => '<arg_type>']
*
* For classes, or if you don't wish to define the `@phpstan-return` tag:
*
* '<class_name>' => [null, '<arg_name>'=>'<arg_type>']
* '<class_name>' => [null, '<arg_name>' => '<arg_type>']
*
* @link https://github.com/phpstan/phpstan-src/blob/1.5.x/resources/functionMap.php
* @link https://github.com/phpstan/phpstan-src/blob/1.10.x/resources/functionMap.php
*/
return [
'addslashes_gpc' => ['T', '@phpstan-template'=>'T', 'gpc'=>'T'],
'get_objects_in_term' => [null, 'args'=>'array{order?: string}'],
'have_posts' => [null, '@phpstan-impure'=>''],
'rawurlencode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'sanitize_category' => ['T', '@phpstan-template'=>'T of array|object', 'category'=>'T'],
'sanitize_post' => ['T', '@phpstan-template'=>'T of array|object', 'post'=>'T'],
'sanitize_term' => ['T', '@phpstan-template'=>'T of array|object', 'term'=>'T'],
'stripslashes_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'urldecode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'urlencode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'wp_clear_scheduled_hook' => ['($wp_error is false ? 0|positive-int|false : 0|positive-int|\WP_Error)', 'args'=>$cronArgsType],
'addslashes_gpc' => ['T', '@phpstan-template' => 'T', 'gpc' => 'T'],
'get_objects_in_term' => [null, 'args' => 'array{order?: string}'],
'have_posts' => [null, '@phpstan-impure' => ''],
'rawurlencode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'sanitize_category' => ['T', '@phpstan-template' => 'T of array|object', 'category' => 'T'],
'sanitize_post' => ['T', '@phpstan-template' => 'T of array|object', 'post' => 'T'],
'sanitize_term' => ['T', '@phpstan-template' => 'T of array|object', 'term' => 'T'],
'stripslashes_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'urldecode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'urlencode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_clear_scheduled_hook' => ['(0|positive-int|($wp_error is false ? false : \WP_Error))', 'args'=>$cronArgsType],
'wp_get_schedule' => [null, 'args'=>$cronArgsType],
'wp_get_scheduled_event' => [null, 'args'=>$cronArgsType],
'WP_Http::get' => [$httpReturnType],
'WP_Http::head' => [$httpReturnType],
'WP_Http::post' => [$httpReturnType],
'WP_Http::request' => [$httpReturnType],
'WP_List_Table::display_tablenav' => ['void', 'which'=>'"top"|"bottom"'],
'WP_List_Table::pagination' => ['void', 'which'=>'"top"|"bottom"'],
'WP_List_Table::set_pagination_args' => ['void', 'args'=>'array{total_items?: int, total_pages?: int, per_page?: int}'],
'WP_List_Table::display_tablenav' => ['void', 'which' => '"top"|"bottom"'],
'WP_List_Table::pagination' => ['void', 'which' => '"top"|"bottom"'],
'WP_List_Table::set_pagination_args' => ['void', 'args' => 'array{total_items?: int, total_pages?: int, per_page?: int}'],
'wp_next_scheduled' => [null, 'args'=>$cronArgsType],
'WP_Post_Type::__construct' => ['void', 'args'=>'array<string, mixed>'],
'WP_Query::have_posts' => [null, '@phpstan-impure'=>''],
'WP_Query::have_posts' => [null, '@phpstan-impure' => ''],
'wp_remote_get' => [$httpReturnType],
'wp_remote_head' => [$httpReturnType],
'wp_remote_post' => [$httpReturnType],
Expand All @@ -56,26 +55,25 @@
'wp_safe_remote_request' => [$httpReturnType],
'wp_schedule_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_schedule_single_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_slash' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'WP_Taxonomy::__construct' => ['void', 'args'=>'array<string, mixed>'],
'wp_slash' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_unschedule_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_unslash' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'wp_unslash' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_widget_rss_form' => ['void', 'args'=>$wpWidgetRssFormArgsType, 'input'=>$wpWidgetRssFormInputType],
'WP_REST_Request' => [null, '@phpstan-template'=>'T of array', '@phpstan-implements'=>'ArrayAccess<key-of<T>, value-of<T>>'],
'WP_REST_Request::offsetExists' => [null, 'offset'=>'@param key-of<T>'],
'WP_REST_Request::offsetGet' => ['T[TOffset]', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset'],
'WP_REST_Request::offsetSet' => ['void', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset', 'value'=>'T[TOffset]'],
'WP_REST_Request::offsetUnset' => ['void', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset'],
'WP_REST_Request' => [null, '@phpstan-template' => 'T of array', '@phpstan-implements' => 'ArrayAccess<key-of<T>, value-of<T>>'],
'WP_REST_Request::offsetExists' => [null, 'offset' => '@param key-of<T>'],
'WP_REST_Request::offsetGet' => ['T[TOffset]', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset'],
'WP_REST_Request::offsetSet' => ['void', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset', 'value' => 'T[TOffset]'],
'WP_REST_Request::offsetUnset' => ['void', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset'],
'WP_Theme' => [null, '@phpstan-type'=>"ThemeKey 'Name'|'Version'|'Status'|'Title'|'Author'|'Author Name'|'Author URI'|'Description'|'Template'|'Stylesheet'|'Template Files'|'Stylesheet Files'|'Template Dir'|'Stylesheet Dir'|'Screenshot'|'Tags'|'Theme Root'|'Theme Root URI'|'Parent Theme'"],
'WP_Theme::get' => ["(\$header is 'Name'|'ThemeURI'|'Description'|'Author'|'AuthorURI'|'Version'|'Template'|'Status'|'Tags'|'TextDomain'|'DomainPath'|'RequiresWP'|'RequiresPHP'|'UpdateURI' ? (\$header is 'Tags' ? string[] : string) : false)"],
'WP_Theme::offsetExists' => ['($offset is ThemeKey ? true : false)'],
'WP_Theme::offsetGet' => ['($offset is ThemeKey ? mixed : null)'],
'WP_Block_List' => [null, '@phpstan-implements'=>'ArrayAccess<int, WP_Block>'],
'WP_Block_List::offsetExists' => [null, 'index'=>'int'],
'WP_Block_List::offsetGet' => ['WP_Block|null', 'index'=>'int'],
'WP_Block_List::offsetSet' => ['void', 'index'=>'int|null'],
'WP_Block_List::offsetUnset' => ['void', 'index'=>'int'],
'is_wp_error' => ['($thing is \WP_Error ? true : false)', '@phpstan-assert-if-true'=>'\WP_Error $thing'],
'WP_Block_List' => [null, '@phpstan-implements' => 'ArrayAccess<int, WP_Block>'],
'WP_Block_List::offsetExists' => [null, 'index' => 'int'],
'WP_Block_List::offsetGet' => ['WP_Block|null', 'index' => 'int'],
'WP_Block_List::offsetSet' => ['void', 'index' => 'int|null'],
'WP_Block_List::offsetUnset' => ['void', 'index' => 'int'],
'is_wp_error' => ['($thing is \WP_Error ? true : false)', '@phpstan-assert-if-true' => '\WP_Error $thing'],
'current_time' => ["(\$type is 'timestamp'|'U' ? int : string)"],
'mysql2date' => ["(\$format is 'G'|'U' ? int|false : string|false)"],
'get_post_types' => ["(\$output is 'names' ? array<int, string> : array<int, \WP_Post_Type>)"],
Expand All @@ -84,11 +82,11 @@
'get_attachment_taxonomies' => ["(\$output is 'names' ? array<int, string> : array<string, \WP_Taxonomy>)"],
'get_taxonomies_for_attachments' => ["(\$output is 'names' ? array<int, string> : array<string, \WP_Taxonomy>)"],
'get_post_stati' => ["(\$output is 'names' ? array<string, string> : array<string, \stdClass>)"],
'get_comment' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Comment|null))"],
'get_post' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))"],
'get_comment' => ["(\$comment is \WP_Comment ? array<array-key, mixed>|\WP_Comment : array<array-key, mixed>|\WP_Comment|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Comment|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_post' => ["(\$post is \WP_Post ? array<array-key, mixed>|\WP_Post : array<array-key, mixed>|\WP_Post|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'" ],
'get_term_by' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|false : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|false : \WP_Term|\WP_Error|false))"],
'get_page_by_path' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))"],
'get_term' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|null : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|null : \WP_Term|\WP_Error|null))"],
'get_term' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|null : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'has_action' => ['($callback is false ? bool : false|int)'],
'has_filter' => ['($callback is false ? bool : false|int)'],
'get_permalink' => ['($post is \WP_Post ? string : string|false)'],
Expand Down Expand Up @@ -127,5 +125,10 @@
'WP_Filesystem_Base::dirlist' => [$filesystemDirlistReturnType],
'WP_Filesystem_SSH2::dirlist' => [$filesystemDirlistReturnType],
'WP_Filesystem_ftpsockets::dirlist' => [$filesystemDirlistReturnType],
'wpdb::prepare' => [null, 'query'=>'literal-string'],
'wpdb::prepare' => [null, 'query' => 'literal-string'],
'wpdb::get_row' => ["null|void|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : \stdClass))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'", 'y' => '0|positive-int'],
'wpdb::get_results' => ["null|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : (\$output is 'OBJECT_K' ? array<string, \stdClass> : \stdClass)))", 'output' => "'OBJECT'|'OBJECT_K'|'ARRAY_A'|'ARRAY_N'"],
'get_bookmark' => ["null|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : \stdClass))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_category' => ["(\$category is object ? array<array-key, mixed>|\WP_Term : array<array-key, mixed>|\WP_Term|\WP_Error|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|\WP_Error|null : (\$output is 'ARRAY_N' ? array<int, mixed>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_category_by_path' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|\WP_Error|null : (\$output is 'ARRAY_N' ? array<int, mixed>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
];
5 changes: 5 additions & 0 deletions tests/TypeInferenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public function dataFileAsserts(): iterable
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_attachment_taxonomies.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_bookmark.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category_by_path.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_comment.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_object_taxonomies.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_post.php');
Expand All @@ -27,8 +30,10 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/is_wp_error.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/mysql2date.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/term_exists.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_clear_scheduled_hook.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_error_parameter.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_theme.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wpdb.php');
}

/**
Expand Down
16 changes: 16 additions & 0 deletions tests/data/get_bookmark.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_bookmark;
use function PHPStan\Testing\assertType;

/** @var \stdClass|int $bookmark */
$bookmark;

assertType('stdClass|null', get_bookmark($bookmark));
assertType('stdClass|null', get_bookmark($bookmark, 'OBJECT'));
assertType('array<string, mixed>|null', get_bookmark($bookmark, 'ARRAY_A'));
assertType('array<int, mixed>|null', get_bookmark($bookmark, 'ARRAY_N'));
24 changes: 24 additions & 0 deletions tests/data/get_category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_category;
use function PHPStan\Testing\assertType;

/** @var object $category */
$category;

assertType('WP_Term', get_category($category));
assertType('WP_Term', get_category($category, 'OBJECT'));
assertType('array<string, mixed>', get_category($category, 'ARRAY_A'));
assertType('array<int, mixed>', get_category($category, 'ARRAY_N'));

/** @var int|object $category */
$category;

assertType('WP_Error|WP_Term|null', get_category($category));
assertType('WP_Error|WP_Term|null', get_category($category, 'OBJECT'));
assertType('array<string, mixed>|WP_Error|null', get_category($category, 'ARRAY_A'));
assertType('array<int, mixed>|WP_Error|null', get_category($category, 'ARRAY_N'));
16 changes: 16 additions & 0 deletions tests/data/get_category_by_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_category_by_path;
use function PHPStan\Testing\assertType;

/** @var bool $bool */
$bool;

assertType('WP_Error|WP_Term|null', get_category_by_path('', $bool, ));
assertType('WP_Error|WP_Term|null', get_category_by_path('', $bool, 'OBJECT'));
assertType('array<string, mixed>|WP_Error|null', get_category_by_path('', $bool, 'ARRAY_A'));
assertType('array<int, mixed>|WP_Error|null', get_category_by_path('', $bool, 'ARRAY_N'));
20 changes: 11 additions & 9 deletions tests/data/get_comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@
use function get_comment;
use function PHPStan\Testing\assertType;

/** @var \WP_Comment|int $comment */
$comment = $comment;
/** @var \WP_Comment|int|string|null $comment */
$comment;

// Default output
assertType('WP_Comment|null', get_comment());
assertType('WP_Comment|null', get_comment($comment));
assertType('WP_Comment|null', get_comment($comment, OBJECT));
assertType('WP_Comment|null', get_comment($comment, 'OBJECT'));

// Associative array output
assertType('array<string, mixed>|null', get_comment($comment, ARRAY_A));
assertType('array<string, mixed>|null', get_comment($comment, 'ARRAY_A'));

// Numeric array output
assertType('array<int, mixed>|null', get_comment($comment, ARRAY_N));
assertType('array<int, mixed>|null', get_comment($comment, 'ARRAY_N'));

// Unknown output
assertType('array<int|string, mixed>|WP_Comment|null', get_comment($comment, (string)$_GET['unknown_string']));
/** @var \WP_Comment $comment */
$comment;

// Unexpected output
assertType('WP_Comment|null', get_comment($comment, 'Hello'));
assertType('WP_Comment', get_comment($comment));
assertType('WP_Comment', get_comment($comment, 'OBJECT'));
assertType('array<string, mixed>', get_comment($comment, 'ARRAY_A'));
assertType('array<int, mixed>', get_comment($comment, 'ARRAY_N'));
18 changes: 10 additions & 8 deletions tests/data/get_post.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@
use function PHPStan\Testing\assertType;

/** @var \WP_Post|int|null $post */
$post = $post;
$post;

// Default output
assertType('WP_Post|null', get_post());
assertType('WP_Post|null', get_post($post));
assertType('WP_Post|null', get_post($post, OBJECT));
assertType('WP_Post|null', get_post($post, 'OBJECT'));

// Associative array output
assertType('array<string, mixed>|null', get_post($post, ARRAY_A));
assertType('array<string, mixed>|null', get_post($post, 'ARRAY_A'));

// Numeric array output
assertType('array<int, mixed>|null', get_post($post, ARRAY_N));
assertType('array<int, mixed>|null', get_post($post, 'ARRAY_N'));

// Unknown output
assertType('array<int|string, mixed>|WP_Post|null', get_post($post, (string)$_GET['unknown_string']));
/** @var \WP_Post $post */
$post;

// Unexpected output
assertType('WP_Post|null', get_post($post, 'Hello'));
assertType('WP_Post', get_post($post));
assertType('WP_Post', get_post($post, 'OBJECT'));
assertType('array<string, mixed>', get_post($post, 'ARRAY_A'));
assertType('array<int, mixed>', get_post($post, 'ARRAY_N'));
2 changes: 1 addition & 1 deletion tests/data/get_term.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
assertType( 'array<string, int|string>|WP_Error|null', get_term( 2, '', ARRAY_A ) );
assertType( 'array<string, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_A ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, '', ARRAY_N ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_N ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_N ) );
12 changes: 12 additions & 0 deletions tests/data/wp_clear_scheduled_hook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function wp_clear_scheduled_hook;
use function PHPStan\Testing\assertType;

assertType('int<0, max>|false', wp_clear_scheduled_hook('hook', []));
assertType('int<0, max>|false', wp_clear_scheduled_hook('hook', [], false));
assertType('int<0, max>|WP_Error', wp_clear_scheduled_hook('hook', [], true));
21 changes: 21 additions & 0 deletions tests/data/wpdb.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use wpdb;
use function PHPStan\Testing\assertType;

// wpdb::get_row()
assertType('stdClass|void|null', wpdb::get_row());
assertType('stdClass|void|null', wpdb::get_row(null, 'OBJECT'));
assertType('array<string, mixed>|void|null', wpdb::get_row(null, 'ARRAY_A'));
assertType('array<int, mixed>|void|null', wpdb::get_row(null, 'ARRAY_N'));

// wpdb::get_results()
assertType('stdClass|null', wpdb::get_results());
assertType('stdClass|null', wpdb::get_results(null, 'OBJECT'));
assertType('array<string, stdClass>|null', wpdb::get_results(null, 'OBJECT_K'));
assertType('array<string, mixed>|null', wpdb::get_results(null, 'ARRAY_A'));
assertType('array<int, mixed>|null', wpdb::get_results(null, 'ARRAY_N'));
Loading

0 comments on commit 5e28d4b

Please sign in to comment.