@@ -192,8 +192,7 @@ private function loadMethodBodies(\ReflectionClass $from): array
192
192
foreach ($ nodeFinder ->findInstanceOf ($ class , Node \Stmt \ClassMethod::class) as $ method ) {
193
193
/** @var Node\Stmt\ClassMethod $method */
194
194
if ($ method ->stmts ) {
195
- $ start = $ method ->stmts [0 ]->getAttribute ('startFilePos ' );
196
- $ body = substr ($ code , $ start , end ($ method ->stmts )->getAttribute ('endFilePos ' ) - $ start + 1 );
195
+ $ body = $ this ->extractBody ($ nodeFinder , $ code , $ method ->stmts );
197
196
$ bodies [$ method ->name ->toString ()] = Helpers::indentPhp ($ body , -2 );
198
197
}
199
198
}
@@ -208,17 +207,60 @@ private function loadFunctionBody(\ReflectionFunction $from): string
208
207
}
209
208
210
209
[$ code , $ stmts ] = $ this ->parse ($ from );
210
+
211
+ $ nodeFinder = new PhpParser \NodeFinder ;
211
212
/** @var Node\Stmt\Function_ $function */
212
- $ function = ( new PhpParser \ NodeFinder ) ->findFirst ($ stmts , function (Node $ node ) use ($ from ) {
213
+ $ function = $ nodeFinder ->findFirst ($ stmts , function (Node $ node ) use ($ from ) {
213
214
return $ node instanceof Node \Stmt \Function_ && $ node ->namespacedName ->toString () === $ from ->name ;
214
215
});
215
216
216
- $ start = $ function ->stmts [0 ]->getAttribute ('startFilePos ' );
217
- $ body = substr ($ code , $ start , end ($ function ->stmts )->getAttribute ('endFilePos ' ) - $ start + 1 );
217
+ $ body = $ this ->extractBody ($ nodeFinder , $ code , $ function ->stmts );
218
218
return Helpers::indentPhp ($ body , -1 );
219
219
}
220
220
221
221
222
+ /**
223
+ * @param Node[] $statements
224
+ */
225
+ private function extractBody (PhpParser \NodeFinder $ nodeFinder , string $ originalCode , array $ statements ): string
226
+ {
227
+ $ start = $ statements [0 ]->getAttribute ('startFilePos ' );
228
+ $ body = substr ($ originalCode , $ start , end ($ statements )->getAttribute ('endFilePos ' ) - $ start + 1 );
229
+
230
+ $ replacements = [];
231
+ // name-nodes => resolved fully-qualified name
232
+ foreach ($ nodeFinder ->findInstanceOf ($ statements , Node \Name::class) as $ node ) {
233
+ if ($ node ->hasAttribute ('resolvedName ' )
234
+ && $ node ->getAttribute ('resolvedName ' ) instanceof Node \Name \FullyQualified
235
+ ) {
236
+ $ replacements [] = [
237
+ $ node ->getStartFilePos (),
238
+ $ node ->getEndFilePos (),
239
+ $ node ->getAttribute ('resolvedName ' )->toCodeString (),
240
+ ];
241
+ }
242
+ }
243
+
244
+ //sort collected resolved names by position in file
245
+ usort ($ replacements , function ($ a , $ b ) {
246
+ return $ a [0 ] <=> $ b [0 ];
247
+ });
248
+ $ correctiveOffset = -$ start ;
249
+ //replace changes body length so we need correct offset
250
+ foreach ($ replacements as [$ startPos , $ endPos , $ replacement ]) {
251
+ $ replacingStringLength = $ endPos - $ startPos + 1 ;
252
+ $ body = substr_replace (
253
+ $ body ,
254
+ $ replacement ,
255
+ $ correctiveOffset + $ startPos ,
256
+ $ replacingStringLength
257
+ );
258
+ $ correctiveOffset += strlen ($ replacement ) - $ replacingStringLength ;
259
+ }
260
+ return $ body ;
261
+ }
262
+
263
+
222
264
private function parse ($ from ): array
223
265
{
224
266
$ file = $ from ->getFileName ();
@@ -235,7 +277,7 @@ private function parse($from): array
235
277
$ stmts = $ parser ->parse ($ code );
236
278
237
279
$ traverser = new PhpParser \NodeTraverser ;
238
- $ traverser ->addVisitor (new PhpParser \NodeVisitor \NameResolver );
280
+ $ traverser ->addVisitor (new PhpParser \NodeVisitor \NameResolver ( null , [ ' replaceNodes ' => false ]) );
239
281
$ stmts = $ traverser ->traverse ($ stmts );
240
282
241
283
return [$ code , $ stmts ];
0 commit comments