@@ -62,8 +62,7 @@ public function extractMethodBodies(string $className): array
62
62
foreach ($ nodeFinder ->findInstanceOf ($ classNode , Node \Stmt \ClassMethod::class) as $ methodNode ) {
63
63
/** @var Node\Stmt\ClassMethod $methodNode */
64
64
if ($ methodNode ->stmts ) {
65
- $ body = $ this ->extractBody ($ nodeFinder , $ methodNode ->stmts );
66
- $ res [$ methodNode ->name ->toString ()] = Helpers::unindent ($ body , 2 );
65
+ $ res [$ methodNode ->name ->toString ()] = $ this ->getReformattedBody ($ methodNode ->stmts , 2 );
67
66
}
68
67
}
69
68
return $ res ;
@@ -72,34 +71,38 @@ public function extractMethodBodies(string $className): array
72
71
73
72
public function extractFunctionBody (string $ name ): ?string
74
73
{
75
- $ nodeFinder = new NodeFinder ;
76
- /** @var Node\Stmt\Function_ $functionNode */
77
- $ functionNode = $ nodeFinder ->findFirst ($ this ->statements , function (Node $ node ) use ($ name ) {
74
+ $ functionNode = (new NodeFinder )->findFirst ($ this ->statements , function (Node $ node ) use ($ name ) {
78
75
return $ node instanceof Node \Stmt \Function_ && $ node ->namespacedName ->toString () === $ name ;
79
76
});
80
77
81
- $ body = $ this ->extractBody ($ nodeFinder , $ functionNode ->stmts );
82
- return Helpers::unindent ($ body , 1 );
78
+ return $ this ->getReformattedBody ($ functionNode ->stmts , 1 );
83
79
}
84
80
85
81
86
- /**
87
- * @param Node[] $statements
88
- */
89
- private function extractBody (NodeFinder $ nodeFinder , array $ statements ): string
82
+ /** @param Node[] $statements */
83
+ private function getReformattedBody (array $ statements , int $ level ): string
90
84
{
91
- $ start = $ statements [0 ]->getAttribute ('startFilePos ' );
92
- $ body = substr ($ this ->code , $ start , end ($ statements )->getAttribute ('endFilePos ' ) - $ start + 1 );
85
+ $ replacements = $ this ->prepareReplacements ($ statements );
86
+ $ body = $ this ->getNodeContents (...$ statements );
87
+ $ body = $ this ->performReplacements ($ body , $ replacements );
88
+ return Helpers::unindent ($ body , $ level );
89
+ }
93
90
91
+
92
+ private function prepareReplacements (array $ statements ): array
93
+ {
94
+ $ start = $ statements [0 ]->getStartFilePos ();
94
95
$ replacements = [];
96
+ $ nodeFinder = new NodeFinder ;
97
+
95
98
// name-nodes => resolved fully-qualified name
96
99
foreach ($ nodeFinder ->findInstanceOf ($ statements , Node \Name::class) as $ node ) {
97
100
if ($ node ->hasAttribute ('resolvedName ' )
98
101
&& $ node ->getAttribute ('resolvedName ' ) instanceof Node \Name \FullyQualified
99
102
) {
100
103
$ replacements [] = [
101
- $ node ->getStartFilePos (),
102
- $ node ->getEndFilePos (),
104
+ $ node ->getStartFilePos () - $ start ,
105
+ $ node ->getEndFilePos () - $ start ,
103
106
$ node ->getAttribute ('resolvedName ' )->toCodeString (),
104
107
];
105
108
}
@@ -111,12 +114,12 @@ private function extractBody(NodeFinder $nodeFinder, array $statements): string
111
114
$ nodeFinder ->findInstanceOf ($ statements , Node \Scalar \EncapsedStringPart::class)
112
115
) as $ node ) {
113
116
/** @var Node\Scalar\String_|Node\Scalar\EncapsedStringPart $node */
114
- $ token = substr ( $ body , $ node -> getStartFilePos () - $ start , $ node-> getEndFilePos () - $ node -> getStartFilePos () + 1 );
117
+ $ token = $ this -> getNodeContents ( $ node );
115
118
if (strpos ($ token , "\n" ) !== false ) {
116
119
$ quote = $ node instanceof Node \Scalar \String_ ? '" ' : '' ;
117
120
$ replacements [] = [
118
- $ node ->getStartFilePos (),
119
- $ node ->getEndFilePos (),
121
+ $ node ->getStartFilePos () - $ start ,
122
+ $ node ->getEndFilePos () - $ start ,
120
123
$ quote . addcslashes ($ node ->value , "\x00.. \x1F" ) . $ quote ,
121
124
];
122
125
}
@@ -127,34 +130,46 @@ private function extractBody(NodeFinder $nodeFinder, array $statements): string
127
130
/** @var Node\Scalar\Encapsed $node */
128
131
if ($ node ->getAttribute ('kind ' ) === Node \Scalar \String_::KIND_HEREDOC ) {
129
132
$ replacements [] = [
130
- $ node ->getStartFilePos (),
131
- $ node ->parts [0 ]->getStartFilePos () - 1 ,
133
+ $ node ->getStartFilePos () - $ start ,
134
+ $ node ->parts [0 ]->getStartFilePos () - $ start - 1 ,
132
135
'" ' ,
133
136
];
134
137
$ replacements [] = [
135
- end ($ node ->parts )->getEndFilePos () + 1 ,
136
- $ node ->getEndFilePos (),
138
+ end ($ node ->parts )->getEndFilePos () - $ start + 1 ,
139
+ $ node ->getEndFilePos () - $ start ,
137
140
'" ' ,
138
141
];
139
142
}
140
143
}
141
144
142
- //sort collected resolved names by position in file
143
- usort ($ replacements , function ($ a , $ b ) {
145
+ return $ replacements ;
146
+ }
147
+
148
+
149
+ private function performReplacements (string $ s , array $ replacements ): string
150
+ {
151
+ usort ($ replacements , function ($ a , $ b ) { // sort by position in file
144
152
return $ a [0 ] <=> $ b [0 ];
145
153
});
146
- $ correctiveOffset = - $ start ;
147
- //replace changes body length so we need correct offset
148
- foreach ($ replacements as [$ startPos , $ endPos , $ replacement ]) {
149
- $ replacingStringLength = $ endPos - $ startPos + 1 ;
150
- $ body = substr_replace (
151
- $ body ,
154
+
155
+ $ correctiveOffset = 0 ;
156
+ foreach ($ replacements as [$ start , $ end , $ replacement ]) {
157
+ $ replacingStringLength = $ end - $ start + 1 ;
158
+ $ s = substr_replace (
159
+ $ s ,
152
160
$ replacement ,
153
- $ correctiveOffset + $ startPos ,
161
+ $ correctiveOffset + $ start ,
154
162
$ replacingStringLength
155
163
);
156
164
$ correctiveOffset += strlen ($ replacement ) - $ replacingStringLength ;
157
165
}
158
- return $ body ;
166
+ return $ s ;
167
+ }
168
+
169
+
170
+ private function getNodeContents (Node ...$ nodes ): string
171
+ {
172
+ $ start = $ nodes [0 ]->getStartFilePos ();
173
+ return substr ($ this ->code , $ start , end ($ nodes )->getEndFilePos () - $ start + 1 );
159
174
}
160
175
}
0 commit comments