Skip to content

Commit 4ed6cf2

Browse files
Add dynamic return type extension for wp_die() (#201)
* Add dynamic return type extension for wp_die() * Update tests for wp_die() Co-authored-by: Viktor Szépe <viktor@szepe.net> --------- Co-authored-by: Viktor Szépe <viktor@szepe.net>
1 parent 76f7835 commit 4ed6cf2

File tree

4 files changed

+73
-1
lines changed

4 files changed

+73
-1
lines changed

extension.neon

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ services:
9595
class: SzepeViktor\PHPStan\WordPress\WpParseUrlFunctionDynamicReturnTypeExtension
9696
tags:
9797
- phpstan.broker.dynamicFunctionReturnTypeExtension
98+
-
99+
class: SzepeViktor\PHPStan\WordPress\WpDieDynamicFunctionReturnTypeExtension
100+
tags:
101+
- phpstan.broker.dynamicFunctionReturnTypeExtension
98102
-
99103
class: SzepeViktor\PHPStan\WordPress\HookDocsVisitor
100104
tags:
@@ -124,7 +128,6 @@ parameters:
124128
- SAVEQUERIES
125129
- SCRIPT_DEBUG
126130
earlyTerminatingFunctionCalls:
127-
- wp_die
128131
- wp_send_json
129132
- wp_send_json_success
130133
- wp_send_json_error
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/**
4+
* Set return type of wp_die().
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace SzepeViktor\PHPStan\WordPress;
10+
11+
use PhpParser\Node\Expr\FuncCall;
12+
use PHPStan\Analyser\Scope;
13+
use PHPStan\Reflection\FunctionReflection;
14+
use PHPStan\Type\Constant\ConstantStringType;
15+
use PHPStan\Type\Type;
16+
use PHPStan\Type\VoidType;
17+
use PHPStan\Type\NeverType;
18+
19+
class WpDieDynamicFunctionReturnTypeExtension implements \PHPStan\Type\DynamicFunctionReturnTypeExtension
20+
{
21+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
22+
{
23+
return $functionReflection->getName() === 'wp_die';
24+
}
25+
26+
// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter
27+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
28+
{
29+
$args = $functionCall->getArgs();
30+
31+
// Called without $args parameter
32+
if (count($args) < 3) {
33+
return new NeverType();
34+
}
35+
36+
$argType = $scope->getType($args[2]->value);
37+
38+
// Return void for non constant arrays.
39+
if (! $argType->isConstantArray()->yes()) {
40+
return new VoidType();
41+
}
42+
43+
// Return never if the key 'exit' is not set.
44+
if (! $argType->hasOffsetValueType(new ConstantStringType('exit'))->yes()) {
45+
return new NeverType();
46+
}
47+
48+
// Note WP's wp_die handlers do lazy comparison
49+
return $argType->getOffsetValueType(new ConstantStringType('exit'))->toBoolean()->isTrue()->yes()
50+
? new NeverType()
51+
: new VoidType();
52+
}
53+
}

tests/DynamicReturnTypeExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function dataFileAsserts(): iterable
3131
yield from $this->gatherAssertTypes(__DIR__ . '/data/term_exists.php');
3232
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_error_parameter.php');
3333
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_parse_url.php');
34+
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_die.php');
3435
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_theme_get.php');
3536
}
3637

tests/data/wp_die.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SzepeViktor\PHPStan\WordPress\Tests;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
/** @var array $array */
10+
$array = null;
11+
12+
assertType('*NEVER*', wp_die('', ''));
13+
assertType('*NEVER*', wp_die('', '', ['exit' => true]));
14+
assertType('void', wp_die('', '', ['exit' => false]));
15+
assertType('void', wp_die('', '', $array));

0 commit comments

Comments
 (0)