Skip to content

Commit b05ac84

Browse files
authored
[depre] Deprecate CreateMockToAnonymousClassRector as requires manual work, often value object setter can be better alternative (#562)
1 parent aa18e4c commit b05ac84

File tree

6 files changed

+7
-337
lines changed

6 files changed

+7
-337
lines changed

rules-tests/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector/CreateMockToAnonymousClassRectorTest.php

Lines changed: 0 additions & 28 deletions
This file was deleted.

rules-tests/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector/Fixture/mocked_more_methods.php.inc

Lines changed: 0 additions & 49 deletions
This file was deleted.

rules-tests/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector/Fixture/skip_with_args.php.inc

Lines changed: 0 additions & 20 deletions
This file was deleted.

rules-tests/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector/Fixture/some_class.php.inc

Lines changed: 0 additions & 42 deletions
This file was deleted.

rules-tests/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector/config/configured_rule.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

rules/CodeQuality/Rector/ClassMethod/CreateMockToAnonymousClassRector.php

Lines changed: 7 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,19 @@
44

55
namespace Rector\PHPUnit\CodeQuality\Rector\ClassMethod;
66

7-
use PhpParser\Modifiers;
87
use PhpParser\Node;
9-
use PhpParser\Node\Arg;
10-
use PhpParser\Node\Expr;
11-
use PhpParser\Node\Expr\Array_;
12-
use PhpParser\Node\Expr\Assign;
13-
use PhpParser\Node\Expr\ClassConstFetch;
14-
use PhpParser\Node\Expr\MethodCall;
15-
use PhpParser\Node\Expr\New_;
16-
use PhpParser\Node\Name;
17-
use PhpParser\Node\Scalar;
18-
use PhpParser\Node\Scalar\String_;
19-
use PhpParser\Node\Stmt;
20-
use PhpParser\Node\Stmt\Class_;
218
use PhpParser\Node\Stmt\ClassMethod;
22-
use PhpParser\Node\Stmt\Expression;
23-
use PhpParser\Node\Stmt\Return_;
24-
use Rector\Exception\NotImplementedYetException;
9+
use Rector\Configuration\Deprecation\Contract\DeprecatedInterface;
2510
use Rector\Exception\ShouldNotHappenException;
26-
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
2711
use Rector\Rector\AbstractRector;
2812
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2913
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
3014

3115
/**
32-
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\CreateMockToAnonymousClassRector\CreateMockToAnonymousClassRectorTest
16+
* @deprecated as this rule works only sometimes. It requires manual check, as value object can be better solution.
3317
*/
34-
final class CreateMockToAnonymousClassRector extends AbstractRector
18+
final class CreateMockToAnonymousClassRector extends AbstractRector implements DeprecatedInterface
3519
{
36-
public function __construct(
37-
private readonly TestsNodeAnalyzer $testsNodeAnalyzer
38-
) {
39-
}
40-
4120
public function getRuleDefinition(): RuleDefinition
4221
{
4322
return new RuleDefinition('Change $this->createMock() with methods to direct anonymous class', [
@@ -91,169 +70,9 @@ public function getNodeTypes(): array
9170
*/
9271
public function refactor(Node $node): ?Node
9372
{
94-
if (! $this->testsNodeAnalyzer->isInTestClass($node)) {
95-
return null;
96-
}
97-
98-
if ($node->stmts === []) {
99-
return null;
100-
}
101-
102-
$anonymousClassPosition = null;
103-
$anonymousClass = null;
104-
$mockExpr = null;
105-
106-
$hasDynamicReturnExprs = false;
107-
108-
$anonymousClassMethods = [];
109-
$createMockMethodCallAssign = null;
110-
111-
foreach ((array) $node->stmts as $key => $classMethodStmt) {
112-
if ($mockExpr instanceof Expr) {
113-
// possible call on mock expr
114-
if ($classMethodStmt instanceof Expression && $classMethodStmt->expr instanceof MethodCall) {
115-
$methodCall = $classMethodStmt->expr;
116-
117-
$rootMethodCall = $methodCall;
118-
while ($rootMethodCall->var instanceof MethodCall) {
119-
$rootMethodCall = $rootMethodCall->var;
120-
}
121-
122-
if (! $this->nodeComparator->areNodesEqual($rootMethodCall->var, $mockExpr)) {
123-
continue;
124-
}
125-
126-
if (! $this->isName($rootMethodCall->name, 'method')) {
127-
continue;
128-
}
129-
130-
if ($methodCall->isFirstClassCallable()) {
131-
continue;
132-
}
133-
134-
// has dynamic return?
135-
if ($hasDynamicReturnExprs === false) {
136-
$returnedExpr = $methodCall->getArgs()[0]
137-
->value;
138-
$hasDynamicReturnExprs = ! $returnedExpr instanceof Scalar && ! $returnedExpr instanceof Array_;
139-
}
140-
141-
$anonymousClassMethods[$key] = $this->createMockedClassMethod($rootMethodCall, $methodCall);
142-
}
143-
144-
continue;
145-
}
146-
147-
$createMockMethodCallAssign = $this->matchCreateMockAssign($classMethodStmt);
148-
if (! $createMockMethodCallAssign instanceof Assign) {
149-
continue;
150-
}
151-
152-
// change to anonymous class
153-
/** @var MethodCall $methodCall */
154-
$methodCall = $createMockMethodCallAssign->expr;
155-
156-
if ($methodCall->isFirstClassCallable()) {
157-
continue;
158-
}
159-
160-
$firstArg = $methodCall->getArgs()[0];
161-
162-
$mockExpr = $createMockMethodCallAssign->var;
163-
164-
$anonymousClass = $this->createAnonymousClass($firstArg);
165-
$anonymousClassPosition = $key;
166-
}
167-
168-
if ($anonymousClassPosition === null) {
169-
return null;
170-
}
171-
172-
if (! $anonymousClass instanceof Class_) {
173-
return null;
174-
}
175-
176-
if ($hasDynamicReturnExprs) {
177-
return null;
178-
}
179-
180-
foreach ($anonymousClassMethods as $keyToRemove => $anonymousClassMethod) {
181-
unset($node->stmts[$keyToRemove]);
182-
$anonymousClass->stmts[] = $anonymousClassMethod;
183-
}
184-
185-
if (! $createMockMethodCallAssign instanceof Assign) {
186-
throw new ShouldNotHappenException();
187-
}
188-
189-
$new = new New_($anonymousClass);
190-
$newAnonymousClassAssign = new Assign($createMockMethodCallAssign->var, $new);
191-
$node->stmts[$anonymousClassPosition] = new Expression($newAnonymousClassAssign);
192-
193-
return $node;
194-
}
195-
196-
private function createAnonymousClass(Arg $firstArg): Class_
197-
{
198-
if ($firstArg->value instanceof ClassConstFetch) {
199-
$className = $firstArg->value->class;
200-
} else {
201-
throw new NotImplementedYetException();
202-
}
203-
204-
if (! $className instanceof Name) {
205-
throw new NotImplementedYetException();
206-
}
207-
208-
// must respect PHPStan anonymous internal naming \Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver::ANONYMOUS_CLASS_START_REGEX
209-
return new Class_('AnonymousClass1234', [
210-
'extends' => $className,
211-
], [
212-
'startLine' => $firstArg->getStartLine(),
213-
'endLine' => $firstArg->getEndLine(),
214-
]);
215-
}
216-
217-
private function matchCreateMockAssign(Stmt $stmt): ?Assign
218-
{
219-
if (! $stmt instanceof Expression) {
220-
return null;
221-
}
222-
223-
if (! $stmt->expr instanceof Assign) {
224-
return null;
225-
}
226-
227-
// assign method call to variable
228-
$assign = $stmt->expr;
229-
if (! $assign->expr instanceof MethodCall) {
230-
return null;
231-
}
232-
233-
if (! $this->isName($assign->expr->name, 'createMock')) {
234-
return null;
235-
}
236-
237-
return $assign;
238-
}
239-
240-
private function createMockedClassMethod(MethodCall $rootMethodCall, MethodCall $methodCall): ClassMethod
241-
{
242-
$rootMethodCallFirstArg = $rootMethodCall->getArgs()[0];
243-
244-
$methodNameExpr = $rootMethodCallFirstArg->value;
245-
if ($methodNameExpr instanceof String_) {
246-
$methodName = $methodNameExpr->value;
247-
} else {
248-
throw new NotImplementedYetException();
249-
}
250-
251-
$returnedExpr = $methodCall->getArgs()[0]
252-
->value;
253-
254-
return new ClassMethod($methodName, [
255-
'flags' => Modifiers::PUBLIC,
256-
'stmts' => [new Return_($returnedExpr)],
257-
]);
73+
throw new ShouldNotHappenException(sprintf(
74+
'"%s" rule is deprecated, as works only sometimes. It requires manual check, as value object can be better solution.',
75+
self::class
76+
));
25877
}
25978
}

0 commit comments

Comments
 (0)