|
4 | 4 |
|
5 | 5 | namespace Rector\PHPUnit\CodeQuality\Rector\ClassMethod; |
6 | 6 |
|
7 | | -use PhpParser\Modifiers; |
8 | 7 | 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_; |
21 | 8 | 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; |
25 | 10 | use Rector\Exception\ShouldNotHappenException; |
26 | | -use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; |
27 | 11 | use Rector\Rector\AbstractRector; |
28 | 12 | use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; |
29 | 13 | use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; |
30 | 14 |
|
31 | 15 | /** |
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. |
33 | 17 | */ |
34 | | -final class CreateMockToAnonymousClassRector extends AbstractRector |
| 18 | +final class CreateMockToAnonymousClassRector extends AbstractRector implements DeprecatedInterface |
35 | 19 | { |
36 | | - public function __construct( |
37 | | - private readonly TestsNodeAnalyzer $testsNodeAnalyzer |
38 | | - ) { |
39 | | - } |
40 | | - |
41 | 20 | public function getRuleDefinition(): RuleDefinition |
42 | 21 | { |
43 | 22 | return new RuleDefinition('Change $this->createMock() with methods to direct anonymous class', [ |
@@ -91,169 +70,9 @@ public function getNodeTypes(): array |
91 | 70 | */ |
92 | 71 | public function refactor(Node $node): ?Node |
93 | 72 | { |
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 | + )); |
258 | 77 | } |
259 | 78 | } |
0 commit comments