Skip to content

Commit 2272a29

Browse files
quentin389GitHub Enterprise
authored andcommitted
Merge pull request #13 from php/DEVXP-372_do_not_remove_never_return_type_from_rewritten_code
[DEVXP-372]: Do not remove 'never' return type from rewritten code.
2 parents 35535ae + 3625047 commit 2272a29

File tree

3 files changed

+45
-20
lines changed

3 files changed

+45
-20
lines changed

src/Badoo/SoftMocks.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ protected function pStmt_ClassMethod(\PhpParser\Node\Stmt\ClassMethod $node): st
276276
. $this->pModifiers($node->flags)
277277
. 'function ' . ($node->byRef ? '&' : '') . $node->name
278278
. '(' . $this->pCommaSeparated($node->params) . ')'
279-
. ($this->functionShouldReturn($node) ? ' : ' . $this->p($node->returnType) : '')
279+
. ($this->functionShouldHaveReturnType($node) ? ' : ' . $this->p($node->returnType) : '')
280280
. (null !== $node->stmts ? '{' . $this->pStmts($node->stmts) . '}' : ';');
281281
}
282282

@@ -288,7 +288,7 @@ protected function pStmt_Function(\PhpParser\Node\Stmt\Function_ $node): string
288288
return $ret
289289
. 'function ' . ($node->byRef ? '&' : '') . $node->name
290290
. '(' . $this->pCommaSeparated($node->params) . ')'
291-
. ($this->functionShouldReturn($node) ? ' : ' . $this->p($node->returnType) : '')
291+
. ($this->functionShouldHaveReturnType($node) ? ' : ' . $this->p($node->returnType) : '')
292292
. '{' . $this->pStmts($node->stmts) . '}';
293293
}
294294

@@ -436,17 +436,9 @@ protected function addAttributeGroupsBeforeStatement(\PhpParser\Node\Stmt $node)
436436
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $node
437437
* @noinspection PhpDocSignatureInspection - PHP 7.4 compatibility
438438
*/
439-
protected function functionShouldReturn(\PhpParser\Node\Stmt $node): bool
439+
protected function functionShouldHaveReturnType(\PhpParser\Node\Stmt $node): bool
440440
{
441-
if ($node->returnType === null) {
442-
return false;
443-
}
444-
445-
if ($node->returnType instanceof \PhpParser\Node\Identifier && $node->returnType->name === 'never') {
446-
return false;
447-
}
448-
449-
return true;
441+
return $node->returnType !== null;
450442
}
451443
}
452444

@@ -2790,7 +2782,7 @@ public function rewriteStmt_ClassMethod(\PhpParser\Node\Stmt\ClassMethod $Node)
27902782
// $mm_callback = SoftMocks::getMockForGenerator();
27912783
// foreach ($mm_callback(...) as $mm_val) { yield $mm_val; }
27922784
//
2793-
// also functions with void return type declarations cannot return values
2785+
// also functions with 'void' or 'never' return type declarations cannot return values
27942786
if ($this->has_yield) {
27952787
$args = [$static, $function];
27962788

@@ -2845,9 +2837,12 @@ public function rewriteStmt_ClassMethod(\PhpParser\Node\Stmt\ClassMethod $Node)
28452837
new \PhpParser\Node\Expr\Variable("__softmocksvariableforcode")
28462838
);
28472839

