66
77use PhpParser \Node ;
88use PhpParser \Node \ArrayItem ;
9+ use PhpParser \Node \Expr ;
10+ use PhpParser \Node \Expr \Assign ;
911use PhpParser \Node \Expr \MethodCall ;
1012use PhpParser \Node \Expr \New_ ;
1113use PhpParser \Node \Expr \StaticCall ;
1214use PhpParser \Node \Identifier ;
15+ use PhpParser \Node \Stmt \ClassMethod ;
16+ use PhpParser \Node \Stmt \Expression ;
1317use Rector \PHPStan \ScopeFetcher ;
18+ use Rector \PHPUnit \CodeQuality \NodeAnalyser \MockObjectExprDetector ;
1419use Rector \PHPUnit \Enum \PHPUnitClassName ;
20+ use Rector \PHPUnit \NodeAnalyzer \TestsNodeAnalyzer ;
1521use Rector \Rector \AbstractRector ;
1622use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
1723use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
2329 */
2430final class CreateStubOverCreateMockArgRector extends AbstractRector
2531{
32+ public function __construct (
33+ private readonly TestsNodeAnalyzer $ testsNodeAnalyzer ,
34+ private readonly MockObjectExprDetector $ mockObjectExprDetector ,
35+ ) {
36+ }
37+
2638 public function getRuleDefinition (): RuleDefinition
2739 {
2840 return new RuleDefinition (
@@ -70,13 +82,13 @@ private function someMethod($someClass)
7082 */
7183 public function getNodeTypes (): array
7284 {
73- return [StaticCall::class, MethodCall::class, New_::class, ArrayItem::class];
85+ return [StaticCall::class, MethodCall::class, New_::class, ArrayItem::class, ClassMethod::class ];
7486 }
7587
7688 /**
77- * @param MethodCall|StaticCall|New_|ArrayItem $node
89+ * @param MethodCall|StaticCall|New_|ArrayItem|ClassMethod $node
7890 */
79- public function refactor (Node $ node ): MethodCall |StaticCall |New_ |ArrayItem |null
91+ public function refactor (Node $ node ): MethodCall |StaticCall |New_ |ArrayItem |ClassMethod | null
8092 {
8193 $ scope = ScopeFetcher ::fetch ($ node );
8294 if (! $ scope ->isInClass ()) {
@@ -88,19 +100,12 @@ public function refactor(Node $node): MethodCall|StaticCall|New_|ArrayItem|null
88100 return null ;
89101 }
90102
91- if ($ node instanceof ArrayItem) {
92- if (! $ node ->value instanceof MethodCall) {
93- return null ;
94- }
95-
96- $ methodCall = $ node ->value ;
97- if (! $ this ->isName ($ methodCall ->name , 'createMock ' )) {
98- return null ;
99- }
100-
101- $ methodCall ->name = new Identifier ('createStub ' );
103+ if ($ node instanceof ClassMethod) {
104+ return $ this ->refactorClassMethod ($ node );
105+ }
102106
103- return $ node ;
107+ if ($ node instanceof ArrayItem) {
108+ return $ this ->refactorArrayItem ($ node );
104109 }
105110
106111 $ hasChanges = false ;
@@ -129,4 +134,72 @@ public function refactor(Node $node): MethodCall|StaticCall|New_|ArrayItem|null
129134
130135 return null ;
131136 }
137+
138+ private function matchCreateMockMethodCall (Expr $ expr ): null |MethodCall
139+ {
140+ if (! $ expr instanceof MethodCall) {
141+ return null ;
142+ }
143+
144+ if (! $ this ->isName ($ expr ->name , 'createMock ' )) {
145+ return null ;
146+ }
147+
148+ return $ expr ;
149+ }
150+
151+ private function refactorClassMethod (ClassMethod $ classMethod ): ?ClassMethod
152+ {
153+ if (! $ this ->testsNodeAnalyzer ->isTestClassMethod ($ classMethod )) {
154+ return null ;
155+ }
156+
157+ $ hasChanged = false ;
158+ foreach ((array ) $ classMethod ->stmts as $ stmt ) {
159+ if (! $ stmt instanceof Expression) {
160+ continue ;
161+ }
162+
163+ if (! $ stmt ->expr instanceof Assign) {
164+ continue ;
165+ }
166+
167+ $ assign = $ stmt ->expr ;
168+ $ createMockMethodCall = $ this ->matchCreateMockMethodCall ($ assign ->expr );
169+
170+ if (! $ createMockMethodCall instanceof MethodCall) {
171+ continue ;
172+ }
173+
174+ // no change, as we use the variable for mocking later
175+ if ($ this ->mockObjectExprDetector ->isUsedForMocking ($ assign ->var , $ classMethod )) {
176+ continue ;
177+ }
178+
179+ $ createMockMethodCall ->name = new Identifier ('createStub ' );
180+ $ hasChanged = true ;
181+ }
182+
183+ if ($ hasChanged ) {
184+ return $ classMethod ;
185+ }
186+
187+ return null ;
188+ }
189+
190+ private function refactorArrayItem (ArrayItem $ arrayItem ): ?ArrayItem
191+ {
192+ if (! $ arrayItem ->value instanceof MethodCall) {
193+ return null ;
194+ }
195+
196+ $ methodCall = $ arrayItem ->value ;
197+ if (! $ this ->isName ($ methodCall ->name , 'createMock ' )) {
198+ return null ;
199+ }
200+
201+ $ methodCall ->name = new Identifier ('createStub ' );
202+
203+ return $ arrayItem ;
204+ }
132205}
0 commit comments