Skip to content

Commit 6b63e9b

Browse files
authored
add implicit method call support (#581)
* add implicit method call support * cs * cs
1 parent 278b4a8 commit 6b63e9b

File tree

5 files changed

+107
-21
lines changed

5 files changed

+107
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Fixture;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Source\SomeClassWithMethodCall;
9+
10+
final class AssertMethodCallTrue extends TestCase
11+
{
12+
public function test()
13+
{
14+
$someMock = $this->getMockBuilder('AnyType')->getMock();
15+
16+
$someMock->expects($this->any())
17+
->method('trans')
18+
->with($this->callback(fn ($arg) => $arg instanceof SomeClassWithMethodCall && $arg->isReady()));
19+
}
20+
}
21+
22+
?>
23+
-----
24+
<?php
25+
26+
declare(strict_types=1);
27+
28+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Fixture;
29+
30+
use PHPUnit\Framework\TestCase;
31+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Source\SomeClassWithMethodCall;
32+
33+
final class AssertMethodCallTrue extends TestCase
34+
{
35+
public function test()
36+
{
37+
$someMock = $this->getMockBuilder('AnyType')->getMock();
38+
39+
$someMock->expects($this->any())
40+
->method('trans')
41+
->with($this->callback(function ($arg): bool {
42+
$this->assertInstanceOf(\Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Source\SomeClassWithMethodCall::class, $arg);
43+
$this->assertTrue($arg->isReady());
44+
return true;
45+
}));
46+
}
47+
}
48+
49+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector\Source;
4+
5+
final class SomeClassWithMethodCall
6+
{
7+
public function isReady(): bool
8+
{
9+
return mt_rand(0, 1) === 1;
10+
}
11+
}

rules/CodeQuality/NodeAnalyser/ClosureUsesResolver.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,7 @@ public function resolveFromArrowFunction(ArrowFunction $arrowFunction): array
5151
$externalVariableNames = array_unique($externalVariableNames);
5252
$externalVariableNames = array_diff($externalVariableNames, ['this']);
5353

54-
$closureUses = [];
55-
foreach ($externalVariableNames as $externalVariableName) {
56-
$closureUses[] = new ClosureUse(new Variable($externalVariableName));
57-
}
58-
59-
return $closureUses;
54+
return $this->createClosureUses($externalVariableNames);
6055
}
6156

6257
/**
@@ -71,4 +66,18 @@ private function resolveParamNames(ArrowFunction $arrowFunction): array
7166

7267
return $paramNames;
7368
}
69+
70+
/**
71+
* @param string[] $externalVariableNames
72+
* @return ClosureUse[]
73+
*/
74+
private function createClosureUses(array $externalVariableNames): array
75+
{
76+
$closureUses = [];
77+
foreach ($externalVariableNames as $externalVariableName) {
78+
$closureUses[] = new ClosureUse(new Variable($externalVariableName));
79+
}
80+
81+
return $closureUses;
82+
}
7483
}

rules/CodeQuality/NodeFactory/FromBinaryAndAssertExpressionsFactory.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PhpParser\Node\Expr\FuncCall;
1313
use PhpParser\Node\Expr\Instanceof_;
1414
use PhpParser\Node\Expr\Isset_;
15+
use PhpParser\Node\Expr\MethodCall;
1516
use PhpParser\Node\Name;
1617
use PhpParser\Node\Name\FullyQualified;
1718
use PhpParser\Node\Scalar\Int_;
@@ -37,6 +38,13 @@ public function create(array $exprs): array
3738
$assertMethodCalls = [];
3839

3940
foreach ($exprs as $expr) {
41+
// implicit bool compare
42+
if ($expr instanceof MethodCall) {
43+
$assertMethodCalls[] = $this->nodeFactory->createMethodCall('this', 'assertTrue', [$expr]);
44+
45+
continue;
46+
}
47+
4048
if ($expr instanceof FuncCall && $this->nodeNameResolver->isName($expr, 'array_key_exists')) {
4149
$variableExpr = $expr->getArgs()[1]
4250
->value;

rules/CodeQuality/Rector/MethodCall/WithCallbackIdenticalToStandaloneAssertsRector.php

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,34 +125,24 @@ public function refactor(Node $node): MethodCall|null
125125
continue;
126126
}
127127

128-
$assertExpressions = $this->fromBinaryAndAssertExpressionsFactory->create($joinedExprs);
129-
if ($assertExpressions === []) {
128+
$assertExprStmts = $this->fromBinaryAndAssertExpressionsFactory->create($joinedExprs);
129+
if ($assertExprStmts === []) {
130130
continue;
131131
}
132132

133133
$nonReturnCallbackStmts = $this->resolveNonReturnCallbackStmts($argAndFunctionLike);
134134

135135
// last si return true;
136-
$assertExpressions[] = new Return_($this->nodeFactory->createTrue());
137-
136+
$assertExprStmts[] = new Return_($this->nodeFactory->createTrue());
138137
$innerFunctionLike = $argAndFunctionLike->getFunctionLike();
139138

140139
if ($innerFunctionLike instanceof Closure) {
141-
$innerFunctionLike->stmts = array_merge($nonReturnCallbackStmts, $assertExpressions);
140+
$innerFunctionLike->stmts = array_merge($nonReturnCallbackStmts, $assertExprStmts);
142141
} else {
143142
// arrow function -> flip to closure
144143
$functionLikeInArg = $argAndFunctionLike->getArg();
145144

146-
$externalVariables = $this->closureUsesResolver->resolveFromArrowFunction($innerFunctionLike);
147-
148-
$closure = new Closure([
149-
'params' => $argAndFunctionLike->getFunctionLike()
150-
->params,
151-
'stmts' => $assertExpressions,
152-
'returnType' => new Identifier('bool'),
153-
'uses' => $externalVariables,
154-
]);
155-
145+
$closure = $this->createClosure($innerFunctionLike, $argAndFunctionLike, $assertExprStmts);
156146
$functionLikeInArg->value = $closure;
157147
}
158148

@@ -273,4 +263,23 @@ private function resolveNonReturnCallbackStmts(ArgAndFunctionLike $argAndFunctio
273263

274264
return [];
275265
}
266+
267+
/**
268+
* @param Stmt[] $assertExprStmts
269+
*/
270+
private function createClosure(
271+
ArrowFunction $arrowFunction,
272+
ArgAndFunctionLike $argAndFunctionLike,
273+
array $assertExprStmts
274+
): Closure {
275+
$externalVariables = $this->closureUsesResolver->resolveFromArrowFunction($arrowFunction);
276+
277+
return new Closure([
278+
'params' => $argAndFunctionLike->getFunctionLike()
279+
->params,
280+
'stmts' => $assertExprStmts,
281+
'returnType' => new Identifier('bool'),
282+
'uses' => $externalVariables,
283+
]);
284+
}
276285
}

0 commit comments

Comments
 (0)