2848-
if ($Node->returnType instanceof \PhpParser\Node\Identifier && $Node->returnType->name === 'void') {
2840+
$returnTypeName = $Node->returnType instanceof \PhpParser\Node\Identifier ? $Node->returnType->name : null;
2841+
if ($returnTypeName === 'void') {
28492842
$body_stmts[] = new \PhpParser\Node\Stmt\Expression($eval);
28502843
$body_stmts[] = new \PhpParser\Node\Stmt\Return_();
2844+
} elseif ($returnTypeName === 'never') {
2845+
$body_stmts[] = new \PhpParser\Node\Stmt\Expression($eval);
28512846
} else {
28522847
$body_stmts[] = new \PhpParser\Node\Stmt\Return_($eval);
28532848
}

tests/unit/Badoo/fixtures/expected/php81.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,28 @@ public function __construct(public readonly \One&\Three $typeIntersection, prote
2828

2929

3030

31-
public function testStoppingProgramFlow(){if (isset(\Badoo\SoftMocks::$mocks_by_name[__FUNCTION__]) && false !== $__softmocksvariableforcode = \Badoo\SoftMocks::isMocked(testThings::class, static::class, __FUNCTION__)) {$mm_func_args = func_get_args();$params = [];$variadic_params_idx = '';return eval($__softmocksvariableforcode);/** @codeCoverageIgnore */}
31+
public function testStoppingProgramFlowWithExit() : never{if (isset(\Badoo\SoftMocks::$mocks_by_name[__FUNCTION__]) && false !== $__softmocksvariableforcode = \Badoo\SoftMocks::isMocked(testThings::class, static::class, __FUNCTION__)) {$mm_func_args = func_get_args();$params = [];$variadic_params_idx = '';eval($__softmocksvariableforcode);/** @codeCoverageIgnore */}
3232

3333
$value = 1 + 2;
3434

3535
\Badoo\SoftMocks::callExit(666);}
3636

3737

38+
/**
39+
* @throws Exception
40+
*/
41+
public function testStoppingProgramFlowWithException() : never{if (isset(\Badoo\SoftMocks::$mocks_by_name[__FUNCTION__]) && false !== $__softmocksvariableforcode = \Badoo\SoftMocks::isMocked(testThings::class, static::class, __FUNCTION__)) {$mm_func_args = func_get_args();$params = [];$variadic_params_idx = '';eval($__softmocksvariableforcode);/** @codeCoverageIgnore */}
42+
43+
$value = 1 + 2;
44+
45+
throw new \Exception('Some exception');}
46+
47+
3848
public function testMakeFunctionClosureWithSpreadOperator(\One&\Three $typeIntersection) : void{if (isset(\Badoo\SoftMocks::$mocks_by_name[__FUNCTION__]) && false !== $__softmocksvariableforcode = \Badoo\SoftMocks::isMocked(testThings::class, static::class, __FUNCTION__)) {$mm_func_args = func_get_args();$params = [$typeIntersection];$variadic_params_idx = '';eval($__softmocksvariableforcode);return;/** @codeCoverageIgnore */}
3949

4050
$closureOne = isset(\Badoo\SoftMocks::$func_mocks_by_name['array_merge']) ? fn() => \Badoo\SoftMocks::callFunction('', 'array_merge', \func_get_args()) : \array_merge(...);
4151
$closureTwo = isset(\Badoo\SoftMocks::$func_mocks_by_name['something']) ? fn() => \Badoo\SoftMocks::callFunction('', 'something', \func_get_args()) : \something(...);
42-
$closureThree = $this->testStoppingProgramFlow(...);
52+
$closureThree = $this->testStoppingProgramFlowWithExit(...);
4353

4454
\Badoo\SoftMocks::call(__NAMESPACE__, $closureOne, [['will'], ['be'], ['merged'], ['some new octal notation:', 016, 033]]);
4555
\Badoo\SoftMocks::call(__NAMESPACE__, $closureTwo, [&$typeIntersection, &$typeIntersection]);}}
@@ -50,6 +60,11 @@ function testTypeIntersectionInFunction(\One&\Three $typeIntersection){}
5060

5161

5262

53-
function neverReturns(){
63+
function neverReturnsWithExit() : never{
5464

5565
\Badoo\SoftMocks::callExit(111);}
66+
67+
68+
function neverReturnsWithException() : never{
69+
70+
throw new \RuntimeException('Some runtime exception');}

tests/unit/Badoo/fixtures/original/php81.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,28 @@ public function __construct(
2828
) {
2929
}
3030

31-
public function testStoppingProgramFlow(): never
31+
public function testStoppingProgramFlowWithExit(): never
3232
{
3333
$value = 1 + 2;
3434

3535
exit(666);
3636
}
3737

38+
/**
39+
* @throws Exception
40+
*/
41+
public function testStoppingProgramFlowWithException(): never
42+
{
43+
$value = 1 + 2;
44+
45+
throw new \Exception('Some exception');
46+
}
47+
3848
public function testMakeFunctionClosureWithSpreadOperator(One & Three $typeIntersection): void
3949
{
4050
$closureOne = array_merge(...);
4151
$closureTwo = something(...);
42-
$closureThree = $this->testStoppingProgramFlow(...);
52+
$closureThree = $this->testStoppingProgramFlowWithExit(...);
4353

4454
$closureOne(['will'], ['be'], ['merged'], ['some new octal notation:', 0o16, 0O33]);
4555
$closureTwo($typeIntersection, $typeIntersection);
@@ -50,7 +60,12 @@ function testTypeIntersectionInFunction(One & Three $typeIntersection)
5060
{
5161
}
5262

53-
function neverReturns(): never
63+
function neverReturnsWithExit(): never
5464
{
5565
exit(111);
5666
}
67+
68+
function neverReturnsWithException(): never
69+
{
70+
throw new \RuntimeException('Some runtime exception');
71+
}

0 commit comments

Comments
 (0)